Визуальный режим - это "инвертированная" грамматика. Обычно вы говорите d (что делать), а затем } (над чем). В визуале наоборот: сначала } строит выделение, вы видите подсвеченный кусок, и только потом жмёте d. Для многих правок такой порядок интуитивнее, а для блочного (столбцового) редактирования визуальный режим вообще незаменим - это его эксклюзивная суперсила.
В этой главе разберём три визуальных режима (v, V, Ctrl-V), опцию selection (inclusive/exclusive), операторы поверх выделения, блочную вставку по столбцу и virtualedit=block, инкремент колонки чисел, восстановление и инверсию выделения, запуск :-команд над диапазоном, повторяемые альтернативы визуалу (gn/gN, форсирование типа оператора dvj) и важный вопрос: когда визуал реально лучше, а когда он - антипаттерн, тормозящий ваше редактирование.
Три визуальных режима
У Vim не один визуальный режим, а три. Они отличаются формой выделяемой области.
Код: Выделить всё
Клавиша | Режим | Форма выделения | Когда использовать
---------+-------------------------------+---------------------------+-------------------------------------------
v | Character-wise (символьный) | От символа до символа | Произвольный кусок внутри/между строк
V | Line-wise (строчный) | Целые строки | Операции над строками целиком
Ctrl-V | Block-wise (блочный) | Прямоугольник (столбцы) | Колонки, выравнивание, вставка по столбцу
Важная деталь о Ctrl-V: в большинстве терминалов это "вертикальный таб", и в Windows-сборках Vim он часто занят под "вставить из буфера". Поэтому в Vim существует синоним Ctrl-Q - он делает то же самое (входит в блочный режим), если Ctrl-V перехвачен. В терминале на macOS/Linux Ctrl-V обычно работает штатно.
Почему отдельный строчный режим
Можно было бы думать, что V - это просто v плюс "расширить до краёв строк". Но разница глубже и проявляется во взаимодействии с регистрами и вставкой. Когда вы удаляете/копируете в строчном режиме, текст хранится как "строчный" - при p он вставится новой строкой ниже, а не в позицию курсора. Это ровно то поведение, которое даёт dd/yy. Символьное же выделение вставляется "в строку". Подробнее о типах регистров - в главе 8.
Опция selection: inclusive против exclusive
Частый источник недоумения - "съеденный" или "лишний" символ на краю выделения. За это отвечает опция selection, у которой три значения:
- inclusive (по умолчанию в Vim) - последний символ под курсором входит в выделение. Когда вы встаёте на символ и жмёте d, этот символ удалится вместе с остальными.
- exclusive - последний символ под курсором не входит в выделение (как в большинстве GUI-редакторов). Тот же d оставит символ под курсором нетронутым.
- old - устаревший режим совместимости, на практике не нужен.
Практический совет: если правки на краю выделения систематически промахиваются на символ - проверьте :set selection?. Менять значение глобально стоит осознанно: большинство сочетаний и примеров в документации Vim рассчитаны на inclusive.
Операторы поверх выделения
Выделив область, вы применяете к ней оператор. Большинство привычных операторов работают и в визуале:
Код: Выделить всё
Клавиша | Действие над выделением
---------+------------------------------------------------------
d или x | Удалить
c или s | Удалить и перейти в режим вставки
y | Скопировать (yank)
> / < | Сдвинуть отступ вправо/влево
= | Автоотступ
gu / gU | В нижний / верхний регистр
g~ | Инвертировать регистр
gq / gw | Переформатировать по textwidth
J | Склеить строки в одну (с пробелом)
gJ | Склеить без добавления пробела
u / U | (в визуале) нижний / верхний регистр выделения
~ | Инвертировать регистр выделения (если tildeop выкл.)
r{char} | Заменить каждый символ выделения на {char}
o | Перейти на другой конец выделения
O | (в блочном) перейти на другой угол по горизонтали
: | Открыть командную строку с диапазоном '<,'>
r в визуальном режиме
r поверх выделения заменяет каждый выделенный символ на указанный. Это отличается от обычного r, который меняет один символ под курсором.
Код: Выделить всё
Было: --------section--------
Действие: выделяем дефисы слева -> r=
Стало: ========section--------
Код: Выделить всё
Было:
foo.bar
baz.qux
xyz.abc
Ctrl-V, выделяем колонку точек (3 строки), r,
Стало:
foo,bar
baz,qux
xyz,abc
Блочный (столбцовый) режим - главная причина, по которой стоит держать визуал в активном арсенале. Никакой оператор+движение не дадут вам так же просто отредактировать прямоугольную область текста.
Вставка по столбцу: I и A
Выделив вертикальный блок, нажмите I (вставить в начало блока) или A (вставить в конец блока), напечатайте текст, затем Esc - и текст продублируется на все строки блока.
Критически важная деталь: изменение появляется на всех строках только после Esc. Пока вы печатаете, правка видна лишь на верхней строке блока. Это сбивает новичков с толку ("не работает!"), но это нормально - жмите Esc и увидите результат.
Код: Выделить всё
Было:
name = "Alice"
name = "Bob"
name = "Carol"
Ставим курсор на 'n' первой строки -> Ctrl-V -> jj (выделили колонку из 3 строк)
-> I -> печатаем "const " -> Esc
Стало:
const name = "Alice"
const name = "Bob"
const name = "Carol"
Код: Выделить всё
Было:
let a = 1
let b = 2
let c = 3
Ctrl-V -> jj -> $ -> A -> печатаем ";" -> Esc
Стало:
let a = 1;
let b = 2;
let c = 3;
Здесь скрыта тонкость. Если строки имеют разную длину, обычное A поставит текст по "прямоугольному" правому краю блока - то есть по координате столбца, а не по фактическому концу каждой строки. Решение - расширить блок до конца строки командой $ перед A:
Код: Выделить всё
Было (строки разной длины):
short
a_longer_line
mid
Ctrl-V -> jj -> $ -> A -> ";" -> Esc
Стало (точка с запятой реально в конце каждой):
short;
a_longer_line;
mid;
virtualedit=block для прямоугольника за концом коротких строк
$A решает задачу "прилепить к фактическому концу каждой строки". Но иногда нужно ровно обратное - выделить и заполнить прямоугольник по виртуальным столбцам, даже там, где строки короче и реальных символов на этих позициях нет. Здесь помогает опция virtualedit.
Значение virtualedit=block разрешает курсору заходить за конец коротких строк именно в блочном режиме. Тогда Ctrl-V выделяет настоящий прямоугольник по столбцам, не "обрезаясь" по самой короткой строке, а A/I/c вставляют ровно по виртуальной координате столбца - Vim сам дополнит недостающие позиции пробелами.
Код: Выделить всё
:set virtualedit=block
Было (строки разной длины):
foo
a_longer
xy
Ctrl-V -> jj -> встаём за конец на 8-й столбец (за концом строк foo и xy) -> A -> "|" -> Esc
Стало (выровнено по виртуальному столбцу, пробелы добавлены):
foo |
a_longer|
xy |
c в блоке
Блочный c удаляет прямоугольник и переводит в режим вставки; напечатанное появится на всех строках блока после Esc. Удобно для замены одинакового по позиции куска:
Код: Выделить всё
Было:
2026-01-15 event A
2026-03-22 event B
2026-07-08 event C
Ctrl-V на колонке "2026" (4 символа x 3 строки) -> c -> "YEAR" -> Esc
Стало:
YEAR-01-15 event A
YEAR-03-22 event B
YEAR-07-08 event C
Одна из самых эффектных команд. Обычный Ctrl-A увеличивает число под курсором на 1 (а Ctrl-X уменьшает) - об этом упоминалось в главе про редактирование. Но в визуальном режиме появляется вариант g Ctrl-A, который превращает колонку одинаковых чисел в возрастающую последовательность.
Сначала про визуальный Ctrl-A (без g): он прибавляет 1 ко всем числам в выделении - все станут одинаково больше. А g Ctrl-A прибавляет нарастающий шаг: к первому числу +1, ко второму +2, к третьему +3... - то есть генерирует ряд.
Код: Выделить всё
Было:
item 0
item 0
item 0
item 0
Ctrl-V выделяем колонку нулей (4 строки) -> g Ctrl-A
Стало:
item 1
item 2
item 3
item 4
Историческая заметка: визуальные g Ctrl-A/g Ctrl-X появились ещё в Vim 7.4 (патч 7.4.754) и есть в Neovim. В очень старых сборках их может не быть - но в 2026 это давно повсеместно.
Код: Выделить всё
Дать сквозную нумерацию строкам "0. ":
Было:
0. apple
0. banana
0. cherry
Ctrl-V на колонке нулей -> g Ctrl-A
Стало:
1. apple
2. banana
3. cherry
o - другой конец
Внутри визуала o перепрыгивает курсор на противоположный конец выделения. Зачем? Часто вы выделили слишком много или мало с начала, а корректировать удобнее именно стартовую границу. o переносит "активный" конец туда, и вы доправляете движениями.
Код: Выделить всё
Выделили /pattern/ слишком далеко вправо.
Жмём o -> курсор прыгает к началу выделения -> правим левую границу b/h -> o возвращает.
gv - восстановить последнее выделение
gv повторно выделяет ту же область, что была выделена в прошлый раз (в нормальном режиме). Это спасает, когда:
- вы применили команду, она сбросила визуал, а вам нужно к тому же куску ещё раз;
- вы случайно вышли из визуала и потеряли с трудом выставленные границы;
- выделение было сделано, например, из подсветки поиска, и его надо вернуть.
Код: Выделить всё
Выделили абзац (vap), сделали gu (нижний регистр).
Теперь надо его же отформатировать: gv -> gq
:-команды над выделением ('<,'>)
Нажмите : в визуальном режиме - командная строка откроется уже с префиксом:
Код: Выделить всё
:'<,'>
Код: Выделить всё
Выделили блок кода (V + движения) -> : -> дописываем s/foo/bar/g -> Enter
Получилось: :'<,'>s/foo/bar/g
Другие полезные комбинации над '<,'>:
Код: Выделить всё
Команда | Что делает над выделением
-------------------+------------------------------------------------------
:'<,'>s/old/new/g | Замена в пределах строк выделения
:'<,'>normal @a | Прогнать макрос a по каждой строке (глава 16)
:'<,'>normal A; | Дописать ; в конец каждой строки
:'<,'>sort | Отсортировать строки
:'<,'>sort u | Отсортировать и убрать дубликаты
:'<,'>g/pattern/d | Удалить совпавшие строки внутри выделения (глава 12)
:'<,'>!sort -r | Прогнать строки через внешнюю утилиту
:'<,'>w other.txt | Записать выделенные строки в файл
Код: Выделить всё
Закомментировать выделенные строки (стиль //):
Выделили строки V+jjj -> : -> 'normal I// ' -> Enter
Результат: :'<,'>normal I//
Каждая строка получит "// " в начале (с учётом отступа).
Это важнейший раздел главы. Визуальный режим соблазнительно нагляден, и новички начинают всё делать через него: v + выделить + d. Это распространённый антипаттерн.
Почему оператор+движение часто лучше
Главная причина - повторяемость точкой (.). Команда daw (delete a word) - это один "атом", который . повторит целиком в новом месте. А viwd - это последовательность из режима; точка повторит лишь последний кусок, и поведение будет непредсказуемым. Если вы редактируете однотипные места по файлу, оператор+текстовый объект + . почти всегда быстрее визуала (см. главы 6 и 7).
Сравните:
Код: Выделить всё
Удалить три слова в скобках, повторяя по файлу:
Хорошо: di( -> затем n . n . (находим и повторяем)
Хуже: vi(d -> точка повторит не то, что ожидаете
gn/gN - повторяемая замена по шаблону поиска
Когда правка завязана на совпадение последнего поиска, визуал - почти всегда худший выбор: v-выделение совпадения с последующим оператором не повторяется точкой. Современная и куда более удачная альтернатива - gn (и gN для движения назад).
gn - это "текстовый объект следующего совпадения": в нормальном режиме он работает как движение/объект, который выделяет следующее совпадение текущего паттерна (/). Ключевая выгода - связка оператора с gn отлично переживает точку-повтор:
Код: Выделить всё
Заменить все foo на bar (повторяемо, выборочно):
/foo<CR> ищем паттерн
cgn bar <Esc> меняем ПЕРВОЕ совпадение на bar
. . . каждая точка прыгает на следующее foo и меняет его
n для пропуска можно пропустить совпадение и продолжить точкой
o_v, o_V, o_CTRL-V - форсирование типа оператора без визуала
Иногда хочется применить оператор character/line/blockwise, но не так, как по умолчанию диктует движение. Для этого в нормальном режиме между оператором и движением можно вставить v, V или Ctrl-V - они форсируют тип операции, не входя в визуальный режим и не теряя точку-повтор:
- dvj - dj обычно строчный (удалит две строки целиком); v форсирует character-wise, и удаление пойдёт ровно от курсора до той же колонки строкой ниже.
- dVi( - наоборот, форсирует line-wise оператор там, где движение дало бы символьное выделение.
- d Ctrl-V j - форсирует blockwise.
Когда визуал объективно лучше
- Граница "на глаз". Вы видите, докуда выделить, но движение придумать сложно/долго. Выделить и нажать оператор - быстрее, чем подбирать f, счётчики и т. п.
- Блочное (столбцовое) редактирование. Ctrl-V + I/A/c/r/g Ctrl-A - у этого нет аналога в режиме оператор+движение. Это уникальная территория визуала.
- Постепенное уточнение. Выделили, посмотрели, расширили (o, движения), и только потом применили. Полезно при незнакомом тексте.
- Однократные операции над "куском между двумя точками поиска". v/end<CR>d иногда нагляднее, чем d/end<CR>.
- gq/=/> над произвольным блоком, который проще выделить, чем описать.
Лучшие практики 2026
- Думайте "глагол + объект", а не "выдели мышкой". Привычка v + движение для каждой мелкой правки - классический антипаттерн. Сначала спросите себя, нет ли готового текстового объекта (iw, i(, ip, it) или движения. Визуал - для случаев, где это реально удобнее, и для блочного режима. Об антипаттернах и привычках подробно в главе 32.
- g Ctrl-A вместо ручной нумерации и макросов. Там, где раньше писали макрос с Ctrl-A, теперь почти всегда достаточно блочного выделения и одного g Ctrl-A. Это надёжнее и не зависит от количества строк.
- :'<,'>normal как мост к макросам. Вместо рекурсивных макросов "до ошибки" (глава 16) часто чище выделить диапазон и сделать :'<,'>normal @a: диапазон задан декларативно, без угадывания.
- $A помните для строк разной длины. Это самая частая ловушка блочной вставки - без $ хвост попадает "под прямоугольник", а не в конец строки.
- Системный буфер из визуала - явным регистром. Чтобы скопировать выделение в системный буфер, используйте "+y в визуальном режиме (xnoremap <leader>y "+y). Не вешайте clipboard=unnamedplus вслепую: в Neovim 0.10+ при работе по SSH это глушит авто-OSC52. Подробно про регистры и буфер - в главе 8.
- p и P поверх выделения ведут себя по-разному с регистром. Визуальный p заменяет выделение содержимым регистра, но при этом кладёт удалённое выделение в безымянный регистр, перетирая то, что вы вставляли. А вот визуальный P (заглавная) делает ту же замену, но намеренно НЕ трогает регистр - он остаётся прежним (:help v_P). Поэтому, если нужно "вставлять одно и то же поверх разных кусков", достаточно использовать P вместо p - штатное поведение уже решает задачу. Маппинг xnoremap <leader>p "_dP (удалить в blackhole, затем вставить) - дополнительный приём для тех же целей, а не обязательная необходимость. Детали - глава 8.
- gv после :s. Если после замены в выделении нужно поработать с тем же куском дальше - gv вернёт его мгновенно.
- В Neovim - учтите структурное выделение по дереву синтаксиса. Помимо классического визуала, для кода есть структурная (incremental) альтернатива произвольному выделению - расширение по узлам синтаксического дерева. Её даёт плагин nvim-treesitter через incremental selection (init_selection/node_incremental/node_decremental): входите в выделение и шаг за шагом расширяете его до родительского узла. Это не встроенная фича ядра Neovim "из коробки", а функция плагина. Отдельно в протоколе LSP существует метод textDocument/selectionRange - это другой механизм (не treesitter-узлы), и встроенного визуального маппинга под этим названием ядро не поставляет: его нужно настраивать/привязывать явно. Подробнее - главы 25 и 27; здесь достаточно знать, что для кода есть структурная альтернатива.
- "Блочная вставка не работает". Вы напечатали текст в Ctrl-V+I, но он появился только на одной строке. Решение: нажмите Esc - правка размножится на все строки блока только после выхода из вставки.
- A ставит текст не в конец строки. При строках разной длины забыли $ перед A. Нужно Ctrl-V -> (выделить строки) -> $ -> A.
- Путаница визуального Ctrl-A и g Ctrl-A. Первый прибавляет одно и то же ко всем числам; второй создаёт возрастающий ряд. Для нумерации нужен g Ctrl-A.
- v вместо текстового объекта ломает .-повтор. viwd не повторяется точкой так, как daw. Для повторяемых правок берите оператор+объект (главы 6-7).
- p в визуале "съел" буфер обмена. Выделенное ушло в безымянный регистр, и повторно вставить тот же текст уже не выйдет. Три выхода: проще всего - использовать визуальный P (заглавная), он намеренно не трогает регистр; либо маппинг "_dP (удалить выделение в blackhole-регистр, затем вставить); либо явно вставлять из yank-регистра командой "0p (регистр "0 хранит последний yank, но сам по себе проблему затирания не решает - нужно из него вставлять явно).
- Ctrl-V не входит в блочный режим. В Windows-сборке/некоторых терминалах он перехвачен - используйте Ctrl-Q.
- : в визуале и сразу %s. Если хотели заменить по всему файлу - '<,'> ограничит выделением; если хотели только в выделении - наоборот, не стирайте префикс '<,'> руками.
- gv после правки, изменившей число строк. Если предыдущая команда добавила/удалила строки, метки '</'> могут указывать не туда - gv восстановит "координаты", а не "логический кусок".
- Префикс по столбцу. Дан список из пяти переменных x = 1 ... x = 5 (каждая на своей строке). Блочным режимом добавьте const в начало каждой строки одним заходом. Затем $A; - поставьте ; в конец каждой. Проверьте, что для строк разной длины (допишите одну подлиннее) точка с запятой реально в конце.
- Нумерация. Создайте десять строк - TODO (одинаковых). С помощью Ctrl-V и g Ctrl-A превратите их в - TODO с номерами так, чтобы получился ряд 1...10 (подсказка: добавьте колонку нулей и инкрементируйте её). Затем сделайте то же с шагом 2 через 2 g Ctrl-A.
- Замена в выделении. Возьмите функцию из 15 строк, выделите её построчно (V+движения) и через :'<,'>s/ переименуйте локальную переменную только внутри неё, не задев остальной файл. Сравните с тем, как опасно было бы сделать %s.
- Макрос по диапазону. Запишите простой макрос (например, оборачивающий слово в кавычки - глава 16), затем выделите блок строк и примените его ко всем через :'<,'>normal @a. Сравните трудозатраты с ручным повтором.
- o и gv. Выделите абзац символьным v, затем клавишей o подвиньте начальную границу на пару слов вправо, не трогая конец. Примените gu. После этого gv восстановите то же выделение и примените gU - убедитесь, что вернулись к тому же куску.
- Колонка -> разделитель. Дан CSV-подобный блок, где поля разделены пробелами и выровнены. Блочным Ctrl-V выделите колонку пробелов между двумя полями и через r, замените их на запятые во всех строках разом.
- Визуальный режим - "обратная" грамматика: сначала выделяем и видим область, потом применяем оператор. Три формы: v (символьный), V (строчный), Ctrl-V/Ctrl-Q (блочный/столбцовый).
- Над выделением работают почти все операторы (d, c, y, >, gU, gq, J...), плюс визуально-специфичные r (заменить каждый символ) и управление выделением o/O.
- Блочный режим - эксклюзив визуала: I/A вставляют по столбцу (правка видна после Esc), $A корректно работает со строками разной длины, c меняет прямоугольник, r заменяет символы блока.
- g Ctrl-A в визуале превращает колонку одинаковых чисел в возрастающий ряд - замена ручной нумерации и многих макросов.
- gv восстанавливает прошлое выделение; : открывает командную строку с диапазоном '<,'>, а :'<,'>normal @a - мощный мост к макросам.
- Для повторяемых правок по структуре предпочитайте оператор + текстовый объект + . (визуал ломает точку-повтор); для повторяемой замены по совпадениям поиска - cgn + .; форсировать тип оператора можно через dvj/dVi(/d Ctrl-V j без входа в визуал. Сам визуал берите для разовых правок с "увиденной" границей и для столбцовых операций.
- Поведение края выделения задаёт опция selection (inclusive/exclusive) - частая причина "съеденного" или "лишнего" символа; для прямоугольника за концом коротких строк включайте virtualedit=block.