# Редактирование в vim

```{note}
Это дополнительный материал к изучению.
Сначала пройдите упражнения из `vimtutor`.
Для этого выполните команду `vimtutor`, которая откроет в `vim` обучающий документ.
```

## Введение

Редактирование текстового файла усложняется тем, что текстовый терминал и интерактивные программы в основном не поддерживают работу с мышью.
Такое положение дел не ограничивает пользователя в действиях, но добавляет ему дополнительной темы для изучения.
Ситуация усложняется еще тем, что вместо привычного 𝑛𝑎𝑛𝑜 мы используем нестандартный текстовый редактор 𝑣𝑖𝑚.
Сложность обучения сегодня компенсируются завтра умением быстро редактировать текст, что является важным навыком для разработчика.

Vim не входит в состав предустановленных программ на большинстве дистрибутивов Linux.
Система Ubuntu в этом не исключение.
Поэтому, если vim отсутствует и у вас нет полномочий суперпользователя на установку, то воспользуйтесь предустановленной утилитой 𝑣𝑖 развитием которой является 𝑣𝑖𝑚.
На нашем уровне использования между ними нет различий.

Для редактирования файла с именем "имя_файла" выполните команду `vim имя_файла`.
Если файла с таким именем существует, то он отобразится в программе, если нет, то отобразится пустой файл, который появится на диске при первом сохранении изменений.

Vim может работать в одном из нескольких режимов.
В зависимости от того, в каком она режиме, нажатия на кнопки интерпретируются по-разному.
В начальный момент vim находится в режиме команд.
Это значит, что вводимые пользователем символы будут интерпретироваться как команды, а не как набираемый текст.
Выход из утилиты произойдет по команде `:q`, если в файле нет несохраненных изменений.
Чтобы выйти из файла без сохранения изменений используйте команду `:q!`.
Сохранение изменений файла на диск используйте команду `:w`.
Во всех трех командах первым символом является двоеточие, которое активирует режим командной строки.
В этом режиме команда на выполнение запускается клавишей "Enter".

Переход из режима команды в режим ввода текста происходит по команде `i` (от "insert").
Обратный переход произойдет по клавише `ESC` или `Ctrl+[`.
Последняя комбинация клавиш подходит, если вы не хотите сбить расстановку пальцев на клавиатуре.

Пяти рассмотренных команд достаточно, чтобы более-менее сносно редактировать текст в `vim`.
Дополнительная информация будет предоставлена в разделе "Текстовый редактор vim"

Программисты и научные сотрудники относятся к категории работников умственного труда.
Большую часть времени они проводят за обдумыванием и переносом мыслей на компьютер.
Для фиксации мыслей используются редакторы – текстовые, офисные, исходного кода.
Чтобы не прервать поток мыслей необходимы удобные инструменты, которые выполняют свои функции и незаметны для пользователя.

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

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

Альтернативой `vim` являются `nano` и `emacs`.
Простой текстовый редактор `nano` включен по умолчанию в большинство дистрибутивов систем UNIX.
Редактор повторяет графический интерфейс приложений в текстовой среде и поддерживает работу с мышью.
По сравнению с `less` и `vim` он привычен пользователям Windows.
Единственный недостаток – это нетипичные горячие клавиши для популярных команд – `Ctrl-O` для сохранения, `Ctrl-W` для поиска, `Alt-6` для копирования.

Тексты чаще редактируют, чем пишут.
Большая часть работы программиста состоит в изучении и редактировании существующих исходных кодов, чем написании новых.
Преимущества `vim` наглядно демонстрируются при редактировании и перемещении по тексту.
Также его команды похожи на зашифрованные в строку алгоритмы.
По этим причинам он получил распространение среди программистов.

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

"Vim" содержит множество команд и бесчисленное количество их комбинаций.
Выучить их все не только невозможно, но и бессмысленно.
Они осваиваются на практике по мере необходимости.
Здесь рассмотрим наиболее часто используемые команды.
Частое использование редактора на практике доводит до набора команд без сознательного усилия.
Со временем строка команды забывается, но в нужный момент пальцы самостоятельно ее наберут.
Это может показаться неожиданным, но примеры автомобилистов и компьютерных игроков говорят об обратном, где сознание контролирует окружающую обстановку, а пальцы и руки автономны.


## Начальные навыки

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

Первое, что советуют перед запуском `vim`, научиться выходить из него.
Запустите редактор командой

```bash
vim [файлы]
```

Если имена файлов не переданы, то откроется окно с заставкой.
На заставке показано, как выйти из программы.

```{figure} images/vim.png
```


## Режимы и команды

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

После запуска `vim` находится в *нормальном режиме*.
Нажимаемые в это время клавиши воспринимаются как команды.

Рассмотрим четыре важные команды для редактора:
* `:q`  -- выход из программы, если нет несохраненных изменений.
* `:q!` -- выход из программы без сохранения изменений в файле.
* `:w`  -- запись изменений на диск.
* `:e file.txt` -- открытие файла с именем `file.txt`.

Все четыре команды начинаются с символа `:`, который переводит редактор в *режим командной строки*.
Вводимая далее команда отображается в нижней части окна и отправляется на выполнение по нажатию `Enter`.

Команды могут объединяться, образуя одну составную: `:wq` выходит из редактора предварительно сохранив изменения.

Команд в `vim` огромное количество.
Выучить их все не только невозможно, но и бесмысленно.
Они осваиваются на практике по мере необходимости.
Здесь рассмотрим наиболее часто используемые команды.
Если вы спросите у водителя, где педаль тормоза (слева, в центре или справа), он не сразу ответит на вопрос.
Но в критической ситуации нога сама нажмет нужную педаль.
Похожая ситуация с редактором, владение которым доведено до автоматизма.
Команды забываются, но пальцы запоминают положение клавиш и сами тянутся к ним.


## Перемещение курсора

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

|   Клавишы   | Команды Vim |          Перемещение        |
|-------------|-------------|-----------------------------|
|     `↓`     |     `j`     | на строку вниз              |
|     `↑`     |     `k`     | на строку вверх             |
|     `←`     |     `l`     | на символ влево             |
|     `→`     |     `h`     | на символ вправо            |
|   `PgUp`    | `Ctrl`+`f`  | на экран вверх              |
|   `PgDn`    | `Ctrl`+`b`  | на экран вниз               |
|   `End`     |     `$`     | в конец текущей строки      |
|   `Home`    |     `^`     | в начало текущей строки (к первому непробельному символу)|
|`Home`+`Home`|     `0`     | в начало текущей строки     |
|`Ctrl`+`Home`|     `gg`    | в начало файла              |
|`Ctrl`+`End` |     `G`     | в конце файла               |
|`Ctrl`+`→`   |     `w`     | на слово вправо             |
|`Ctrl`+`←`   |     `b`     | на слово влево              |
|`Ctrl`+`↑`   | `Ctrl`+`y`  | экрана на строку вверх, курсор остается на месте|
|`Ctrl`+`↓`   | `Ctrl`+`e`  | экрана на строку вниз, курсор остается на месте |

Дополнительные команды перемещения:
* `e`         перемещает курсор к последнему символу в слове.
* `}`, `{`    перемещает курсор на абзац вниз, вверх.
* `W`, `B`    перемещает курсор до пробела вперед, назад.
* `<number>G` перемещает курсор на строку под номером <number>.
* `z-`        делает текущую строку верхней на экране.
* `z.`        делает текущую строку средней на экране.
* `z`+`Enter` делает текущую строку нижней на экране.
* `H`         перемещает курсор на верхнюю строку.
* `M`         перемещает курсор на среднюю строку.
* `L`         перемещает курсор на нижнюю строку.

Перемещения курсора могут происходить посредством поиска:
* `f<symbol>` переходит к следующему символу `<symbol>` в текущей строке.
* `F<symbol>` переходит к предыдущему символу `<symbol>` в текущей строке.


## Редактирование текста

Рассмотрим команды, редактирующие текст:
* `x`, `X` удаляет символ под курсором, перед курсором.
* `J` сливает текущую строку со следующей.
* `~` меняет регистр буквы на противоположный.

Команда `d` совместно с командами перемещения удаляет текст.
* `dw` удаляет символы с текущего до конца слова и пробел тоже.
* `de` похожа на `dw`, но пробел не удаляет.
* `dd` удаляет текущую строку.
* `d<n>d` удаляет <n> строк, начиная с текущей.
* `diw` удаляет слово под курсором.
* `db` удаляет символы от курсора до начала слова.
* `d$` удаляет от курсора до конца строки.
* `d^` удаляет от курсора до начала строки.
* `d0` удаляет от курсора до начала строки.
* ...

Удаленный текст помещается в буфер и может быть добавлен оттуда по команде `p`.

Остальные команды, которые понадобятся:
* `u` отмена изменений.
* `U` отмена всех последних изменений в строке.
* `:redo`, `Ctrl`+`r` повторяет последнюю отмененную команду.
* '.` повторяет последнюю команду.

В *режиме вставки* `vim` превращается в обычный редактор, в котором набираемые символы появляются в файле.
Переход в него происходит по многим командам, которые отличаются тем, куда устанавливают курсор:
* `i` добавляет символы за текущим символом.
* `I` добавляет символы в начале строки.
* `a` добавляет символы перед текущим символом.
* `A` добавляет символы в конец строки.
* `o` добавляет пустую строку за текущей строкой и переходит на ее заполнение.
* `O` добавляет пустую строку перед текущей строкой и переходит на ее заполнение.
* `cc` удаляет строку и переходит на добавление символов в начало строки.

Переход из режима вставки в нормальный режим происходит по `Esc` или `Ctrl`+`[`.

Для выделения текста используется визуальный режим.
* `v` выделяет текст посимвольно;
* `V` выделяет текст построчно;
* `Ctrl`+`V` выделяет текст прямоугольником.

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


## Вопросы для самоконтроля

1. Запустите и закройте редактор `vim`.
2. В нижеследующем фрагменте кода замените строку ": invalid filename" на ": invalid blob".
   Не забудьте выровнять обратные косые черты по вертикали.
```c++
#define PARSE_BLOB(val, res)                                                  \
  do {                                                                        \
    if (!ParseFilename(val, res)) {                                           \
      cmSystemTools::Error(cmStrCat("-E cmake_module_compile_db failed to ",  \
                                    "parse ", path, ": invalid filename"));   \
      return {};                                                              \
    }                                                                         \
  } while (0)
```
3. В нижеследующем коде измените положение фигурных скобок так, чтобы они расположились в отдельных строках.
```c++
static bool ParseFilename(Json::Value const& val, std::string& result)
{
  if (val.isString()) {
    result = val.asString();
  } else {
    return false;
  }

  return true;
}
```
4. Скопируйте в домашний каталог файл `/usr/include/math.h`.
   Удалите перед функциями ключевое слово `extern`.
   После удаления слова в начале строки не должны оставаться пробелы.

5. Во многих заголовочных файлах присутствуют многострочные комментарии (строки, обрамленные символами `/*` и `*/`).
   Замените такие комментарии на однострочные (строки, начинающиеся с `//`).

6. Скопируйте в домашний каталог файл `/usr/include/string.h`.
   Замените у функций возвращаемый тип с `int` на `size_t`.

7. Скопируйте в домашний каталог файл `/usr/include/string.h`.
   Измените стиль кода так, чтобы скобка `{` размещалась не с новой строки, а в конце предыдущей строки.
