[Из песочницы] Как я полюбил vim, Emacs и клавиатуру
В какой-то степени эта статья ответ — или, скорее, дополнение — к публикации «Зачем vi-топор программисту 21-го века». Я увидел, что в комментариях люди по-прежнему удивлялись: какой смысл в этих редакторах, когда есть полноценные IDE; статья приводила немного реальных примеров и, понимая, что мне есть, что сказать, я решил поделиться собственным опытом. Написано в художественном стиле, так как думаю, если бы люди хотели сухую выжимку, они бы просто пошли читать мануалы. Так же предупрежу, что в мануалах по Емаксу клавиша «Alt» упоминается как «Meta». Я буду говорить «Alt», так как для многих это название привычней.Забегая вперед, скажу, что в данный момент я использую для кодинга Емакс с плагином Evil (плагин, эмулирующий функционал VIM’а) и отключенными в этом плагине комбинациями для режима вставки (т.е. стоит мне нажать «Escape», и Emacs перевоплощается в vim, но в режиме вставки он все тот же обычный Emacs. Только представьте: ночью вы супер-герой Х, но никто не знает ваше истинное альтер-эго, ибо днем вы обычный супер-герой Y.).«Какова ваша скорость набора текста?» — вопрос, заданный при устройстве на практику всего полгода назад, вызвал у меня смущенную улыбку, заставил потупить глаза и промямлить «Ну, точную скорость я не измерял, но полуслепой…» О, да, я нередко видел в комментариях на Хабре, посвященных тренажерам слепого набора, подобного рода гордые ответы в комментариях, «полуслепой…». К сожалению, если кто-то из читателей обладает «полуслепым набором» и вы хотите большего, то смиритесь: мое скромное мнение говорит, что вам противопоказано неиспользование Vim или Емакс. Потому что когда вы пишете код (aka много текста) в этих редакторах, не обладая подобного рода набором, у вас будет только два пути: забить и пользоваться обычным редактором или научиться печатать вслепую. Потому что когда вы вместо стрелок используете для перемещения по тексту «Ctrl+n/Ctrl+p» и «Ctrl/Alt+b/f», и пр., вы просто не можете каждую секунду опускать глаза, чтобы посмотреть, куда вы жмете. Поначалу я, правда, сильно недоумевал — «Почему кнопка «n» на месте кнопки «b»? И какого хрена я только что нажал на кнопку «р», а эффект, как будто я нажал на клавишу »[»?». Но поверьте, это пройдет.
Относительно недавно я был обычным студентом с богатой фантазией, кучей поверхностных знаний и без какого-либо серьезного опыта программирования — среднестатистический энтузиаст. Совершенно случайно этому студенту посчастливилось устроиться в отделение одной большой компании, которое пишет ПО для контролеров с запущенным на них GNU/Linux и, конечно же, под «самую популярную ОС». Изначально я попал туда в качестве практики от института, начал писать некое небольшое ПО в виде сервера под GNU/Linux и клиента под Windows®, потом был принят в качестве программиста и дописывал его уже числясь в рабочем люде.
Как у «среднестатистического энтузиаста», у меня дома стоит GNU/Linux (Kubuntu), поэтому, когда мне дали задание и голый компьютер с неудобной WinХР (в сравнении с KDE) для работы — я, понимая, что мне в любом случае придется для разработки держать одну систему под виртуалкой, принял решение отвести эту роль ХР'юше и установить на офисный ПК Кубунту.
«Какое отношение это имеет к нашей статье?», спросите вы. О-о, самое прямое: как следствие принятого мной решения я был авто-лишен Visual Studio. Тогда я еще не знал про ее аналог для Линукса aka QtCreator, точнее знал, но думал, что его можно использовать только для разработки на Qt. Поэтому выбор пал на CodeBlocks. Отчасти, так же этот выбор был обусловлен тем, что эта IDE широко используется в нашей конторе для ПО под Linux.
CodeBlocks недолго просуществовал у меня в качестве редактора, я быстро скатился к редактированию кода в чем-то стороннем и запуске оной IDE исключительно для компиляции. У меня был небольшой опыт использования SublimeText — после него редактировать код в CodeBloсks’е казалось крайне неудобно. По прошествии времени я не могу припомнить ничего конкретного, что меня в CB не устраивало, кроме полного отсутствия семантики автоскобок, из-за чего их было проще отключить, лучшей цветовой схемы в ST и, конечно же, киллер-фиче последнего «mini-map».
К сожалению, момент, когда я перешел с SublimeText на Emacs, напрочь выпал из головы. Могу только гадать, как это произошло. Могу предположить, что хотелось чего-то нового. А может быть меня вдохновили многочисленные статьи о том, как это круто кодить на Емаксе, написанные независимыми людьми с довольно длительным стажем программирования. Я помню, как пытался пару раз перейти на Емакс, а потом жаловался приятелю с другого города, который, по его словам, активно использует. Я помню, как я называл этот редактор нехорошими словами, поливал грязью и всячески унижал в надежде, что кто-нибудь скажет «Парень, ты идиот, ты просто не понимаешь вот это, и вот это, и потому так говоришь; хватит нести чушь!», но приятель был единственным человеком, кто мог ответить что-то дельное, и он почему-то молчал. А потом, словно после аварии на большой скорости и негоночной трассе, я неожиданно очутился в кресле, рядом бежали циферки tcpdump’а в терминале и я что-то быстро набирал в редактор Емакс. «Очнулся — гипс»©.
У людей, впервые берущих Емакс в руки есть в корне неправильное ожидание от этого редактора, на чем я не раз оступался, и из-за чего далеко не сразу стал его использовать. Я вижу, как крутые дяди с опытом программирования 30+ лет, доктора наук, используют его вместо IDE и потом пишут об этом посты, как все круто в их мире. Но в моем мире, когда я попросил сварочный аппарат на пару десятков киловатт, мне дали в руки трут, много дров, огромный фолиант, и сказали, что завтра здесь будет жарко. И еще посоветовали не перепутать томик с древесиной.
Необходимо понимать, что прежде, чем он у вас заработает, вас придется потратить уйму времени на его настройку. И, даже не надейтесь, что вам удастся избежать изучения elisp (язык, используемый оным редактором для скриптов) — если, конечно, вы не хотите искать помощи только из-за того, что найденный кусок кода в какой-нибудь социалке на вроде Github’а с чьего-нибудь конфига работает не совсем так, как написано в комментарии.
Но это все лирика — я совсем не профи в лиспе, да и статья, как мы помним, отнюдь не о нюансах конфигурации Емакса, поэтому постараюсь оставить в стороне эту тему.
Итак, поскольку по временному отрезку мы еще не достигли Vim’а, у нас есть только знаменитые своим неудобством комбинации для передвижения через Alt/Ctrl плюс буква. Мини-памятка для тех, кто не в курсе, или не помнит:
Forward char ⇒ Ctrl+f Back char ⇒ Ctrl+b Forward word ⇒ Alt+f Back word ⇒ Alt+b Line up ⇒ Ctrl+p Line down ⇒ Ctrl+n Поверьте, их неудобство вызвано лишь непривычкой! Я знаю, есть люди, кто меняют местами Caps-Lock и Ctrl, я этого не стал делать, и привык передвигаться на упомянутые клавиши вместо стрелок всего за пол-недели. Насколько это удобно в сравнении со стрелками, спросите вы. О, это очень, очень удобно! Во-первых, вам не надо переносить руку к стрелкам. Это очень круто, потому что если ваш слепой набор базируется не на отличной ориентации в пространстве — когда вы можете держа пальцы, где угодно, попасть не глядя на любую клавишу —, а на расположении указательных пальцев на засечках кнопок «f, j», то вам придется каждый раз для печати искать эти выемки; и неважно, наугад или взглядом. Во-вторых, стрелки могут на [нет/ноут]буках, и клавиатурах не очень адекватных производителей располагаться на довольно разных расстояниях, окруженные очень разными клавишами, и возможно даже без зазоров (как на моем ноуте) — т.е. если у вас нет идеального ощущения пространства и вы не пользуетесь этой клавой много лет вам придется каждый раз или подглядывать, куда вы перенесли пальцы, или часто ошибаться, нажав случайно не ту кнопку. Говоря честно, кнопка Ctrl на некоторых клавах тоже может находиться черт знает где, и тут придут на помощь комбинации vim’а, но об этом позже.Другая незаменимая комбинация — «Ctrl+x b», она переносит курсор в поле для ввода имени буфера (aka открытого файла), в который вы хотите перейти. Автодополнение по табу. И, если у вас включен «ido-mode», как у меня, то в этом поле так же будет список поместившихся имен буферов, вам достаточно будет лишь набрать часть имени буфера и этот список отфильтруется соотв. Вы можете дописать имя или просто выбрать на «Ctrl+s», «Ctrl+r» подходящее имя. Насколько это удобно? Скажу так: я не так давно кодил в Visual Studio, и, чтобы перейти на вкладку, мне приходилось использовать комбинации VsVim типа «Пред. вкладка», «След. вкладка», «Вкладка №n». И это ok’ей, пока у вас не открыто 100500 вкладок, пара сплит скринов и как переключаться между этим всем богатством становится совершенно непонятно. Остается только брать в руки мышь. Часто брать в руки мышь. Наверное, для людей непосвященных это покажется странным доводом: ну и что с того, почему бы и не воспользоваться курсором? Скажем так — когда вы знаете, что есть способ сделать что-то намного быстрее, и практически рефлекторно другие пути, которые требуют переключения внимания, занимают больше времени, и не вводят никаких плюсов, начинают просто раздражать.
Чтобы вы прониклись с идеей про мышь, я приведу пример, очень близкий сердцам IDE’шников: представьте, что вам надо переименовать локальную переменную под курсором. Итак, вы можете α) Вывести контекстное меню, и ввести новое имя β) Написать простенькую регулярку вида »\bmy_var\b», и проследить, чтобы замены были только в пределах функции. Если вы не знаете про вариант α, вам будет совершенно комфортно со случаем β, т.к. это рядовая ситуация, и она явно лучше, чем переименование вручную. Но, когда вы вкусили острые крики переменной, растворяющейся в небытии лишь парой ваших кликов, вы будете стараться всеми силами избегать варианта β: он плохой, он злой, он враг, он раздражает, он заставляет вас делать слишком много движений, он заставляет вас переключаться, одно неверное движение — и вы порезались.
Еще в Емакс есть буфер »*scratch*». Это черновик, автоматически создается каждый раз, когда вы запускаете его. Там стоит предупреждение о его предназначении. Суть, что он по-умолчанию не сохраняется. Его можно применять для написания кратких мыслей, например, о том, как будет выглядеть ваша архитектура — просто, чтобы быть уверенным, что ничего не упущено. Или для тестирования регулярок, а может для краткой заметки, что доделать, как вы вернетесь с выходных (это, если вы, как я, не выключаете ПК — я его просто кидаю в гибернацию). Да куча применений, я уверен, что у вас есть что-то подобное. Пока я юзал SublimeText, у меня всегда был подобного рода файл открыт, правда проблема была в том, что этот файл всегда сохранялся, хотя мне это нужно не было. В какой IDE есть подобная штука? Да, хотя бы, в каком еще текстовом редакторе такая вещь есть?
Когда я начал использовать Visual Studio, я был просто поражен тем, насколько она зависима от intellisense. Стоит в коде появиться малейшей ошибке, и индентация перестает работать. Представьте, что у вас есть функция всего на около полусотни строк с кучей полей видимости, try-catch, и прочего хлама. И вас неожиданно озаряет, что, в-общем то вот тут исключения точно не будет, да, и, вон там можно все переделать. Вы начинаете удалять одни куски кода, переносить другие, и тут — achtung! — интеллисенс обнаруживает ошибки, и вы не можете больше нажать на кнопку, чтобы изменить индентацию по функции, она быстро погружается в хаос! Но такая ситуация может быть довольно редко, поэтому другой пример — до того, как я попробовал Visual Studio, у меня была частая привычка выписывать функцию псевдокодом, а потом писать поверх черновика настоящий код. Основано на печальном опыте, когда логика какой-то функции кажется очевидной, и ты пишешь сразу код, кучу проверок на ошибки, и пр., а потом обнаруживаешь, что не учел сущую мелочь, и теперь надо все перелопатить. Так вот, в Емаксе достаточно выделить кусок кода, и нажать на таб — и он выравняется независимо от того, какие ошибки в коде нашел «flycheck». То же относится и к vim (клавиша »=» для выравнивания).
Другая просто незаменимая клавиша «Super-i». Нет, не ищите, это кастомная комбинация, она запускает функцию «ido-menu», и я просто не представляю, как люди, пользующиеся IDE живут без нее. Она работает похожим образом, как выбор буфера, упомянутый мной ранее, только выводит список функций в текущем файле. Это невероятно удобно: вы нажали гор. клавишу, ввели часть функции, какая вам навскидку пришла в голову, и нажали ввод. Вернуться к предыдущему месту можно на «Ctrl-u Ctrl-space».
Но самая крутая штука в Емаксе — что вы можете найти/написать функцию, выполняющую какое угодно действие, и прибайндить к абсолютно любому событию в редакторе. Причем вам даже не надо рестартовать редактор, все происходит на лету. Например: никто не любит висящие пробелы в конце строк — зачем они? Не правда ли, был бы приятно, если бы перед сохранением они удалялись? Отлично, находим функцию »(delete-trailing-whitespace)», находим, что хук, выполняющийся перед сохранением файла, называется «before-save-hook», и добавляем функцию туда. А, может быть вам стукнуло в голову, как было бы круто, если бы в С++ перед сохранением файла все инклуды сортировались в алфавитном порядке? Великолепно! Пишем на тот же «before-save-hook» лямбду, которая проверяет, что текущий включенный режим С/С++, и ищет инклуды, затем их сортирует. Я таким образом случайно нашел в одном хедере два дублировавшихся инклуда.
Другая штука, которой не хватало позже в Visual Studio — «Alt+q», он выравнивает текущий параграф под заданное максимальное кол-во символов на строку. Т.е. если кол-во букв слишком большое, слова переносятся на следующую строку. Незаменимая вещь при редактировании комментариев к коду, и я не знаю, чтобы она была в, по-крайней мере, Visual Studio или CodeBlocks.
Если честно, я даже понятия не имею, что еще упомянуть, чтобы не сделать статью скучным перечислением фич Емакса. Функций в Emacs невероятно много на все случаи жизни, я уж не говорю, что не выходя из редактора, там есть поддержка терминала — серийного и обычного — дебаггера, контроль версий (правда в оном я не разобрался, но, просто, сильно не вникал), клавиатурные макросы, и еще черт знает что. Те, кто говорят, что полноценная IDE круче, просто не в курсе, что все их фичи в Емакс либо есть, либо могут быть доустановлены. Например для C# имеется т.н. omnisharp-server, который запускается отдельно, и потом к нему можно подключать Емакс для получения всех фич, вроде «go to definition», «переименование переменных и ссылок к ним», автодополнение, и пр. Проблемы обычно начинаются от незнания elisp, и нежелания при малейших вопросах просто посмотреть, как этот код работает. Я говорю потому, что сам был таким — не знал толком лиспа, и не мог настроить «omnisharp-mode». Туториалы мне казались недостаточно подробными. Вопросы отпали после того, как отчаявшись, но еще не желая задавать вопрос на форуме, я решил заглянуть в код плагина, и обнаружил, что на github даже пример конфигурации валяется.
К слову, первая ласточка интереса к Vim’у проснулась именно, пока я пользовался Емаксом. Абсолютно случайно я обнаружил, что там на кнопке «о» в «нормальном режиме» есть крутая функция, которая работает, как, если бы вы нажали в обычном редакторе «End» и «Enter» — она начинает новую строку без разрыва текущей. А большая «О» начинает новую строку над текущей строкой. Очень удобно, я забайндил подобную вещь на отдельную клавишу, но мне стало любопытно:, а что еще есть в Vim, чего нет в Емакс?
Поэтому перейдем же, наконец, к VIM. Мое знакомство с этим редактором состоялось при печальных обстоятельствах: я начал работать в Visual Studio с кодом на С#, времени разбираться с работой Omnisharp server’a не было, т.к. я торчал на работе по 12+ часов по причинам проблем со сроками сдачи проекта и старался получить как можно больше опыта, на случай, если меня, как неопытного студента, просто уволят. Поэтому я решил просто настроить Visual Studio так, чтобы можно было комфортно передвигаться. И тут меня ждало ужасное разочарование: найденный плагин с Емаксовыми кейбайндингами напрочь отказывался работать; и даже когда я решил кое-как просто перенастроить, к примеру, «Ctrl-→» на «Alt-f», студия работала с комбинациями просто отвратительно. Во-первых, если нажать Alt и отпустить — бывает такое, что хотел прыгнуть на слово вперед, а потом передумал — при попытке продолжить писать код ты можешь закрыть файл, запустить дебаггер, вызвать из бездн ада яблочного монстра или случайно стать первым человеком, убитым самозародившейся сингулярностью. Потому что при отпускании альта без нажатия любой другой клавиши курсор перепрыгивает в меню студии (где File, Edit, и пр.), где каждой букве соответствует какое-нибудь подменю. Это очень большая проблема, и как это отключить, я так и не смог отыскать. Исходя из поиска в интернете, я сделал вывод, что это «фича» оконного менеджера под Windows и ее отключить невозможно.
А во-вторых, в Visual Studio (achtung!) нет команды «прыгнуть к концу слова»! Т.е. шорткат «Ctrl-→», работающий везде именно таким образом, в IDE вас отправлял к началу следующего слова! Это было просто ужасно, я промучался так пару недель и осознал, что в 80% случаев после того, как я допрыгал до начала следующего за интересующим меня слова, приходится еще раз жать клавишу, чтобы возвратиться на символ обратно.
Тогда-то я вспомнил, что читал про некий плагин под Visual Studio, эмулирующий функционал VIM. Называется он VsVim, и он великолепен. И да, таки в нем есть команда «перейти к концу слова»! Это был новый виток эволюции: зная, что что-то должно быть автоматизировано нажатием на одну клавишу, я просто вводил в гугл, как это сделано в VIM’е, и, практически всегда, это было реализовано и в VsVim, теми же клавишами, или командами. К передвижению на hjkl я привык в течении, может, половины недели, как максимум.
«Почему Vim?» Помните, я рассказывал, как круто использовать комбинации «Ctrl/Alt-key» вместо стрелок. Так вот: тут вам не надо было даже нажимать Ctrl. Поначалу кажется, что отстукивать каждый раз по Escape проигрывает, но поверьте мне, это тоже просто дело привычки. Кроме, может, крайних случаев, когда надо переместиться лишь на несколько букв вправо/влево.
Навигация в Vim отточена умопомрачительно. Весь код в пределах нескольких клавиш. Переместиться в центр, начало, или конец экрана? M (iddle), H (ihg), L (ow) в вашем распоряжении. Пролистнуть половину экрана? «Ctrl+d»/«Ctrl+u». Перейти к открывающей/закрывающей скобке? [<скобка>, и ]<скобка> соответственно. Перейти на пять строк выше? Просто нажмите »5k». Перейти на три слова влево?»3b». Прыг к провозглашению функции? «gd». Прыжок к следующей запятой в строке? «f,» Возвратиться на предыдущее, следующее место в коде? «Ctrl-o» и «Ctrl-i» соответственно.
Помимо лучшей навигации по коду это дало мне, наконец, полноценный слепой набор и научило навскидку оценивать кол-во тех или иных объектов. Причина последнего в том, что почти любая команда vim принимает цифру, которая означает, как правило, кол-во раз, которое команда должна быть выполнена. Разумеется, это было и в Emacs, но там необходимо было дополнительно с цифрой жать Alt или Ctrl, что, в отсутствие умения наживать на цифру вслепую, энтузиазма не добавляло. И потому цифры там мной использовались только в крайних случаях, но никак не в повседневных операциях, вроде перехода на несколько слов вбок. Здесь же добавить к команде префикс было проще простого и потому я очень скоро запомнил, какие цифры (и символы, которые там тоже в активном использовании) находятся на цифровом ряду, и какими пальцами их лучше нажимать.
Ну и, под конец, коронная фича vim — текстовые объекты. Незаменимая штука во время кодинга. Дело в том, что многие команды (в частности, удаление, выравнивание, копирование) принимают постфиксы, причем довольно интуитивные. К примеру, надо нам выровнять код внутри квадратных скобок? Жмем »=i{» Хотим удалить все изнутри угловых скобок, включая их самих? Жмем «da<». Правило постфиксов довольно простое: действие, затем i(nside) или a(думайте, как о неопределенном артикле), затем объект, над которым хотим провести действие. Помимо скобок это может быть так же w(ord), и это, пожалуй, наиболее часто применяемый объект. Постфикс «а» работает в данном случае над словом с пробелом в конце, если есть. «i», очевидно, над самим словом.
Если бы я сравнивал навигацию по коду в vim и Emacs, я бы сказал, что vim однозначно выигрывает. Но ведь не за то люди Емакс любят, а за его гигантскую расширяемость! Хм… А что, если… Если кто-то даже написал плагин под Емакс, который эмулирует функционал vim’a? И да, таки такой плагин есть, он называется «Evil»! На клавишу «Escape» в Emacs ничего особенно полезного не забайндено, так почему бы не сделать на эту клавишу включение «нормального режима» vim? И оставить остальные клавиши не измененными? Сказано — сделано:
;; remove all keybindings from insert-state keymap (setcdr evil-insert-state-map nil) ;; but [escape] should switch back to normal state (define-key evil-insert-state-map [escape] 'evil-normal-state) Так же, помимо слепого набора, быстрого редактирования текста, и умения на глаз прикидывать кол-во тех, или иных объектов, это позволило мне познакомиться с замечательным языков LISP, чего и вам желаю.Я еще не говорил, что IDE в сравнении с Emacs идут лесом? А, ну вот, сказал.
Ну, и по хорошей традиции, установленной автором прошлого поста, я упомяну, что использую FireFox и расширение к нему Pentadactyl. Это форк от Vimperator, который, к сожалению, сейчас не развивается. Вообще, должен предупредить, что с Pentadactyl происходит что-то странное. Вроде бы как проект живой, но в рабочем состоянии для новых версий огнелиса были только ночные билды. Недавно и они перестали появляться. Когда я обновил браузер и столкнулся с подобной проблемой, нашел на страничке Mozilla, посвященной Pentadactyl среди отзывов один от кого-то сочувствующего, кто пообещал выкладывать билды. Я порадовался, установил дома, и, каково же было мое удивление, когда в следующий раз, когда я с работы зашел в отзывы, чтобы воспользоваться линком, отзыв не был мной обнаружен. Тогда я не поленился зарегистрироваться, продублировал отзыв и на следующий день он так же оказался удален. Как бы там ни было, раз кто-то удаляет отзывы, значит проект жив, что не может не радовать.
А еще в настоящее время в офисе я использую оконный менеджер Awesome, что очень удобно для работы, но это уже другая история.