Neovim с нуля: init.lua и базовая конфигурация на lua шаг за шагом

Neovim с нуля: фундамент — `init.lua` и базовые настройки

Когда я только начинал осваивать Neovim как Python‑разработчик, быстро упёрся в неприятный факт: понятных русскоязычных разборов как собрать свой конфиг с чистого листа практически нет. Есть готовые «дистрибутивы» (NvChad, LazyVim, AstroNvim), есть переводы отдельных статей, но нет последовательного объяснения, почему конфиг устроен именно так, а не просто «скопируй эти 500 строк».

Свой рабочий конфиг я собирал фрагментами: по блогам, роликам, чужим репозиториям, документации. В этом цикле статей мы пойдём в обратную сторону: спокойно и осознанно построим конфигурацию Neovim на Lua, шаг за шагом.

Для кого этот цикл

Материал будет полезен, если вы:

- Уже знакомы с базовыми концепциями Vim/Neovim: режимы, `hjkl`, базовые команды.
- Пользовались готовыми сборками и хотите перейти на собственный конфиг, который понимаете.
- Устали слепо копировать фрагменты настроек и плагины.
- Ищете минималистичный, но расширяемый фундамент под разработку.

Важно: это не учебник Vim. Мы не будем разбирать, что такое normal mode или как сохранять файл. Предполагается, что Neovim у вас уже установлен и вы умеете выполнять базовые команды.

Фокус этого цикла — современная конфигурация Neovim на Lua.

Что вы получите к концу цикла

После прохождения всех частей у вас будет:

- Чистый, логичный конфиг на Lua, где вы понимаете каждую строку.
- Подключённый менеджер плагинов `lazy.nvim`.
- Современное автодополнение через `blink.cmp`.
- Подсветка синтаксиса и парсинг кода через Treesitter.
- Настроенный встроенный LSP‑клиент.
- Форматтеры и линтеры для ваших языков.

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

Технические детали и требования

Конкретные примеры в серии будут показываться:

- на Linux (Arch‑подобная система, но это не принципиально),
- на Neovim версии 0.11.5 (минимально — 0.10).

Вам понадобится:

- установленный Neovim 0.10+;
- Git (для менеджера плагинов);
- базовое понимание Lua (уровень: что такое функции, таблицы и модули).

Если вы Lua никогда не видели, этого вполне достаточно: большая часть кода будет очень однообразной и легко читаемой.

Начинаем с чистого листа: убираем старый конфиг

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

1. Найти текущий каталог настроек (чаще всего `~/.config/nvim`).
2. Сделать бэкап:
```bash
mv ~/.config/nvim ~/.config/nvim_backup
```
3. Запустить Neovim — он стартует в состоянии «почти по умолчанию».

Теперь вы уверены, что никакие старые автокоманды, плагины и непонятные маппинги не влияют на поведение.

Два подхода к конфигу: монолит против модулей

Типичный путь новичка:

- один огромный `init.lua` (или `init.vim`) на сотни/тысячи строк,
- всё — в одном файле: опции, клавиши, плагины, автокоманды.

Этот вариант рабочий, но быстро превращается в хаос: править больно, расширять страшно.

Более современный и удобный подход — модульная структура:

- каждая логическая часть настроек живёт в отдельном файле;
- файлы группируются по директориям;
- `init.lua` остаётся маленьким «оркестратором», который просто подключает нужные модули.

Мы пойдём именно этим путём.

Базовая структура конфигурации

Создадим каркас в каталоге настроек Neovim. Для Unix‑подобных систем это обычно:

```bash
mkdir -p ~/.config/nvim/lua/core
```

Стартовая структура будет такой:

- `~/.config/nvim/init.lua` — точка входа.
- `~/.config/nvim/lua/` — директория, из которой Neovim может импортировать Lua‑модули.
- `~/.config/nvim/lua/core/` — каталог с «ядром» настроек: опции, горячие клавиши, базовые вещи.

Внутри `core` создадим первый модуль:

```bash
touch ~/.config/nvim/lua/core/options.lua
```

Пока можно оставить его пустым.

Как Neovim находит Lua‑модули

Neovim автоматически добавляет каталог `lua/` вашего конфига в `package.path`. Это означает, что в Lua‑коде вы можете писать:

```lua
require("core.options")
```

и Neovim найдёт файл:

```text
~/.config/nvim/lua/core/options.lua
```

Несколько правил:

- расширение `.lua` в `require()` не указывается;
- слэши в путях заменяются точками;
- первый вызов `require` загружает модуль, последующие — используют кеш.

Заполняем `init.lua`: подключаем модули

Откроем `~/.config/nvim/init.lua` и превратим его в минимальную точку входа:

```lua
require("core.options")
```

Позже мы добавим сюда и другие модули (горячие клавиши, плагины и т.д.), но на старте нам важно лишь то, чтобы:

- `init.lua` был максимально коротким и понятным;
- внутри него не было никакой «магии» — только импорт модулей.

`options.lua`: задаём поведение редактора

Теперь откроем `~/.config/nvim/lua/core/options.lua` и начнём описывать базовое поведение Neovim.

В современном Neovim предпочтительно использовать API `vim.opt` — это удобный и типобезопасный способ выставлять опции (аналог команды `set` из Vimscript).

В начале файла удобно написать:

```lua
local opt = vim.opt
```

Теперь вместо длинного `vim.opt.number = true` мы будем использовать состояние `opt.number = true`.

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

Отступы и табуляция

Отступы — одно из самых важных и спорных мест в конфиге. Базовый набор опций:

- `tabstop` — сколько пробелов воспринимать как один таб;
- `shiftwidth` — насколько смещать строку при автоотступах и командах сдвига;
- `softtabstop` — как ведёт себя клавиша `` и `` в местах отступов;
- `expandtab` — сохранять ли табы как пробелы.

Пример логики (на словах):

- выставляем ширину таба на 2 или 4 пробела (для Lua часто используют 2, для Python — 4);
- включаем `expandtab`, чтобы табы сохранялись как пробелы;
- синхронизируем `shiftwidth` и `softtabstop` с `tabstop`, чтобы поведение было предсказуемым.

Позже Treesitter и другие плагины смогут переопределять эти значения в зависимости от типа файла (например, для Makefile использовать реальные табы).

Отображение: нумерация строк и визуальные удобства

Минимальный набор для комфортного чтения кода:

- `number = true` — показывает абсолютный номер текущей строки;
- `relativenumber = true` — для остальных строк показывает номер относительно курсора;
- опции для переноса строк, отображения правого края, скрытия/показа спецсимволов.

Сочетание `number` + `relativenumber` даёт сильное ускорение навигации:

- вы видите, что нужная строка находится на `10` строк выше;
- просто жмёте `10k` вместо того, чтобы считать строки глазами.

Текущая строка при этом отображается с реальным номером в файле, остальные — как смещения.

Поиск: регистр и поведение

Комфортный поиск чаще всего настраивают так, чтобы он был:

- регистр‑независимым по умолчанию;
- но при этом «уважал» явно введённые заглавные буквы.

Для этого комбинируют:

- `ignorecase = true` — игнорировать регистр;
- `smartcase = true` — если в запросе есть заглавные буквы, искать с учётом регистра.

Пример поведения:

- запрос `/hello` найдёт `hello`, `Hello`, `HELLO`;
- запрос `/Hello` найдёт только `Hello`, но не `hello` и не `HELLO`.

Такой подход позволяет не думать о регистре, пока это не принципиально, и сохраняет точность, когда важно.

Интерфейс: цвета, мышь и комфорт

Есть несколько ключевых опций, без которых современные конфиги выглядят бледно:

- `termguicolors = true` — включает поддержку 24‑битного цвета;
- `mouse = "a"` — включает поддержку мыши во всех режимах.

`termguicolors` необходимо, чтобы полноценно работали современные цветовые схемы и плагины с подсветкой. При этом важно, чтобы ваш терминал тоже поддерживал truecolor.

Опция `mouse = "a"` позволяет:

- скроллить колесом;
- кликать по тексту;
- выделять блоки мышью.

Если вы фанат «чистого» Vim‑стиля без мыши — это можно отключить, но для многих разработчиков плавный переход удобнее с подключенной мышью.

Файлы, буферы, история

Ещё один пласт настроек — управление файлами и историей изменений:

- `undofile = true` — включение постоянного undo;
- возможно, настройка каталога для хранения undo‑файлов;
- управление swap‑файлами и backup.

Ключевой момент здесь — `undofile = true`: вы можете закрыть файл, через неделю вернуться к нему, и история отмен (undo) сохранится. Это заметно снижает страх «сломать что‑то безвозвратно».

Дополнительные удобства

В `options.lua` часто попадают и другие мелочи:

- поведение поиска при вводе (`incsearch`, `hlsearch` аналогами через `vim.opt`);
- уровень сообщений и логирования;
- ограничения по ширине текста;
- настройки для разделения окон и сплитов.

Важно держать файл структурированным: логические блоки разделять комментариями, сгруппировать родственные опции. Тогда через несколько месяцев вы без труда вспомните, за что отвечает каждая секция.

Проблема работы с несколькими файлами: буферы и окна

Одна из типичных трудностей начинающих — понимание, как в Neovim устроена работа с несколькими файлами:

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

Стандартные команды (`:bnext`, `:bprev`, `:split`, `:vsplit`) мощные, но плохо запоминаются. Поэтому в следующем шаге мы перейдём к кастомным горячим клавишам, чтобы:

- быстро переключаться между буферами;
- гибко управлять окнами;
- сократить количество команд, которые нужно держать в голове.

Для этого создадим отдельный модуль.

`core/keymaps.lua`: ускоряем повседневную работу

Логичный следующий файл в нашем ядре — `~/.config/nvim/lua/core/keymaps.lua`. В нём будут:

- базовая функция‑обёртка над `vim.keymap.set` для удобства;
- настройка «главной» клавиши — `leader`;
- минимальный набор полезных маппингов.

Подключение в `init.lua` будет выглядеть так:

```lua
require("core.options")
require("core.keymaps")
```

Функция для описания горячих клавиш

Чтобы не дублировать в каждом маппинге опции вроде `noremap = true` и `silent = true`, удобно завести небольшую вспомогательную функцию:

- принимаем на вход режим (`"n"`, `"i"`, `"v"` и т.д.), сочетание клавиш и команду;
- под капотом вызываем `vim.keymap.set` с набором общих параметров;
- добавляем возможность указывать описание (description), которое пригодится позже для подсказок.

Такой слой абстракции не обязателен, но делает файл с клавишами гораздо чище.

Leader key: ваша «главная» клавиша

Во многих конфигурациях `leader` — это точка входа в ваш личный «пространство комбинаций». Часто её ставят на:

- пробел (`" "`), или
- запятую, или
- обратный слэш.

В Neovim это настраивается через:

```lua
vim.g.mapleader = " "
```

После этого вы можете создавать собственные команды в стиле:

- `f` — найти файл;
- `e` — открыть файловый менеджер;
- `q` — аккуратно закрыть окно.

`leader` превращает набор случайных комбинаций в хорошо организованную «клавиатурную палитру», которую легче запомнить.

Базовые улучшения и навигация

В `keymaps.lua` логично добавить:

- удобные команды для сохранения (`w`) и выхода (`q`);
- переназначения для перемещения по визуально перенесённым строкам (`gj`, `gk` по умолчанию);
- быстрый чистый поиск (`h` для отключения подсветки поиска).

Для работы с несколькими файлами:

- маппинги на `:bnext` / `:bprev` для быстрого пролистывания буферов;
- сокращения для создания и закрытия буферов.

Для окон:

- комбинации для перемещения между сплитами (например, ``, ``, ``, ``);
- быстрые команды разделения окна по горизонтали / вертикали.

Так вы перестанете каждый раз думать, как именно формулируется нужная команда, и начнёте просто «летать» по проекту.

Почему модульная структура выигрывает в долгую

На старте может показаться, что разносить всё по файлам — лишняя морока, но в перспективе это даёт несколько важных преимуществ:

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

2. Управляемость
Когда что‑то ведёт себя странно, вы легко находите правильный модуль и быстро сужаете область поиска.

3. Переиспользование
Отдельные модули проще копировать между машинами и проектами. Например, вы можете иметь общие `core/options.lua` и `core/keymaps.lua` для разных рабочих окружений.

4. Расширяемость
Добавление новой функциональности выглядит как создание очередного файла и одной строки `require()` в `init.lua`, а не как попытка воткнуть ещё 200 строк в уже переполненный монолит.

О чём мы уже позаботились

К этому моменту у нас уже есть:

- чистый конфиг без наследия прошлых экспериментов;
- минимальная структура каталогов `lua/` и `core/`;
- базовый `init.lua`, который подключает модули;
- файл `options.lua` с фундаментальными настройками редактора;
- план по заведению `keymaps.lua` для ускорения работы.

Функционально ваш Neovim уже станет ощутимо удобнее стандартных настроек, даже без единого плагина.

Что будет дальше

Дальнейшие шаги логично построить так:

1. Завершить работу с `keymaps.lua`
Продумать и описать горячие клавиши для всех частых операций, чтобы не возвращаться к этому каждый день.

2. Подключить менеджер плагинов
Мы выберем `lazy.nvim` и аккуратно интегрируем его в текущую модульную структуру.

3. Добавить Treesitter и подсветку синтаксиса
Настроим базовый набор языков, посмотрим, как это влияет на отступы и форматирование.

4. Настроить LSP, форматтеры и линтеры
Чтобы Neovim превратился в полноценную среду разработки, а не просто текстовый редактор.

5. Организовать структуру конфигов плагинов
Вынесем настройки плагинов в отдельные модули, сохранив понятность и модульность ядра.

---

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

2
6
Прокрутить вверх