9.7 KiB
9.7 KiB
Terminal Audit — Plan & Status
Аудит терминала ServerManager для полной совместимости с TUI-программами (mc, vim, htop, nano, less, claude, opencode и др.) Цель: уровень MobaXterm / PuTTY
КРИТИЧНО (без этого TUI не работают)
1. [DONE v1.5.3] 256-color / truecolor рендеринг
- Файл:
gui/widgets/terminal_widget.py—_color_tag(),_make_tags() - pyte возвращает hex-строки (
"ff0000") для 256/truecolor - Старый код распознавал только 16 именованных ANSI-цветов → все остальные игнорировались
- Решение: динамическое создание тегов tkinter для любого hex-цвета с кешем (лимит 4096)
2. [DONE v1.5.3] Reverse video + strikethrough
- Файл:
gui/widgets/terminal_widget.py—_render(),_make_tags() char_data.reverseиchar_data.strikethroughне извлекались из буфера- mc/vim/htop активно используют reverse для выделения/меню
- Решение: добавлены в кортеж атрибутов, reverse swap fg/bg в
_make_tags
3. [DONE v1.5.3] Alternate screen buffer (smcup/rmcup)
- Файл:
gui/widgets/terminal_widget.py— класс_Screen - pyte 0.8.x не реализует alternate buffer (private modes 47, 1047, 1049)
- Все TUI-программы используют alternate screen → при выходе экран был мусором
- Решение: подкласс
_Screen(pyte.Screen)с_enter_alt()/_exit_alt(), сохраняет/восстанавливает buffer + cursor
4. [DONE v1.5.3] write_process_input → SSH bridge
- Файл:
gui/widgets/terminal_widget.py—_Screen.write_process_input() - pyte вызывает
write_process_input()для DA/DSR ответов (Device Attributes, Cursor Position Report) - Без этого программы зависали ожидая ответа от терминала
- Решение: переопределён метод →
_write_cb→_send()→ SSH
5. [DONE v1.5.3] Alt+key комбинации
- Файл:
gui/widgets/terminal_widget.py—_on_key() - Alt+1/2 для переключения панелей mc, Alt+B/F для readline, Alt+key для nano
- Не обрабатывались вообще
- Решение: проверка
event.state & 0x20000(Alt на Windows), отправкаESC + key
6. [DONE v1.5.3] Shift+Arrow / Ctrl+Arrow (модификаторы)
- Файл:
gui/widgets/terminal_widget.py—_on_key(),_xterm_modifier() - Ctrl+Left/Right для навигации по словам, Shift+Arrow для выделения
- Не было поддержки модификаторов → отправлялись обычные стрелки
- Решение: xterm modifier encoding
ESC[1;{mod}A, функция_xterm_modifier()
7. [DONE v1.5.3] Ctrl+A блокировался
- Файл:
gui/widgets/terminal_widget.py bind("<Control-a>", lambda e: "break")съедал Ctrl+A- Ctrl+A = tmux prefix, readline home, select all в nano
- Решение: убран отдельный bind, Ctrl+A проходит через общий ctrl-handler →
\x01
8. [DONE v1.5.2] DECCKM (Application Cursor Keys)
- Файл:
gui/widgets/terminal_widget.py - mc/vim/htop включают
?1h(DECCKM) → стрелки должны слатьESC O AвместоESC [ A - Решение: проверка
_DECCKM in self._screen.mode, словарь_APP_CURSOR_MAP
ВАЖНО (для стабильной работы)
9. [DONE v1.5.3] Shift+Tab (backtab)
- Файл:
gui/widgets/terminal_widget.py—_on_key() ESC[Z— обратная табуляция, нужна в mc и для reverse completion- Решение: обработка
ISO_Left_TabиTab + Shift
10. [DONE v1.5.3] Bracketed paste mode
- Файл:
gui/widgets/terminal_widget.py—_on_ctrl_v() - Без обёртки
ESC[200~...ESC[201~вставка в vim/nano добавляла auto-indent мусор - Решение: проверка
_BRACKETED_PASTE in screen.mode, оборачивание при вставке
11. [DONE v1.5.3] Cursor hidden (DECTCEM)
- Файл:
gui/widgets/terminal_widget.py—_render() - htop/vim скрывают курсор при перерисовке → курсор-блок рисовался зря
- Решение:
if is_cursor_row and not cursor_hidden
12. [DONE v1.5.3] Incremental UTF-8 decoder
- Файл:
gui/widgets/terminal_widget.py—feed() - SSH мог разрезать multi-byte UTF-8 → mojibake
- Решение:
codecs.getincrementaldecoder("utf-8")("replace")
13. [DONE v1.5.3] Mouse tracking
- Файл:
gui/widgets/terminal_widget.py—_on_mouse_* - Клики в mc панелях, htop элементах, vim mouse mode
- Поддержка: basic (1000), button-event (1002), any-event (1003), SGR (1006)
14. [DONE v1.5.3] pyte dirty set для оптимизации
- Файл:
gui/widgets/terminal_widget.py—_render() - Старый код сравнивал каждую строку с prev_buffer
- Решение: используем
screen.dirtyдля пропуска чистых строк
15. [DONE v1.5.3] Thread safety: session races
- Файл:
gui/tabs/terminal_tab.py _sessionчиталась из main thread и писалась из SSH thread- Решение: все записи
_sessionчерезself.after(0, ...), локальные ref в_send_to_shell
16. [DONE v1.5.3] _on_disconnected из неправильного потока
- Файл:
gui/tabs/terminal_tab.py - Вызывался из SSH read thread, менял
_session = None - Решение: вся логика обёрнута в
self.after(0, _handle)
17. [DONE v1.5.3] Ctrl+special chars
- Файл:
gui/widgets/terminal_widget.py—_on_key() - Ctrl+[ → ESC, Ctrl+\ →
\x1c, Ctrl+] →\x1d, Ctrl+Space → NUL - Не обрабатывались
18. [DONE v1.5.4] Smart Ctrl+C
- Одинарный Ctrl+C с выделением → копирует
- Одинарный Ctrl+C без выделения → SIGINT
- Двойной Ctrl+C (<300мс) → всегда SIGINT
- Защита от случайного убийства программы
19. [DONE v1.5.3] Mousewheel smooth scroll
- В alternate screen → 3 стрелки вместо PageUp/Down
- С mouse tracking → mouse wheel events (btn 64/65)
ЖЕЛАТЕЛЬНО (полировка)
20. [ ] Wide characters (CJK)
- Файл:
gui/widgets/terminal_widget.py—_render() - CJK символы занимают 2 колонки, pyte ставит stub во вторую
- Без обработки → смещение колонок после wide char
- Решение: проверять
wcwidth(), пропускать stub-ячейки - Приоритет: низкий (актуально для CJK-пользователей)
21. [ ] Scrollback buffer
- Файл:
gui/widgets/terminal_widget.py - Нет истории: вывод выше экрана потерян
- Решение: использовать
pyte.HistoryScreenкак базу для_Screen - Требует рендеринг scrollback + mousewheel навигация
- Приоритет: средний (удобство для обычных команд)
22. [DONE v1.5.3] Numpad keys
- Файл:
gui/widgets/terminal_widget.py—_on_key() - KP_0..9, KP_Add, KP_Subtract и др.
23. [DONE v1.5.3] Resize debounce 200ms → 100ms
- Файл:
gui/widgets/terminal_widget.py—_on_configure()
24. [DONE v1.5.3] Send errors → disconnect
- Файл:
core/ssh_client.py—send() - При OSError вызывается
on_disconnectвместо тихого проглатывания
25. [DONE v1.5.3] Right-click context menu
- Copy / Paste / Select All
- Как в MobaXterm / Windows Terminal
26. [DONE v1.5.3] Double-click word select
27. [ ] Ctrl+Shift+C/V стиль Windows Terminal
- [DONE] Ctrl+Shift+C → копирование
- [DONE] Ctrl+Shift+V → вставка
- Возможно добавить визуальный feedback при копировании (flash)
28. [ ] TERM variable alignment
- Shell открывается с
term="xterm-256color", но pyte не поддерживает все xterm features - Пока OK, но если будут проблемы — можно сменить на
"xterm"
29. [ ] Font fallbacks для Unicode
- Consolas покрывает box-drawing, но не все Unicode блоки
- Tkinter не поддерживает font fallback stacks
- Приоритет: низкий
Статистика
| Статус | Количество |
|---|---|
| DONE | 26 |
| TODO | 3 |
Версии релизов
| Версия | Изменения |
|---|---|
| v1.5.1 | Убран LNM, дебаунсинг рендера, батчинг данных, recv 64KB |
| v1.5.2 | DECCKM, thread-safe queue |
| v1.5.3 | Полная переработка: alt buffer, 256/truecolor, reverse, mouse, DA/DSR, Alt+key, modifiers, bracketed paste, UTF-8, dirty optimization, context menu |
| v1.5.4 | Smart Ctrl+C (copy/SIGINT по двойному нажатию) |