Владимир Попов
Заметка с размышлениями о vim,
имела некоторый резонанс, в связи с чем разговор об этом мощном редакторе
хочется продолжить. Парадоксально, но, признав некоторую сложность vim в прошлый
раз, сейчас я попытаюсь обосновать утверждение о его исключительной простоте.
Парадокса, собственно, никакого и нет: все зависит от того, с чьей позиции
смотреть. Для пользователя, только что загрузившего дистрибутив vim, он
действительно сложен. Достаточно сказать, что в файле index.txt свыше
1200 строк, а ведь этот файл - всего лишь перечень доступных команд с краткими
описаниями в одно, максимум два предложения. 1000, пусть 500 команд не
способствуют желанию познакомиться с редактором. Не будем торопиться. Во-первых,
команды довольно часто дублируются. Во-вторых, часть из них унаследована от vi и
предполагает возможность ввода на любом алфавитно-цифровом терминале.
Современному пользователю более естественным покажется использование
функциональных клавиш и клавиш позиционирования курсора, мыши, наконец. Все эти
возможности vim, разумеется, поддерживает, но и старые варианты набора команд не
отменяются. Список сокращается: предположим, до 150 команд. Не так уж и много
для редактора, который может "все" (уточнять и в этот раз не будем),
но есть ли основания говорить об "исключительной простоте"? Как это ни
странно, есть. И основания эти следующие:
- логика интерфейса, заложенная авторами, позволяет свести все многообразие
команд к сочетаниям значительно меньшего числа их "составляющих";
- исключительная модифицируемость vim дает возможность создавать
"проблемно-ориентированные", при желании - очень простые конфигурации;
- гибкая система помощи, которую, кстати, можно дополнять самостоятельно и на
любом языке;
- если же потребуется конфигурация, воспользоваться которой можно сразу, не
обременяя себя знакомством с документацией, то можно воспользоваться
возможностью создания меню, которая у vim тоже есть.
Таким образом сконфигурированный,
документированный и дополненный системой меню vim становится "образцом
дружественности" к пользователю. Вас что-то не устраивает? Cделайте так,
как считаете более удобным! Для этого не нужно обладать какими-то специальными
знаниями, но что-то ДЕЛАТЬ - действительно нужно. Здесь придется еще раз
признать (и напомнить), что vim написан программистами и для программистов. Но
поскольку ряды последних все ширятся, то и круг пользователей также должен
расширяться. Если это не так, то, возможно, и потому, что вышеупомянутые более
чем 1000 строк одного перечисления команд кого-то "оттолкнули" при
знакомстве. Именно на этого кого-то и ориентирован данный материал.
Для начала стоит объяснить, зачем все-таки нужно
такое количество команд, если большинство редакторов вполне обходится системой
меню. Для примера предлагаю взять части текста, выделяемые для выполнения над
ними какой-то операции и называемые, как правило, текстовыми объектами. Можно
выделять их мышью, как это и делается во многих редакторах: решение
универсальное, но крайне не эргономичное - попробуйте выделить абзацев 5-6. В
общем случае текстовым объектом может быть символ, слово, предложение, абзац,
текст в целом плюс блоки, которые, в свою очередь, могут быть ограничены
угловыми, квадратными, фигурными или круглыми скобками (мы ведь говорим о тексте
программы). Курсор (или указатель мыши) в момент выбора также может находиться в
начале, конце или внутри текстового объекта. Можно, конечно, "метить"
начало и конец текстового объекта - но это бывает так утомительно...
Согласитесь, также, что меню, отражающие все эти возможности, выглядело бы
весьма громоздким. А вот как это сделано в vim: если курсор в начале объекта, то
первая буква команды выделения - <a> (add), а если внутри,
то <i> (inner). Теперь осталось указать, что является
объектом. Вторая буква - <w>, <s>,
<p> или <b>. Нетрудно догадаться об их
происхождении : word, sentence, paragraph, block. Не ошибетесь, если
предположите, что любая из возможных скобок в качестве второго символа команды,
означает, что объект - это блок, ограниченный этим типом скобок. Изящно. И
просто. А между тем, это без малого три десятка команд в визуальном
режиме.
Логика интерфейса такова, что если вы обнаружили
какую-то возможность в одном из режимов, то почти наверняка найдете аналогичную
в другом. Упомянутые в первой статье <Ctrl-n> и
<Ctrl-p>, обеспечивающие в режиме вставки переход к
следующему (next) и предыдущему (previous) вариантам автозаполнения, при
автозаполнениях работают практически везде. Одни и те же символы в командах, как
правило, несут одну и ту же смысловую нагрузку: <i> -
идентификатор, <d> - макроопределение,
<f> - файл. Поэтому <[i> - найти первое
появление идентификатора (фактически - определение переменной),
<[d> - то же для макроопределения. Понятие "первое
появление" для файла смысла не имеет, поэтому <[f>
идентично <gf> и означает открытие для редактирования файла,
имя которого находится под курсором. Если тем же i,d,f предшествует
<Ctrl-W> (признак window-команд), то результатом
будет открытие нового окна (а для файла - и нового буфера) с переходом к
определению переменной или макрокоманды. Если команда имеет "соседей по
смыслу", то скорее всего они будут вызываться изменением регистра второго
(уточняющего) символа. Так, <[I> и <[D>
распечатают все строки с данным идентификатором или макропеременной. Те же
символы присутствуют в составе <Ctrl-X> (eXtended -
расширенного) подрежима режима вставки. Этот подрежим полностью ориентирован на
автозаполнение. Нетрудно догадаться, что символы <I>,
<D>, <F> в качестве завершающих (после
<Ctrl-X-Ctrl>) инициируют автозаполнение имен переменной,
макрокоманды и файла соответственно, а <n> и
<p>, как и прежде, будут означать следующий и предыдущий
варианты автозаполнения.
"Универсальными" могут быть не только
последние символы команд, как в предыдущих примерах, но и первые. Прежде всего,
это уже упоминавшиеся <Ctrl-X> - первый символ
расширенного подрежима вставки, и <Ctrl-W> - первый
символ window-команд. Как правило, команда детализируется вторым
символом. Кроме уже названных, для window-команд это:
<+> - увеличить, <-> - уменьшить,
<=> - сделать равными размеры окон, <s>
- разделить (split), <c> - закрыть (close),
<n> - открыть новое (new), <r> и
<R> - поменять местами (rotate) окна. Еще одним
"универсальным" символом может быть символ, идентифицирующий
именованный буфер или, в соответствии с документацией, регистр. Если помните,
комбинация <"x> (где 'x' - любой символ:
a-zA-Z0-9%#:-") означает использование регистра с командами
<y>,<d>,<p> -
копирование, удаление, вставка (yank, delete, paste). Аналогично,
<qx> означает переход в режим записи в регистр, а
<q> - выход из него. Записываются как символы, так и
управляющие последовательности (фактически - команды редактора). Если в регистр
записаны команды редактора, то его содержимое можно выполнить командой
<@x>. Но это возможно уже только с регистрами a-z.
Содержимое регистра можно вставить командой <Ctrl-R>, причем
это допустимо как непосредственно в тексте (режим вставки), так и в
командном режиме. На этом список символов - "универсальных
составляющих" команд - можно считать исчерпанным, но - не исчерпывающим,
поскольку есть и уникальные комбинации, не имеющие аналогов в других режимах.
Например, <Ctrl-U> в режиме вставки удаляет строку, а
<Ctrl-V> позволяет ввести символ посредством ввода его
трехзначного десятичного кода. В нормальном режиме
<Ctrl-L> перерисовывает экран, <Ctrl-R>
отменяет действия undo (<u>), а <Ctrl-A>
и <Ctrl-X> инкрементируют или декрементируют число под
курсором. Так же уникальны команды поиска и замены, перечисленные в первой
статье. <U> в визуальном режиме переводит выделенный
фрагмент в верхний регистр, а <u> - в нижний.
<~> поменяет регистр для одного символа в нормальном
режиме и для выделенного фрагмента - в визуальном.
Некоторые символы сохраняют свое назначение и в
командном режиме: <!> - фильтр,
<@x> - выполнить содержимое регистра 'x',
'<' и '>' - уменьшить и, соответственно, увеличить
"отступ" строк. Вообще, командный режим стоит несколько
"особняком", поскольку является практически самодостаточным: в нем
доступны практически все действия, инициируемые командами остальных режимов,
разве что объем ввода будет больше. Зато текст команд достаточно
"прозрачен". Например:
:buffer N - перейти к буферу
N; :Print - распечатать; :set - показать или установить
опции.
А количество вводимых символов уменьшается благодаря допустимым
сокращениям и уже неоднократно упоминавшемуся автозаполнению. Перечислять эти
самые "EX" команды нет смысла - их без малого три сотни, а вот
просмотреть этот список - стоит. Хотя бы для того, чтобы знать, какие еще
возможности имеет vim. Кроме команд, дублирующих команды других режимов, мы
найдем здесь команды управления буферами (==открытыми файлами), меню,
"привязкой" команд к клавиатурным последовательностям (map), средства
программирования, индексации (tags), управления редактором и многое, многое
другое.
Так мы подошли к следующему достоинству vim,
обеспечивающему его "простоту" - исключительным возможностям
настройки. Прежде всего обратимся к конфигурационному файлу vimrc (для
графического режима - gvimrc). На www.vim.org стоит взять vimrc.forall - файл написанный
Свеном Гуксом
(Sven Guckes) "на все случаи жизни". Файл прекрасно
прокомментирован и действительно при некоторых модификациях может устроить
многих. Но лучше использовать его как "руководство к действию".
Познакомившись для начала с командой
map:
map \\ <C-]>
которая заменяет
<Ctrl-]> (переход по ссылке в help (tag)), на более удобную
последовательность <\\>, переходим к весьма обширному блоку
определения опций (set ...). Автоотступ, автоматическое сохранение копий, размер
табуляции и так далее, и так далее: перечисление в рамках статьи представляется
невозможным - vimrc.forall имеет объем в 75К. Но одну опцию я все-таки
приведу:
set langmap=йцу...ЙЦУ...;qwe...QWE...
Три точки в
данном случае означают "все остальные символы на клавиатуре" в нижнем
и верхнем регистрах для раскладок ru и us. <;> перед 'qwe'
отделяет "подменяемый" набор от "подменяющего". Точку с
запятой (в наборе, а не разделяющую) и двойные кавычки нужно исключать (quote) с
помощью backslash (\), как обычно. Данная опция делает не нужным переключение
раскладки клавиатуры, когда требуется латинский символ в нормальном
режиме - несуществующий, как видите, недостаток vim, о котором я писал в первой
статье. Спасибо всем указавшим на эту опцию. Что касается Свена Гукса, то,
позаботившись о вводе таких необходимых ему умляутов, он действительно не учел
нашу привязанность к кириллице - вполне простительно для жителя Берлина.
Следующая секция vimrc.forall научит использовать сокращения - abbreviations.
Дело вкуса. Занятно использовать сокращения в качестве
"автокорректора" опечаток: aslo->also. Или - записной книжки:
Ysnail->Sven Guckes<C-M>Pariser Str. 52<C-M>D-10719 Berlin.
Обратите внимание, что сокращению команды abbreviate (ab) могут предшествовать
символы <i>, <c> и
<un> (insert, command, undo). Как Вы, наверное, догадались,
это означает актуальность (действенность) сокращения для режимов вставки
и команд или отмену сокращения. Если этот небольшой список мы расширим
еще символами <a>, <n>,
<o> и <v> (all, normal, operator и
visual) - то получим список "универсальных" модификаторов, применимых
и к некоторым другим командам, таким, как map и menu. Узнаваемая логика, не
правда ли? Следующая секция 'MAPings' содержит определения привязки команд к
определяемым пользователем клавиатурным последовательностям. Вот где истинный
простор для "подгонки" vim под Ваши вкусы. Хотите выходить из
редактора по <F10>? Пожалуйста:
map
<F10> :q<CR> imap <F10> <Esc>:q<CR> cmap <F10> <Esc><Esc>:q<CR>
Последние
две команды можно заменить одной: map! <Esc>:q<CR>, но для
этого уже нужно знать о существовании map! (map для режимов команд и
вставки) Во второй позиции может быть и последовательность символов.
Например,
map <F6>:set
number<CR> map n<F6>:set
nonumber<CR>
будет по <F6> включать
нумерацию строк, а по <n><F6> -
выключать. Последующие секции, описывающие применение автокоманд для
использования vim в качестве почтового клиента, PGP-шифрование и операции с
синтаксисом, очень интересны, но уже не имеют отношения к разговору о
"простоте" vim.
Вышеизложенное должно было убедить читателя, что
"не так страшен vim..." и изучать устрашающих размеров help может
быть, и не придется... У меня, во всяком случае, на каком-то этапе знакомства в
этим редактором сложилось впечатление, что имей я под рукой 1-2 странички
подсказок... А почему - нет? Поскольку по <F1> vim вызывает
файл help.txt из каталога $VIMRUNTIME/doc/ (значение $VIMRUNTIME можно уточнить
по :set helpfile), почему бы его не "подменить", сохранив оригинальный
help.txt и переименовав в help.txt свой файл? Несколько "варварский",
но действенный способ. Изящнее будет вставить свой help в существующую систему
помощи: путь к персональному help-у удлинится на пару нажатий клавиш, но зато в
Вашем распоряжении всегда будут и свой файл и оригинальная система помощи. Не
вдаваясь в тонкости работы со ссылками (tags) приведу краткий рецепт:
- Предположим, Ваш файл называется myhelp.txt. Первой строкой в него
вставим что-то вроде: *myhelp.txt* . Текст может быть любым - это всего
лишь ссылка, на которую будет позиционироваться система поиска в help-файлах.
- В файле help.txt, в строке, например, второй (чтобы сразу была видна
на экране) вставим указатель. Например: |$MyHelp| . Текст, опять-таки
значения не имеет, а символ <$> поставлен на первую позицию лишь затем,
что бы наша ссылка оказалась поближе к началу индексного файла tags.
- В индексный файл tags вносим
строку:
$MyHelp myhelp.txt /*myhelp.txt* Все элементы строки,
надеюсь, понятны: первый - ссылка, второй - имя файла, третий - позиция в этом
файле. Файл tags - сортирован по алфавиту и, если не хотите сортировать его
заново, строку нужно поместить в соответствующее место. В данном случае между
строками, $LANG.... и $VIM...
Готово. Запускаем vim, нажимаем
<F1> и переходим по ссылке $MyHelp
(<Ctrl-]> - по умолчанию, <\\> - если Вы
воспользовались советом Свена, или двойной клик, если предпочитаете мышь).
Ну, а поскольку "эталоном"
дружественности интерфейса долгое время считалась система выпадающих меню, то
осталось посмотреть, как таковая реализуется в vim. Дистрибутив содержит файл
menu.vim, активный по умолчанию только для графической среды. Для
появления меню в консольном режиме во все тот же vimrc нужно вставить
следующие
команды:
source $VIMRUNTIME/menu.vim set wildmenu set cpo-=< set wcm=<C-Z> map <F9>
:emenu <C-Z>
На месте <F9> может быть,
разумеется, любая клавиатурная последовательность. Можно иметь личный меню-файл,
тогда первая строка должна указывать на него. Меню как меню. Но это - vim, а,
значит, его можно модифицировать. Файл menu.vim сравнительно невелик:
менее 22К для версии 5.6. Часть его составляют функции, собственно и
обеспечивающие функционирование системы меню. Поскольку программирование в vim
нас на настоящий момент не интересует, то обратим внимание только на блоки,
первым словом строк которых является команда menu с предшествующими ей
уже известными модификаторами <a>, <c>,
<i>, <n>, <o> и
<v> в соответствии с существующими режимами. Плюс
tmenu - для организации всплывающих подсказок (tooltips) в графической
среде. Обычно строка такого блока выглядит следующим
образом:
amenu 10.330 &File.&Close<Tab>:q :confirm
q<CR>
Элементы строки разделяются пробелами. В данном случае
первый из них, amenu - команда, обеспечивающая появление данной позиции
меню во всех (all) режимах. Второй - число, часть до точки которого определяет
позицию в главном (горизонтальном), а после точки - в выпадающем (вертикальном)
меню. Подобным образом лексемы до и после точки третьего элемента строки
представляют собой текстовое содержание позиции меню. Непечатаемые символы в
составе лексем вводятся в соответствии с правилами для конфигурационного файла,
пробелы и точки исключаются (quote) с помощью обратной косой черты (backslash).
Ведущим (hot) символам в составе лексем предшествует амперсенд (&).
Четвертый элемент - собственно команда, которую нужно выполнить. Просто и
эффективно. Если команда предполагает редактирование или если Вам требуется
дополнительный контроль над командами - не завершайте строки <CR>.
Фактически, система меню просто вводит за вас необходимую
"EX"-команду.
Таким образом vim может обретести интерфейс,
проще которого (при заданном уровне функциональности) уже не будет. Все желаемые
усовершенствования Вы можете сделать сами. Средств для этого - достаточно. Не
стану утверждать, что путь к этой "простоте" так уж, извините за
тавтологию, прост, но "нет ничего ценнее хорошего инструмента". В том
числе и для программиста.
Многих возможностей vim, кстати, ни, первая ни
вторая статья даже не касались. Вне рассмотрения остались интеграция с Perl и
Python, программирование пользовательских функций, форматирование текста и
многие другие темы, достойные отдельного обсуждения.
Языки программирования: разное
|