fix: Char namedtuple save/restore — use blink not width, construct new Char objects

pyte.screens.Char is a namedtuple (immutable), so fields can't be
mutated directly. Also 'width' doesn't exist — the correct field is
'blink'. Now creates new Char(...) objects for buffer restoration.
Fixes server switching being completely broken (AttributeError on save).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chrome-storm-c442
2026-02-24 03:25:36 -05:00
parent afa75b6d9c
commit 4b505f39d1
2 changed files with 12 additions and 11 deletions

View File

@@ -364,6 +364,7 @@ class TerminalWidget(tk.Frame):
def get_current_buffer(self) -> bytes: def get_current_buffer(self) -> bytes:
"""Export full pyte screen state as serialized data for session pool.""" """Export full pyte screen state as serialized data for session pool."""
import pickle import pickle
from pyte.screens import Char
screen_state = { screen_state = {
'buffer': {}, 'buffer': {},
@@ -380,11 +381,12 @@ class TerminalWidget(tk.Frame):
line_dict = {} line_dict = {}
for x in range(self._screen.columns): for x in range(self._screen.columns):
c = self._screen.buffer[y][x] c = self._screen.buffer[y][x]
# Char is a namedtuple — store all fields
line_dict[x] = { line_dict[x] = {
'data': c.data, 'fg': c.fg, 'bg': c.bg, 'data': c.data, 'fg': c.fg, 'bg': c.bg,
'bold': c.bold, 'italics': c.italics, 'bold': c.bold, 'italics': c.italics,
'underscore': c.underscore, 'reverse': c.reverse, 'underscore': c.underscore, 'reverse': c.reverse,
'strikethrough': c.strikethrough, 'width': c.width, 'strikethrough': c.strikethrough, 'blink': c.blink,
} }
screen_state['buffer'][y] = line_dict screen_state['buffer'][y] = line_dict
@@ -393,6 +395,7 @@ class TerminalWidget(tk.Frame):
def restore_buffer(self, buffer_data: bytes): def restore_buffer(self, buffer_data: bytes):
"""Restore full pyte screen state from serialized data.""" """Restore full pyte screen state from serialized data."""
import pickle import pickle
from pyte.screens import Char
try: try:
state = pickle.loads(buffer_data) state = pickle.loads(buffer_data)
@@ -403,22 +406,20 @@ class TerminalWidget(tk.Frame):
self._screen.reset() self._screen.reset()
self._screen.resize(rows, cols) self._screen.resize(rows, cols)
# Char is a namedtuple — must replace entire objects
for y, line_dict in state['buffer'].items(): for y, line_dict in state['buffer'].items():
if y >= self._screen.lines: if y >= self._screen.lines:
continue continue
for x, cd in line_dict.items(): for x, cd in line_dict.items():
if x >= self._screen.columns: if x >= self._screen.columns:
continue continue
ch = self._screen.buffer[y][x] self._screen.buffer[y][x] = Char(
ch.data = cd['data'] data=cd['data'], fg=cd['fg'], bg=cd['bg'],
ch.fg = cd['fg'] bold=cd['bold'], italics=cd['italics'],
ch.bg = cd['bg'] underscore=cd['underscore'], reverse=cd['reverse'],
ch.bold = cd['bold'] strikethrough=cd['strikethrough'],
ch.italics = cd['italics'] blink=cd.get('blink', False),
ch.underscore = cd['underscore'] )
ch.reverse = cd['reverse']
ch.strikethrough = cd['strikethrough']
ch.width = cd['width']
self._screen.cursor.x = state.get('cursor_x', 0) self._screen.cursor.x = state.get('cursor_x', 0)
self._screen.cursor.y = state.get('cursor_y', 0) self._screen.cursor.y = state.get('cursor_y', 0)