Почему порой так сложно вводить текст в терминал

в 9:00, , рубрики: cli, linux, readline, ruvds_перевод, VI, vim, командная строка, редакторы текста

Почему порой так сложно вводить текст в терминал - 1


Как-то раз я спросила у пользователей Mastodon, что их не устраивает в работе с терминалом, и одним из ярких замечаний оказалось «редактирование уже введённой команды».

Мне эта проблема тоже реально знакома. Несмотря на то, что ввод текста и его редактирование является «базовой» задачей, мне потребовалось около 15 лет каждодневной работы с терминалом, чтобы привыкнуть к использованию Ctrl+A для перехода к началу строки (или Ctrl+E для перехода в конец — я использовала вместо этого Home/End).

Так что сегодня речь пойдёт о том, что ввод текста порой вызывает сложности. Я также поделюсь с вами кое-какими советами, которые сама была бы рада услышать давно.

Несогласованность между разными программами

В значительной степени ввод текста в терминале усложняет то, что разные программы обрабатывают его по-разному. Например:

  1. Некоторые программы (cat, nc, git commit --interactive и так далее) не поддерживают использование стрелок. Если вы будете нажимать в них соответствующие клавиши, то увидите лишь ^[[D^[[D^[[C^[[C^.
  2. Многие программы (вроде irb, python3 в Linux и другие) используют библиотеку readline, которая предоставляет богатую базовую функциональность (просмотр истории, клавиши стрелок и так далее).
  3. Некоторые программы (например, /usr/bin/python3 на моём Mac) поддерживают самые простые возможности ввода вроде использования стрелок, но не другие вроде Ctrl+влево или обратного поиска с помощью Ctrl+R.
  4. В некоторых программах (вроде оболочки fish, ipython3, micro или vim) реализована собственная продуманная система ввода, специализированная конкретно под них.

Так что вариаций получается множество, и, пожалуй, стоит проговорить каждый пункт подробнее.

Пункт 1: основа

Во-первых, есть «основа» — что происходит, если программа просто получает текст через вызов fgets() или другую функцию и больше никак не стремится повысить удобство в работе. Для меня использование подобных инструментов обычно выглядит так — если я запускаю установленную на моей машине версию dash (довольно минималистичную оболочку) и нажимаю стрелку влево, то она просто выводит в терминал ^[[D.

$ ls l-^[[D^[[D^[[D

Поначалу не кажется, что все эти инструменты «базового» уровня имеют много общего, но по факту есть несколько функциональных особенностей, которые вы получаете автоматически просто от самого терминала без какой-либо помощи со стороны программы.

Что же это за возможности:

  1. Естественно, ввод текста.
  2. Обратное перемещение курсора.
  3. Ctrl+W для удаления предыдущего слова.
  4. Ctrl+U для удаления всей строки.
  5. Ещё несколько возможностей, не связанных с редактированием текста (например, Ctrl+C для прерывания процесса, Ctrl+Z для его приостановки и так далее).

Такие возможности нельзя назвать крутыми, но их наличие означает, что если вы хотите удалить слово, то обычно можете сделать это с помощью Ctrl+W вместо того, чтобы 15 раз нажимать возврат, даже если работаете в среде, которая не предлагает никакой функциональности. Список всех поддерживаемых вашим терминалом комбинаций с клавишей Ctrl можно вывести командой stty -a.

Пункт 2: инструменты, которые используют readline

Следующей группой идут инструменты, использующие readline. Readline — это широко используемая библиотека GNU, которая позволяет сделать текст более опрятным. Вот мои любимые комбинации, которые предоставляет эта библиотека:

  1. Ctrl+E (или End) для перехода в конец строки.
  2. Ctrl+A (или Home) для перехода в начало строки.
  3. Ctrl+влево/вправо для перемещения вперёд/назад на 1 слово.
  4. Стрелка вверх для возврата к предыдущей команде.
  5. Ctrl+R для поиска по истории.

При этом вы также можете использовать Ctrl+W/Ctrl+U из «базового» списка, хотя Ctrl+U вместо удаления всей строки удаляет только текст от курсора и до начала строки. Думаю, что Ctrl+W также может несколько иначе трактовать понятие «слова».

Есть и многие другие комбинации (вот полный список). Я же перечислила только те, которые часто использую сама.

Наиболее известным инструментом, использующим readline, наверняка является оболочка bash (когда вы используете Ctrl+R для поиска по истории в bash, то эту возможность по факту предоставляет readline), но есть и много других программ — например, psql, irb, python3 и так далее.

▍ Совет: можно использовать readline из любого инструмента с помощью rlwrap

Одним из самых приятных моментов я нахожу то, что если у вас есть программа вроде nc без поддержки readline, то вы можете просто выполнить rlwrap nc, чтобы эту поддержку в неё встроить.

Это невероятная возможность, которая делает многие почти непригодные для использования инструменты более удобными в работе. Можно даже включить в rlwrap собственные варианты автозавершения, хотя я никогда этого не пробовала.

Почему инструменты могут не использовать readline

Думаю, что поддержка readline может отсутствовать в инструментах по следующим причинам:

  • Программа очень проста (например, cat или nc) и мейнтейнеры, возможно, не хотят привносить в неё относительно крупную зависимость.
  • Нюансы лицензирования. Если лицензия программы не GPL-совместима — readline имеет лицензию GPL, а не LGPL.
  • Интерактивной является лишь небольшая часть программы, в связи с чем поддержку readline могли не счесть как значимый элемент. Например, в git немного интерактивных функций (таких как git add -p), и обычно вы просто вводите один символ вроде y или n — если же требуется ввести что-то более значительное, git переносит вас в текстовый редактор.

Например, в idris2 говорят, что не задействуют readline ради сокращения числа зависимостей и для получения более интерактивных возможностей предлагают использовать rlwrap.

Как понять, используете ли вы readline

Простейший тест, какой мне приходит на ум, это нажатие Ctrl+R. Если вы увидите:

(reverse-i-search)`':

Значит, наверняка используете readline. Естественно, это не 100%-метод (некоторые иные библиотеки тоже могут использовать термин reverse-i-search), но я не знаю другую систему, которая бы задействовала его для поиска по истории.

Комбинации клавиш readline взяты из Emacs

Поскольку я пользуюсь vim, то далеко не сразу поняла, откуда взяты эти комбинации (почему Ctrl+A используется для перехода в начало строки??? Очень странно).

Как понимаю я, эти привязки были позаимствованы из Emacs — Ctrl+A и Ctrl+E делают в Emacs то же, что и в Readline. Так что предполагаю, что и многие другие комбинации между ними тоже совпадут, хотя я пробовала Ctrl+W и Ctrl+U в Emacs, и в нём их действия отличаются от действий в терминале. В общем, отличия всё же есть.

Подробнее об истории проекта Readline можно почитать здесь.

Пункт 3: другая библиотека ввода (вроде libedit)

На моём ноутбуке с Mac /usr/bin/python3 работает странным половинчатым образом, поддерживая лишь часть возможностей readline (например, клавиши стрелок). Скажем, при нажатии Ctrl+влево программа выводит ;5D:

$ python3
>>> importt subprocess;5D

Разобраться с этим вопросом мне помогли ребята с Mastodon. Оказывается, в предустановленном на Mac дистрибутиве Python модуль readline по факту заменён модулем libedit, который представляет аналогичную библиотеку, но с менее широкой функциональностью. Причина может заключаться в том, что Readline имеет лицензию GPL.

В конечном итоге выяснить, что в моей версии Python используется libedit, я смогла так:

$ python3 -c "import readline; print(readline.__doc__)"
Importing this module enables command line editing using libedit readline.

Тем не менее обычно Python использует именно readline, если устанавливается под Linux или через Homebrew. Просто конкретная версия, которую инженеры Apple включают в свои системы, работает на libedit.

Кроме того, в Python 3.13 собираются убрать зависимость от readline, заменив её кастомной библиотекой, так что вскоре выражение «Python использует readline» перестанет быть актуальным.

Предполагаю, что на Mac есть и другие программы, которые используют libedit, но я в этом не разбиралась.

Пункт 4: кастомное решение

К последней группе программ относятся те, в которых есть собственная (а иногда и намного более изощрённая) система редактирования текста. К ним относятся:

  • Большинство редакторов текста для терминала (nano, micro, vim, emacs и так далее).
  • Некоторые оболочки вроде fish. Например, fish позволяет при вводе команды использовать отмену через нажатие Ctrl+Z. В zsh задействуется текстовый редактор zle.
  • Некоторые REPL вроде ipython, в котором вместо readline используется библиотека prompt_toolkit.
  • Многие другие программы (вроде atuin).

Вот некоторые из их особенностей:

  • Более эффективное автозавершение, подстроенное под сам инструмент.
  • Более удобное управление историей (например, с выделением синтаксиса) в сравнении с тем, которое по умолчанию предоставляет readline.
  • Больше всевозможных комбинаций клавиш.

▍ Кастомные системы ввода зачастую основаны на readline

Я решила посмотреть, как обрабатывает ввод Atuin (прекрасный инструмент для поиска по истории оболочки, которым я начала пользоваться недавно). Если взглянуть на код и его обсуждение, то становится ясно, что хоть реализация этого инструмента и кастомная, основана она именно на readline. На мой взгляд, это разумно, так как многие пользователи привыкли к используемым в ней комбинациям клавиш, и это обеспечивает для них дополнительное удобство при работе.

Аналогично дела обстоят с prompt_toolkit (библиотекой, которую использует IPython) — фактически она поддерживает множество опций (включая привязки клавиш в стиле vi), но по умолчанию в ней используются привязки именно как в readline.

И есть немало программ, которые поддерживают самые простые привязки клавиш vim (вроде j для «вниз» и k для «вверх»). Например, Fastmail поддерживает j и k, несмотря на то, что основная часть остальных его привязок не имеют отношения к vim.

Предполагаю, что большинство кастомных систем ввода на основе readline имеют различные тонкие расхождения с этой библиотекой, но меня это не волнует, поскольку я крайне плохо разбираюсь в большинстве возможностей readline. Я использую всего где-то 5 комбинаций, поэтому до тех пор, пока такие системы поддерживают 5 базовых известных мне команд (которые в них есть всегда), меня это вполне устраивает. Причём эти кастомные системы зачастую предоставляют намного более качественное автозавершение, чем можно получить при использовании только readline, поэтому обычно я предпочитаю именно их.

Многие оболочки поддерживают комбинации клавиш из редактора vi

Bash, zsh и fish предлагают для ввода текста «режим vi». В очень ненаучном опросе, который я провела на Mastodon, 12% людей сказали, что используют именно его. Так что, похоже, этот режим довольно популярен.

В readline тоже есть «режим vi» (таким образом реализована её поддержка в Bash), то есть по аналогии эта поддержка есть и во многих других программах.

Я всегда считала, что режим vi очень крут, но хоть я и пользуюсь vim, почему-то его так и не освоила.

Важно понимать ситуацию

Я долгие годы недоумевала, почему используемое мной приложение командной строки не работает так, как я бы хотела. Поэтому хорошо, когда можешь в той или иной степени понять, с чем имеешь дело.

Думаю, что при вводе текста в командную строку я размышляю примерно так:

  1. Работают ли клавиши стрелок? Возможно, системы ввода нет совсем, но я по крайней мере могу использовать Ctrl+W и Ctrl+U, а также дополнить инструмент с помощью rlwrap, если мне потребуется больше возможностей.
  2. Будет ли Ctrl+R выводить reverse-i-search? Если да, то это наверняка readline, и тогда я смогу использовать все привычные мне комбинации, а также выводить какую-то базовую историю и получать предыдущую команду нажатием клавиши вверх.
  3. Делает ли Ctrl+R что-то другое? В этом случае, скорее всего, используется кастомная библиотека, которая будет работать более-менее схожим с readline образом. При этом, если я захочу узнать, как конкретно она работает, то всегда могу заглянуть в документацию.

Возможность подобным образом проверить, что конкретно происходит при использовании разных комбинаций, делает командную строку более предсказуемой и менее хаотичной.

О чём в этом посте не говорилось

При вводе текста существует и много других сложностей, о которых я не сказала. Например:

  • проблемы, связанные с ssh / tmux / и прочим,
  • переменная среды TERM,
  • то, что разные терминалы (gnome, iTerm, xterm и прочие) по-разному реализуют копирование/вставку текста,
  • Юникод,
  • и другие.

Автор: Bright_Translate

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js