Задача текстовых редакторов

После основных утилит для работы с файлами и текстом первая программа, которая понадобится любому пользователю Linux -- это текстовый редактор (для краткости -- просто редактор). Из предыдущих лекций и собственных экспериментов Мефодию уже стало понятно, какое значительное место занимают в системе Linux данные в текстовом формате, т. е. состоящие из символов, которые могут быть отображены на экране терминала и которые может прочесть человек. Однако пока Мефодий мог работать с текстом только последовательно: строка за строкой, даже если имел дело с файлом, он не мог вернуться и отредактировать уже переданные системе строки. Именно для того, чтобы работать с текстовым файлом как со страницей, по которой можно перемещаться и редактировать текст в любой точке, и нужны текстовые редакторы(1).

Текстовый редактор потребуется пользователю Linux в первую очередь для того, чтобы изменить настройки системы или своего окружения, например, shell -- при этом нужно будет редактировать конфигурационные файлы, которые всегда представлены в текстовом формате (см. лекции Возможности командной оболочки и Конфигурационные файлы). Но и собственные задачи пользователя могут потребовать редактирования текстовых файлов: например, сценарии и программы, электронные письма, а также заметки для себя, которые пишет Мефодий -- это всё данные в текстовом формате. Текстовые данные, полученные при помощи стандартных утилит, тоже бывает удобно сохранять в файлах и редактировать.

Не стоит путать текстовые редакторы и текстовые процессоры. Текстовые процессоры, -- например, OpenOffice Writer или Microsoft Word -- предназначены для создания документов, в которых, помимо собственно текста, содержится и различная метаинформация (информация об оформлении): размещение текста на странице, шрифт и т. п. Поскольку в текстовом формате не предусмотрено средств для сохранения информации об оформлении (там есть только символы и строки), текстовые процессоры используют свои собственные форматы для хранения данных. Текст, в котором нет никакой метаинформации об оформлении, называют "plain text" (только текст, "плоский", простой текст).

Однако при помощи текстовых редакторов можно работать не только с форматом plain text. Различная метаинформация (об оформлении, способе использования текста, например, в качестве ссылки и пр.) может быть записана и в виде обычных символов (т. е. в текстовом формате), но со специальным соглашением, что эти символы нужно интерпретировать особым образом: как инструкции по обработке текста, а не как текст. Такие инструкции называются разметкой. Таким образом устроен, например, формат HTML. Для того, чтобы обработать разметку HTML и в соответствии с ней отобразить текст, нужна специальная программа -- броузер, но редактировать файлы HTML и прочие форматы разметки можно и при помощи текстового редактора. Кроме того, программы на любых языках программирования и сценарии (программы на shell), тоже представляют собой текстовые файлы. Многие текстовые редакторы ориентированы на работу не только с плоским текстом, но и с текстом в различных форматах. Для этого придумана масса усовершенствований, уменьшающих количество символов, которые нужно вводить вручную: специальные команды, клавиатурные сокращения и автодополнение ключевых слов и конструкций.

Важнейшее условие для текстового редактора в Linux -- возможность работать в терминале, т. к. это основной способ управления системой. Поэтому и ввод данных, и редактирование должны полностью осуществляться средствами терминала, т. е. алфавитно-цифровыми и некоторыми функциональными клавишами. Поскольку функциональных клавиш, на которые можно рассчитывать на любом терминале, совсем немного, а команд, которые нужно отдавать редактору, -- много очень, требуется способ вводить любые команды ограниченными средствами терминала. Это условие, равно как и требование удобной работы с разнообразными структурированными текстами, выполнено в двух "главных" текстовых редакторах Linux -- Vi и Emacs, о которых в основном и будет идти речь в этой лекции.

<<Anchor: execution failed [Too many arguments] (see also the log)>>

Vi и лучше, чем Vi

В любой системе Linux, даже самой минимальной, всегда присутствует текстовый редактор, поскольку в любой -- даже самой катастрофической -- ситуации у пользователя должна быть возможность отредактировать конфигурационные файлы, чтобы привести систему в рабочее состояние. По сложившейся традиции текстовым редактором, который обязательно запустится из любой командной строки Linux, является Vim(2). Однако верно и обратное: если Вы работаете в незнакомой системе Linux или произошёл сбой, в результате которого доступна только очень небольшая часть системы, нельзя быть увереным, что найдётся хоть какой-нибудь другой текстовый редактор кроме Vim. Поэтому каждому пользователю Linux нужны хотя бы основные навыки работы в Vim. При первом знакомстве c Vim работа обычно не ладится: очень уж он непривычен, его нельзя с удобством использовать, запомнив только две-три простейшие команды редактирования. Стоит понять основные принципы работы в Vim и потратить некоторое время на его освоение, тогда в нём откроется мощный инструмент, позволяющий очень эффективно работать с текстом.

Под именем Vim, на самом деле, могут скрываться несколько разных программ: с момента появления Vim в операционной системе UNIX (а это произошло около 30-ти лет назад), этот редактор стал чем-то вроде стандарта. К настоящему времени существует ряд программ либо в точности повторяющих вид и поведение "классического" Vim (например, nvi), либо очень похожих на него, но со значительно расширенными возможностями (Vi, elvis). Наибольшей популярностью пользуется Vi, возможности которого огромны, для их описания потребовалось почти сто тысяч строк документации. Когда пользователь Linux набирает в командной строке Vim, скорее всего будет запущена "облегчённая" версия Vi, которая настроена таким образом, чтобы максимально воспроизводить поведение классического редактора Vim. Естественно, в таком режиме часть возможностей Vi недоступна. Все свойства, которыми Vi отличается от Vim, обязательно снабжены в руководстве по Vi указанием "not in vi". В дальнейшем изложении под Vim мы будем понимать именно Vi в режиме совместимости, все возможности, недоступные в этом режиме, будут отдельно оговариваться. Чтобы вызвать Vi в полнофункциональном режиме, достаточно набрать команду Vi.

Популярность Vi не случайна: этот текстовый редактор позволяет не только производить простые операции редактирования текстовых файлов, но и хорошо приспособлен для максимально быстрого и эффективного решения ряда смежных с редактированием задач. Среди самых важных его возможностей -- инструменты для работы с текстами на различных языках программирования и в различных форматах разметки. Vim умеет подсвечивать разными цветами синтаксические конструкции языка программирования или разметки(3), автоматически выставлять отступы, что облегчает восприятие структуры документа. Кроме того, в Vi есть специальные средства для организации цикла отладки программы: компиляция--правка исходного текста--компиляция... Подробнее об этих и прочих возможностях Vi можно узнать из руководств по Vi. Объём данной лекции позволяет описать только самые начала работы с Vi, более подробное введение в этот текстовый редактор можно найти в книге[Курячий:2004].

Запуск vi

Чтобы начать сеанс редактирования в Vim, достаточно выполнить команду Vim на любом терминале. Чтобы открыть для редактирования уже существующий файл, путь к этому файлу нужно указать в качестве параметра: "vi путь_к_файлу". Как и всякая уважающая себя программа UNIX, Vim может быть запущен с множеством модифицирующих его поведение ключей, которые подробно описаны в руководстве. Вызванный без параметра, редактор откроет пустой буфер -- чистый лист для создания нового текста. В центре экрана при этом может появиться краткое приветственное сообщение, где указаны версия программы и команды для получения помощи и выхода из редактора (что нетривиально!). Однако такое сообщение может и не возникнуть -- это зависит от версии Vim, установленной в системе.

Для отображения текста и работы с ним Vim использует весь экран терминала, только последняя строка предназначена для диалога с пользователем: вывода информационных сообщений и ввода команд. Пока буфер не заполнен текстом, в начале каждой строки экрана отображается символ "~", обозначающий, что в этом месте буфера нет ничего, даже пустой строки. Общий вид экрана в начале работы будет примерно такой:

#
~
~
~
~
~

Начало работы с vi

Символ "#" обозначает курсор. На экране терминала умещается больше строк, но в примерах мы будем для компактности изображать только необходимый минимум.

Режимы

В Vim проблема разделения команд редактору и вводимого текста решена при помощи режимов: в командном режиме нажатие на любую клавишу -- это команда редактору, в режиме вставки нажатие на клавишу приводит к вставке соответствующего символа в редактируемый текст. Поэтому при работе с Vim пользователю всегда нужно обращать внимание на то, в каком режиме находится редактор.

режимы vi

Состояния редактора Vim, в которых он по-разному обрабатывает нажатия клавиш. Различают три режима Vim: командный (нажатие любой клавиши считается командой и немедленно исполняется), вставки (нажатие клавиши-печатного символа приводит к вставке этого символа в текст) и командной строки (для ввода длинных команд, отображаемых на экране; ввод завершается Enter.

Vim всегда начинает работу в командном режиме. В этом режиме есть два способа отдавать команды редактору. Во-первых, нажатие практически на любую клавишу редактор воспринимает как команду. В Vi, даже в режиме Vim-совместимости, командное значение определено для всех латинских букв (в верхнем и нижнем регистрах), цифр, знаков препинания и большинства других печатных символов. При нажатии на эти клавиши вводимые команды нигде не отображаются, они просто исполняются.


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


Во-вторых, у Vim есть своя командная строка: чтобы её вызвать, нужно ввести ":" в командном режиме. В результате в начале последней строки экрана появится двоеточие -- это приглашение командной строки. Здесь вводятся более сложные команды Vim, которые включают в себя целые слова (например, имена файлов), причём текст набираемой команды, конечно, отображается. Команды передаются Vim клавишей Enter. В современных версиях Vim с командной строкой можно работать так же, как и в shell: редактировать её, достраивать команды клавишей Tab, пользоваться историей команд.

Главная команда командной строки Vi -- вызов подсистемы помощи ":helpEnter". Двоеточие переводит Vi в режим командной строки, "help" -- собственно команда, Enter передаёт команду. help можно вызывать с аргументом: названием команды или настройки Vi. Vim очень хорошо документирован, поэтому по команде ":help объект" можно получить информацию о любом свойстве Vi, например, команда ":help i" выведет сведения о значении клавиши "i" в командном режиме Vi.

Команда ":set имя_настройки" позволяет настраивать Vim прямо в процессе работы с ним. Например, отдав команду ":set wrap" пользователь тем самым включает настройку "wrap", что заставляет редактор переносить слишком длинные строки, не умещающиеся в ширину терминала. Выключить эту настройку можно командой ":set nowrap", так что концы длинных строк исчезнут за правым краем экрана.

Наконец, чтобы ввести текст, нужно перейти из командного режима в режим вставки, нажав клавишу "i" (от "insert" -- "вставка"). В этот момент в последней строке появится информационное сообщение о том, что редактор находится в режиме вставки: "--INSERT--" или "--ВСТАВКА--"(4), в зависимости от установленного языка системных сообщений.

В режиме вставки можно вводить текст, завершая строку нажатием на Enter. Однако нужно помнить, что в некоторых (ортодоксальных) версиях Vim в режиме ввода не работают никакие команды перемещения по тексту, здесь можно только набирать. Если Вы заметили, что ошиблись в наборе -- не нужно сразу пытаться переместить курсор и пытаться исправлять ошибку: гораздо удобнее будет вносить все исправления потом, в командном режиме, где доступно множество специальных команд быстрого перемещения и замены текста. Чтобы перейти из режима вставки обратно в командный режим, нужно нажать ESC.


Если Vim пришёл в непонятное для Вас состояние, нажмите ESC, чтобы вернуться в командный режим (иногда требуется нажать ESC дважды).


Мефодий начал упражняться с Vim на файле примеров:

methody@oblomov:~ $ vi textfile
Это файл для примеров.
Пример 1.
~
~
~
~
~
"textfile" 2L, 33C                         1,1   Весь

Vim в командном режиме

Vim начал работу -- как и положено -- в командном режиме. В последней строке возникли некоторые полезные сведения об открытом файле: его имя, общее количество строк ("2L"), символов ("33С"), позиция курсора ("1,1" -- номер_строки, номер_символа). "Весь" обозначает, что всё содержимое файла уместилось на экране терминала. Теперь Мефодий нажмёт "i" и введёт немного текста:

Это файл для примеров.
Пример 1.
Моя первая сторка в vi!
~
~
~
~
-- ВСТАВКА --                              3,24  Весь

Vim в режиме вставки

Теперь Vim в режиме вставки: в последней строке появилось информационное сообщение об этом. Набрав текст, Мефодий может вернуться в командный режим, нажав ESC (подсказка "--ВСТАВКА--" при этом исчезнет из последней строки).

На самом деле, из командного режима можно перейти в режим ввода несколькими командами, разница между ними заключается в том, в какой точке начнётся ввод символов. Например, по командам "O" и "o" ("open") можно вводить текст с новой строки (до или после текущей), по команде "I" -- с начала строки, команды "a" и "A" ("append") ведают добавлением символов (после курсора или в конец строки) и т. п.

Работа с файлами

Редактируя текст в Vim, пользователь работает не непосредственно с файлом, а с буфером. Если открывается уже существующий файл, Vim копирует его содержимое в буфер и отображает буфер на экране. Все изменения, которые делает пользователь, происходят именно в содержимом буфера -- открытый файл пока остаётся неизменным. Если же Vim вызван без параметра, то создаётся пустой буфер, который пока не связан ни с каким файлом(5).

Чтобы записать сделанные изменения в файл, используется команда ":wEnter" (чтобы её отдать, нужно сначала перейти в командный режим). О том, что "w" -- это сокращение от англ. "write", "записать", можно узнать, нажав Tab после ":w" -- и Vim дополнит эту команду до "write". Подобным образом можно поступить с большинством команд в командной строке Vim -- в этом редакторе очень последовательно соблюдается принцип аббревиативности. Мефодий выполнил "write" и получил такое информационное сообщение:

Это файл для примеров.
Пример 1.
Моя первая сторка в vi!
~
~
~
~
"textfile" 3L, 57C записано                3,24   Весь

Запись файла

Мефодий не указал, куда именно записать содержимое буфера, и по умолчанию оно было записано в тот файл, который он и открывал для редактирования: "textfile". Однако команде "write" можно указать любое имя файла в качестве параметра -- и тогда содержимое буфера будет записано в этот файл, а если такого файла нет, то он будет создан. Параметр "write" обязательно потребуется, если текст в буфере ещё не записан ни в каком файле.

Наиболее важна для новичка команда выхода из Vim -- ":qEnter" (сокращение от "quit"). Пользователь, запустивший редактор в первый раз, нередко сталкивается с тем, что никак не может его закрыть: не работает ни один из привычных способов завершения программы, даже "^C" Vim обрабатывает по-своему(6). И ":w" и ":q" -- команды режима командной строки, в этот режим Vim переводится из командного режима с помощью ":" в мх начале.

Однако если в буфере есть изменения, которые ещё не записаны ни в каком файле, то Vim откажется выполнять команду ":q", предложив сначала сохранить эти изменения. Если Вы не хотите сохранять изменения, нужно настоять на своём желании выйти их Vim, добавив к команде выхода восклицательный знак: ":q!". В этом случае все несохранённые изменения будут выброшены. Восклицательный знак можно добавить в конце любой файловой команды в командной строке Vim, в этом случае Vim будет выполнять команды, не предъявляя пользователю никаких возражений.

В Vim предпринято множество усилий для экономии сил и времени пользователя, командующего редактором. Поэтому вполне можно одним разом записать текст и выйти из редактора: командой ":wq" или аналогичной командой ":x" или просто нажав "ZZ" в командном режиме.

Перемещение по тексту

При редактировании в тексте всегда есть точка, в которой вы "находитесь" в данный момент: вводимые с клавиатуры символы появятся именно здесь, удаляться символы будут тоже отсюда, к этой точке будут применяться команды редактора и т. п. Обычно эта точка обозначается курсором, а в последней (информационной) строке экрана Vim указывает номера текущей строки и колонки (номер символа в строке), в которых находится курсор.

Для того, чтобы выполнять редактирование текста, по нему необходимо перемещаться, т. е. перемещать курсор. Самый очевидный способ это делать -- воспользоваться клавишами со стрелками. Нажатие на одну из этих клавиш обычно заставляет курсор переместиться на один символ влево/вправо или на одну строку вверх/вниз. Трудно придумать более неэффективный и медленный способ перемещения, если нужно попасть на другой конец объёмистого текста, и даже простое перемещение к началу или концу строки может занять несколько секунд.

Заметим, что в процессе редактирования текста обычно возникает необходимость перемещаться не в произвольную точку, а в некоторые ключевые: начало и конец строки, слова, предложения, абзаца, выражения, заключённого в скобки, целого текста. Особенно это заметно, если требуется редактировать структурированный текст: программу (например, сценарий), конфигурационный файл и т. п. В Vim для каждого такого перемещения предусмотрены специальные команды, обычно состоящие в нажатии одной клавиши в командном режиме. Используя их, можно не только одной кнопкой переместиться на любое расстояние в тексте, но и двигаться по структурным элементам, переходя к предыдущему/следующему слову, предложению, абзацу, скобке и т. д.


Прежде чем начинать экспериментировать с перемещением, нужно перейти в командный режим.


Итак, передвинуть курсор на начало текущей строки можно командой "0", на первый непробельный символ в строке -- "^", в конец строки -- "$"(7). Абзацами Vim считает фрагменты текста, разделённые пустой строкой, к началу предыдущего/следующего абзаца можно попасть командами "{" и "}" соответственно. Очень распространённая необходимость -- попасть в самый конец файла: для этого служит команда "G" ("Go"), в самое начало -- "gg" ("go-go"?).

Передвинуть курсор вперёд на начало следующего слова можно командой "w" (от "word", слово), на начало предыдущего -- "b" (от "backward", назад). К началу предыдущего/следующего предложений можно переместиться командами "(" и ")" соответственно. Нужно учитывать, что границы слов и предложений Vim находит по формальным признакам (руководствуясь специально определёнными регулярными выражениями), поэтому решение Vim может иногда не совпадать с представлениями пользователя о границах слов и предложений. Однако пользователь всегда властен изменить соответствующие регулярные выражения, подробности -- в документации по Vi.

В Vim никогда не следует вручную повторять по нескольку раз одну и ту же команду: если нужно перейти на три слова вперёд, не следует трижды нажимать "w", для повторения команды используется множитель. Множитель, это любое число, набранное перед командой Vim: команда будет повторена такое число раз. Например, "3w" -- означает "трижды переместить курсор на слово вперёд", иначе говоря, переместить курсор на три слова вперёд. Обратите внимание, что множители могут применяться не только с командами перемещения, а с любыми командами Vim. Аналогично можно переместить курсор на 10 абзацев вперёд командой "10}".

множитель

Число, предшествующее команде Vim, и означающее, что данную команду следует выполнить указанное число раз.

Не сразу очевидно, что поиск шаблона в тексте (строки или регулярного выражения) -- это тоже команда перемещения. Как и любое перемещение, поиск осуществляется в командном режиме: прежде всего нужно нажать "/": в последней строке возникнет символ "/". Далее следует ввести шаблон для поиска, он будет отображаться в этой строке, его можно редактировать. Обычно Vim настроен таким образом, что шаблон для поиска интерпретируется как регулярное выражение, где ряд символов имеет специальное значение, эту настройку можно выклчить (":set nomagic"). После того, как введён шаблон, следует нажать Enter -- курсор переместится к ближайшему (далее по тексту) совпадению с шаблоном. Поиск в обратном направлении (к предыдущему совпадению) следует начинать с команды "?".

Совсем просто перейти к следующему употреблению в тексте того слова, на котором стоит курсор: для этого нужно просто нажать "*" в командном режиме. Аналогичная команда поиска слова в обратном направлении -- "#". Можно специально отметить в тексте точку и затем в любой момент возвращаться к ней, как к закладке, одну закладку определяет сам Vim -- "``", место в тексте, где было сделано последнее изменение. Подробно об этих и других командах перемещения можно прочесть в руководстве по Vi по команде ":help usr_03.txt".

Изменение текста

В командном режиме нельзя вводить символы в текст с клавиатуры, но изменить текст при этом можно, например, удаляя символы. Чтобы удалить отдельный символ (тот, на котором стоит курсор), достаточно нажать "x" в командном режиме, а чтобы удалить сразу целую строку (естественно, текущую, то есть ту, в которой находится курсор), "dd". "d" -- это сокращение от "delete", удалить, а "dd" -- характерный приём Vim: удвоение команды означает, что её нужно применить к текущей строке.

Из командной строки Vim можно выполнить операцию поиска и замены: для простой строки или для регулярного выражения. Причём синтаксис команды поиска и замены полностью воспроизводит синтаксис потокового редактора sed, о котором уже шла речь в лекции Работа с текстовыми данными.

Это файл для примеров.
Пример 1.
Моя первая сторка в vi...
~
~
~
:s/.$/.../

Замена по шаблону в Vim

Мефодий хотел заменить в своём файле точки в концах строки многоточиями. Для этого в командном режиме он нажал ":" (вызов командной строки Vim), где набрал команду "s" (сокращение от "substitute", заменить), за которой следует уже знакомое по "sed" выражение "/что_заменить/на_что_заменить/". Только результат получился совсем не тот, какого ожидал Мефодий: заменился на многоточие восклицательный знак последней строки. Не учёл он следующего: по умолчанию команды шаблоны для поиска и замены -- это регулярные выражения, то есть "." означает вовсе не точку, а "любой символ", имея в виду точку, следовало написать "\." "$", как и ожидал Мефодий, это конец строки. В момент выполнения команды поиска курсор находился в последней строке, в первом совпадении после курсора и была произведена замена.

Форматирование текста -- это расставление символов конца строки, пробелов и табуляций таким образом, чтобы текст хорошо смотрелся на экране терминала. Делать форматирование вручную крайне неэффективно. В Vi автоматичекое форматирование текста (если редактируется программа на каком-либо языке программирования, то с учётом правил этого языка) может происходить прямо в режиме вставки, в режиме вставки же можно изменять отступ текущей строки (по командам "^D" и "^T"). Для выравнивания текста по центру, правому или левому краю есть команды ":center", ":left" и ":right" соответственно. Эти команды, как и большинство команд командной строки, можно применять к диапазону строк способом, описанным ниже.

Режим ввода не богат специальными командами изменения текста, что и понятно: он предназначен именно для ввода, и больше ни для чего. Однако в Vi (но не в Vim!) есть некоторые удобства, упрощающие и сам процесс набора. Если слово, которое нужно ввести, уже встречалось в тексте, можно набрать только первые буквы и нажать "^P" ("previous") -- Vi попробует сам завершить его. Если Vi не угадал и предложил не то слово, можно продолжить перебирать варианты. Команда "^N" ("next") подставляет слова, которы встречаются ниже по тексту. Подробнее об этой функции можно узнать из руководства по команде ":help ins-completion".

Иногда, изменив текст, тут же хочется вернуть всё обратно, для этого в Vim предусмотрена команда отмены последнего изменения: "u" в командном режиме (от "undo", отменить). Сколь бы сложным, масштабным (и разрушительным) ни было изменение, совершённое последней командой, "u" вернёт текст в исходное состояние. Впрочем, саму отмену тоже можно отменить. В классическом Vim доступна отмена только последней выполненной команды, в Vi отменить можно сколько угодно последних команд, а также повторить их командой "^R".

Работа с фрагментами текста

Любая команда перемещения определяет две точки в тексте: та, в которой был курсор до перемещения, и та, в которую он переместился в результате данной команды. Расположенный между этими двумя точками отрезок текста однозначно задаётся командой перемещения. Например, команда ")" захватывает текст от текущего положения курсора до начала следующего предложения. Vim позволяет прменить к этому фрагменту любую команду -- так устроены гнездовые команды. Гнездовая команда состоит из действия и следующего за ним перемещения. Перемещение задаёт фрагмент текста, а действие определяет, что с этим фрагментом сделать. Например, команда "d)" удалит весь текст от текущей позиции курсора до начала следующего предложения. Наиболее полезные действия -- "d" ("delete"), "c" ("cchange"), ">" и "<" (сдвинуть), "y" (запомнить) и "gq" (отформатировать).

гнездовая команда

Команда редактора Vim, позволяющая применить указанное действие к указанному отрезку текста. Отрезок задаётся стандартной командой перемещения по тексту.

Очень часто возникает необходимость заменить фрагмент в тексте: слово, предложение, строку и т. д. Это можно сделать в два действия: сначала удалить часть текста, затем перейти в режим вставки и вставить замену. Vim предоставляет возможность упростить эту операцию, сведя два действия к одному: заменить. Гнездовая команда "c" предназначена именно для этого. Например, команда "cw" (буквально: "cange word") заменит текст от курсора до начала следующего слова (так можно заменить одно слово), "c)" заменит текст от курсора до начала следующего предложения.

Мефодий не забыл, что команды перемещения можно использовать с множителями, и попробовал заменить сразу три слова в своём файле на другие: для этого он в командном режиме подогнал курсор в начало слова "первая" и набрал "c3w" ("заменить фрагмент отсюда до начала третьего слова", буквально: "change 3 words"). Результат этой команды выглядел так:

Это файл для примеров.
Пример 1.
Моя #vi...
~
~
~
-- ВСТАВКА --                      3,5   Весь

Команда замены в Vim

В примере знак "#" обозначает позицию курсора: как видно, Vim удалил три слова, попавшие в зону действия команды и сразу перешёл в режим вставки. Мефодию осталось только набрать что-то взамен.

Перестановка частей -- типичная задача, возникающая в процессе редактирования. Для перестановки требуется удалить фрагмент в одном месте текста и вставить его же в другом. Для решения первой части задачи в Vim не понадобится специальных средств, потому что любая команда удаления ("d", "c", "x" и др.) сохраняет удалённый текст в специальном регистре. Для вставки последнего удалённого фрагмента служит команда "p" в командном режиме (от "put", положить). При помощи этой команды Мефодий может вставить только что удалённые им командой "c3w" три слова:

Это файл для примеров.
Пример 1.
Моя новая строка для vi...
первая сторка в
~
~
                                  4,1    Весь

Вставка удалённого фрагмента

Для того, чтобы скопировать фрагмент текста, служит команда "y" (от "yank", забрать, сдёрнуть): она не удаляет текст, а просто сохраняет его в том же регистре, что и команды удаления. Команду "y" можно использовать в гнездовых командах, например, "y5w" сохранит в регистре фрагмент текста от курсора до начала пятого слова. Вставить скопированный фрагмент можно всё той же командой "p". Однако таким способом можно вставлять только текст, удалённый или скопированный последним, для хранения нескольких разных фрагментов текста следует использовать именованные регистры, см. подробнее в руководстве по Vi.

Для того, чтобы применить команду к нескольким строкам текста, не обязательно подгонять к ним курсор. В командной строке Vim любой команде может предшествовать указание диапазона в тексте, к которому следует эту команду применить. Команды с указанием диапазона выглядят так: ":начало,конецкоманда", где начало и конец -- это адреса начальной и конечной строк диапазона (т. е. фрагмента текста), а команда -- это команда режима командной строки, такая как ":w" или ":r". Многие команды командного режима (в частности, "d" и "y") доступны также и в командной строке. В качестве адреса можно использовать номера строк в файле (команда ":1,5y" будет означать "скопировать в регистр строки с первой по пятую"), есть специальные обозначения для текущей строки ("."), последней строки ("$") и всего файла ("%"). Указать границу диапазона можно и при помощи шаблона: граничной будет считаться та строка, в которой обнаружится шаблон.

Последним свойством Мефодий воспользовался, чтобы удалить плоды своих экспериментов: он выполнил команду ":/Пример 1/,$d" (от строки "Пример 1" до конца файла -- удалить).

Это файл для примеров.
~
~
~
3 fewer lines

Удаление диапазона по шаблону. Выполнена команда ":/Пример 1/,$dEnter".

Настройка Vi и Vim

Вид и поведение Vim и Vi можно довольно существенно изменить при помощи настроек, приспособив редактор именно к своим вкусам и привычкам. Прямо во время работы редактора можно менять настройки из командной строки Vim при помощи команды ":set имя_настройки". Кроме того, можно сделать настройку постоянной, вписав все нужные значения в конфигурационный файл .vimrc (или .exrc -- для Vim) в домашнем каталоге пользователя. При каждом запуске Vim/Vi читает этот файл и исполняет все содержащиеся в нём команды. Объём данной лекции не позволяет подробно остановиться на настройке Vi, читатель может заняться изучением этого вопроса сам: все необходимые сведения есть в руководствах. Чтобы оценить возможности настройки, можно выполнить в Vi (но не в Vim!) команду ":options", по которой будет выведен список всех доступных опций с кратким описанием их смысла.

<<Anchor: execution failed [Too many arguments] (see also the log)>>

Лучше, чем Emacs?

Заголовок этого раздела сформулирован таким провокационным образом не случайно: любому пользователю похожей на UNIX операционной системы (к таким системам относится и Linux), в любом случае необходим текстовый редактор. Выбор очень многих пользователей падает на один из двух наиболее популярных и, как следствие, наиболее универсальных (реализованных и работающих везде) текстовых редактора: Vim (или одну из его улучшенных версий, чаще всего Vi) и Emacs. Оба эти редактора появились около тридцати лет назад, но их почтенный возраст только пошёл им на пользу: огромное количество пользователей по всему миру все эти годы занималось их отладкой, локализацией и расширением.

Vim и Emacs образуют альтернативную пару не только по исторической случайности: оба редактора претендуют на роль универсального средства для работы с текстом на любых естественных и искусственных языках. И действительно, трудно назвать сравнимый с ними по возможностям текстовый редактор, да ещё и настолько нетребовательный к интерфейсу: и Vi, и Emacs будут работать на любом терминале. Однако ограниченные возможности интерфейса терминала требуют от программ надёжного способа отделения команд редактору от вводимого текста. В Vi и Emacs эта задача решена по-разному -- отсюда большая часть различий в стиле работы с этими редакторами, отсюда и традиционный спор приверженцев этих редакторов о том, который из них лучше.

Тексты на разных языках

Главное свойство, которое сделало Emacs таким популярным и многофункциональным редактором -- это заложенная в нём с самого начала принципиальная расширяемость. Emacs почти полностью написан на специально созданном для него языке программирования: Emacs Lisp, и у любого пользователя есть возможность запрограммировать любые необходимые именно ему функции и подключить их в качестве модуля к Emacs. При этом сам Emacs никак изменять не требуется. Сообщество программистов не замедлило воспользоваться расширяемостью Emacs, и к настоящему времени важнейшее достоинство этого редактора состоит именно в свободно распространяемых пакетах расширений, содержащих инструменты для решения самых разнообразных задач, связанных с редактированием текста.

Современный Emacs -- это не просто текстовый редактор, а интегрированная среда для работы в системе. Основная идея сообщества разработчиков и пользователей Emacs состоит в том, что Emacs позволяет работать с любыми данными, которые могут быть представлены как текст (в лекции Работа с текстовыми данными обсуждалось, что таким образом можно представить очень многое в системе). Естественно, список содержащихся в каталоге файлов, программа на каком-либо языке программирования или электронное письмо -- это тексты, которые сильно различаются по структуре и по тому, что от них нужно пользователю. В Emacs для работы с текстами разного типа используются режимы.

режим emacs

Комплекс команд и настроек Emacs, предназначенных для работы с текстом определённой структуры, например, содержимым каталога, программой на Си и. т. п.

Каждый буфер в Emacs находится в одном из основных режимов. Основной режим -- это набор функций и настроек Emacs приспособленных для редактирования текста определённого вида. Каждый основной режим по-своему переопределяет некоторые управляющие символы, так что наиболее доступными становятся команды, чаще всего нужные именно для работы с текстом данного типа. Команды, специфичные для текущего основного режима, обычно начинаются с управляющего символа C-c. Некоторое представление о возможностях Emacs может дать весьма неполный список тех текстов, для которых существуют основные режимы:

Когда требуется много и быстро работать с текстом на каком-либо искусственном языке (языке программирования, разметки и пр.), возможно, Emacs -- это лучший выбор.


Обратите внимание, что в Emacs понятие "режим" имеет совершенно иной смысл, чем в Vim!


Не менее хорошо в Emacs развиты средства работы с текстами на самых разных естественных языках с самыми экзотическими письменностями. Просто для оценки возможностей Emacs в этой области можно выполнить команду "C-h h", по которой будет выведен файл, изображающий приветствие на разных языках.

Команды Emacs

Если в вашей системе установлен Emacs, то вы можете запустить, набрав emacs в командной строке любого терминала. Как и Vim, Emacs использует весь экран терминала, хотя интерфейс у него более богатый: вверху экрана находится строка с пунктами меню, под ней окно для отображения и редактирования текста, которое заканчивается строкой режима, в которой отображаются сведения о происходящем в окне. В самом низу экрана -- строка минибуфера, используемая для диалога с пользователем, в частности для отображения и редактирования вводимых команд.

Vi и вслед за ним Vi -- это многорежимные редакторы, когда команды вводятся в одном режиме, а текст -- в другом, что позволяет использовать в качестве командных любые клавиши. В Emacs нет специального командного режима, но использован тот факт, что с клавиатуры можно вводить не только печатные, но и некоторые управляющие символы. Для этого используются несколько управляющих клавиш терминала (прежде всего Ctrl и Alt), нажатые в сочетании с различными текстовыми символами. Чтобы ввести такой символ, нужно нажать управляющую клавишу (например, Ctrl) и, удерживая её, нажать клавишу с одним из печатных символов (например, "x"). Кроме того, в Emacs используется управляющая клавиша Meta, на тех терминалах, где она отсутствует, её функции обычно передаются клавише Alt. На "настоящих" терминалах обычно не бывает ни Meta, ни Alt; из клавиатурных модификаторов присутствуют только Ctrl и Shift. Тогда на помощь приходит старая добрая ESC: нажатие ESC, а после неё -- печатного символа (того же "x") эквивалентно "Meta x".

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

Общее правило здесь таково: чем чаще нужна команда, тем короче вызывающий её ключ, и наоборот. Для лаконичной записи длинных клавиатурных комбинаций в сообществе пользователей Emacs сложилась особая традиция сокращённых обозначений. Клавишу Ctrl обозначают заглавной буквой "C", Meta -- "M"(8). Сочетания с командной клавишей обозначаются дефисом, например, запись С-h обозначает, что нужно, удерживая Ctrl, нажать "h". C-h -- это префиксный ключ для команд справочной системы Emacs. Начинающему пользователю стоит выполнить команды "C-h ?" (набрать C-h и затем нажать "?") -- справка по командам помощи, "C-h t" -- интерактивный учебник для начинающих пользователей Emacs, и "C-h i" -- полное руководство по Emacs (в формате info). С ключа C-x начинаются основные команды Emacs, в частности, для работы с файламии буферами. Чтобы завершить работу Emacs, нужно ввести "C-x C-c".

У любой команды Emacs есть собственное имя, по этому имени можно вызвать команду даже если она не привязана ни к какому клавиатурному ключу. Для вызвова команд по имени используется префиксный ключ M-x. Например, посмотреть справку о помощи в Emacs можно командой "M-x help-for-help".

Работа с файлами

В Emacs, как и в Vim, пользователь редактирует текст не в самом файл, а в буфере. Отличие Emacs в том, что нельзя написать "безымянный" текст и затем сохранить его в файле. При запуске Emacs без параметров открывается специальный буфер -- "*scratch*", он предназначен для временных заметок -- его содержимое будет выброшено при закрытии Emacs. Если нужно создать новый файл -- его следует открыть командой "C-x C-f", точно так же открывается для редактирования уже существующий файл.

После того, как Мефодий нажал "C-x C-f", в минибуфере возникло приглашение: "Find file: ~/". Теперь нужно ввести путь к файлу, начиная с текущего каталога (Emacs любезно подсказал его Мефодию). С текстом в минибуфере можно обращаться почти так же, как с командной строкой shell или Vi: редактировать, использовать автодополнение (клавишей Tab), перемещаться по истории стрелочками вверх/вниз. Мефодий не замедлил воспользоваться этой возможностью и, набрав "te", нажав Tab и Enter, приступил к редактированию того же "textfile". Сохранить сделанные изменения можно командой "C-x C-s".

Когда Мефодий захотел открыть ещё один буфер, чтобы отердктировать один из своих сценариев, он запамятовал точное название нужного файла и, набрав "C-x C-f bin/", нажал Enter. При в окне возник список файлов в подкаталоге "~/bin", похожий на вывод ls -l:

File Edit Options Buffers Tools Operate Mark Regexp Immediate Subdir Help
  /home/methody/bin:
  итого 24
  drwxr-xr-x   2 methody methody 4096 Дек  2 15:21 .
  drwx------  10 methody methody 4096 Дек  2 15:21 ..
  -rwxr-xr-x   1 methody methody   26 Ноя  9 21:34 loop
  -rwxr-xr-x   1 methody methody   23 Ноя  9 21:34 script
  -rwxr-xr-x   1 methody methody   32 Ноя  9 21:34 to.sort
  -rwxr-xr-x   1 methody methody   44 Ноя  9 21:34 two


-RRR:%%-F1  bin (Dired by name)--L5--C51--All--Reading directory /home/methody/bin/...done

Emacs. Режим dired

Как указано в строке режима, это Dired, редактор каталогов, режим emacs, предназначенный для просмотра и изменения каталогов прямо из редактора. В Dired можно выбирать отдельные файлы, или группы файлов и производить над ними различные действия: открыть для редактирования, удалить, скопировать, переместить, переимновать по определённой схеме -- словом, Dired, довольно мощное средство для наглядной работы с файловой системой, особенно он удобен для работы с группой файлов. Подробности о командах, доступных в этом режиме, можно найти в руководстве по Emacs.

Перемещение по тексту

В Emacs, как и в Vim есть понятие точка, это то место в буфере, где будет происходить вставка или удаление данных. Перемещение по тексту -- это перемещение точки. Команды перемещения по структурным элементам текста развиты не менее, чем в Vim, помимо обычных стрелок, действуют команды перемещения в начало и конец строки (C-a и C-e), буфера (M-< и M->), предложения (M-a и M-e); к предыдущему и следующему слову (M-f и M-b), абзацу (M-{ и M-\ }). Различные основные режимы предоставляют специализированные команды для перемещения по структурным элементам текстов на разных языках программирования, разметки и пр.

В Emacs несколько видов поиска: существуют отдельные команды для поиска строки и поиска по регулярному выражению. Если требуется найти ближайшее употребление конкретного слова, удобнее всего воспользоваться наращиваемым поиском по команде C-s. Наращиваемый поиск уже встречался Мефодию: так был устроен поиск по истории команд в bash. По мере набора первых символов искомой строки Emacs переносит точку к ближайшему такому сочетанию симвлов после курсора. Поиск в обратном направлении (к началу буфера) осуществляется командой C-r. Наращиваемый поиск можно выполнять по регулярному выражению (C-M-s). Все виды наращиваемого поиска в Emacs не различают прописные и строчные буквы.

Изменение текста

В Emacs доступно множество команд, экономящих усилия при редактировании текста. Если пользователь осознаёт, что набрал что-то неправильно, то можно удалить разом последнее слово (M-Del), предложение (C-x Del). Можно уничтожать и вперёд: до конца слова (M-d) и предложения (M-k). Emacs хранит не только последний удалённый фрагмент, но и все предыдущие, формируя список удалений. Только что уничтоженный текст можно вставить командой C-y. После этого его можно заменить предыдущим уничтоженным фрагментом -- M-y. Можно двигаться и далее назад по списку удалений, повторяя M-y.

Хорошо продуманы команды для перестановки частей текста вокруг точки: двух знаков (C-t), слов (M-t), строк (C-x C-t). Команда M-t не перемещает знаки препинания между словами, поэтому "потеха, дело" превратится в "дело, потеха".

Прямо из Emacs можно вызвать программу проверки орфографии ("M-x ispell-buffer") или даже включить проверку "на лету", когда неправильно написанные слова выделяются другим цветом ("M-x flyspell-mode"). Можно проверить написание отдельного слова, в котором находится точка ("M-x $") или завершить недописанное слово, основываясь на орфографическом словаре ("M-x Tab").

В Emacs так много специальных команд для изменения текста, что команды поиска и замены бывают нужны не так часто. Произвести замену строки всюду в буфере можно по команде "M-x replace-string что заменить Enter на_что_заменить Enter", для замены регулярного выражения -- аналогичная команда "M-x replace-regexp".

Если нужно заменить строку только в некоторых случаях, пригодится команда M-%, запрашивающая подтверждение о замене при каждой найденной строке. Аналогичная команда для регулярных выражений -- C-M-%.

Любые изменения в тексте можно отменить командой C-_ (нужно нажать Ctrl, Shift и "-").

Работа с фрагментами текста

Многие команды Emacs работают с произвольным фрагментом текущего буфера. Такие команды всегда применяются к текущей области. Область -- это отрезок текста между точкой (где находится курсор) и меткой. Метка в любой момент присутствует в любом буфере, пользователь может установить её в любом месте текста явно -- командой M-Пробел. Метка может перемещаться и без вмешательства пользователя: команды перемещения и редактирования могут изменять положение метки. Таким образом, чтобы выделить в буфере фрагмент текста, можно произвести следующие операции:

Теперь можно выполнять команду редактирования -- она будет применена именно к выделенной области. Например, C-w удалит текст области, а M-w скопирует его. Вставить удалённый или скопированный фрагмент можно командой C-y.

Есть группа команд, позволяющих работать с меткой более эффективно: установить метку после конца следующего слова (M-@), пометить текущий абзац (M-h), весь буфер ("C-x h"). Различные основные режимы предоставляют команды для пометки структурных элементов текста, например, разделов документа, определения функции (в тексте программы) и т. п. Все положения метки хранятся в списке пометок, перенести точку в любое из предшествующих положений метки можно, нужное количество раз повторив команду "C-u C-@".

область

Непрерывный отрезок текста, ограниченный точкой с одной стороны и меткой с другой.

Как и в Vim, в Emacs можно использовать для хранения информации регистры. В регистре Emacs можно сохранить позицию в буфере и затем перейти к этой позиции ("C-x r Пробел x" записывает позицию точки в регистр "x", а "C-x r j x" переходит в эту позицию). В регистре можно сохранить текст из области ("C-x r s x" сохраняет область в регистре "x", "C-x r i x" -- вставляет текст из этого регистра). В регистрах также можно хранить числа, имена файлов, конфигурацию окон. Подробности как всегда доступны в руководстве.

Настройка Emacs

Коротко говоря, в Emacs можно настроить всё: связи между ключами и командами редактора, определить макрокоманды, написать собственные расширения. Есть возможность изменять настройки Emacs как в процессе работы, так и при помощи конфигурационного файла .emacsrc.

Просто текстовые редакторы

И в Vim, и в Emacs интегрировано множество средств для автоматизации прочесса редактирования. Эти редакторы становятся удобны в том случае, если прежде, чем браться делать что-то вручную, пользователь обращается к руководству и находит в нём способ выполнить свою задачу максимально быстро и с минимальными затратами ручного труда. Однако если пользователя не устраивает такой принцип работы (когда нужно часто и подолгу читать документацию и думать, чтобы "ручную" работу выполнял компьютер), Vim и Emacs будут не самым лучшим выбором. Для обычного редактирования текста вручную лучше выбрать один из текстовых редакторов с простым и привычным интерфейсом: в дистрибутивах Linux можно найти огромное количество таких текстовых редакторов с большими или меньшими возможностями: mcedit, joe, pico (часть почтовой программы pine) -- всех не перечислить. Есть редакторы, которые предназначены для работы не в терминале, а в графической среде (например, nedit), у тех же Vi и Emacs есть графические варианты (GVim и Emacs-X11 или XEmacs), в которых доступны дополнительные возможности графического пользовательского интерфейса: меню, иконки и пр.


(1) Эта кажущаяся сегодня тривиальной возможность сколько угодно редактировать текст, не оставляя при этом никаких следов, была радикальнейшим достижением прогресса по сравнению с пишущей машинкой.

(2) Vi, как и большинство основных утилит и принципов, унаследован Linux от UNIX. Название Vim происходит от visual editor, "визуальный", экранный редактор, поскольку Vim -- первый редактор для UNIX, использующий весь экран для отображения текста и позволяющий работать с текстом не построчно, а перемещаясь по нему в любых направлениях, как по странице.

(3) Обычно современные терминалы и программы-эмуляторы терминалов поддерживают вывод текста по крайней мере несколькими разными цветами.

(4) Если используется не Vi, или настройка showmode по умолчанию запрещена, сообщения может и не быть.

(5) В действительности содержимое буфера хранится в специальном временном файле (swap file). Если сеанс работы в редакторе по какой-то причине прервался, то этот временный файл не будет удалён, и при следующей попытке продолжить незаконченную работу с файлом Vim предложит провести процедуру восстановления -- на случай, если во временном файле остались несохранённые изменения.

(6) Управляющая последовательность "^C" приводит к аварийному завершению текущей команды vi, а не самого редактора.

(7) Символами "^" и "$" в Linux повсеместно обозначаются начало и конец строки, в частности, в регулярных выражениях.

(8) За свои длинные команды из разных комбинаций управляющих клавиш название Emacs получило шуточную расшифровку: Escape-Meta-Alt-Control-Shift.