msiu_logo
Кафедра информационных систем и технологий
http://edu.msiu.ru

1. Введение

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

2. Дополнительные возможности модуля NERDTree

Мы уже знакомы с некоторыми из следующих команд, доступных в окне NERDTree:

o (open — открыть)
  • для директории, имя которой указано в текущей строке, раскрыть в окне NERDTree её содержимое; если содержимое уже было раскрыто, то закрыть его

  • для файла, имя которого указано в текущей строке, открыть его содержимое для просмотра или редактирования в правом окне и сделать его активным (переместить в него курсор)

    Подсказка Нажатие на клавишу Enter или двойной клик левой кнопкой мыши выполняют те же самые действия.
i (split — расщепить)

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

m (menu — меню)

показать меню работы с файлами

R (Refresh — освежить)

обновить информацию о файлах и поддиректориях — полезно, если содержимое дерева, показываемого NERDTree, изменилось с помощью действий, внешних по отношению к Vim

I (hIdden — скрытый)

переключить режим показа скрытых файлов и директорий (имена которых начинаются с точки): если они не показывались, то начать показывать, и наоборот

Файлы и директории в окне NERDTree могут быть снабжены дополнительными пометками, называемыми bookmarks:

Vim
Внимание Пометки не должны содержать пробелов, поэтому можно при необходимости «склеивать» слова символом подчёркивания.

Для того чтобы пометить текущую строку в окне NERDTree, следует перейти в режим командной строки, нажав двоеточие, набрать далее B и нажать клавишу Tab. Команда должна продолжиться до :Bookmark (её можно, конечно, и вручную набрать). Далее надо ввести пробел и текст пометки, включив при необходимости режим ввода русских букв. Таким образом, вся последовательность клавиш может быть, например, такой:

:B Tab␣ Ctrl + ^ Нужная_программа

Для удаления пометки можно воспользоваться командой :ClearBookmarks, набирать которую целиком вовсе не обязательно. После ввода двоеточия и буквы C следует нажать на клавишу Tab. Редактор продолжит команду, но, скорее всего, не до нужной нам :ClearBookmarks, а до идущей первой (в алфавитном порядке) :ClearAllBookmarks, которая удалит все имеющиеся пометки. Так что не спешите нажимать на Enter — любые команды удаления необратимы!

Если команда продолжилась до :ClearAllBookmarks, то нажмите Tab ещё раз, чтобы получить нужную команду :ClearBookmarks. После этого можно выполнить её.

Важно Будьте очень внимательные, выполняя команды удаления. Как правило, восстановить удалённые объекты невозможно!

3. Базовые команды Vim

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

3.1. Команды перемещения (движения)

% (go to match — перейти к соответствующей)

перемещение между парными круглыми, квадратными или фигурными скобками («прыжки» от открывающей скобки к закрывающей и обратно)

H (High — высоко)

перемещение («прыжок») на верх экрана

M (Middle — посередине)

перемещение («прыжок») в середину экрана (или файла, если он занимает не весь экран)

L (Lower — низко)

перемещение («прыжок») в низ экрана (или файла, если он занимает не весь экран)

G (Go — перейти)

перемещение («прыжок») в самый конец файла

Замечание Если команде G предшествует число n, то перемещение происходит в строку с номером n (или наиболее близкую к ней). В частности, команда 1G вызывает перемещение в начало файла.
- (минус)

перемещение на первый не пробельный символ предыдущей строки

+ (плюс)

перемещение на первый не пробельный символ следующей строки

Следующая команда формально не относится к командам движения, она является командой прямого действия, однако её вполне логично упомянуть именно здесь, так как с точки зрения пользователя она выполняет «перемещение»:

K

«перемещение» к разделу справочной информации (редактора Vim, операционной системы, языка программирования и т.п.), описывающей слово под курсором

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

Следующие две команды особенно полезны при редактировании обычных текстов.

(

перемещение в начало текущего предложения

)

перемещение в конец текущего предложения

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

{

перемещение на предыдущую пустую строку (в начало текущего абзаца)

}

перемещение на следующую пустую строку (в конец текущего абзаца)

Команд, начинающихся с открывающей и закрывающей квадратных скобок, несколько десятков. Увидеть их все можно, выполнив команду :h [. Основная масса этих команд особенно полезна при редактировании текстов программ на языках C и C++, с которыми вы будете иметь дело на втором курсе.

Из остальных команд, начинающихся с квадратных скобок, нужно отметить команды, используемые при проверке орфографии (spell checking) и команды перехода к другому файлу:

[f и ]f

переход к редактированию файла (или просмотру содержимого директории), имя которого находится под курсором

Замечание О проверке орфографии текстов на различных языках речь пойдёт несколько позже.

3.2. Команды прямого действия

J (Join — присоединить)

присоединить к текущей строке следующую за ней (или все выделенные строки)

r (replace — заменить)

заменить текущий символ на символ, введённый непосредственно после r

C (Change — изменить)

удаляет символы от текущего до конца строки и выполняет переключение в режим вставки; является сокращением известного нам оператора c$

D (Delete — удалить)

удаляет символы от текущего до конца строки без переключения в режим вставки; является сокращением известного нам оператора d$

Y (Yank — копировать)

копирует текущую строку в системный буфер обмена или регистр; является сокращением известного нам оператора yy

s (substitute — заменить)

удаляет символ под курсором и выполняет переключение в режим вставки

S

удаляет все символы текущей строки и выполняет переключение в режим вставки

~ (toggle case — переключить регистр)

меняет регистр символа под курсором (превращает большую букву в маленькую и наоборот)

3.3. Операторы

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

>

установить абзацный отступ

>

убрать абзацный отступ

=

отформатировать указанный диапазон текста

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

gg=G или 1G=G

В ней сначала осуществляется переход в начало файла (gg или 1G), а затем выполняется операция форматирования над фрагментом от первой строки до последней (так как команда G перемещает курсор в конец файла).

3.4. Команда замены

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

Наиболее общая форма команды замены (substitute) имеет следующий весьма «страшный» вид:

:[range]s[ubstitute]/{pattern}/{string}/[flags] [count]

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

Замечание Подробная информация о команде замены может быть получена в справочной системе: :h s.
:%s/stop/end/

заменить во всех строках файла первое вхождения фрагмента stop на end; s (substitute) — заменить

:%s/stop/end/g

заменить все имеющиеся в файле вхождения фрагмента stop на end; g (global) — глобально заменять все вхождения в каждой (%) из строк

.%s/stop/end/g

заменить все вхождения фрагмента stop на end в текущей (.) строке

.+3%s/stop/end/g

заменить все вхождения фрагмента stop на end в третьей строке после текущей (.+3)

2,4%s/stop/end/g

заменить все вхождения фрагмента stop на end в строках от второй (2) до четвёртой (4)

$%s/stop/end/g

заменить все вхождения фрагмента stop на end в последней ($) строке

:%s/stop/end/gc

заменить все имеющиеся в файле вхождения фрагмента stop на end, спрашивая в каждом из случаев подтверждения (confirmation)

:%s/ab\|bc\|cd/qq/g

заменить все имеющиеся в файле вхождения фрагментов ab, bc и cd на qq; в шаблоне /ab\|bc\|cd/ экранированная символом бэкслеш вертикальная черта означает «или»

:%s/ab.*yz/qq/g

заменить все имеющиеся в файле вхождения всех тех фрагментов, которые начинаются на ab и заканчиваются на yz, на qq; в шаблоне /ab.*yz/ выражение .* означает произвольное количество, включая нулевое, любых символов

:%s/\s\+$//

удалить пробельные символы в конце всех строк; здесь выражение \s соответствует символу пробела или табуляции, \+ означает любое большее нуля количество таких символов, знак доллара говорит о том, что заменяемый фрагмент должен находиться в конце строки

:%s/\s\+$

более краткая версия предыдущей команды; в случае замены фрагмента на пустую строку её можно опускать

4. Работа с Ruby-программами

4.1. Редактирование кода

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

n1 = getabcdefghijklmnopqrstuvwxyz0123456789_s_.to_i
n2 = getabcdefghijklmnopqrstuvwxyz0123456789_s_.to_i
abcdefghijklmnopqrstuvwxyz0123456789_s_ = 0
i = n1
while i <= n2
  abcdefghijklmnopqrstuvwxyz0123456789_s_ += i
  i += 2
end
putabcdefghijklmnopqrstuvwxyz0123456789_s_ abcdefghijklmnopqrstuvwxyz0123456789_s_

Как проще всего это сделать?

Можно заметить, что одна и та же последовательность символов (abcdefghijklmnopqrstuvwxyz0123456789_) была вставлена несколько раз в различные места программы. Но это явно не всё. Что же было сделано на самом деле?

Посмотрев на программу более внимательно, можно догадаться, что к каждому символу s были дописаны с двух сторон следующие фрагменты текста: перед ним уже отмеченный нами фрагмент abcdefghijklmnopqrstuvwxyz0123456789_, а после него — фрагмент, состоящий из одного символа подчёркивания. Таким образом, для восстановления исходного вида программы нужно заменить все фрагменты abcdefghijklmnopqrstuvwxyz0123456789_s_ на s.

Нам уже известна команда редактора Vim, позволяющая осуществить во всём файле замену некоторого шаблона (регулярного выражения) на заданную строку:

:%/шаблон/строка/g

заменить во всём файле шаблон на строка

В нашем конкретном случае нет никакой необходимости использовать в качестве шаблона тот длинный фрагмент, которым злоумышленник заменил символы s. Можно заменить фрагменты, которые начинаются с символа a и заканчивается символами s_. Все они удовлетворяют шаблону a.*s_, в котором комбинация .* означает «произвольное количество произвольных символов (отличных от перевода строки)».

Итак, выполним команду :%s/a.*s_/s/g. Вот результат:

n1 = gets.to_i
n2 = gets.to_i
s = 0
i = n1
while i <= n2
  s += i
  i += 2
end
puts

Почему-то получилось не вполне то, что нам хотелось, — в последней строке «пропала» буква s: вместо puts s у нас просто puts. В чём же дело?

Всё объясняется весьма просто. Использованному нами шаблону /a.*s_/ удовлетворяют не только фрагменты putabcdefghijklmnopqrstuvwxyz0123456789_s_ и abcdefghijklmnopqrstuvwxyz0123456789_s_, которые мы хотели заменить, но и все символы последней строки, начиная с четвёртого. А так как по умолчанию операция сопоставления с шаблоном, включающим в себя *, является «жадной» (greedy), то есть старающейся найти фрагмент максимальной длины, удовлетворяющий шаблону, то и заменяется этот один длинный фрагмент.

Для замены «жадного» поиска на «ленивый» (lazy), который ограничивается фрагментом минимальной длины, удовлетворяющей шаблону, шаблон необходимо изменить. Вместо /a.*s_/ следует использовать /a.\{-}s_/.

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

Если выполнить команду откатки u, а затем — команду замены с модифицированным шаблоном, то будет получен требуемый результат.

4.2. Выравнивание кода Ruby-программы

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

n = gets.to_i
       m = 10
                while n > 0
           k = n%10
if k < m && k%2 != 0
                       m = k
                       end
                       n /= 10
end
                 if m != 10
            puts m
      else
  puts "Не найдено"
end

Эта программа получена «искусственным путём», но первокурсники зачастую создают ещё более ужасный код.

Использование среды MsiuVim позволяет с помощью простой команды исправить все отступы в неправильно выровненной программе:

gg=G (или 1G=G)

отформатировать код в соответствии со стандартами Ruby-мира

Реально эта команда состоит из двух: команды движения (1G или gg), перемещающей курсор в начало буфера (файла), и оператора форматирования (=), областью действия которого оказывается вся программа целиком, ибо следующая за ним команда движения (G) перемещает курсор в конец буфера.

Вот каким становится код после выполнения этой команды:

n = gets.to_i
m = 10
while n > 0
  k = n%10
  if k < m && k%2 != 0
    m = k
  end
  n /= 10
end
if m != 10
  puts m
else
  puts "Не найдено"
end

5. «Шпаргалка» по командам Vim

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

./images/vim-chart3.png