Объединяет их одно: всё это работает "из коробки", без единого плагина. На голом Vim на чужом сервере, в Docker-контейнере, в режиме восстановления после сбоя - эти инструменты всегда с вами. Полноценный LSP-автокомплит и современные сниппет-движки мы разберём позже (см. главы 25 и 26), а здесь освоим тот фундамент, на котором они стоят и который незаменим, когда "тяжёлой артиллерии" под рукой нет.
Часть 1. Свёртки (folding)
Зачем это нужно
Большой файл редко интересен целиком. Когда вы правите один метод в классе на 800 строк, остальные 750 строк - визуальный шум. Свёртки позволяют схлопнуть блок в одну строку-заголовок, оставив на экране только структуру: список функций, секции конфига, заголовки Markdown. Это и навигация, и "карта" файла одновременно.
Главная концепция: foldmethod определяет, ОТКУДА берутся свёртки
Ключевое решение при работе со свёртками - выбор foldmethod (можно сокращённо fdm). Эта опция отвечает на вопрос "по какому признаку Vim решает, где начинается и кончается свёртка". От неё зависит всё остальное поведение.
Код: Выделить всё
Значение foldmethod | Откуда берутся свёртки | Когда использовать
---------------------+-----------------------------------------------------------------+------------------------------------------------
manual | Вы создаёте свёртки вручную через zf | Разовые задачи, временное скрытие кусков
indent | По уровню отступа: глубже отступ - глубже свёртка | Python, YAML, любой код с осмысленным отступом
syntax | По правилам подсветки синтаксиса | Языки с хорошим syntax-файлом (C, Vimscript)
expr | По вашему выражению foldexpr (вычисляется для каждой строки) | Гибкая логика; основа Treesitter-фолдинга
marker | По текстовым маркерам в самом тексте (по умолчанию {{{ и }}}) | Конфиги, заметки, ручная разметка секций
diff | Автоматически в режиме vimdiff | Включается само при сравнении файлов
По умолчанию foldmethod=manual и foldenable включён, но без созданных свёрток ничего не происходит. Поэтому новички часто вообще не подозревают, что фолдинг существует.
Команды управления свёртками
Все команды свёрток начинаются с z - буква визуально похожа на сложенный лист бумаги. Это удобная мнемоника.
Код: Выделить всё
Клавиша | Действие
------------+-------------------------------------------------------------------------------------------------------
zf{motion} | Создать свёртку (только при foldmethod=manual/marker); работает как оператор
zo | Открыть свёртку под курсором (open)
zO | Открыть свёртку под курсором и все вложенные
zc | Закрыть свёртку под курсором (close)
zC | Закрыть свёртку и все вложенные
za | Переключить (toggle) свёртку: открыть закрытую, закрыть открытую
zA | То же рекурсивно
zR | Открыть ВСЕ свёртки в буфере (Reduce folding - меньше свёрнутого, foldlevel поднимается до максимума)
zM | Закрыть ВСЕ свёртки (Maximum folding)
zr | Открыть на один уровень глубже (поднять foldlevel на 1)
zm | Закрыть на один уровень (опустить foldlevel на 1)
zj | Прыгнуть к началу СЛЕДУЮЩЕЙ свёртки
zk | Прыгнуть к концу ПРЕДЫДУЩЕЙ свёртки
zd | Удалить свёртку под курсором (manual)
zE | Удалить все свёртки в окне (Eliminate; только при foldmethod=manual/marker)
zv | Открыть ровно столько свёрток, чтобы стала видна строка с курсором
Разница между zc/zo (одна свёртка) и zm/zr (один уровень для всего буфера через foldlevel) тонкая, но важная. foldlevel=0 значит "закрыть всё, что на уровне 0 и глубже", то есть весь файл свёрнут до верхнего уровня. foldlevel=99 - "ничего не закрывать", всё открыто.
Полезные опции
Код: Выделить всё
Опция | Что делает
--------------------+-------------------------------------------------------------------------
foldcolumn | Ширина левой колонки с индикаторами свёрток (например set foldcolumn=1)
foldlevel | Уровень, до которого свёртки открыты при входе в буфер
foldlevelstart | С каким foldlevel открывать новые буферы (-1 = всё открыто)
foldnestmax | Максимальная вложенность свёрток (для indent/syntax)
foldtext | Функция/выражение, формирующее текст строки-заголовка свёртки
foldenable (nofen) | Глобальный выключатель: zi переключает его
Код: Выделить всё
set foldlevelstart=99
Ручная свёртка функции. Курсор на первой строке функции из 10 строк (foldmethod=manual):
Код: Выделить всё
было:
function calc(a, b) { <- курсор здесь
...8 строк...
}
function next() { ... }
нажимаем: zf} (zf + motion "до конца абзаца")
стало:
+-- 10 lines: function calc(a, b) {-----
function next() { ... }
Код: Выделить всё
:setlocal foldmethod=indent
Маркерная свёртка в конфиге. В ~/.bashrc размечаем секции:
Код: Выделить всё
# Aliases {{{
alias ll='ls -lah'
alias gs='git status'
# }}}
# Functions {{{
mkcd() { mkdir -p "$1" && cd "$1"; }
# }}}
Сохранение manual-свёрток между сессиями: :mkview/:loadview
Главная боль foldmethod=manual - свёртки живут только в памяти и пропадают, как только вы закрыли окно или сменили метод. Решение - команды :mkview и :loadview: первая сохраняет "вид" окна (свёртки, позицию курсора, локальные опции) в файл в viewdir (по умолчанию ~/.vim/view или ~/.local/state/nvim/view), вторая - восстанавливает.
Что именно сохраняется, регулирует опция 'viewoptions'. Чтобы хранить только свёртки и курсор, но не тащить с собой локальные опции и рабочий каталог (частый источник сюрпризов), сузьте её:
Код: Выделить всё
set viewoptions=folds,cursor
Код: Выделить всё
augroup remember_folds
autocmd!
autocmd BufWinLeave *.* mkview
autocmd BufWinEnter *.* silent! loadview
augroup END
Современный фолдинг: Treesitter и nvim-ufo (Neovim, 2026)
foldmethod=syntax исторически был лучшим вариантом для кода, но он медленный на больших файлах и зависит от качества syntax-файла языка. В Neovim 2026 канонический подход - фолдинг на основе Treesitter через foldmethod=expr:
Код: Выделить всё
vim.wo.foldmethod = 'expr'
vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()'
vim.o.foldlevelstart = 99
Поверх этого многие ставят плагин nvim-ufo (kevinhwang91/nvim-ufo). Он решает две болевые точки встроенного фолдинга:
- "мигающие" свёртки: ufo подтягивает информацию о свёртках лениво (через LSP foldingRange или Treesitter), не пересчитывая всё при каждой правке;
- красивый foldtext: вместо унылого +-- 10 lines показывает первую строку блока с подсветкой и счётчиком скрытых строк.
Часть 2. Встроенное автодополнение (insert-mode completion)
Зачем это нужно
Vim умеет дополнять слова в режиме вставки сам, без LSP и плагинов. Это не "умное" дополнение с пониманием типов, но оно мгновенно, всегда доступно и покрывает 80% бытовых случаев: дописать длинное имя переменной, путь к файлу, слово из словаря. На чужом сервере без интернета и плагинов это единственный доступный автокомплит.
Главная концепция: два базовых триггера и "источники"
Базовое дополнение в режиме вставки запускается двумя клавишами:
Код: Выделить всё
Клавиша (в режиме вставки) | Действие
----------------------------+------------------------------------------------------------------------
Ctrl-N | Следующий (Next) кандидат: ищет слова в буферах и заполняет popup-меню
Ctrl-P | Предыдущий (Previous) кандидат: то же, но листает список вверх
Специализированные виды дополнения: семейство Ctrl-X
Кроме общего Ctrl-N, есть "прицельные" режимы, которые запускаются префиксом Ctrl-X (в режиме вставки). Это мощная и недооценённая часть Vim.
Код: Выделить всё
Комбинация | Что дополняет
---------------+--------------------------------------------------------------------------------
Ctrl-X Ctrl-N | Слова только из текущего файла
Ctrl-X Ctrl-F | Имена файлов и путей (по содержимому ФС)
Ctrl-X Ctrl-L | Целые строки (Line) - дополняет по совпадающим строкам
Ctrl-X Ctrl-K | Слова из словаря (dictionary)
Ctrl-X Ctrl-T | Синонимы из тезауруса (thesaurus)
Ctrl-X Ctrl-I | Слова из включённых (include) файлов
Ctrl-X Ctrl-] | Дополнение по тегам (ctags)
Ctrl-X Ctrl-O | "Омни"-дополнение (omnifunc) - самое умное, его задают плагины/синтаксис-файлы
Ctrl-X Ctrl-V | Дополнение команд Vim (в командной строке Ex)
Ctrl-X Ctrl-S | Орфографические подсказки (по словам со spell)
Чтобы Ctrl-X Ctrl-K (словарь) реально что-то дополнял, опция 'dictionary' должна указывать на файл со словами - по одному на строку. На большинстве Linux это уже лежащий в системе словарь:
Код: Выделить всё
set dictionary+=/usr/share/dict/words
Код: Выделить всё
setlocal dictionary+=~/.config/nvim/dict/api-terms.txt
Опция completeopt: как ведёт себя меню
Поведение popup-меню настраивается опцией completeopt. Это влияет на "ощущение" автокомплита сильнее всего.
Код: Выделить всё
Флаг completeopt | Эффект
------------------+----------------------------------------------------------------------------------------
menu | Показывать popup-меню (по умолчанию)
menuone | Показывать меню даже при единственном кандидате
noinsert | Не вставлять текст автоматически, пока вы не выберете явно
noselect | Не выделять кандидата автоматически - ничего не выбрано, пока не нажмёте
preview | Показывать доп. информацию о кандидате в preview-окне
popup | Показывать инфо во всплывающем окне вместо preview-окна (есть и в Vim 9.1, и в Neovim)
fuzzy | Нечёткий (fuzzy) поиск кандидатов вместо префиксного (есть и в Vim 9.1, и в Neovim)
nosort | Не сортировать кандидатов (полезно вместе с fuzzy; доступен в Vim 9.1 и Neovim)
Код: Выделить всё
set completeopt=menuone,noinsert,noselect
Нативный автокомплит Neovim 0.12 (факт 2026)
В Neovim 0.12 (вышел 29 марта 2026) появилась экспериментальная опция 'autocomplete' - встроенное автодополнение в режиме вставки без сторонних UI вроде nvim-cmp/blink.cmp: меню всплывает само по мере набора. Это "тише" и проще, чем полноценный движок, и помечено экспериментальным - закладываться на него в продакшен-конфиге пока рано. Кроме того, начиная с 0.11, есть vim.lsp.completion.enable() - базовый LSP-автокомплит через omnifunc без плагинов. Полноценное сравнение движков (blink.cmp против nvim-cmp) - в главе 26.
Практика: было -> нажимаем -> стало
Дополнение длинного имени. В буфере уже встречается userAuthenticationToken:
Код: Выделить всё
было (режим вставки): const token = userA|
нажимаем: Ctrl-N
стало: const token = userAuthenticationToken|
Код: Выделить всё
было: source ~/.config/nvim/lua/conf|
нажимаем: Ctrl-X Ctrl-F
стало: source ~/.config/nvim/lua/config/ (и меню с файлами каталога)
Код: Выделить всё
было: logger.info(|
нажимаем: Ctrl-X Ctrl-L
стало: logger.info("request received", { id }) (подставлена совпавшая строка)
Зачем это нужно
Аббревиатуры - встроенный механизм автозамены: вы набираете короткую последовательность, и Vim заменяет её на длинную при вводе разделителя (пробел, точка, Enter и т.п.). Два главных применения:
- Автоисправление опечаток: вечно печатаете teh вместо the или recieve вместо receive - пусть Vim чинит это сам.
- Мини-сниппеты: sig -> ваша подпись, lorem -> абзац рыбного текста, pr -> print().
Главная концепция: три области действия
Код: Выделить всё
Команда | Где работает
-------------------+--------------------------------------------------------------------
:abbreviate (:ab) | Везде: и в режиме вставки, и в командной строке :
:iabbrev (:iab) | Только в режиме вставки (insert) - это то, что нужно в 95% случаев
:cabbrev (:ca) | Только в командной строке (для алиасов команд)
Есть non-recursive варианты - :noreabbrev/:inoreabbrev/:cnoreabbrev (правая часть, rhs, не подвергается дальнейшему ремаппингу аббревиатур и мэппингов). Это не про "точное совпадение слова", а про отсутствие рекурсии в подстановке. А вот тип срабатывания (full-id / end-id / non-id) зависит от того, состоит ли сам триггер из keyword-символов (по 'iskeyword') - именно поэтому неслово-триггеры вроде @@ удобны и предсказуемы. Отдельно есть флаг <buffer> (аббревиатура только для текущего буфера) - он идеален для языко-специфичных сниппетов через ftplugin.
Как именно срабатывает аббревиатура (важно для ловушек)
Аббревиатура разворачивается, когда вы набираете символ-разделитель после ключевого слова: пробел, ., ,, (, Enter и т.д. Сам разделитель при этом вставляется. Если нужно вставить слово БЕЗ разворачивания, нажмите Ctrl-V перед разделителем - это подавит срабатывание. Также Ctrl-] в режиме вставки принудительно разворачивает аббревиатуру без ввода разделителя.
Практика: исправления и сниппеты
Автоисправления опечаток (в init.lua/.vimrc):
Код: Выделить всё
iabbrev teh the
iabbrev recieve receive
iabbrev fro for
iabbrev adn and
iabbrev functino function
Код: Выделить всё
было (вставка): for teh|
нажимаем: <Space>
стало: for the |
Код: Выделить всё
iabbrev @@ dev2.khovanskiy@gmail.com
iabbrev ssig -- \nИван Хованский\nCyberlake
iabbrev cl console.log()
Код: Выделить всё
было: contact: @@|
нажимаем: <Space>
стало: contact: dev2.khovanskiy@gmail.com |
Код: Выделить всё
iabbrev <buffer> ifmain if __name__ == "__main__":
- Всегда :iabbrev, а не :abbreviate для текстовых замен - чтобы не ломать командную строку.
- Триггер должен быть "несловом": используйте сочетания, которые вы никогда не наберёте как настоящее слово - @@, ;sig, pr;. Иначе аббревиатура сработает там, где не нужно.
- Языко-специфичное - через <buffer> в ftplugin, чтобы cl (console.log) не разворачивалось в Markdown.
- Не путайте аббревиатуры со сниппет-движками. Для сложных сниппетов с табстопами, плейсхолдерами и динамикой нужен LuaSnip / нативный vim.snippet + friendly-snippets (глава 26). Аббревиатуры - для простых одношаговых замен.
- Триггер - обычное слово. iabbrev no number означает, что вы больше никогда не напишете слово "no" - оно всегда станет "number". Берите неслова.
- Ожидание срабатывания без разделителя. Аббревиатура не развернётся, пока вы не введёте пробел/знак препинания/Enter. Если нужно немедленно - Ctrl-].
- Использование :abbreviate и удивление, почему :command ведёт себя странно. Это та самая ловушка области действия.
- Лишний пробел/символ в значении. iabbrev cl console.log( с хвостовым пробелом вставит лишний пробел - следите за концом строки.
Зачем это нужно
Встроенная проверка орфографии Vim подсвечивает слова с ошибками и предлагает замены - без плагинов, в комментариях кода, в Markdown, в коммит-сообщениях. Работает на десятках языков.
Включение и навигация
Код: Выделить всё
set spell
set spelllang=en,ru " несколько языков сразу
Код: Выделить всё
Клавиша/команда | Действие
-----------------+---------------------------------------------------------------------
]s | Прыгнуть к СЛЕДУЮЩЕМУ слову с ошибкой
[s | Прыгнуть к ПРЕДЫДУЩЕМУ слову с ошибкой
]S / [S | То же, но только "плохие" слова (без редких/региональных)
z= | Показать список вариантов замены для слова под курсором
zg | Добавить слово в личный словарь (good - считать правильным)
zw | Пометить слово как ошибочное (wrong)
zug / zuw | Отменить (undo) добавление слова в словарь
1z= | Сразу заменить на ПЕРВЫЙ вариант без показа меню (быстрый автофикс)
Практика
Код: Выделить всё
было: This sentance has a typo. (sentance подчёркнуто)
нажимаем: ]s (прыгаем на слово)
нажимаем: z= (видим список: 1 sentence, 2 ...)
вводим: 1<Enter>
стало: This sentence has a typo.
Хорошая привычка
Включать spell локально через автокоманду только для текстовых файлов, чтобы он не мешал в коде:
Код: Выделить всё
vim.api.nvim_create_autocmd('FileType', {
pattern = { 'markdown', 'gitcommit', 'text' },
callback = function() vim.opt_local.spell = true end,
})
Лучшие практики 2026 (сводно)
- Фолдинг на Treesitter, а не на syntax. В Neovim используйте foldexpr='v:lua.vim.treesitter.foldexpr()' и foldlevelstart=99, чтобы файлы открывались развёрнутыми, но структура была доступна по zM/za. На чистом Vim 9.1 - indent или marker.
- nvim-ufo - приятная, но не обязательная опция. Берите его за красивый foldtext и отсутствие "мигания" свёрток; базовый Treesitter-фолдинг и так хорош.
- Встроенный автокомплит - ваш аварийный комплект. Ctrl-N, Ctrl-X Ctrl-F, Ctrl-X Ctrl-L спасают на серверах без плагинов. Настройте completeopt=menuone,noinsert,noselect (флаг fuzzy доступен и в Vim 9.1, и в Neovim).
- Нативный 'autocomplete' Neovim 0.12 - экспериментальный. Полезно знать, что он есть, но в стабильный конфиг лучше брать blink.cmp (глава 26).
- :iabbrev для опечаток и микро-сниппетов, неслова в качестве триггеров. Сложные сниппеты - отдельным движком, не аббревиатурами.
- spell включайте автокомандой по типу файла, а не глобально, чтобы не подчёркивало половину кода.
- Меняют foldmethod на manual, создают свёртки, потом переключают метод - и свёртки пропадают (manual-свёртки не сохраняются при смене метода). Для постоянных свёрток используйте marker или :mkview/:loadview (с viewoptions=folds,cursor и автокомандами BufWinLeave/BufWinEnter - см. раздел выше).
- Жалуются, что "фолдинг не работает", хотя foldmethod=manual и ни одной свёртки не создано. Выберите осмысленный метод (indent/expr).
- Ждут "умного" дополнения от Ctrl-N - но это всего лишь поиск слов по буферам, не LSP. Для умного нужен omni (Ctrl-X Ctrl-O) или LSP (глава 25).
- Заводят аббревиатуру на обычное слово и потом не могут его напечатать.
- Используют :abbreviate вместо :iabbrev и ломают ввод команд в :.
- Включают spell глобально и тонут в подчёркиваниях внутри кода.
- Фолдинг по отступам. Откройте любой Python- или YAML-файл, выполните :setlocal foldmethod=indent, нажмите zM, затем zR. Походите по свёрткам через zj/zk и раскройте одну через za.
- Маркеры. В своём ~/.vimrc/init.vim разметьте две-три секции маркерами {{{ }}}, поставьте :setlocal foldmethod=marker и убедитесь, что секции схлопываются.
- Treesitter-фолдинг (Neovim). Включите foldmethod=expr с vim.treesitter.foldexpr() для одного буфера и сравните границы свёрток с вариантом indent на том же файле.
- Автокомплит путей и строк. В режиме вставки начните набирать путь к существующему файлу и допишите его через Ctrl-X Ctrl-F. Затем повторите длинную строку из буфера через Ctrl-X Ctrl-L.
- Свой набор автоисправлений. Добавьте 5-7 iabbrev для слов, в которых вы регулярно делаете опечатки, и одну сниппет-аббревиатуру с неслово-триггером (например ;date).
- Орфография. Включите :set spell spelllang=en, найдите ошибки через ]s, исправьте через z=/1z=, добавьте один технический термин в словарь через zg.
- Свёртки управляются опцией foldmethod (manual/indent/syntax/expr/marker) и командами на z: za (toggle), zo/zc (одна), zR/zM (раскрыть всё / схлопнуть всё через foldlevel), zj/zk (навигация), zf (создать). В Neovim 2026 - фолдинг на Treesitter (foldexpr), опционально nvim-ufo.
- Встроенное автодополнение - Ctrl-N/Ctrl-P (слова из буферов) плюс прицельное семейство Ctrl-X Ctrl-* (пути, строки, омни, теги). Поведение меню настраивается completeopt. Это аварийный комплект без плагинов.
- Аббревиатуры :iabbrev - встроенные автозамены для опечаток и мини-сниппетов; ключевое правило - неслово-триггеры и именно :iabbrev, а не :abbreviate.
- Орфография :set spell с навигацией ]s/[s, заменами z=/1z= и словарём zg.