Skip to content

Latest commit

 

History

History
2201 lines (1785 loc) · 176 KB

File metadata and controls

2201 lines (1785 loc) · 176 KB

Об одном текстовом редакторе

Введение

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

Ниже приведен обзор возможностей Emacs и того, как ими пользоваться. Изложение в нём структурировано следующим образом:

  • Те, кому просто нужен текстовый редактор, могут ограничить чтение секциями “Установка”, “Обозначения” и “Начало работы” (совсем небольшими по объему).
  • Тем, кто уже начал использовать Emacs и хотел бы узнать побольше о его основных возможностях, к прочтению рекомендуются все разделы. Думаю, что на их освоение уйдет один дождливый или морозный выходной.
  • Те, кто овладел основными возможностями Emacs и хочет узнать о более интересных способах его использования, могут найти полезные ссылки в заключении.

Содержание

Установка

Для установки Emacs, пользователи ОС Ubuntu могут воспользоваться следующей командой:

sudo apt-get install emacs24

Для установки предлагаемой конфигурации:

git clone https://github.com/snosov1/dot-emacs.git ~/.emacs.d

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

Обозначения

Единственное, что нужно обговорить перед тем, как перейти непосредственно к работе - обозначения комбинаций клавиш:

  1. С- обозначает Ctrl.
  2. M- обозначает Alt. Пользователи продукции Apple могут не найти у себя такой кнопки, её место (насколько мне известно) занимает клавиша Cmd и именно она функционирует в роли M-.
  3. S- обозначает Shift.

Эти символы участвуют в обозначении комбинаций клавиш, например:

  • C-n означает Ctrl-n
  • C-x C-f означает, что надо нажать Ctrl-x и потом Ctrl-f (Ctrl можно не отпускать между нажатиями x и f)
  • C-c f - означает, что нужно нажать Ctrl-c и потом (с отпущенным Ctrl) нажать f

Самые часто используемые команды, такие как перемещение курсора, как правило, выполняются нажатием одного модификатора и одной буквенной клавиши. При этом буквенный символ чаще всего является мнемоническим, например, C-n - переместить курсор на следующую строчку (next line). Для менее частых, но тоже важных команд, как правило, используется префикс C-x, например, C-x C-f - открыть файл (find file). Для схожих по частоте и важности команд, определенных пользователем, используется префикс C-c, например, C-c C-o - открыть файл (или интернет-адрес), путь к которому находится под курсором.

Теперь можно начинать!

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

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

Предлагаю попробовать набрать небольшой абзац - уверен, что всё получится без дополнительных объяснений. Большинство распространенных команд и сочетаний работают “как обычно”.

Единственное, возможно, кто-то привык использовать кнопки Ctrl-x, Ctrl-c и Ctrl-v при редактировании. В Emacs эти комбинации выполняют совсем другие функции. Подробнее я расскажу о том, как устроены копирование и вставка в Emacs позже, а первое время можно просто использовать следующие аналоги:

  • C-w, либо S-<delete> - вырезать
  • M-w, либо С-S-<insert> - копировать
  • C-y, либо S-<insert> - вставить

Комбинации, указанные вторыми, являются довольно традиционными и работают в большинстве современных редакторов. А комбинации, укзанные первыми, являются традиционными для Emacs.

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

Теперь попробуем открыть какой-нибудь файл. Для этого используем комбинацию C-x C-f. Внизу, в т.н. минибуфере появится имя текущей директории и начало списка находящихся в ней файлов.

По мере набора имени файла будут оставаться только те варианты, которые соответствуют набранным символам. Например, можно набрать “rdme”, и если в директории есть файл с именем Readme.txt (регистр не учитывается), то он останется в числе кандидатов. При наборе можно пропускать символы, но порядок должен оставаться тем же, что и в имени файла, т.е. если, набрать “drme”, то Readme.txt уже пропадет из списка кандидатов.

При открытии файла работают следующие команды:

  • Enter - открыть подсвеченный файл или зайти в директорию
  • Backspace - вверх на одну директорию
  • C-s - следующий кандидат в списке
  • C-r - предыдущий кандидат в списке
  • C-f - переход к “простому” вводу имени файла (в частности, необходим для создания новых файлов)
  • ~/ - домашняя директория
  • /-<символ> - корневая директория

После внесения изменений, файл можно сохранить командой C-x C-s (save file). Сохранить его с другим именем можно командой C-x C-w (write file).

Для простого поиска по файлу используются сочетания:

  • C-s и C-r - поиск вперед и назад, соответственно (повторные нажатия переводят курсор к очередному кандидату)
  • C-g или ESC - отмена поиска и возврат курсора в исходную позицию
  • C-m или Enter - выход из поиска

Для выхода из Emacs используется сочетание C-x C-c.

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

  • Для отмены последних редактирований (т.н. undo) можно воспользоваться сочетанием C-z или равнозначным ему C-/ (подробнее об отмене позже).
  • В остальных случаях можно попробовать нажать C-g, что для большинства команд означает “отмена” (либо “усиленный” вариант отмены - ESC).

И последнее. При переключении языка ввода на русский, можно заметить, что практически все разобранные в этой секции комбинации перестают работать - внизу появляются сообщения вроде C-ы is undefined. В принципе, из этого сообщения можно понять, что происходит, но остается вопрос, что делать. Ответ прост - для переключения языка в Emacs нужно использовать комбинацию C-\ - таким образом язык переключается не на уровне системы, а на уровне Emacs. Т.е. в Emacs попадают команды с латинскими буквами, но после того, как было нажато C-\, Emacs будет переводить символы латинского алфавита в соответствующие (в смысле раскладок QWERTY-ЙЦУКЕН) символы русского алфавита.

Обогащенные этими знаниями должны быть в состоянии пользоваться Emacs в повседневной жизни вместо своего прошлого любимого текстового редактора, практически не изменяя старым привычкам. Дальше пойдут бонусы.

Минимальные требования

Этот раздел написан для тех читателей, которые собираются всерьез подойти к изучению Emacs. В целом, без выполнения требований этого раздела можно сразу начать им пользоваться, как обычным текстовым редактором - большинство часто используемых команд можно найти в общепринятых или легко доступных местах. Наиболее значимые исключения составляют клавиши Ctrl-x, Ctrl-c и Ctrl-v, о чем было сказано в разделе “Начало работы”.

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

Слепая печать

Ты должен научиться печатать вслепую. Точка. Точнее, восклицательный знак.

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

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

Самый простой способ научиться - пройти курс “Соло на клавиатуре”. Первым делом нужно пройти английский курс, после этого, по желанию - русский.

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

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

Caps Lock - третий Ctrl

Нужно изменить конфигурацию клавиатуры, чтобы Caps Lock выступал в роли третьего Ctrl’а. С первого взгляда такой поворот событий может показаться диким, но это обязательно нужно сделать.

Все современные операционные системы (кроме Windows, если там ничего не изменилось) имеют для этого соответствующую галочку в настройках клавиатуры.

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

  • Создать файл, с расширением .reg, например capstoctrl.reg
  • Открыть его при помощи блокнота (или Emacs’a, если он уже установлен) и заполнить его следующим содержимым:
    Windows Registry Editor Version 5.00
    
    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
    "Scancode Map"=hex:00,00,00,00,00,00,00,00,02,00,00,00,1d,00,3a,00,00,00,00,00
        
  • Щелкнуть по нему два раза мышью и согласиться на внесение изменений в реестр

Переключение языка на Super(Win)-Space

И последнее. Рекомендую привыкнуть переключать языки (с русского на английский и наоборот) сочетанием Super(Win)-Space, иначе говоря, “Кнопка Виндоуз”-Пробел. А другие возможности для переключения языка лучше отключить.

Дело в том, что в Emacs время от времени придется использовать сочетания, предусматривающие одновременное нажатие Ctrl-Alt, Ctrl-Shift и Shift-Alt. И если какая-то из этих комбинаций также переключает язык - то время от времени он будет нечаянно переключаться.

Насколько мне известно, “яблочные” системы используют аналогичное сочетание, с каких-то пор в Windows оно работает по умолчанию. Ubuntu тоже, кажется, следует моде. Нечасто в нашем деле можно встретить такое единение - предлагаю присоединиться.

Файловый менеджер

Есть довольно известный в определенных кругах анекдот: “Из Emacs получилась бы отличная операционная система, если бы в нём был нормальный текстовый редактор”. Я не буду подробно объяснять в чем же, собственно говоря, юмор. Вместо этого я расскажу о встроенном в Emacs файловом менеджере.

Вообще, файловый менеджер - это самый первый инструмент для работы на компьютере, с которым я познакомился. В те далекие годы, когда я не знал, как написать даже самую простую программу, я, тем не менее, умел открыть голубой экран Norton Commander’a и стремительно носиться по файлам и папкам без использования мышки - в чем и была главная функция файлового менеджера.

Для этих же целей в Emacs имеется свой собственный файловый менеджер - Dired (directory editor). Открыть его можно нажатием C-x C-j (dired jump), при этом мы окажемся в папке, в которой находится редактируемый в данный момент файл. Если нажать C-x C-j, уже находясь в dired, то это перебросит нас на директорию выше - гораздо более удобная альтернатива беготне до строки с двумя точками.

Единственное, что стоит ещё отметить, это то, что Dired не обновляет своё содержимое автоматически. Т.е. если в какую-то директорию, открытую в Dired, скопировать файл или создать в ней новый файл, то отображаемое содержимое директории не изменится. Для того, чтобы обновить содержимое, используется кнопка g.

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

Однако, смею заверить, что это лишь вершина айсберга - возможности dired гораздо более широки. Dired - на удивление мощный, гибкий и гармоничный менеджер - особенно элегантный на фоне своих аналогов - Norton Commander’a, FAR’a, Total Commander’a и проч. Но разговор об этом я буду вести после того, как опишу другие базовые возможности Emacs.

Базовые операции

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

  • C-n - вниз (next line)
  • C-p - вверх (previous line)
  • C-f - вперед (forward char)
  • C-b - назад (backward char)

Любое перемещение рук с их рабочего положения - к стрелочкам, PgUp-ам/PgDown-ам/Home-ам/End-ам - это работа от локтя, которая плохо автоматизируется и менее энергоэффективна, чем работа пальцами. Поэтому в первую очередь мы будем переучиваться использовать буквенные клавиши для выполнения частых операций.

Вот эквиваленты других часто используемых команд:

  • C-a - в начало строки (Home)
  • C-e - в конец строки (End)
  • C-v - вниз на величину экрана (PgDown)
  • M-v - вверх на величину экрана (PgUp)
  • M-> - в конец буфера
  • M-< - в начало буфера
  • C-h - удалить символ слева от курсора (Backspace)
  • C-d - удалить символ справа от курсора (Delete)
  • С-j - перевод строки

Можно было бы сказать, что С-j - замена клавиши Enter, но это будет не совсем корректно. Если задуматься, то Enter, вообще говоря, выполняет 2 функции - перевод строки и “ввод”. Например, если ты набираешь строку поиска в Гугл, то, нажав Enter, ты выполняешь поиск, а не переводишь строку, т.е. в зависимости от ситуации, Enter ведет себя тем или иным образом.

В Emacs эти две функции разнесены на разные кнопки. 95 процентов времени используется именно C-j - и для перевода строки, и как “ввод” - в тех случаях, когда это не вызывает двусмысленности. Одним из наиболее важных примеров, когда действия C-j и C-m отличаются, является процесс открытия файлов. Если после нажатия C-x C-f текущим выбором является директория (а не файл), то нажатие C-m приведет к тому, что мы продолжим выбор файлов, но уже внутри этой директории. А нажатие C-j приведет к тому, что текущая директория будет открыта в Dired.

Отдельно хочу отметить замечательную комбинацию C-l. При первом нажатии, она устанавливает содержимое буфера так, чтобы курсор находился в самом центре окна. При повторном нажатии, содержимое меняется, чтобы курсор оказался в самом верху, а при третьем - в самом низу. Очень полезная и часто используемая функция.

Работа со словами и другими структурными единицами

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

Если в посимвольных командах использовать клавишу M-, то это позволит оперировать более сложными единицами:

  • M-f - следующее слово (forward word)
  • M-b - предыдущее слово (backward word)
  • M-a - в начало предложения (выражения в языках программирования)
  • M-e - в конец предложения (выражения)
  • M-h - вырезать слово слева от курсора
  • M-d - вырезать слово справа от курсора

Некоторые из этих команд могут быть ещё больше “усилены” добавлением C-. Например, для перемещения по сбалансированным скобкам, в Emacs используются команды:

  • C-M-f - следующее “скобочное выражение” (forward sexp)
  • C-M-b - предыдущее “скобочное выражение” (backward sexp)

Эти функции работают почти также, как и функции “следующее слово” и “предыдущее слово”, с тем исключением, что они расценивают выражение в круглых, фигурных или прямоугольных скобках, а также строки в кавычках, за одну единицу. Т.е. если перед курсором открывающаяся скобка и ты нажмешь C-M-f, то курсор переместится к закрывающей скобке. Вывести курсор за пределы скобок, в которых он находится, при помощи этих функций нельзя.

  • С-M-a - в начало абзаца (функции в языках программирования)
  • С-M-e - в конец абзаца (функции)

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

  • С-M-p - предыдущая пустая строка (previous paragraph)
  • С-M-n - следующая пустая строка (next paragraph)

Отмечу, что для обычного текста эти сочетания по функциональности ничем не отличаются от перемещения между абзацами.

Таким образом, в Emacs выделяются следующие текстовые единицы:

  • символы и строки (префикс С-)
  • слова и предложения (префикс M-)
  • скобочные выражения (префикс С-M-)
  • абзацы (выражения и функции в языках программирования) (префикс С-M-)

При разговоре о скобочных выражениях необходимо также отметить команду C-S-h (splice sexp). Она несколько выбивается из рассматриваемого ряда по функциональности (а потому и по форме “аккорда” - использованием Shift вместо Alt), но тем не менее слишком важна, чтобы не упомянуть её. Указанная комбинация удаляет обрамляющие символы скобочного выражения, внутри которого находится курсор. Т.е. если курсор находится внутри цитаты, заключенной в кавычки, то C-S-h удаляет обе - открывающую и закрывающую. Эта команда позволяет легко следить за тем, чтобы скобки (и кавычки) всегда были сбалансированы.

В завершение этой секции, я приведу последнюю команду, которая используется для работы с языковыми единицами, и которую нечасто встретишь в других редакторах:

  • C-t - поменять буквы слева и справа от курсора местами (transpose chars)
  • M-t - поменять слова слева и справа от курсора местами (transpose words)

Не сказать, что эти функции используются очень часто, но лично у меня на душе становится теплее, когда нет-нет да и получится их использовать. Кроме того, эти функции обладают интересным свойством, если, например, использовать M-t несколько раз подряд, то это будет иметь эффект, как будто ты “тащишь” слово вперед по тексту.

Окна и буферы

Определения

Современные приложения - браузеры, редакторы и т.п. - позволяют пользователю открыть несколько т.н. вкладок. Например, если ты гуляешь по интернету, то в браузере у тебя одновременно открыты ВКонтакте, Твиттер, Фейсбук, Ю-тюб и ещё много чего, чтобы ты, не дай Бог, не пропустил момент, когда кто-то пришлет тебе веселую картинку или ролик.

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

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

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

Зачастую, причины, по которым в Emacs что-то сделано определенным образом, являются чисто историческими. Например, поскольку на UNIX-терминалах 1970-х годов не было ни мышек, ни даже графических интерфейсов, придумать и реализовать вкладки в их современном виде тогда не пришло бы никому в голову.

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

Этим я хочу сказать, что как только тебе в голову начнут залезать предательские мысли о том, что что-то в Emacs делается “не так, как должно бы” - гони их прочь. Скорее всего, в тебе просто говорит привычка и нежелание учиться и переучиваться. Практически во всех случаях после непродолжительного использования и размышления становится понятно, что предложенное решение является разумным, целостным, продуманным и вполне годным.

Конечно, идеальных решений не существует и, поразмыслив над какой-то проблемой, возможно, ты только ещё больше убедишься в том, что решать её надо по-другому. В этом случае мой совет такой - если ты пользуешься Emacs’ом меньше полугода - просто прикуси губу и попытайся работать так, “как задумано композитором” (с) Chet Atkins.

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

А теперь вернемся к работе с окнами и буферами.

В Emacs есть 3 основных понятия, связанные с организацией рабочего пространства - это фрейм (frame), окно (window) и буфер (buffer).

Рассмотрим диаграмму, на которой изображен пример рабочей сессии в Emacs.

+-------------------------------------------------------------------------------------+
| emacs@sergei-MS-7758                                                                |
+-------------------------------------------------------------------------------------+
| File Edit Options Buffers Tools Org Tbl Help                                        |
+------------------------------------------+------------------------------------------+
| #!/usr/bin/env rdmd                      | * Работа со словами и абзацами           |
| // Computes average line length for      |                                          |
| // standard input.                       | Работать в редакторе с отдельными символа→
| import std.stdio;                        | эффективно, как умножение заменять сложен→
|                                          | оперирует в голове отдельными символами, →
| void main() {                            | единицами - словами, предложениями, абзац→
|     ulong lines = 0;                     | программирования соответствует идентифика→
|     double sumLength = 0;                | (либо функциям). Поэтому гораздо удобнее →
|     foreach (line; stdin.byLine()) {     | которые оперируют с этими же структурными→
|         ++lines;                         |                                          |
|         sumLength += line.length;        | Если в посимвольных командах использовать→
|     }                                    | позволит оперировать более сложными едини→
|     writeln("Average line length: ",     |                                          |
|         lines ? sumLength / lines : 0);  | - =M-f= - следующее слово (forward word) →
| }                                        | - =M-b= - предыдущее слово (backward word→
|                                          | - =M-a= - в начало предложения (выражения→
|                                          | - =M-e= - в конец предложения (выражения)→
+------------------------------------------+------------------------------------------+
|1 U:--- lc.d    All L12   (D/l hs Abbrev) |2:U:**- README.org     84% L472           |
+------------------------------------------+------------------------------------------+
| * Установка...                                                                      |
| * Предисловие...                                                                    |
| * Минимальные требования                                                            |
|                                                                                     |
|   Список того, что требуется от читателя - совсем небольшой - но очень              |
|   важный:                                                                           |
|                                                                                     |
|   - Во-первых, ты должен научиться печатать вслепую. Переоценить                    |
|     важность этого навыка невозможно. Никакие программы, инструменты,               |
|     авто-дополнения, подсказки, интуитивно понятные интерфейсы не улучшат           |
|                                                                                     |
|     Конечно же, в целом, без этого можно прожить - но выглядеть это будет           |
+-------------------------------------------------------------------------------------+
|3 U:**- README.org     2% L120        (Org Ind ARev)                                 |
+-------------------------------------------------------------------------------------+
|                                                                                     |
+-------------------------------------------------------------------------------------+

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

Внутри фрейма могут создаваться окна - контейнеры, отвечающие за его “геометрическую организацию”. На приведенной диаграмме окна пронумерованы - их номера записаны в самом начале т.н. строки состояния (modline) - 1 U:--- lc.d <...>.

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

Ещё раз обращаю внимание, что окна - чисто геометрические сущности, а буферы наполняют их содержанием.

Например, в первом окне отображен буфер, соответствующий файлу “lc.d”, что отражено в строке состояния. А буфер, соответствующий файлу “README.org” отображен сразу в двух окнах - втором и третьем, причем отображают они разные части файла. Но поскольку это один и тот же буфер, его изменеие в одном окне влияет на содержимое другого.

Список буферов

Для того, чтобы создать буфер, нужно просто открыть файл. Как уже оговаривалось, сделать это можно командой C-x C-f.

Для переключения между буферами используется комбинация C-<TAB>, для закрытия буфера - C-x k.

Если во время выбора буфера или файла ты вдруг передумал открывать что-либо, то можно нажать C-g. Повторюсь, что эта комбинация означает “отмена” не только в этом случае, но и для большинства нетривиальных команд Emacs.

Открыв несколько файлов, можно получить список всех буферов с помощью клавиш C-x C-b, который выглядит примерно следующим образом:

 MR Name                    Size Mode             Filename/Process
 -- ----                    ---- ----             ----------------
[ org ]
    README.org             36003 Org              ~/.dev-setup/dot-emacs/README.org
[ dired ]
[ D ]
[ C/C++ ]
[ magit ]
[ Markdown ]
[ emacs ]
 *  *Messages*               554 Fundamental
[ shell commands ]
[ Default ]
 *  *shell*                   25 Shell            (shell run) ~/
    .emacs                 44231 Emacs-Lisp       ~/.dev-setup/dot-emacs/.emacs
    *scratch*                  0 Emacs-Lisp
    config                   337 Conf[Space]      ~/.ssh/config
 *% *Compile-Log*            102 Special

    7 buffers              81252                  4 files, 1 process

В этом списке можно навести курсор на строчку с именем буфера и нажать Enter, либо C-m для того, чтобы открыть соответствующий буфер.

Разберем, что указано в столбцах этого списка.

Расшифровка загадочного названия первого столбца - “Modified, Read-only”. Если буфер имеет несохраненные изменения, то первый символ в этом столбце - “*”. Если буфер нельзя редактировать, то второй символ в этом столбце - “%”.

Во втором столбце указано имя буфера, в третьем - размер содержимого буфера в байтах.

В четвертом столбце указан основной режим (mode) буфера. Существуют, например, режимы для редактирования файлов с программами на языках С++, D, Python и т.д.; есть режимы для редактирования HTML, LaTex; есть также специальные режимы, которые предназначены не для редактирования файлов, а для взаимодействия с другими программами, например, для просмотра директорий или выполнения команд в терминале.

Основной режим определяет способы редактирования и отображения буфера. Например, в языке программирования С++ есть такие ключевые слова, как inline, const, class, struct и др. И если открыть файл с программой на С++, то эти слова выделятся специальным цветом. А в языке Python, например, слова inline, const и struct не являются ключевыми, в то время как слова class, in, elif и др. - являются. Для того, чтобы выделить ключевые слова корректно, буферы с файлами на языках C++ и Python будут открыты в разных режимах, каждый со своими представлениями о том, какие слова считать ключевыми.

Как правило, режим, в котором открывается буфер определяется по расширению файла. Например, в приведенном списке буферов, файл “README.org” открыт в режиме Org, предназначенном для редактирования файлов с одноименной разметкой.

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

Также в списке буферов присутствуют горизонтальные разделители в квадратных скобках (например, “[С/C++]”), они объединяют файлы в группы по каким-то общим признакам. Состав групп и используемые признаки могут настраиваться, но мы не будем на этом сейчас останавливаться.

Работа с окнами

Нередко при работе требуется, чтобы перед глазами одновременно было несколько буферов или разные части одного и того же буфера. Для этого в Emacs и предназначены окна.

Для работы с ними используются следующие команды:

  • Создание
    • C-x 2 - разделить текущее окно по горизонтали
    • C-x 3 - разделить текущее окно по вертикали
  • Уничтожение
    • C-x 1 - уничтожить все окна, кроме текущего
    • C-x 0 - уничтожить текущее окно
  • Переход между окнами
    • M-1, M-2, M-3 и т.д. - переход в окно с указанным номером
    • C-x o - переход в следующее окно (other window)

Пользуясь командами для создания и уничтожения, можно строить довольно замысловатые конструкции из окон. Однако, лично у меня 95 процентов времени открыто либо одно, либо два окна.

Такой подход разительно отличается от того, что предлагают практически все современные “интегрированные среды разработки” (IDE). Рабочее пространство в них, как правило, ужасно захламлено. Одновременно там отображается редактор кода, дерево файловой системы, панели со всевозможными настройками, функциями и проч. Думаю, что во многом по этой причине, я практически не встречал людей, которые при работе в IDE открывают файлы одновременно в двух окнах, а предпочитают переключаться между вкладками.

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

На мой взгляд, рабочее место человека является прямым отражением того, что у него происходит в голове. И если рабочее место человека - это непонятная свалка, то и в голове у него точно такая же свалка. Нарисовать в таких условиях картину в стиле “героиновый сон” и сказать, что художник “так видит”, наверное, можно. Но вот создать архитектурный проект “на века”, наверное, уже нельзя.

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

В конце отмечу, что поскольку чаще всего одновременно я использую не больше двух окон, то переключаюсь между ними я при помощи комбинации C-x o, что позволяет не держать в голове номер текущего окна. Кроме того, при наличии двух окон, полезными оказываются следующие команды:

  • C-c f - поменять вертикальное разделение на горизонтальное и наоборот (flip windows)
  • C-c s - поменять местами буферы, отображаемые в окнах (swap buffers)

Строка состояния

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

3 U:**- README.org 2% L120 (Org Ind ARev)

Разберем её слева направо.

  • 3 - номер окна
  • U - кодировка текущего буфера; в данном случае - UTF-8
  • : - разделитель
  • **- - 3 символа, описывающие состояние буфера; возможные значения:
    • первый символ:
      • - или * - буфер доступен для редактирования
      • % - буфер доступен только для чтения
    • второй символ:
      • - - все изменения буфера сохранены
      • * - в буфере есть несохраненные изменения
    • третий символ:
      • - - буфер является локальным, т.е. соответствует файлу или процессу на том же компьютере, на котором запущен Emacs
      • @ - буфер является удаленным, т.е. соответствует файлу или процессу на удаленном сервере
  • README.org - имя буфера
  • 2% - позиция окна в буфере; 2 процента означают, что отображаемый в окне текст находится почти в самом начале буфера; также вместо числа процентов может быть указано: Top - окно отображает самое начало буфера, Bot - окно отображает самый конец буфера, All - окно отображает буфер целиком
  • L120 - символ L и номер строки, на которой находится курсор
  • (Org Ind ARev) - перечень режимов, работающих в этом буфере; первым всегда указан основной режим, после чего указан неполный перечень дополнительных режимов

Вырезать/Вставить

Выделение регионов

Важной функцией любого редактора является работа с областями текста, которые в Emacs называются регионами. Для выделения регионов многие люди используют мышку, более продвинутые - используют стрелочки с зажатой клавишей Shift. В Emacs оба эти способа тоже работают, однако считаются неоптимальными.

Для выделения произвольного региона нужно нажать C-SPC, по-русски говоря, Ктрл-Пробел. После этого при изменении положения курсора начнет выделяться регион между текущим положением и положением, где находился курсор во время нажатия C-SPC.

Для выделения всего буфера используется сочетание C-x h (mark whole buffer).

Для снятия выделения используется сочетание C-g, которое, как говорилось в самом начале, для большинства команд обозначает “отмена”.

Кроме такого способа, Emacs также предлагает выделение структурных единиц при помощи комбинации C-=. Разберем её работу на примере следующего отрывка:

"А смею спросить, - продолжал он, - зачем изволили вы перейти из гвардии в
гарнизон?" Я отвечал, что такова была воля начальства. "Чаятельно, за
неприличные гвардии офицеру поступки", - продолжал неутомимый
вопрошатель. "Полно врать пустяки, - сказала ему капитанша, - ты видишь,
молодой человек с дороги устал; ему не до тебя...  (держи-ка руки
прямее...). А ты, мой батюшка, - продолжала она, обращаясь ко мне, - не
печалься, что тебя упекли в наше захолустье. Не ты первый, не ты
последний. Стерпится, слюбится."  (А.С. Пушкин, "Капитанская дочка")

Допустим, курсор находится в середине последнего слова - “дочка”. При последовательных нажатиях C-= будут выделены следующие регионы:

  • дочка
  • Капитанская дочка
  • “Капитанская дочка”
  • А.С. Пушкин, “Капитанская дочка”
  • (А.С. Пушкин, “Капитанская дочка”)
  • При очередном нажатии отрывок будет выделен целиком.

Т.е. C-= осуществляет последовательное расширение региона (expand region). Эта функция пытается увеличить выделенный регион, раздвигая его границы к началу и концу структурных единиц, вмещающих текущее выделение. В приведенном примере сначала выделяется слово, потом то, что находится внутри кавычек, потом захватываются сами кавычки, потом - внутренность скобок, потом - сами скобки и, наконец, весь фрагмент.

Структурными единицами являются:

  • слова
  • внутренности скобок и кавычек
  • внутренности скобок и кавычек вместе с обрамляющими символами
  • абзацы
  • весь буфер

Кроме того, в зависимости от основного режима, в буфере могут быть определены другие структурные единицы, например, выражения и функции в языках программирования.

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

Базовые операции

Итак, допустим регион выделен - но что же с ним делать? Список основных действий с регионами таков:

  1. При нажатии печатных символов на клавиатуре регион будет удалён и набранные символы появятся на его месте.
  2. При нажатии клавиш C-d или C-h и регион будет просто удален.
  3. При нажатии на символы открывающихся скобок - “(“, “{“, “[“, а также символ кавычки, регион будет обернут (wrapped) - набранный символ вставится в начало региона, а соответствующий закрывающий символ - в конец.
  4. При нажатии M-w регион будет скопирован.
  5. При нажатии C-w регион будет вырезан.

Список можно было бы назвать самым обычным, если бы не особенности копирования и вставки в Emacs. В англоязычной документации для этих действий даже специально употребляются слова kill/yank, вместо традиционных cut/paste. Я не придумывал специальные русские термины для того, чтобы подчеркнуть эту разницу, поэтому употребляю общеизвестные вырезать/вставить, хотя, наверное, это и не совсем корректно.

Главное отличие рассматриваемых команд в Emacs от традиционных редакторов в том, что вырезаемые данные записываются в последовательность, называемую кольцо вставки (kill ring). Т.е. в каждый момент времени у пользователя есть возможность вставить не только самый последний вырезанный регион, а также и любой другой, находящийся в кольце.

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

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

В некоторых ситуациях (в основном, когда нужно найти что-то вырезанное давно), удобно просмотреть содержимое кольца вставки. Для этого используется команда C-x C-y. После того, как требуемые регион найден, его можно вставить нажатием C-m (Enter).

Поскольку хранить абсолютно все вырезанные регионы нецелесообразно (они могут занимать слишком много места), то выбранная структура хранения этих регионов - именно кольцо. По умолчанию, его размер - 60 регионов. Т.е. 60 первых вырезанных регионов будут записаны в кольцо друг за другом, а при вырезании следующего (61-го) региона, из кольца будет удален самый старый (1-ый) регион, а 61-ый будет записан вместо него и т.д.

Дополнительные операции вырезания

Вырезание строк

В Emacs некоторые структурные единицы можно вырезать, предварительно не выделяя их в регион. Одной из главных таких единиц является строка.

Вырезать текст от курсора до конца строки можно с помощью команды C-k. Обращаю внимание, что при этом символ переноса строки не удаляется. Для того, чтобы его удалить требуется повторно нажать C-k. Однако зачастую это не совсем приводит к желаемому результату.

Допустим, мы редактируем следующий отрывок:

if (supported)
{
    performOperation(first_argument,
                     second_argument);
}

Мы хотим, чтобы круглые скобки находились на одной строке. Для этого, можно поставить курсор после запятой и нажать C-k. Поскольку мы уже находимся в конце строки, то будет удален (условно невидимый) символ перевода строки и отрывок примет новый вид:

if (supported)
{
    performOperation(first_argument,                     second_argument);
}

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

Для того, чтобы с ним расправиться можно нажать M-\ (fixup whitespace) - эта команда превратит любое количество пробелов вокруг курсора в один.

Но есть и другой способ - вместо нажатия C-k, можно нажать M-j (join following line). Эта команда как бы “подтягивает” текст следующей строчки на текущую, после чего отрывок выглядит так:

if (supported)
{
    performOperation(first_argument, second_argument);
}

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

Итак, команда C-k удаляет строку от курсора и до её конца, а если курсор уже находится в конце, то удаляется символ перевода строки. Поговорим ещё об интересных особенностях этой команды.

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

Т.е. если 6 раз подряд нажать C-k, то будет вырезано три полных строки с символами перевода строк и при следующем нажатии C-y, будут вставлены все 3 строки.

Вырезание слов

Внимательный читатель мог обратить внимание, что операции M-d и M-h не удаляют, а вырезают соответствующие слова. Впрочем, в Emacs вообще практически все операции, удаляющие текст длиннее одного символа, являются операциями вырезания, что позволяет “не терять” содержательные куски. Значит, после использования указанных команд слова можно вставить при помощи C-y. Кроме того, на них также распространяется описанное только что правило - последовательные исполнения этих команд складируют вырезанные слова в первом элементе кольца вставки.

Пытливый читатель может заметить, что эта функциональность перекрывается с выделением регионов, и резонно задать вопрос - а что лучше/эффективнее использовать - C-SPC, M-f, M-f, M-f, C-w или M-d, M-d, M-d и почему вообще существует 2 способа сделать одно и то же?

Причина здесь, как часто бывает, историческая. Мы все давно привыкли к использованию регионов, но было время, когда их использование не было так распространено. На старых терминалах у символов нельзя было изменять фон, а значит - нельзя было “подсветить” выделенный регион. Т.е. использовать регионы в Emacs можно было точно так же, как и сейчас, но увидеть выделенный регион было нельзя, что было несколько неудобно. Я предполагаю, что именно этот факт и явился главной причиной того, почему вырезание и вставка в Emacs работают так, как работают. Такой подход позволяет альтернативным способом визуализировать то, что происходит - вместо выделения региона, куски текста вырезались. Сегодня, когда вопрос о цвете фона символов стоит не так остро, наверное, проще всегда использовать регионы, если нужно вырезать больше одного слова (во всяком случае я делаю так в 95% случаев).

Казалось бы, выделять регион можно и когда требуется вырезать всего одно слово, воспользовавшись комбинациями C-=, C-w. Но, во-первых, всё-таки в голове это проходит по двум пунктам - “выделить слово и вырезать”, вместо - “вырезать слово”, во-вторых, это и две комбинации вместо одной, ну и, в-третьих, есть одно отличие в работе этих команд от M-d и M-h, которое позволяет им очень удачно дополнять друг друга.

В программировании часто используется т.н. “верблюжий” стиль (camel case) именования функций, переменных и т.п. - разные слова в имени начинаются с заглавных букв, например - LongFunctionName или longFunctionName.

Так вот, комбинация C-=, C-w вырезает всё имя функции целиком, а команды M-d и M-h вырезают “подслова” в имени.

Вырезание до символа

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

Но тем не менее, я всё-таки хочу рассказать о последней специальной команде, которая довольно часто пригождается - M-z (zap to char).

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

Для того, чтобы оставить точку, можно воспользоваться командой M-Z (zap up to char), которая во всём эквивалента M-z, кроме того, что не вырезает указанный символ.

Префиксный аргумент

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

Численный аргумент

Начну с того, на чем закончился предыдущий раздел - команды M-z, которая вырезает все символы, начиная с текущей позиции курсора до первого появления укзанного символа (включая сам символ).

Допустим, мы с её помощью хотим удалить деепричастный оборот в предложении “Убедившись, что понять этого он не может, ему стало скучно (Л. Толстой)”. Деепричастный оборот расположен в самом начале предложения и заканичается запятой после слова “может”. Соответственно, для того, чтобы его удалить, можно расположить курсор в начале предложения, нажать M-z, запятую - таким образом вырежется текст до первой запятой (“Убедившись,”) - а потом опять M-z и запятую - чтобы вырезать весь необходимый текст. Т.е. для достижения цели нам пришлось 2 раза подряд выполнить одну и ту же команду.

В таких ситуациях удобно передать исполняемой команде префиксный аргумент. В рассмотреном примере вместо того, чтобы два раза выполнить одну и ту же команду, можно выполнить C-2 M-z и нажать запятую, для достижения того же результата.

Т.е. любой команде в Emacs можно передать префиксный аргумент нажатием C-<NUM> перед самой командой. В подавляющем большинстве случаев это будет сигналом к тому, что указанную команду нужно выполнить <NUM> раз.

Один пример использования префиксного аргумента (вкупе с командой M-z) уже был рассмотрен. Вот другие примеры:

  • C-3 M-Z - вырезать текст до третьего появления указанного символа (исключая сам символ)
  • С-8 0 / или С-8 С-0 / - вставить 80 символов ‘/’
  • C-5 C-n - спустить курсор на 5 строчек вниз
  • C-6 C-k - вырезать 6 строк

Последний пример требует определенного пояснения. Если 6 раз подряд выполнить команду C-k, то вырезаны будут всего 3 строчки, потому что первое нажатие вырежет текст до конца строки; второе - символ конца строки; третье, по аналогии с первым - текст до конца строки и т.д. Однако, если нажать C-6 C-k, то вырезаны будут именно 6 строк.

Связано это с тем, что, вообще говоря, правило о том, что префиксный аргумент означает количество раз, которое нужно повторить следующую команду не является строгим. Т.е. этот функционал реализован не на уровне Emacs, а на уровне самих функций. И описанное правило является всего лишь соглашением, которому должны следовать “правильные” функции.

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

Для некоторых команд предписание “выполнись N раз подряд” не имеет особого смысла. Например, функция C-l располагает содержимое буфера так, чтобы курсор оказался в центре окна, последовательное нажатие располагает содержимое, чтобы курсор оказался вверху, потом - внизу, а потом опять в центре - и так по кругу. Особого смысла предоставлять возможность выполнить эту команду произвольное число раз подряд нету, поскольку, фактически, у неё всего 3 возможных исхода.

В таких случаях авторы функций, как правило, стараются подобрать для префиксного аргумента какое-нибудь более или менее осмысленное значение. Функция C-l, например, если ей передать N в качестве аргумента, расположит содержимое буфера так, чтобы курсор находился на (N+1)-ой строчке окна.

Отрицательный аргумент

Будучи математиком по образованию и профессии, могу предположить, что разработчиками Emacs двигала та же мотивация, что и Диофантом, когда они стали использовать отрицательные префиксные аргументы. Объяснить с бытовой точки зрения, что значит выполнить команду минус 3 раза не очень просто, но слишком уж гармонично всё выстраивается, если наплевать на эту бытовую точку зрения!

К примеру, если выполнить C-- 3 C-n, то курсор переместится на три строки вверх, несмотря на то, что мы выполнили команду перевода курсора вниз. В погоне за красивыми математическими параллелями можно даже отметить, что после выполнения, команды курсор попадает в такую точку, что если в ней выполнить C-3 C-n, то он окажется в исходном положении!

Аналогично, если выполнить C-- M-z (минус в качестве префиксного аргумента эквивалентен минус единице), то будет вырезан кусок текста с текущего положения до ближайшего указанного символа перед курсором.

Как и в случае с положительными префиксными аргументами, какого-то строгого правила, что делать с отрицательными аргументами нет. Но негласная договорённость состоит в том, что они должны модифицировать выполнение команды точно так же, как и положительные, только наоборот.

Универсальный аргумент

Помимо численных префиксных аргументов, функциям можно передать т.н. универсальный аргумент при помощи префикса C-u.

Если численный аргумент чаще всего означает “выполнить следующую команду N раз”, то универсальный аргумент имеет несколько значений.

Во-первых, если команда не обрабатывает его особенно, то он соответствует численному аргументу, равному 4. Почему именно четырем сказать трудно, но с другой стороны, а почему бы и нет?! Например, C-u C-m - вставить 4 пустых строки, C-u C-u C-m - вставить 16 пустых строк, C-u C-u C-u C-m - вставить 64 пустых строки и т.д. Естественно, точные значения, получаемые при помощи универсального аргумента (степени четверки) не очень полезны, но можно относиться к этим величинам, как к качественным:

  • один аргумент - “повтори несколько раз”,
  • два аргумента - “повтори с дюжину раз”,
  • три аргумента - “повтори с полсотни раз”,
  • четыре аргумента - “повтори с сотню раз” и т.д.

Во-вторых, универсальный аргумент может сигнализировать команде “выполнись, но не как обычно”. Что именно значит “не как обычно” каждая команда решает по-своему. В качестве примера, рассмотрим команду C-y, ради чего я и завел разговор о префиксных аргументах именно сейчас.

Допустим, у нас есть следующий кусок кода:

int fun()
{
    if (supported)
    {
        performFirstOperation(first_argument, second_argument);
    }

    performSecondOperation();
    performThirdOperation();
}

И мы решили, что и вторую и третью операцию нужно выполнять, только при условии supported. Т.е. мы хотим преобразовать этот код в следующий:

int fun()
{
    if (supported)
    {
        performFirstOperation(first_argument, second_argument);
        performSecondOperation();
        performThirdOperation();
    }
}

Очевидное решение было бы следующим - вырезать строчки

performSecondOperation();
performThirdOperation();

и вставить их куда надо - что может быть проще?! Однако, тут имеется тонкий момент. В какое положение нужно поставить курсор для выделения региона и в какое положение его нужно поставить для вставки?

Допустим, мы поставим курсор перед первой буквой “p” и вставим ровно в том положении, где она должна оказаться. Тогда (в “обычном” редакторе) мы получим следующую картину:

int fun()
{
    if (supported)
    {
        performFirstOperation(first_argument, second_argument);
        performSecondOperation();
    performThirdOperation();
    }
}

Другой вариант - поставим курсор в начале строки с вызовом функции performFirstOperation(), а при вставке - в начало строки, где мы хотим расположить вырезанный кусок, тогда получим:

int fun()
{
    if (supported)
    {
        performFirstOperation(first_argument, second_argument);
    performSecondOperation();
    performThirdOperation();
    }
}

И, вообще говоря, как бы мы ни старались - в “обычном” редакторе вставленный текст всегда будет выровнен неправильно. А значит, после вставки его придется ещё и форматировать.

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

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

Но в редких случаях, такое выравнивание будет играть не на руку - регион нужно просто вставить “как есть”. Тогда можно передать команде вставки универсальный аргумент - C-u C-y - и текст будет вставлен без автоматического выравнивания.

Откат

Как известно, не ошибается тот, кто ничего не делает, поэтому Emacs предоставляет возможность откатить последние действия. Для этого можно использовать сочетание C-z (как и в других редакторах), либо С-/. Лично я использую C-/, потому что его удобнее нажимать.

В целом, эта тема не стоила бы отдельного раздела, если бы мы не ошибались во время исправления наших ошибок - жмешь C-/ столько раз, сколько нужно, пока все ошибки не исчезнут. Но что делать, если ты нажал C-/ лишнего и теперь тебе нужно вернуть всё, как было перед последним нажатием? Для ответа на этот простой вопрос придется довольно подробно разобраться, как работает система откатов в Emacs.

Рассмотрим такой пример: первой командой мы ввели слово “Береги “, второй - “деньги “, третьей - “смолоду”. Не очень важно, как мы это делали - мы могли как набирать слова по отдельным символам, так и вставлять их различными способами (не обо всех из которых я успел сказать) - главное, что мы выполнили три команды вставки.

Проиллюстрируем это следующей диаграммой:

o  (пустой буфер)
|
|
o  Береги (вставка)
|
|
o  Береги деньги (вставка)
|
|
x  Береги деньги смолоду (вставка)

Теперь, допустим, мы пересмотрели свои ценности и захотели исправить ошибку во втором слове. Для этого выполняем два раза откат и приходим к следующей картине:

o  (пустой буфер)
|
|
x  Береги (вставка)
|
|
o
|
|
o

Однако, эта схема не совсем верна с точки зрения внутреннего устройства Emacs, поскольку он считает произведенный откат за очередные изменения буфера:

o  (пустой буфер)
|
|
o  Береги (вставка)
|
|
o  Береги деньги (вставка)
|
|
o  Береги деньги смолоду (вставка)
|
|
o  Береги деньги (откат)
|
|
x  Береги (откат)

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

                 (пустой буфер) o
                                |
                                |
               Береги (вставка) o  x (откат)
                                |  |
                                |  |
        Береги деньги (вставка) o  o (откат)
                                | /
                                |/
Береги деньги смолоду (вставка) o

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

В случае “обычного” редактора, который позволяет двигаться по истории только вперед или назад, история выглядела бы следующим образом:

                 (пустой буфер) o
                                |
                                |
               Береги (вставка) o
                                .\
                                . \
        Береги деньги (вставка) o  o Береги честь (вставка)
                                .
                                .
Береги деньги смолоду (вставка) o

Обращаю внимание, что оригинальная ветвь канула в лету и вернуть её из истории уже не получится. В Emacs же, напротив, все узлы остаются в истории:

                 (пустой буфер) o
                                |
                                |
               Береги (вставка) o  o (откат)
                                |  |\
                                |  | \
        Береги деньги (вставка) o  o  | (откат)
                                | /   |
                                |/    |
Береги деньги смолоду (вставка) o     |
                                      |
                                      |
                                      x Береги честь (вставка)

Единственный вопрос, что нужно сделать, если мы пересмотрели свои ценности второй раз и захотели вернуть первоначальный вариант пословицы? Ничего особенного - точно так же жмем C-/. В результате чего получаем:

                 (пустой буфер) o
                                |
                                |
               Береги (вставка) o  o (откат)   o (откат)
                                |  |\         /|
                                |  | \       / |
        Береги деньги (вставка) o  o  |     /  o (откат)
                                | /   |    /   |
                                |/    |   /    |
Береги деньги смолоду (вставка) o     |  /     x
                                      | /
                                      |/
                                      o Береги честь (вставка)

Как, надеюсь, видно из рисунка, буфер можно вернуть в любое состояние, нажав C-/ достаточное количество раз.

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

                 (пустой буфер) o
                                |
                                |
               Береги (вставка) o  x (откат)
                                |  |
                                |  |
        Береги деньги (вставка) o  o (откат)
                                | /
                                |/
Береги деньги смолоду (вставка) o

Если теперь нажать C-/ (предполагая, что мы уже два раза нажали C-/, для выполнения откатов и больше ничего не делали), то буфер перейдет в начальное состояние:

                 (пустой буфер) o  x (откат)
                                |  |
                                |  |
               Береги (вставка) o  o (откат)
                                |  |
                                |  |
        Береги деньги (вставка) o  o (откат)
                                | /
                                |/
Береги деньги смолоду (вставка) o

Но, что если мы хотим выполнить не очередной откат, а пойти по истории в обратную сторону? Т.е. как-то сигнализировать, что мы хотим изменить направление, в котором мы шагаем по истории. В прошлый раз мы вставили слово “честь” и после этого очередные нажатия C-/ вели нас в прошлое.

Правило заключается в следующем: любая команда, не являющаяся откатом, выступает в роли такой “поворотной точки”. Пока мы жмем C-/ - мы наращиваем точки “отката” в истории. А как только мы сделали что-то другое, то следующие нажатия C-/ поведут нас в прошлое уже от наращённых точек.

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

  1. Для того, чтобы вернуться к предыдущему состоянию буфера нужно жать C-/ до наступления желаемого эффекта.
  2. Если ты “промотал” лишку, то нужно нажать C-g - для смены направления движения по истории - и опять жать C-/.

Навигация и поиск

Навигация

В самом начале я уже рассказал о том, что поиск в буфере можно осуществлять с помощью комбинаций C-s и C-r. Сейчас я хочу поподробнее рассказать о них, о поиске вообще и не только.

Вопрос, который мог бы возникнуть при знакомстве с этими функциями - почему им отданы такие короткие и замечательные комбинации? C-s даже двигает с насиженного места функцию сохранения, претендуя на большую популярность, что несколько удивительно. Ведь поиск, как правило, довольно тяжеловесная процедура в других редакторах. Для ввода строки открывается отдельное окошко, в нем имеется ряд галочек и кнопочек, поэтому лишний раз пользоваться им не будешь.

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

Ответ, однако же, довольно прост - поиск в Emacs используется, в частности, и для навигации по буферу. Наблюдательный читатель уже мог заметить, что Emacs предоставляет широкие возможности “отрезать столько, сколько надо” - можно работать с символами, со словами, с абзацами, с блоками, с регионами и т.д.

Точно так же и здесь - с помощью поиска в Emacs можно прыгнуть ровно в то место, в которое нужно. Допустим, например, что курсор находится в нижней части буфера. Чтобы прыгнуть ближе к верхнему краю - ты можешь промотать экран с помощью M-v, добежать до нужной строчки с помощью C-n, C-p или, двигаясь по абзацам, с помощью C-M-n, C-M-p.

А можешь нажать C-s или C-r и начать набирать то слово, к которому ты хочешь переместить курсор - пары символов для этого, как правило, достаточно. Процесс перехода при этом значительно упрощается.

Кроме того, после выхода из поиска, в месте его старта Emacs оставляет маркер (mark) и если после редактирования в какой-то момент ты захочешь “вернуться обратно”, то комбинация C-M-\ возвратит тебя к этому маркеру. Последующие нажатия C-M-\ будут возвращать тебя ко всё более ранним маркерам. Таким способом можно пробежать все позиции в буфере, в которых ты уже был. (Справедливости ради нужно заметить, что по умолчанию Emacs хранит не все, а только 16 последних маркеров).

Кстати, выставляются маркеры не только командой поиска, но и многими другими командами, которые потенциально перемещают курсор на большие расстояния, например, переходы в начало и конец буфера (M-< и M->), переход к строке с заданным номером (M-g M-g), а также командой C-SPC.

Сама по себе, команда C-M-\, выполняет переходы между маркерами только в пределах одного буфера, но её можно использовать и для перехода между маркерами во всех буферах. Для этого ей нужно всего лишь передать универсальный аргумент C-u C-M-\.

Поиск в буфере

Использование поиска для навигации по буферу, возможно, интересно и свежо. Но, наверное, неплохо бы было рассказать подробнее и о собственно поиске, потому что пока я затронул только самые базовые его возможности.

Итак, поиск по буферу можно осуществлять при помощи комбинаций C-s и C-r для поиска “вперед” и “назад”, соответственно. Одно приятное дополнение к простому поиску состоит в том, что если перед его началом выделить слово (или любой другой регион, умещающийся на одной строке), то оно будет использовано в качестве искомой строки.

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

Следующий момент касается чувствительности поиска к регистру. По умолчанию, поиск не различает большие и маленькие буквы и есть по крайней мере 2 способа это изменить. Наиболее удобный - если в искомой строке присутствует хотя бы одна заглавная буква - он автоматически становится чувствительным к регистру. Этот способ будет хорошо работать всегда, когда в искомой строке есть заглавные буквы. Если же их нет, то можно явно включить чувствительность с помощью комбинации M-s c (case sensitivity).

Другая возможность поиска - показать список всех кандидатов сразу. Сделать это можно, нажав M-s o (occurrences) и введя искомое выражение. Та же самая комбинация сработает, если её нажать во время поиска. Тогда она уже не будет явно спрашивать строку, а использует текущую.

Если функции M-s o передать численный аргумент, то каждый кандидат появится не просто со строкой, в которой он находится, но и со строками, находящимися до и после нее. Количество дополнительных строк определяется численным аргументом.

В открывшемся буфере можно будет при помощи комбинации C-m (или Enter) переходить к соответствующей строке в исходном буфере. Кроме того, список кандидатов можно дополнительно сузить, выполнив M-s o в буфере со списком ещё раз. Получается довольно элегантно, не так ли?! А всё потому, что в Emacs действует негласное правило - относиться ко всем буферам, как к обычным текстовым файлам. Но то ли ещё будет!

Комбинация C-x C-q в буфере со списком кандидатов переведет его в режим редактирования. Т.е. текст в нем можно будет править обычными средствами, а изменения будут перенесены в исходный буфер (при помощи той же комбинации C-x C-q). Нужно ли говорить, что это крайне удобная функция, которая позволяет эффективно редактировать разные частей буфера одновременно.

Поиск во множестве файлов

Уже описанных возможностей вполне хватает для большинства бытовых поисковых нужд при редактировании. Но, как можно заметить, они осуществляют поиск лишь в одном файле. Если же требуется найти что-то в большем количестве файлов, то для этого можно использовать известную утилиту grep.

Насколько мне известно, в операционных системах Windows эта утилита не установлена по умолчанию, т.е. её требуется установить отдельно (а также команду find, которая идет с grep рука об руку). Конечно, это не очень приятно, но я решительно убежден, что операционные системы без утилиты grep не имеют права на жизнь, и поэтому оставляю за собой право игнорировать их существование. В поддержку своей позиции замечу, что Оксфордский Словарь Английского Языка содержит определение слова grep и как существительного, и как глагола с 2003-го года. А слово google, например, появилось в нем тремя годами позже. Отсюда можно сделать осторожный вывод, что система, не умеющая грепать, более бесполезна, чем система, не умеющая гуглить.

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

find . -type f -exec grep -nHi -e <курсор> {} +

Возможно она выглядит страшновато для непривычного человека, но использовать её совсем несложно. На месте курсора нужно просто написать искомую строку (если она содержит пробелы, то её нужно заключить в кавычки) и нажать Enter.

После этого в открывшемся буфере появятся результаты поиска во всех файлах текущей директории. C-m (или Enter) точно так же будет открывать соответствующие строчки в файлах, а C-x C-q - переводить буфер в режим редактирования и обратно.

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

  • grep можно запустить без использования find, но всегда нужно передавать аргумент -n, например, grep "искомая строка" -nr .
  • Для учета регистра нужно удалить аргумент -i при запуске grep, например, find . -type f -exec grep -nH -e "искомая строка" {} +
  • Искомая строка утилиты grep интерпретируется, как регулярное выражение, что значительно расширяет возможности поиска. Подробнее о регулярных выражениях можно прочитать в соответствующем разделе секции вопросов и ответов.
  • Набор файлов, в которых будет производиться поиск может быть изменен при помощи аргументов утилиты find, например, find . -type f -name '*.[ch]' -exec grep -nHi -e include {} + будет искать строку include только в файлах с расширениями .c или .h.
  • C-u C-F выполнит команду git-grep, вместо связки find + grep.

Замена

Замена - действие, обычно идущее рука об руку с поиском. В программировании часто, например, приходится переименовать переменную или функцию. Для этой задачи в Emacs есть две команды - M-% и C-M-%. Отличие меджу ними состоит лишь в том, используется для поиска обычная строка или регулярное выражение.

После нажатия соответствующей комбинации сначала нужно ввести искомую строку, а потом замену для нее. После чего курсор будет переходить к очередному кандидату и спрашивать, требуется ли осуществить замену. Для положительного ответа нужно нажать y, для отрицательного - n. Для того, чтобы автоматически ответить y для всех кандидатов, нужно нажать !.

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

Клавиатурные макросы

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

Поэтому естественно, что Emacs, будучи серьезным инструментом, обладает богатыми средствами автоматизации самых различных задач. Реализация одного из наиболее доступных методов опирается на простейший принцип - “делай, как я”.

Рассмотрим такой пример. Допустим, у нас в тексте имеется такая таблица:

0 1 0 1 0 0 0
1 1 0 0 1 1 1
0 1 0 0 1 1 0
1 1 0 0 1 1 0
0 1 0 1 0 1 0
1 0 0 1 1 0 1
0 1 0 0 0 0 0

Те, кто знают, что такое матрица смежности графа, могут думать, что это одна из их представительниц. Те, кто не знают - могут придать этому набору нулей и единиц любое другое значение.

Я же предлагаю подумать над такой задачей - как все элементы на “главной” диагонали превратить в единицы? Т.е. сделать так, чтобы таблица выглядела следующим образом:

1 1 0 1 0 0 0
1 1 0 0 1 1 1
0 1 1 0 1 1 0
1 1 0 1 1 1 0
0 1 0 1 1 1 0
1 0 0 1 1 1 1
0 1 0 0 0 0 1

Конечно, это всегда можно сделать вручную - таблица всего лишь 7 на 7. Но этот пример игрушечный, а что если нам потребовалось бы выполнить подобные однотипные действия 100 или больше раз? Неплохо бы этот процесс автоматизировать.

Замена - наверное, единственная из рассмотренных функций, которая как-то могла бы нам в этом помочь. Но для того, чтобы она сработала, нам нужно написать строчку или регулярное выражение, которое соответствовало бы диагональным элементам, что не представляется возможным.

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

Т.е. последовательность команд выглядела бы следующим образом:

M-< C-d 1 C-n C-f C-d 1 C-n C-f C-d 1 C-n C-f C-d 1 C-n C-f ...

Для наглядности, разделим эти команды на группы символами |:

M-< | C-d 1 C-n C-f | C-d 1 C-n C-f | C-d 1 C-n C-f | C-d 1 C-n C-f | ...

Нетрудно видеть, что команды во второй и последующих группах одни и те же. Соответственно, если бы у нас была возможность каким-то образом сохранить/запомнить последовательность этих команд, а потом повторить их нужное количество раз - это сильно облегчило бы нам жизнь.

В Emacs для этой цели существует механизм т.н. клавиатурных макросов. В приведенном примере им можно воспользоваться так:

M-< | <F3> C-d 1 C-n C-f <F4> | <F4> | <F4> | <F4> | ...

Т.е. перед первым выполнением повторяющейся группы команд нужно нажать <F3>, обозначив тем самым начало записи клавиатурного макроса. Команды, которые будут выполнены после этого, будут сохраняться до нажатия <F4>, означающего конец записи макроса. Последующие нажатия <F4> выполнят все записанные команды.

Думаю, все согласятся, что дело теперь обстоит значительно лучше. Единственное, жать <F4> 6 раз подряд после записи макроса тоже как-то не с руки. Но здесь, как можно было догадаться, нам поможет префиксный аргумент - если передать его команде <F4>, то макрос выполнится указанное количество раз:

M-< | <F3> C-d 1 C-n C-f <F4> | С-6 <F4>

Клавиатурные макросы - казалось бы, простейшая идея, но она обладает большим потенциалом.

Во-первых, при записи макроса можно (и нужно) пользоваться операциями для работы с семантическими единицами. Например, если бы значения в таблице были не просто цифрами 0 или 1, а многозначными числами, то удаление с помощью C-d было бы затруднительным - ведь выполнить C-d нужно столько раз, сколько в числе цифр. Но если вместо C-d использовать M-d - всё прекрасно отработает.

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

В-третьих, использовать макросы можно не только для редактирования текстов, но и для любых других действий - в конце концов, это ведь всего лишь повторение нажатий клавиш. Представим, например, что мы находимся в директории с исходными кодами программы, каждый из которых содержит “заголовок” с лицензией, e-mail’ом автора и т.п. Допустим, нам нужно поменять год лицензии на текущий и старый e-mail - на новый. Для этого можно перейти к верхнему файлу в директории, начать запись макроса, открыть файл, выполнить нужные правки, сохранить его, перейти обратно в dired (C-x C-j), спуститься на строчку вниз - к следующему файлу и закончить запись макроса. Последующие его выполнения будут обновлять заголовки очередных файлов. Неплохо? Более того, если передать 0 в качестве префиксного аргумента команде <F4>, макрос будет повторяться “пока возможно”. В данном примере выполнение прервется, когда мы попытаемся перейти к следующему файлу, находясь на последней строчке.

Итак, клавиатурные макросы - простой и гибкий инструмент для автоматизации разнообразных задач в Emacs. По началу его использование может показаться непривычным и несколько странноватым, но со временем запись макросов не будет составлять особого труда - руки привыкнуть пользоваться командами для работы со словами и более крупными единицами, пропадет желание записать “как можно более короткий” макрос, будет не страшно допускать и исправлять ошибки во время записи макроса.

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

Заключение

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

Но как и после любого значительного достижения, у многих внутри может возникнуть ощущение пустоты, связанное с внезапно возникшей неопределенностью. Буквально только что путь к успеху был так ясен и понятен, а что делать теперь? А теперь можно заняться содержательной работой и продолжать изучать Emacs в процессе.

Официальное название Emacs читается примерно так: “Расширяемый, настраиваемый, самодокументируемый, интерактивный экранный редактор”. Программа проверки орфографии обратила мое внимание на слово “самодокументируемый”, а я хочу обратить на него внимание читателя.

Одна из фундаментальных особенностей Emacs заключается в том, что он имеет превосходную встроенную документацию для всех функций. В качестве примера, предлагаю нажать <F1> k C-f. Эта комбинация откроет буфер, в котором подробно изложено, что за функция выполняется при нажатии C-f, а именно - forward-char. Аналогичным образом можно узнать назначение любой комбинации - нужно всего лишь набрать перед ней <F1> k.

Использовать эту возможность хорошо в том случае, если ты забыл, что именно делает та или иная комбинация. Однако возможен и обратный сценарий - ты помнишь, что есть такая функция forward-char, но не помнишь, какой комбинацией она вызывается. В этом случае нужно нажать <F1> f forward-char C-m и будет открыт тот же буфер с документацией, в котором сверху написано, что её можно вызвать при помощи C-f. Обращаю внимание, что по мере набора названия функции (forward-char), можно нажимать клавишу <TAB> и Emacs будет предлагать возможные продолжения, основываясь на списке всех имеющихся функций.

Также, если имя функции известно, то её можно вызвать по имени. Для этого нужно нажать M-x forward-char С-m (здесь работают те же правила, что и при смене буфера). В том случае, если её можно вызвать при помощи какой-либо комбинации, сообщение об этом появится в строке сообщений (в самом низу фрейма).

Отдельно хочу отметить, что не всем функциям в Emacs отведены клавиатурные комбинации. Соответственно, вызвать их иначе, как с помощью M-x, не получится (если быть откровенным, то, конечно, получится - но другие способы ещё сложнее). Например, в Emacs есть замечательная функция align-regexp без собственной клавиатурной комбинации, которая легко позволяет превратить вот такой регион:

object.width = 30;
object.height = 150;
object.temperature = 300;

вот в такой:

object.width       = 30;
object.height      = 150;
object.temperature = 300;

Всё, что для этого нужно сделать - это выделить все три строчки в регион и нажать M-x align-regexp C-m = C-m.

Уверен, что все эти возможности вызывают у большинства читателей такой же искренний восторг, как и у меня. Однако, приливы радости может несколько омрачать тот факт, что совсем непонятно, откуда можно узнать о том, какие в Emacs есть функции и как они называются. Но не стоит отчаиваться, потому что решение для этой проблемы тоже есть.

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

  • В Emacs есть встроенная игра Гомоку (известная также, как “крестики-нолики”, “5 в ряд” и т.д.) - M-x gomoku
  • Веб-браузер M-x eww и E-mail клиенты
  • Возможен просмотр pdf-файлов, картинок и проч. (не уверен на счет музыки и видео, хотя и не исключаю)

Во-вторых, в каждом буфере можно нажать <F1> m и в открывшейся справке будет указано, какие функции доступны в текущем буфере (в соответствии с включенными в нём режимами). Например, если нажать <F1> m в буфере Dired, то можно узнать, что в нём можно выделять файлы при помощи m (mark) и снимать выделение при помощи u или U (unmark). Выделенные файлы можно скопировать в другую директорию при помощи C (copy), либо переместить - при помощи R (rename). Удалить их можно при помощи D и т.д.

В-третьих, при помощи комбинации <F1> a можно искать функции примерно догадываясь об их названии. Например, найти описанную функцию algin-regexp можно было бы предположив, что выполнять такое действие должна функция, в названии которой есть слово align. Т.е. мы пишем <F1> a align и видим список функций, в названии которых есть слово align, и по их описанию находим нужную (для того, чтобы открыть полное описание функции нужно нажать C-m, находясь на её имени).

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

В частности, я в скором времени собираюсь написать статьи на следующие темы:

  • Специальные возможности Emacs (взаимодействие с операционной системой, более “продвинутые” возможности редактирования и т.д.)
  • Расширение и настройка Emacs
  • Как начать программировать в Emacs
  • Как работать с большими программными проектами в Emacs
  • Как создавать презентации в Emacs

Надеюсь, дорогой товарищ, этим обзором мне удалось заинтересовать тебя и показать с новой и интересной стороны такую, казалось бы, посредственную тему, как редактирование текстов. Желаю тебе успехов и свершений во всех твоих начинаниях. Я буду очень признателен за любые отзывы, вопросы и комментарии - по поводу и без. Будем помогать друг другу становиться лучше!

Вопросы и ответы

Для кого предназначен этот обзор?

Возможно, ты вообще никогда ничего не программировал в своей жизни и при работе с компьютером ограничивался браузером и меню компьютерных игр, а теперь тебе захотелось написать свою собственную игру или сайт. Возможно, ты что-то программировал в школе или университете, глядя в голубой экран с текстом на языке Паскаль и вот сейчас в твоих висках неожиданно застучали воспоминания и огнём вспыхнули дерзкие мысли. Возможно, ты программировал на C# в Visual Studio под Windows и чувствуешь, что настоящая жизнь проходит мимо и отправился её искать.

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

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

А также попутно решили вопрос с тем, как человек может удобно организовать и обработку созданного текста. Языки программирования приходят и уходят, а Emacs остается. Языки вёрстки - LaTeX, HTML, Markdown - приходят и уходят - а Emacs остается. Операционные системы приходят и уходят, а Emacs - прекрасно работает на любой из них.

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

Так ли уж важно уметь печатать вслепую?

Гораздо важнее, чем ты думаешь.

На мой взгляд, совершенно очевидно, что это мега-полезный навык. А все отговорки - не выдерживают малейшей критики.

Главный аргумент, почему люди не учатся печатать вслепую - “у меня и так всё нормально”. Естественно, ничего у них не нормально.

Когда речь заходит о слепой печати - в первую очередь люди думают о скорости набора. И те, кто научился двумя пальцами набирать по 100 знаков в минуту, говорят, что они и так хорошо справляются - быстрее не надо.

Действительно, со стороны, скорость - самый заметный и внешне привлекательный аспект - но с практической точки зрения он интересен разве только стенографисткам. Средний программист, к примеру, в день набирает около 100 (ста) строк кода. Скорость, с которой он их наберет даже тыкая двумя пальцами по клавиатуре - всего лишь небольшая толика 8ми-часового рабочего дня.

Может показаться, что 100 строк в день - заниженная оценка, но на самом деле она легко объясняется. Как правило, программист гораздо больше думает о том, что нужно написать, чем непосредственно пишет. То же самое можно сказать и о писателе или журналисте. Человек не может сочинять текст на скорости 300 символов в минуту. Нужно подбирать слова, перечитывать написанное, переставлять абзацы и предложения - именно это занимает большую часть времени.

Поэтому в навыке слепой печати намного важнее то, что человек перестает думать о том, КАК он печатает и у него освобождается время для обдумывания того, ЧТО нужно напечатать.

При печати двумя пальцами, человеку нужно перевести взгляд с монитора на клавиатуру, а потом обратно, нужно найти буквы на клавиатуре. В результате фраза “Добрый день” в голове превращается в “Lj,hs-блин, язык не переключил,del,del,del,del,del-Д-о-б-р-ы-ы-ы-где-ы?-ы-й д-е-н-ь!”. И к тому времени, как человек её набрал он уже забыл, что хотел написать в письме.

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

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

Второй аргумент, почему люди не учатся печатать вслепую - “у меня нет времени на обучение”.

Этот аргумент ещё мощнее первого. “Вслепую я печатаю в три раза медленнее, сбиваюсь и забываю клавиши, а мне нужно срочно писать курсовую/диплом/проект на работе/…”.

Прохождение курса “Соло на клавиатуре” в среднем занимает у человека 40 (сорок) часов работы за клавиатурой (всё время занимает немногим больше). Наверное, что-то с тобой не так, если для обретения навыка, который качественно улучшит твою профессиональную деятельность до конца жизни, у тебя нет сорока часов. 40 часов - это один месяц по 2 часа в день, неделя - по 6 часов в день. Сколько времени ты посвящаешь чтению новостей, просмотру YouTube, прослушиванию музыки и т.п.?

Кроме того, представь, что тебе полгода и ты научился ползать по квартире. В год родители тебя заставляют ходить - а ты им объясняешь, что можешь доползти куда хочешь и тебе непонятно, зачем нужно ходить - перемещаешься ты гораздо медленнее, постоянно падаешь, быстро устаешь. И где бы ты был, если бы в 20 лет по-прежнему ползал и не умел ходить?

Третий аргумент. Многим кажется, что овладеть слепой печатью очень сложно. Действительно, задуматься только - надо же запомнить порядка 30 клавиш, а если печатать на 2х языках - то порядка 70. Их все нужно ПОСТОЯННО ПОМНИТЬ.

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

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

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

Надеюсь, этот прием поможет и тебе, мой ленивый читатель.

Зачем менять Caps Lock на Ctrl?

Во-первых, используешь ты Emacs или нет, Caps Lock - абсолютно бесполезная кнопка, которая занимает одну из самых удобных позиций на клавиатуре. Объяснить это чем-то кроме исторического недоразумения невозможно.

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

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

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

Для набора текста раскладка Dvorak по всем параметрам лучше QWERTY. Все мировые рекорды скорости до недавнего времени ставились только на ней. QWERTY не было даже близко в рекордных таблицах.

И по уму, все уже давно должны были перейти на Dvorak, но реальность диктовала свои условия - куда бы ты ни пришел - везде стоят только QWERTY-клавиатуры, операционные системы не поддерживают других раскладок или их не очень просто настроить. Плюс - многие полезные комбинации кнопок, например, откат последнего действия, вырезать, копировать, вставить, располагаются на Ctrl-Z, Ctrl-X, Ctrl-C, Ctrl-V, и если сменить раскладку - то они разлетятся по всей клавиатуре.

Для преодоления этих трудностей относительно недавно была придумана раскладка Colemak - которая сравнима по ключевым параметрам с Dvorak, но гораздо больше похожа на QWERTY, чем Dvorak. В частности, названные клавиши - Z, X, C, V - вообще остались на тех же местах. Всё это, плюс - поддержка современными операционными системами, плюс - активная реклама, сделали Colemak третьей по популярности на сегодняшний день.

Но для чего я это рассказываю? А для того, что создатели Colemak тоже заметили, что Caps Lock - это бесполезная кнопка на отличном месте. И на её место они посадили Backspace. Печатальщики-пьюристы, наверное, раскритиковали бы такое решение, дескать, “настоящему печатальщику не нужен Backspace, потому что он не совершает ошибок”. Но, на мой взгляд, решение это, в целом, хорошее. И не пользуйся я Emacs’ом - поступил бы точно так же. Однако самая часто используемая не-буквенная клавиша при работе в Emacs - Ctrl, поэтому именно он заслуживает самого удобного положения. А вопрос с Backspace’ом там решен по-другому.

Кроме того, раз уж мы рассматриваем вопрос в историческом контексте, то на старых клавиатурах для Unix-овых терминалов Ctrl располагался именно на месте Caps Lock’a. Либо, на некоторых вариантах - на месте нынешнего Alt’a - тоже в легко досягаемой позиции. Что, собственно, и мотивировало его частое использование в редакторах того времени, к которым относится Emacs.

Что такое регулярные выражения?

Поиск по умолчанию ищет точное (с возможной поправкой на регистр) совпадение строки поиска с какой-либо подстрокой в текущем буфере. Но бывают случаи, когда требуется найти строку, имеющую определенный вид.

Рассмотрим такой пример. В Emacs есть встроенный легковесный язык разметки - Org. Он используется для верстки простых документов, которым не требуется сложное форматирование, как, например, этот обзор.

Org позволяет выделять заголовки и подзаголовки разных уровней, вставлять примеры кода и изображения, выделять текст жирным, курсивом и т.п. Текст, сверстанный в Org можно экспортировать в множество других форматов, например, PDF или HTML. Но в отличие от более серьезных языков верстки, таких как LaTeX или тот же HTML, его исходный код содержит минимум вспомогательных синтаксических элементов. Всё это позволяет легко и быстро писать документы, заботясь, в основном, об их содержании, а не о внешнем виде.

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

* Навигация и поиск

** Навигация

В самом начале я уже рассказал о том, что поиск в буфере можно осуществлять с
помощью комбинаций =C-s= и =C-r=. Сейчас я хочу поподробнее рассказать о них, о
поиске вообще и не только.

** Поиск

Использование поиска для навигации по буферу, возможно, интересно и свежо. Но,
наверное, неплохо бы было рассказать подробнее и о собственно поиске, потому что
пока я затронул только самые базовые его возможности.

*** Дополнительные удобства

Итак, "простой" поиск по буферу можно осуществлять при помощи комбинаций =C-s= и
=C-r= для поиска "вперед" и "назад", соответственно.

*** Регулярные выражения

Уже описанные расширения функциональности, конечно, важны, но они являются
скорее "косметическими". В этой секции я хочу рассказать о качественно
отличающихся возможностях поиска.

* Разное

В разделе "Разное" я планирую рассказать о разном, после того, как закончу
отсальные разделы.

Что делать, если я хочу перейти к заголовку текущего раздела? С одной стороны, его можно найти по названию, но для этого нужно держать в голове название раздела, в котором ты находишься, что не всегда возможно, и уж точно совсем не удобно. С другой стороны, можно попробовать найти заголовок по звездочкам, но звездочки могут встречаться в тексте и сами по себе и для выделения текста жирным. Однако, если звездочки встречаются в самом начале строки, то эта строка обязательно является заголовком. Соответственно, нам нужно как-то ограничить поиск, чтобы он выделял звездочки только в начале строки.

Для того, чтобы обогатить возможности поиска строк в различных текстах, человечество придумало и использует т.н. регулярные выражения (regular expressions). Фактически, это специальный язык, который позволяет выражать более сложные условия, по сравнению с точным совпадением символов.

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

Т.е. для перехода к текущему подзаголовку можно поступить следующим образом:

  1. нажать C-r для перехода в режим поиска
  2. нажать M-s r для перехода в режим поиска по регулярным выражениям
  3. ввести ^* для перехода предыдущему подзаголовку

Обращаю внимание, что если бы мы не перешли в режим поиска по регулярным выражениям, то искалась бы подстрока ^*, а не заголовочные звездочки.

Пойдем дальше. Что, если нам нужно найти заголовок первого уровня? Нетрудно догадаться, что это можно сделать при помощи выражения ^*<пробел>. Звездочки заголовков более низких уровней не будут с ним совпадать, поскольку их больше одной.

Разумно было бы предположить, что если мы хотим найти заголовки второго уровня, то это можно было бы сделать при помощи выражения ^**<пробел>. Однако, оно будет находить начало каждой строки, а не только начальные звездочки заголовков.

Дело в том, что символ * тоже имеет специальное значение в регулярных выражениях. Он соответствует условию “0 или более повторений предыдущего выражения”. Т.е. выражение ^**<пробел> можно прочитать так: “начало строки, за которым следует 0 или более повторений символа *, после чего следует пробел”.

Чтобы вторая звездочка рассматривалась поиском, как обычная звездочка, а не специальный символ, перед ней нужно поставить экранирующий символ (escape symbol) - \. Выражение будет выглядеть следующим образом: ^*\*<пробел>. И оно уже будет искать заголовки второго уровня. По аналогии, можно искать заголовки третьего уровня: ^*\*\*<пробел> и т.д.

У внимательного читателя может возникнуть вопрос - если звездочка имеет специальное значение, то почему нам не приходилось экранировать её, в выражении ^*? Дело в том, что в этом конкретном выражении, она стоит в таком положении, что её специальное значение не имеет смысла. Действительно, что значит “0 или более повторений начала строки”? Начало у каждой строки всегда одно - “начAл” не бывает 0 или 2. А в тех случаях, когда значение специального символа не имеет смысла, то он рассматривается как обычный символ, без дополнительного экранирования. Аналогично, например, символ ^, появившийся не в начале выражения, будет рассматриваться, как обычный.

Мне не хотелось бы дальше распространяться на тему регулярных выражений, потому что, во-первых, о них уже написано огромное количество материалов, в которых они разбираются во всех деталях. А, во-вторых, потому что, на мой взгляд эта тема, несмотря на всю свою важность, не стоит долгого разговора. Самый правильный способ учиться пользоваться регулярными выражениями, на мой взгляд - применение их в ежедневной работе. Большого смысла в том, чтобы специально разбирать бесконечное число различных конструкций нет, потому что применяются они не так часто, и всё равно очень быстро вылетают из головы.

Поэтому в заключение я лишь приведу список наиболее простых и важных конструкций:

  • . (точка) - специальный символ, на месте которого может стоять любой другой символ (ровно один), кроме перевода строки. Например, выражение a.b совпадает с любым набором ровно из трех букв, который начинается на a и заканчивается на b.
  • * (звездочка) - оператор, обозначающий, что предыдущее подвыражение может быть повторено 0 или более раз. Например, o* совпадает с любым числом повторений символа o, включая ни одного.

    * всегда относится к самому короткому предшествующему выражению. Например, fo*, будет совпадать со строками f, fo, foo, и т.д., но не fofo.

    Кроме того, * является “жадным” оператором, т.е. он захватит максимально возможное количество совпадающих подвыражений. Например, fo*. при поиске в тексте foooooob, будет совпадать со всем текстом.

  • + (плюс) - оператор, аналогичный * за единственным исключением - предыдущее подвыражение должно быть повторено хотя бы один раз. Например, ca+r будет совпадать со строками car и caaaar, но не будет совпадать с cr, тогда как ca*r будет совпадать со всеми тремя строками.
  • ? (вопросительный знак) - оператор, аналогичный * за единственным исключением - предыдущее подвыражение может повторяться 0 или 1 раз. Например, ca?r будет совпадать со строками car и cr и никакими другими.
  • *?, +?, ?? - “ленивые” (“нежадные”) версии соответствующих операторов. В отличие от своих “жадных” аналогов, они будут захватывать минимально возможное количество символов. Например, fo*?. при поиске в тексте foooooob, будет совпадать с подстрокой fo, а не всем текстом (в данном случае оператор *? захватывает минимально возможное число символов - 0).
  • [ ... ] (символы, заключенные в квадратные скобки) - соответствуют условию “один из”. Например, c[ad]r совпадает со строками car или cdr и никакими другими. c[ad]*r совпадает с сr, car, cdr, caddaar, и т.п.

    Также в скобках можно указывать интервалы, используя символ -. Например, [a-zA-Z] будет совпадать с любым буквенным символом латинского алфавита в верхнем или нижнем регистре.

    Для того, чтобы включить в множество символ ], его нужно указать самым первым (в этом случае потеряется смысл его специального значения, как закрывающей скобки). Аналогично, символ - можно указать первым или последним символом в множестве. Например, []-] совпадает со строками ] и - и никакими другими.

    Если первым символом после открывающей скобки является ^, то смысл конструкции меняется на противоположный - “ни один из”. Например, [^a-zA-Z] будет совпадать с любым символом, не являющимся буквой латинского алфавита в верхнем или нижнем регистре.

  • ^ (шляпа) - специальный символ, совпадающий с началом строки. Выполняет специальную функцию только если является первым символом регулярного выражения. Например, ^a будет совпадать только с символом a, находящимся в начале строки.
  • $ (доллар) - аналогично ^, но совпадает с концом строки, а не началом. Например, x+$ совпадает с подстрокой из одного или более x‘ов, находящихся в конце строки.

На этом, пожалуй, список основных функций и операторов в регулярных выражениях заканчивается. Есть ещё функции, позволяющие выражать различные единицы, например, “буква”, “цифра”, “пробельный символ”, “слово” и т.п. Есть оператор “или” и многое другое. За более полным описанием регулярных выражений можно обратиться, например, к документации, встроенной в сам Emacs: <f1> i, в открывшемся буфере перейти по ссылкам “Emacs”, затем “Search”, затем “Regexps”, либо “Regexp Backslash”.