= ОБЪЕДИНЕНИЕ КОМАНДНОЙ СТРОКИ ПАНЕЛЕЙ И САБШЕЛЛА = == Предисловие == В настоящее время комстрока под панелями и комстрока в сабшелле - это две разных сущности. При переходе в другой каталог производится попытка сменить каталог в сабшелле посылкой команды "cd printf ...". Но так как сейчас не отслеживается "неполная занятость" сабшелла, происходит добавление этой команды к неполностью набранной команде в комстроке сабшелла. Нужно корректно отслеживать заполненность комстроки сабшелла и при необходимости перехода в другой каталог очищать комстроку сабшелла, призводить переход и заполнять комстроку заново. По-настоящему объединить комстроку сабшелла и комстроку под панелями не получится, но можно попытаться их синхронизировать. === Комстрока под панелями === реализация находится в src/filemanager/command.[ch]. === Комстрока в сабшелле === реализация находится в файле src/subshell.c. В строке 562 происходит посимвольное чтение из stdin. Читаются за один раз как ASCII-символы, так и UTF-8 и ESC-последовательности == Синхронизация == За основную комстроку принять комстроку под панелями. Работать только с ней. При переходе в сабшелл перехватывать нажатия клавиш в src/subshell.c:562, корректно обрататывать ввод ESC-последовательностей. При включении панелей производится работа только с комстрокой панелей. При отключении панелей содержимое комстроки панелей передаётся сабшеллу на stdin. Дополнительнае фишка: Можно отследить нажатие enter (запуск комстроки сабшелла на исполнение) и передать комстроку парсеру комстроки панелей, который проихводит метаподстановки mc. Например, %t превратится в список выделенных файлов в текущей панели (при этом панели погашены). Варианты синхронизации комстроки панелей в комстроку сабшелла: 1) очищать комстроку сабшелла полностью (послать столько BackSpace, сколько символов в комстроке панелей) и заполнять заново из панельной комстроки. Достоинства: * нет зависимости от используемого шелла. Недостатки: * при огромной комстроке возможны задержки и мерцание почти на каждый символ. 2) Посылать введённый символ сабшеллу, паралельно обрабатывать в комстроке панели. Достоинства: * нет задержек на огромных комстроках. Недостатки: * зависимость от парсера комстроки различных шеллов (например, один шелл может ctrl+w обработать как удаление предыдущего слова, а второй - как удаление до начала строки) FIXME: оба варианта гавно. нужно думать. == Смена текущего каталога в сабшелле == 1) Послать в сабшелл столько Backspace, сколько символов находится в комстроке панелей 2) выполнить переход в другой каталог (cd printf...) 3) Послать из комстроки панелей символы в сабшелл == Обработка автодополнения в сабшелле == Алгоритм автодополнения такой: 1) При нажатии на TAB шелл 0x9. Возвращается один байт 0x7, если есть несколько вариантов автодополнения. 2) Второе нажатие TAB опять генерит для шелла 0x9. В ответ возвращаются варианты автодополнения с промптом и нашей недовведённой строкой в конце. 3) может быть произведен набор с клавиатуры для уточнения выбора 4) Автодополнение с одним вариантом (непосредственно автодополнение строки) посылает 0x9 и принимает больше одного байта (и он не 0x7) На основе этого можно сделать алгоритм внесения автодополненных данных в комстроку панели: 1) добавляем static-переменную в src/subshell.c с названием is_autocomplete_started с дефолтным значением FALSE 2) при внесении в сабшелл байта с кодом 0x7 выставляем is_autocomplete_started=TRUE 3) если от шелла не был получен один байт (а если и был, то он не со значением 0x7, то копируем полученные символы от шелла в конец комстроки панелей 4) выставляем is_autocomplete_started=FALSE == управление строкой == При перемещении стрелками, удалении части строки в сабшелл передаётся строка символов, начинающаяся с 0xb (ESC или 27[dec]). Исключение составляет BackSpace: в сабшелл передаётся один байт 0x7f. Вероятно, можно распарсить эти ESC-последовательности отдельно от реального stdin и "подсунуть" их комстроке панелей. FIXME: нужна информация по обработке ESC-последовательностей в виджете WInput == Отладка == На период изучения использовался патч: diff --git a/src/subshell.c b/src/subshell.c index a07deed..3e0a4dd 100644 --- a/src/subshell.c +++ b/src/subshell.c @@ -461,7 +461,17 @@ synchronize (void) /* --------------------------------------------------------------------------------------------- */ /** Feed the subshell our keyboard input until it says it's finished */ - +static char* +log_hex(char *buff, int len) +{ + GString *hex=g_string_new("hex: "); + int i; + for (i=0;i 31)?buff[i]:'.'); + } + return g_string_free(hex, FALSE); +} static gboolean feed_subshell (int how, int fail_on_error) { @@ -527,6 +537,7 @@ feed_subshell (int how, int fail_on_error) fprintf (stderr, "read (subshell_pty...): %s\r\n", unix_error_string (errno)); exit (EXIT_FAILURE); } +mc_log("from subshell: bytes=%d (%s)\n%s\n", bytes, log_hex(pty_buffer, bytes), pty_buffer); if (how == VISIBLY) write_all (STDOUT_FILENO, pty_buffer, bytes); @@ -577,6 +588,7 @@ feed_subshell (int how, int fail_on_error) return TRUE; } +mc_log("to subshell: bytes = %d (%s)\n%s\n", bytes, log_hex(pty_buffer, bytes), pty_buffer); write_all (mc_global.tty.subshell_pty, pty_buffer, bytes); if (pty_buffer[bytes - 1] == '\n' || pty_buffer[bytes - 1] == '\r')