Pull to refresh

Пишем конфигурацию для Neovim

Reading time13 min
Views38K

Привет, сегодня будет писать конфигурацию для терминального редактора Neovim на чистом Lua. Мы не будем использовать VimScript от слова совсем. Я расскажу в чем плюсы создания таких конфигураций, как соблюдать KISS (Keep It Stupid Simple) все время дополняя такие конфигурации, а также расскажу про полезные плагины для веб-разработки и не только.

В чем плюсы?

Конфигурации на VimScript не самые понятные для новых пользователей Vim. Они часто перегружены лишней информацией, команды в них используются совсем непростые, а для того чтобы минимально настроить тот же пробел вместо таба приходится бороздить документацию сверху до низу, из-за того что у вас будут ошибки в синтаксисе🐛 (а они непременно будут🤐).

Данную проблему решали по-разному. Сейчас например вообще вышел новый язык для конфигурации Vim, который называется Vim9script. Но, он тоже не решит проблему😕

Проблему решил Neovim. Это тот же Vim, который переписывается командой энтузиастов и сообществом для того чтобы сделать Vim доступнее для людей. Именно в Neovim впервые речь зашла о том, чтобы использовать не VimL (VimScript), а Lua. И ребята это сделали, у редактора есть полноценная поддержка Lua.

Установка

Установить Neovim можно на все три платформы (Windows, Linux, MacOS). Делается это все достаточно просто.

Windows 🪟

Заходим в PowerShell и качаем Chocolatey:

Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

Качаем сам Neovim:

choco install neovim --pre

Linux 🐧

Заходим в терминал и в зависимости от вашего дистрибутива качаем пакет с Neovim

# Debian, Ubuntu, Elementary, Mint
sudo apt install neovim python3-neovim

# Fedora, RH
sudo dnf install neovim python-neovim

# Arch
sudo pacman -Sy neovim python-pynvim

MacOS 🍏

Качаем homebrew на наш мак:

/bin/bash -c \
"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Качаем сам Neovim с необходимыми пакетами

xcode-select --install
brew install --HEAD tree-sitter
brew install --HEAD luajit
brew install --HEAD neovim

Конфигурация

Мы будем конфигурировать редактор постепенно, вы смело можете пропускать разделы, если вы уже сталкивались с написанием конфигураций для Neovim/Vim. Новичкам же рекомендую читать все последовательно для лучшего понимания материала🤗

Структура директорий

Для начала нам нужно понять что такое корневой конфигурационный файл (init.lua).

init.lua - это файл, который Neovim будет загружать впервую очередь по умолчанию. Именно с его создания стоит начинать конфигурацию редактора.

За мой опыт в 3 года использования данного редактора я видел много конфигураций. Есть два лагеря:

  • Те, кто пишут в init.lua только импортирование других файлов;

  • Те, кто пишут в init.lua базовые настройки и импортирование других файлов.

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

Однако мы будем поступать первым способом. Он гарантирует нам то, что со временем наша конфигурация не станет похожа на сад с сорняками, где исправив одно хочется обрубить половину конфигурации🔪

Структура будет следующей:

.
└── lua
   ├── base
   ├── keys
   └── plugins

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

Базовая настройка

После того как мы создали базовые директории - нам необходимо прописать общие правила для Neovim.

Поиск

Давайте создадим файл под названием search.lua и запишем туда все необходимые настройки для поиска:

--[[ Переменные ]]--
-- Переменная для настройки опций Neovim
-- Все время использовать vim.opt - не удобно, поэтому сделаем алиас
local opt = vim.opt

-- Глобальные переменные
-- То же самое делаем и с vim.global
local g = vim.g

--[[ Поиск ]]--
-- Игнорировать регистр при поиске
-- Если теперь введем "IGNORE", то он найдет и "ignore"
opt.ignorecase = true

-- Не игнорировать регистр, если есть символы в верхнем регистре
-- Если напишем "Ignore", то он будет искать только "Ignore"
opt.smartcase = true

-- Подсвечивать найденные текстовые объекты
opt.showmatch = true

Neovim предоставляет нам API, который мы можем использовать с помощью Lua. Если мы введем в редакторе команду :h <команда>, то вверху помимо полного названия команды увидим пространство имен в котором находится команда.

В основном все команды находятся в vim.opt, так что сейчас поэтому поводу заморачиваться не стоит, но все же если есть такая потребность, то вся документация под рукой📕

Тут мы видим сокращения для vim.opt и vim.g. Проще говоря с помощью local в Lua мы просто объявляем переменную и как значение присваиваем ссылку на объект vim.opt и vim.g соответственно.

Табы

Создадим ещё один файлик под названием tabs.lua в директории base/. В него запишем следующее:

--[[ Настройка табов ]]--
-- Установка количества пробельных символов, когда сдвигаем с помощью "<", ">"
-- По сути не смотря на expandtab в терминале все равно отображаются пробельные символы, поэтому установим их количество на одно нажатие этих кнопок
opt.shiftwidth = 2

-- 1 таб == 2 пробела c новой строки
-- При нажатии <CR> будут вставлять табы. Табы рисуются как пробелы. Именно поэтому мы должны установить что каждый таб в новой строке - 2 пробела
opt.tabstop = 2

-- Подстраивать новые строки под предыдущий отступ
opt.smartindent = true

Тут мы просто задаем опции для таба в редакторе. Обратите внимание, что я не написал части с сокращениями для vim.opt и vim.g, тут её нужно будет тоже указать.

Дополнительные настройки

Для всех остальных настроек я создаю файл под названием other.lua в той же директории base/. Тут запишем следующее:

--[[ Настройка панелей ]]--
-- Вертикальные сплиты становятся справа
-- По умолчанию панели в Neovim ставятся в зависимости от расположения текущей панели. Данная настройка поможет нам держать панели в порядке
opt.splitright = true

-- Горизонтальные сплиты становятся снизу
opt.splitbelow = true

--[[ Дополнительные настройки ]]--
-- Используем системный буфер обмена
opt.clipboard = 'unnamedplus'

-- Отключаем дополнение файлов в конце
opt.fixeol = false

-- Автодополнение (встроенное в Neovim)
opt.completeopt = 'menuone,noselect'

-- Не автокомментировать новые линии при переходе на новую строку
vim.cmd [[autocmd BufEnter * set fo-=c fo-=r fo-=o]]

Тут все по прежнему, кроме последней команды. Обратите внимание на строку с vim.cmd[[]]. vim.cmd это специальная команда которая позволяет выполнять команды VimScript из Lua файла. Двойные скобки говорят о том, что мы передадим строку. Вообще можно было записать это и так:

vim.cmd("autocmd BufEnter * set fo-=c fo-=r fo-=o")

Однако, синтаксис с двумя скобками кажется мне более легким для чтения и лакончиным. Тут дело выбора за вами👋

Включаем файлы в init.lua

Сейчас мы создали три файла: search.lua, tabs.lua, other.lua, все они располагаются в директории base/, однако пока ещё настройки в них не будут работать. Для того чтобы все заработало нам необходимо импортировать все три файла в init.lua, так как Neovim будет подключать все конфигурации именно из этого корневого файла. Делается подключение достаточно легко:

require('base/search')
require('base/tabs')
require('base/other')

Обратите внимание, что мы не указываем полный путь, мы указываем путь начиная с директории lua. Также мы не указываем расширения файлов, Lua понимает, что по умолчанию мы будем подключать Lua файлы, так что часть с расширениями нужно упускать.

Сейчас структура нашей конфигурации выглядит вот так:

.
└── lua
   ├── base
   │  ├── other.lua
   │  ├── search.lua
   │  └── tabs.lua
   ├── keys
   └── plugins

Горячие клавиши

Самое время настроить кастомные горячие клавиши! Обычно я создаю два файла для горячих клавиш:

  • main.lua - Горячие клавиши для дефолтных действий в редакторе

  • plugins.lua - Горячие клавиши для плагинов

Сейчас мы будем заниматься созданием только первого файла🤗

Давайте для начала создадим специальный файл и назовем его alias.lua, в него мы запишем сокращения для команд присваивания клавиш, выглядеть он будет вот так:

-- Алиас для быстрого доступа к методу установки горячих клавиш
local map = vim.api.nvim_set_keymap 

--[[
Метод для установки горячих клавиш (normal)
key - {string} Строка с горячей клавишей
command - {string} Команда
]]--
function nm(key, command) 
	map('n', key, command, {noremap = true})
end

--[[
Метод для установки горячих клавиш (input)
key - {string} Строка с горячей клавишей
command - {string} Команда
]]--
function im(key, command)
	map('i', key, command, {noremap = true})
end

--[[
Метод для установки горячих клавиш (visual)
key - {string} Строка с горячей клавишей
command - {string} Команда
]]--
function vm(key, command)
	map('v', key, command, {noremap = true})
end

--[[
Метод для установки горячих клавиш (terminal)
key - {string} Строка с горячей клавишей
command - {string} Команда
]]--
function tm(key, command)
	map('t', key, command, {noremap = true})
end

За установку горячих клавиш отвечает функция vim.api.nvim_set_keymap, однако мы её сократили до map с помощью создания переменной с ссылкой на данную функцию. Если бы мы этого не сделали, то та же функция nm выглядела бы вот так:

--[[
Метод для установки горячих клавиш (normal)
key - {string} Строка с горячей клавишей
command - {string} Команда
]]--
function nm(key, command) 
	vim.api.nvim_set_keymap('n', key, command, {noremap = true})
end

Думаю, никто не скажет, что это выглядит компактно😅 Именно поэтому мы и используем сокращения.

Функция vim.api.nvim_set_keymap принимает 4 аргумента:

  • Режим в котором будет использоваться данная горячая клавиша

  • Сама комбинация клавиш

  • Команда которая должна выполняться при нажатии горячей клавиши

  • Дополнительные аргументы (по типу noremap, который заменяет уже существующую комбинацию клавиш, если она есть)

Всего тут создано четыре функции:

  1. nm - создает горячую клавишу в нормальном режиме

  2. im - создает горячую клавишу в режиме ввода

  3. vm - создает горячую клавишу в визуальном режиме

  4. tm - создает горячую клавишу в терминальном режиме

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

Базовые горячие клавиши

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

Создав файл main.lua мы можем написать следующее:

require('keys/alias')

-- Назначает дополнительной клавишей для отключения режима Ctrl + K
im('<C-k>', '<escape>')

Таким образом мы теперь легко сможем создавать новые горячие клавиши.

На данный момент наша структура директорий выглядит следующим образом:

.
└── lua
   ├── base
   │  ├── other.lua
   │  ├── search.lua
   │  └── tabs.lua
   ├── keys
   │  ├── alias.lua
   │  ├── main.lua
   │  └── plugins.lua
   └── plugins

Плагины

Наступило время для самого сладкого - плагинов😳

Плагины в Neovim это уже написанные скрипты/функционал, которые расширяют возможности редактора, делая его ещё круче!😎

Для того чтобы у нас была возможность устанавливать плагины - нам нужно установить Packer. Это такой менеджер плагинов для Neovim. Как только мы его установим - мы сразу же можем переходить к настройке и установке плагинов.

Установка плагинов

Давайте создадим файл packer_install.lua в директории plugins/. Именно в данном файле мы будем перечислять все плагины, которые мы будем скачивать. После скачивания Packer у нас должна появиться команда PackerSync, сейчас мы будем пользоваться ей регулярно🥹

-- Добавляем Packer как пакет в Neovim
vim.cmd [[packadd packer.nvim]]

-- Используем данный коллбэк как список для плагинов
return require('packer').startup(function()

	-- Добавляем Packer в список, чтобы он обновлял сам себя
	use 'wbthomason/packer.nvim'

	-- LSP сервер
	use 'neovim/nvim-lspconfig'
	
	-- Иконки для автодополнения
	use {
		'onsails/lspkind-nvim',
		config = function()
			require('plugins/lspkind')
		end
	}

	-- Инсталлер для серверов LSP
	use {
		'williamboman/nvim-lsp-installer',
		config = function()
			require('plugins/lsp-installer')
		end
	}

	-- Удобное меню для обозрения проблем LSP
	use {
		"folke/trouble.nvim",
		requires = "kyazdani42/nvim-web-devicons",
		config = function()
			require("trouble").setup {}
		end,
	}
end)

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

Обратите внимание, что весь список плагинов я пишу внутри коллбэка для Packer, а каждый новый плагин начинается с ключевого слова use, после чего идут фигурные скобки с описание плагина. use это специальный метод из Packer, который берет как аргумент объект. Мы опять же могли написать это следующим образом, однако не стали, чтобы не портить читабельность и лаконичность:

-- Статуслайн
	use({
		'nvim-lualine/lualine.nvim',
		requires = { 'kyazdani42/nvim-web-devicons', opt = true },
		config = function()
			require('plugins/lualine')
		end
	})

Объекты внутри которых могут находиться переменные и методы называются в Lua таблицами. Более подробно о таблицах можно почитать вот тут.

Заметьте что во многих таблицах переменных (или поля таблицы) повторяются:

  • Имя в кавычках

  • Зависимые плагины requires

  • Конфигурация плагина config, которая прописывается через вложенную функцию

Мы конечно же можем писать конфигурацию для плагина прямо внутри config, однако я не рекомендую так делать. У вас просто разрастется файл packer_install.lua.

Давайте рассмотрим конфигурацию для плагина автодополнения. В packer_install.lua я добавил его в самый низ:

-- Добавляем Packer как пакет в Neovim
vim.cmd [[packadd packer.nvim]]

-- Используем данный коллбэк как список для плагинов
return require('packer').startup(function()

	-- Добавляем Packer в список, чтобы он обновлял сам себя
	use 'wbthomason/packer.nvim'

	-- LSP сервер
	use 'neovim/nvim-lspconfig'
	
	-- Иконки для автодополнения
	use {
		'onsails/lspkind-nvim',
		config = function()
			require('plugins/lspkind')
		end
	}

	-- Инсталлер для серверов LSP
	use {
		'williamboman/nvim-lsp-installer',
		config = function()
			require('plugins/lsp-installer')
		end
	}

	-- Удобное меню для обозрения проблем LSP
	use {
		"folke/trouble.nvim",
		requires = "kyazdani42/nvim-web-devicons",
		config = function()
			require("trouble").setup {}
		end,
	}
	
	-- Автодополнение
	use {
		'hrsh7th/nvim-cmp',
		requires = {
			'L3MON4D3/LuaSnip',
			'saadparwaiz1/cmp_luasnip',
			'hrsh7th/cmp-nvim-lsp',
			'hrsh7th/cmp-path',
			'hrsh7th/cmp-emoji',
			'hrsh7th/cmp-nvim-lsp-signature-help',
			'hrsh7th/cmp-nvim-lua'
		},
		config = function()
			require('plugins/cmp')
		end
	}
end)

Заметьте, что у данного плагина много зависимостей, а также конфигурация находится в отдельном файле, который располагается в ~/.config/nvim/lua/plugins/cmp.lua, если мы перейдем в этот файл — мы увидим следующее:

local cmp = require('cmp')
local lspkind = require('lspkind')
cmp.setup{
	snippet = {

		-- REQUIRED - you must specify a snippet engine
		expand = function(args)
			require'luasnip'.lsp_expand(args.body) -- Luasnip expand
		end,
	},

	-- Клавиши, которые будут взаимодействовать в nvim-cmp
	mapping = {

		-- Вызов меню автодополнения
		['<C-Space>'] = cmp.mapping(cmp.mapping.complete(), { 'i', 'c' }),
		['<CR>'] = cmp.config.disable,                      -- Я не люблю, когда вещи автодополняются на <Enter>
		['<C-y>'] = cmp.mapping.confirm({ select = true }), -- А вот на <C-y> вполне ок

		-- Используем <C-e> для того чтобы прервать автодополнение
		['<C-e>'] = cmp.mapping({
			i = cmp.mapping.abort(), -- Прерываем автодополнение
			c = cmp.mapping.close(), -- Закрываем автодополнение
		}),
		['<C-p>'] = cmp.mapping(cmp.mapping.select_prev_item(), { 'i', 'c' }),
		['<C-n>'] = cmp.mapping(cmp.mapping.select_next_item(), { 'i', 'c' }),
	},

	sources = cmp.config.sources({
		{ name = 'nvim_lsp' },                -- LSP 👄
		{ name = 'nvim_lsp_signature_help' }, -- Помощь при введении параметров в методах 🚁
		{ name = 'luasnip' },                 -- Luasnip 🐌
		{ name = 'buffer' },                  -- Буфферы 🐃
		{ name = 'path' },                    -- Пути 🪤
		{ name = "emoji" },                   -- Эмодзи 😳
	}, {
	}),
	formatting = {
		format = lspkind.cmp_format({
			mode = 'symbol', -- show only symbol annotations
			maxwidth = 50,   -- prevent the popup from showing more than provided characters (e.g 50 will not show more than 50 characters)
		})
	}
}

Вот тут уже легко запутаться, неправда ли? Однако, в данный момент вам не нужно понимать всего написанного, так как вы не читали документацию для данного плагина.

Нужно понять несколько основных принципов:

  1. Конфигурацию мы всегда стараемся отделить от списка плагинов.

  2. Для каждой конфигурации мы создаем свой отдельный файлик. В данном случае это файл lua/plugins/cmp.lua

Давайте ещё раз посмотрим на то, как описан плагин в списке для плагинов:

-- Автодополнение
	use {
		'hrsh7th/nvim-cmp',
		requires = {
			'L3MON4D3/LuaSnip',
			'saadparwaiz1/cmp_luasnip',
			'hrsh7th/cmp-nvim-lsp',
			'hrsh7th/cmp-path',
			'hrsh7th/cmp-emoji',
			'hrsh7th/cmp-nvim-lsp-signature-help',
			'hrsh7th/cmp-nvim-lua'
		},
		config = function()

			-- ДАННАЯ ЧАСТЬ ОЧЕНЬ ВАЖНА
			require('plugins/cmp')
		end
	}

Я отметил строку кода, на которую нужно смотреть для удобства. Если мы не импортируем нашу конфигурацию, которая была в листинге до этого, то конфигурация не будет работать. Импортирование работает точно так же, как и импортирование в init.lua, мы просто через require() указываем путь до файла.

Как настраивать плагины

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

В большинстве случаев у вас уже будет пример конфигурации на README в Github, однако мы должны заметить пару моментов, на которых часто бывают ошибки. Рассмотрим конфигурацию:

require('lualine').setup {
	options = {
		icons_enabled = true,
		theme = 'auto',
		component_separators = { left = '', right = ''},
		section_separators = { left = '', right = ''},
		disabled_filetypes = {},
		always_divide_middle = true,
		globalstatus = false,
	},
	sections = {
		lualine_c = {'filename', 'lsp_progress'},
		lualine_y = {'progress'},
		lualine_z = {'location'}
	},
}

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

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

Давайте рассмотрим нашу структуру директорий уже сейчас:

.
└── lua
   ├── base
   │  ├── other.lua
   │  ├── search.lua
   │  └── tabs.lua
   ├── keys
   │  ├── alias.lua
   │  ├── main.lua
   │  └── plugins.lua
   └── plugins
	  ├── <ваши файлы для конфигурации плагинов>
      └── packer_install.lua

Вот список всех плагинов, которые я использую:

Плагин

Описание

nvim-lspconfig

Плагин для того чтобы в Neovim была поддержка LSP, он позволяет включать автодополнение, проверку синтаксиса и ещё много прочего

fidget.nvim

Плагин для того чтобы показывать процесс загрузки LSP

trouble.nvim

Позволяет удобно показывать все ошибки и предупреждения, которые нашел LSP

nvim-cmp

Позволяет включить автодополнение в Neovim

lspkind-nvim

Добавляет иконки для пунктов автодополнения

symbols-outline.nvim

Добавляет меню с объектами из LSP для быстрого переключения между функциями, методами и классами

nvim-lsp-installer

Позволяет устанавливать LSP-сервера быстро и без боли

gitsigns.nvim

Интеграция Git в Neovim

gruvbox-material

Тема для Neovim

nord-vim

Ещё одна тема в Neovim

lualine.nvim

Добавляет статуслайн внизу

neo-tree.nvim

Добавляет проводник для Neovim

kommentary

Удобное комментирование кода в Neovim

nvim-treesitter

Подсветка синтаксиса в Neovim

nvim-autopairs

Автодополнение всяких скобок, кавычек и так далее

telescope.nvim

Быстрый и удобный поиск

bufferline.nvim

Статуслайн с буферами вверху

vim-test

Тестирование прямо из Neovim (Mocha, Jest, JUnit)

Горячие клавиши для плагинов

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

require('keys/plugins')


vim.g.mapleader = ' '                                             -- Используем Space, как клавишу для альтернативных хотекеев

-- LSP (все горячие клавиши начинаются с g), кроме ховера
nm('K', '<cmd>lua vim.lsp.buf.hover()<CR>' )                      -- Ховер для объекта
nm('gf', '<cmd>lua vim.lsp.buf.formatting()<CR>')                 -- Форматировать документ
nm('ga', '<cmd>lua vim.lsp.buf.code_action()<CR>')                -- Действия с кодом
nm('gR', '<cmd>lua vim.lsp.buf.rename()<CR>')                     -- Переименовать объект

-- Отркыть NvimTree
nm('<leader>v', '<cmd>NeoTreeRevealToggle<CR>')

-- Telescope
nm('gd', '<cmd>Telescope lsp_definitions<CR>')                       -- Объявления в LSP
nm('<leader>p', '<cmd>Telescope oldfiles<CR>')                       -- Просмотр недавних файлов
nm('<leader>o', '<cmd>Telescope git_files<CR>')                      -- Поиск файлов
nm('<leader>b', '<cmd>Telescope git_branches<CR>')                   -- Ветки в Git
nm('<leader>f', '<cmd>Telescope live_grep<CR>')                      -- Поиск строки
nm('<leader>q', '<cmd>Telescope buffers<CR>')                        -- Буфферы

-- Git
nm('<leader>gp', '<cmd>Gitsigns preview_hunk<CR>')
nm('<leader>gb', '<cmd>Gitsigns blame_line<CR>')

-- SymbolsOutline
nm('<leader>s', '<cmd>SymbolsOutline<CR>')                        -- Структура для файла

-- BufferLine
nm('ç', '<cmd>bd<CR>')                                            -- Закрыть буффер
nm('≤', '<cmd>BufferLineCyclePrev<CR>')                           -- Перейти в предыдущий буффер
nm('≥', '<cmd>BufferLineCycleNext<CR>')                           -- Перейти в следующий буффер
nm('˘', '<cmd>BufferLineMoveNext<CR>')                            -- Закрыть буффер слева
nm('¯', '<cmd>BufferLineMovePrev<CR>')                            -- Закрыть буффер справа

-- Formatter
nm('<leader>l', '<cmd>Format<CR>')


-- Trouble
nm('<leader>x', '<cmd>TroubleToggle<CR>')                         -- Открыть меню с проблемами LSP
nm('gr', '<cmd>Trouble lsp_references<CR>')                       -- Референсы в LSP

Как можно увидеть тут из необычного только первая строка. В Neovim есть специальная кнопка для альтернативных сочетаний клавиш, у меня это <Space>. Везде где написано <leader> достаточно просто в голове держать, что это Space.

Полную конфигурацию можно увидеть в вот этом репозитории

На этом на сегодня все, если вам было интересно читать данную статью, то можете заглянуть и в паблик в телеграм, там много всего интересного про разработку. Хорошего дня!

Tags:
Hubs:
Total votes 13: ↑13 and ↓0+13
Comments24

Articles