Статья рассказывает о том, как я с нуля переписывал свой nvim-конфиг (init.vim) в конфиг с поддержкой lua (init.lua).

Предисловие

Я тут сидел и прибывал в прокрастинации. Писать код было лень. И, листая старую тетрадь расстрелянного генерала, я увидел комментарии, в которых мне напомнили, что было бы круто переехать на lua. Я слежу за nvim&lua движением на редите, но все как-то руки не доходили, а тут, бах, и прокрастинацию как рукой сняло от таких мыслей:

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

  • Vim супер быстрый, но с помощью lua он станет ещё быстрее

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

  • Заменить кое-какие плагины на более современные, некоторые из которых уже написаны на lua

  • В мире vi* сейчас идет настоящая революция, связанная с использованием neovim с lua, и приобщиться к этому будет весело

Мой старый .vimrc (init.vim)

Мой init.vim представлял вот такой файл
call plug#begin('~/.local/share/nvim/plugged')
"-------------------------------------------------------------------------------
" ПЛАГИНЫ
"-------------------------------------------------------------------------------
" --- Python ---
Plug 'python-mode/python-mode', { 'for': 'python', 'branch': 'develop' }
Plug 'mitsuhiko/vim-jinja'
Plug 'fisadev/vim-isort', {'do': 'pip install isort'} " pip install isort Может сортировать импорты в шапке.
" --- Perl ---
Plug 'WolfgangMehner/perl-support'
" --- JavaScript ---
Plug 'pangloss/vim-javascript'
" --- JSON ---
Plug 'elzr/vim-json'
" --- Bash ---
Plug 'WolfgangMehner/bash-support'    " \rr - для запуска скрипта
" --- HTML ---
Plug 'othree/html5.vim'               " Поддержка microdata и прочей лабуды в html
Plug 'idanarye/breeze.vim'            " Подсвечивает закрывающий и откры. тэг. Если, где-то что-то не закрыто, то не подсвечивает.
Plug 'alvan/vim-closetag'             " Закрывает автоматом html и xml тэги. Пишешь <h1> и он автоматом закроется </h1>. Нажми >!
" --- CSS ---
Plug 'JulesWang/css.vim'              " CSS syntax file
Plug 'groenewege/vim-less'            " Vim syntax for LESS (dynamic CSS)
Plug 'hail2u/vim-css3-syntax'
Plug 'ap/vim-css-color'
" --- Оформление ---
Plug 'vim-airline/vim-airline'        " Крутая строка состояния внизу экрана
Plug 'vim-airline/vim-airline-themes'
Plug 'flazz/vim-colorschemes'        " Может менять цветовую схему. Список схем: https://github.com/flazz/vim-colorschemes/tree/prep
Plug 'joshdick/onedark.vim'          " Тема для вима
Plug 'challenger-deep-theme/vim'      " Тема вима
"Plug 'Yggdroot/indentLine'            " Точки для табов
" --- Автоформатирование кода для всех языков ---
Plug 'Chiel92/vim-autoformat'         " Форматирует все, но надо ставить модули, например для perl надо поставить perltidy.
" --- Автодополнялки ---
"  Здесь список всех поддерживаемых автодополнялкой языков:
"  https://github.com/Shougo/deoplete.nvim/wiki/Completion-Sources
"  Для PHP, GO, TypeScript - смотри там же
Plug 'Shougo/deoplete.nvim', { 'do': ':UpdateRemotePlugins' }     " Асинхронная автодополнялка, работает быстро в отличии от COC
Plug 'deoplete-plugins/deoplete-jedi'                             " Подплагин для автодополнения python
Plug 'carlitux/deoplete-ternjs'                                   " Подплагин для автодополнения javascript
Plug 'ternjs/tern_for_vim', {'do': 'cd ~/.local/share/nvim/plugged/tern_for_vim && npm install'}
" --- Навигация ---
Plug 'majutsushi/tagbar'              " Показывает дерево классов и функций, можно очень быстро перемещаться кнопка F8
Plug 'scrooloose/nerdtree'            " Дерево файлов. Для открытия файла в режиме таблицы юзай t, а для сплита s
Plug 'mileszs/ack.vim'                " Удобный grep по файлам
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'
" --- Разное ---
Plug 'cohama/lexima.vim'              " Закрывает автоматом скобки
Plug 'scrooloose/nerdcommenter'       " Комментирует блок \cc, снимает комменты с блока \cu
Plug 'tpope/vim-surround'             " Обрамляет или снимает обрамление. Выдели слово, нажми S и набери <h1>
Plug 'powerman/vim-plugin-ruscmd'     " Русская раскладка в командом режиме
Plug 'chr4/nginx.vim'                 " nginx подсветка
Plug 'sheerun/vim-polyglot'           " Подсветка синтаксиса для тьмы языко, в т.ч. и конфиги nginx
Plug 'w0rp/ale'                       " Нужен, чтобы заработал eslint, как в атоме
Plug 'tpope/vim-unimpaired'           " ]p - вставить из буфера на строку выше, [p - ниже
Plug 'google/vim-searchindex'         " Считает кол-во совпадений при поиске
Plug 'tpope/vim-repeat'               " Может повторять через . vimsurround
Plug 'terryma/vim-multiple-cursors'   " Может изменять имя переменной одновременно в нескольких местах ctrl-n на имени и с
Plug 'mhinz/vim-startify'             " Стартовая страница, если просто набрать vim в консоле
Plug 'skanehira/translate.vim'        " Переводчик
Plug 'mattn/emmet-vim'                " Обрамляет строку в теги по ctrl- y
call plug#end()

"-------------------------------------------------------------------------------
" GLOBAL
"-------------------------------------------------------------------------------
syntax on
set autoindent
filetype on
filetype plugin on
filetype plugin indent on
" Цветовая тема и палитра 256 или 24бит цветов
if ($MYCOLOR=='24bit')
        set termguicolors
endif
"Use 24-bit (true-color) mode in Vim/Neovim when outside tmux.
"If you're using tmux version 2.2 or later, you can remove the outermost $TMUX check and use tmux's 24-bit color support
"(see < http://sunaku.github.io/tmux-24bit-color.html#usage > for more information.)
if (empty($TMUX))
        if (has("nvim"))
                "For Neovim 0.1.3 and 0.1.4 < https://github.com/neovim/neovim/pull/2198 >
                let $NVIM_TUI_ENABLE_TRUE_COLOR=1
        endif
        "For Neovim > 0.1.5 and Vim > patch 7.4.1799 < https://github.com/vim/vim/commit/61be73bb0f965a895bfb064ea3e55476ac175162 >
        "Based on Vim patch 7.4.1770 (guicolors option) < https://github.com/vim/vim/commit/8a633e3427b47286869aa4b96f2bfc1fe65b25cd >
        " < https://github.com/neovim/neovim/wiki/Following-HEAD#20160511 >
        if (has("termguicolors"))
                set termguicolors
        endif
endif
colorscheme challenger_deep
"colorscheme onedark
" Орфография для английского и русского языка
set spelllang=en,ru
" Два пробела при табуляции в качестве отступа для js/html/xml файлов, для
" остальных 4
set shiftwidth=4
set tabstop=4
set softtabstop=4
" Как vim сплитит экран
set splitright
set splitbelow
" Даже, если ща русская раскладка, все равно можно вводить любые команды типа
" Ctrl + r и т.д.
set keymap=russian-jcukenwin
set iminsert=0  " Чтобы при старте ввод был на английском, а не русском (start > i)
set imsearch=0  " Чтобы при старте поиск был на английском, а не русском (start > /)
" Включаем номерацию строк
set number
" Вкл. относительную нумерацию строк, напр. 10j или 5k
set relativenumber
" Курсор всегда в центре экрана
set so=999
" Подсветка строки, на которой находится курсор
set cursorline
set nostartofline
hi CursorLine cterm=underline
" Возможность отката назад в файле
set undofile
"-------------------------------------------------------------------------------
" LET'S
"-------------------------------------------------------------------------------
" python-mode
let g:pymode_python = 'python3'                           " По умолчанию python-mode использует проверку синтаксиса python 2. Чтобы включить python 3
" Здесь правильнее писать путь к виртуальному окружению, а не общему. На рокки
" не работало без этого
let g:python3_host_prog='/usr/bin/python3'
let g:pymode_lint_ignore=["E722", "C901"]                 " Игнорировать определенные линты
" Тема для айрлайна и все остальное настройка tabline
let g:airline_theme='papercolor'
"let g:airline_theme='onedark'
let g:airline#extensions#tabline#formatter = 'unique_tail'
let g:airline#extensions#tabline#enabled = 1           " enable airline tabline
let g:airline#extensions#tabline#tabs_label = ''       " can put text here like BUFFERS to denote buffers (I clear it so nothing is shown)
let g:airline#extensions#tabline#buffers_label = ''    " can put text here like TABS to denote tabs (I clear it so nothing is shown)
let g:airline#extensions#tabline#fnamemod = ':t'       " disable file paths in the tab
let g:airline#extensions#tabline#show_tab_count = 0    " dont show tab numbers on the right
let g:airline#extensions#tabline#show_buffers = 1      " dont show buffers in the tabline
let g:airline#extensions#tabline#tab_min_count = 1     " minimum of 2 tabs needed to display the tabline
let g:airline#extensions#tabline#show_splits = 0       " disables the buffer name that displays on the right of the tabline
let g:airline#extensions#tabline#show_tab_nr = 0       " disable tab numbers
let g:airline#extensions#tabline#show_tab_type = 0     " disables the weird ornage arrow on the tabline
let g:airline#extensions#tabline#left_sep = ''
let g:airline#extensions#tabline#left_alt_sep = '|'
" fzf
let g:fzf_buffers_jump = 1
"let g:fzf_action = {  'enter': 'tab drop',  'ctrl-t': 'tab drop'}
" Включаем автодополнялку при старте
let g:deoplete#enable_at_startup = 1
call deoplete#custom#option('num_processes', 4)
" Чтобы работало по <F8> навигация по перловому файлу
let g:tagbar_type_perl = {
                        \ 'ctagstype' : 'perl',
                        \ 'kinds'     : [
                        \ 'p:package:0:0',
                        \ 'w:roles:0:0',
                        \ 'e:extends:0:0',
                        \ 'u:uses:0:0',
                        \ 'r:requires:0:0',
                        \ 'o:ours:0:0',
                        \ 'a:properties:0:0',
                        \ 'b:aliases:0:0',
                        \ 'h:helpers:0:0',
                        \ 's:subroutines:0:0',
                        \ 'd:POD:1:0'
                        \ ]
                        \ }
" Компактный вид у тагбара
let g:tagbar_compact = 1
" Отк. сортировка по имени у тагбара
let g:tagbar_sort = 0
" Конфиг ale + eslint
let g:ale_fixers = { 'javascript': ['eslint'] }
let g:ale_sign_error = '❌'
let g:ale_sign_warning = '⚠️'
let g:ale_fix_on_save = 1
" Запуск линтера, только при сохранении
let g:ale_lint_on_text_changed = 'never'
let g:ale_lint_on_insert_leave = 0
" Используем ag вместо grep. Он будет игнорить папки помеченные .gitignore
if executable('ag')
        let g:ackprg = 'ag --vimgrep'
endif
" Показывать скрытые файлы и папки в NERDTree
let NERDTreeShowHidden = 1
" Направление перевода с русского на английский
let g:translate_source = "ru"
let g:translate_target = "en"
let g:translate_popup_window = 0
"-------------------------------------------------------------------------------
" AUTOCMD
"-------------------------------------------------------------------------------
" Для питоновский скрипов автоматом вызывает Дерево функций и классов
autocmd VimEnter .py,.pl,.js,.php TagbarToggle
autocmd FileType javascript setlocal expandtab shiftwidth=2 tabstop=2 softtabstop=2
autocmd BufRead,BufNewFile .htm,.html,.xml,.json,.php,.css,*.rss setlocal tabstop=2 shiftwidth=2 softtabstop=2
" Автоматический перенос текста для текстовых файлов
autocmd BufRead,BufNewFile *.txt  setlocal textwidth=80
" С этой строкой отлично форматирует html файл, который содержит jinja2
au BufNewFile,BufRead *.html set filetype=htmldjango
autocmd BufRead,BufNewFile *.conf let b:autoformat_autoindent=0
" Запоминает где nvim последний раз редактировал файл
au BufReadPost * if line("'"") > 1 && line("'"") <= line("$") | exe "normal! g'"" | endif
" Запуск php скриптов с помощью \rr
autocmd FileType php noremap \rr :w!<CR>:!/bin/php %<CR>
"-------------------------------------------------------------------------------
" ГОРЯЧИЕ КНОПКИ
"-------------------------------------------------------------------------------
" Типа 'Нажимает' на ESC при быстром нажатии jj, чтобы не тянутся
imap jj <Esc>
" Отключаем стрелочки
nnoremap <Left> :echoe "Use h"<CR>
nnoremap <Right> :echoe "Use l"<CR>
nnoremap <Up> :echoe "Use k"<CR>
nnoremap <Down> :echoe "Use j"<CR>
" Системный буфер обмена shift - Y / P
noremap <S-Y> "+y
" По F1 очищаем последний поиск с подсветкой
nnoremap <silent><F1> :noh<CR>
" shift + F1 = удалить пустые строки
nnoremap <S-F1> :g/^$/d<CR>
" Используй F2 для временной вставки из буфера, чтобы отключить авто идент
set pastetoggle=<F2>
" Перечитать .vimrc / init
noremap <F3> :source ~/.config/nvim/init.vim<CR>
" Открыть .config/nvim/init.vim через Shift + <F3>
" Может не работать, если echo $TERM  xterm-256color
noremap <S-F3> :edit ~/.config/nvim/init.vim<CR>
" Поиск слова под курсором, воскл. знак, чтобы не было автооткрытия файла
noremap <F4> :Ack! <cword> --ignore-dir={static,logs,files}<cr>
noremap <S-F4> :Ack! --ignore-dir={static,logs,files}
" Тогле включение и отклю. показа строк и обычных и релативных
nnoremap  <silent> <F5> :exec &nu==&rnu? "se nu!" : "se rnu!"<cr>
" Дерево файлов. Используй для открытия файлов t  и s  чтобы открывать в режиме таблицы или сплита
noremap <F6> :NERDTreeRefreshRoot<CR> :NERDTreeToggle<CR>
" Показ дерева классов и функций, плагин majutsushi/tagbar
nnoremap <F8> :TagbarToggle<CR>
" Проверка орфографии <F11> для русского и английского языка
nnoremap <silent> <F11> :set spell!<cr>
inoremap <silent> <F11> <C-O>:set spell!<cr>
" CTRL-s сохранялка и автоформат
inoremap <C-s> <esc>:Autoformat<CR>:w<CR>
noremap <C-s> <esc>:Autoformat<CR>:w<CR>
" Пролистнуть на страницу вниз (как в браузерах)
nnoremap <Space> <PageDown> zz
" Пролистнуть на страницу вверх
nnoremap <C-Space> <PageUp> zz
" fzf
noremap <C-a> :Files<CR>
noremap <C-p> :Buffers<CR>
" Переводчик
vmap t <Plug>(VTranslate)
" Переключение между буферов с помощью TAB
function! BSkipQuickFix(command)
        let start_buffer = bufnr('%')
        execute a:command
        while &buftype ==# 'quickfix' && bufnr('%') != start_buffer
                execute a:command
        endwhile
endfunction
nnoremap <Tab> :call BSkipQuickFix("bn")<CR>
nnoremap <S-Tab> :call BSkipQuickFix("bp")<CR>

Писать я его начал ещё тогда, когда neovim не существовал. Что-то добавлялось, удалялось и накопилось всякого разного. Все это я и буду конвертировать в lua, за одно и причешу и избавлюсь от лишнего.

Стартовые условия

(Можно пропустить, если у вас из пакетного менеджера сразу ставится neovim 0.5.х и выше)

Я решил взять старенькую машину с Centos 7, исходя из принципа, что если я смогу на ней все настроить, то на современных и подавно все запущу. Ещё мне надо было убедиться, что на старых машинах так же работает, ибо много легаси болтается на Centos 7, которое надо поддерживать.

Естественно, по умолчанию через yum ставилась старая версия nvim. Но после таких манипуляций версия была уже последняя.

curl -LO https://github.com/neovim/neovim/releases/latest/download/nvim.appimage
chmod u+x nvim.appimage
mkdir .local/bin
mv nvim.appimage .local/bin/nvim

И в файле .bash_profile поменял PATH на локальный в первую очередь.

PATH=$HOME/.local/bin:$HOME/bin:$PATH

AppImage - универсальный пакет для всех, вне зависимости от дистрибутива (Ubuntu, Redhat и т.д.) просто скачиваете файл, запускаете и все сразу работает.

Старенький git обновил таким образом. Без современного git плагин менеджер Packman не работал.

Больше никаких проблем с Centos 7 не было.

С нуля

В ~/.config/nvim создал 4 пустых файла и одну папку. Вот такая получилась структура файлов:

.
├── init.lua
├── lua
│   ├── keymaps.lua
│   ├── plugins.lua
│   └── settings.lua

И начал эти файлы заполнять...

Файл init.lua

Он только считывает файлы с плагинами, настройками и моими хоткеями из директории ~/.config/nvim/lua

-----------------------------------------------------------
-- Импорт модулей lua
-----------------------------------------------------------
require('plugins')
require('settings') 
require('keymaps')

Файл keymaps.lua

Сконвертировать мои хоткеи на lua не составило труда.

keymaps.lua
local map = vim.api.nvim_set_keymap
local default_opts = {noremap = true, silent = true}

-- Системный буфер обмена shift - Y
map('v', 'S-Y', '"+y', {})
-- Типа 'Нажимает' на ESC при быстром нажатии jj, чтобы не тянутся
map('i', 'jj', '<Esc>', {noremap = true})
-- Стрелочки откл. Использовать hjkl
map('', '<up>', ':echoe "Use k"<CR>', {noremap = true, silent = false})
map('', '<down>', ':echoe "Use j"<CR>', {noremap = true, silent = false})
map('', '<left>', ':echoe "Use h"<CR>', {noremap = true, silent = false})
map('', '<right>', ':echoe "Use l"<CR>', {noremap = true, silent = false})
-- Автоформат + сохранение по CTRL-s , как в нормальном, так и в insert режиме
map('n', '<C-s>', ':Autoformat<CR>:w<CR>',  default_opts)
map('i', '<C-s>', '<esc>:Autoformat<CR>:w<CR>', default_opts)
-- Переключение вкладок с помощью TAB или shift-tab (akinsho/bufferline.nvim)
map('n', '<Tab>', ':BufferLineCycleNext<CR>', default_opts)
map('n', '<S-Tab>', ':BufferLineCyclePrev<CR>', default_opts)
-- Пролистнуть на страницу вниз / вверх (как в браузерах)
map('n', '<Space>', '<PageDown> zz', default_opts)
map('n', '<C-Space>', '<PageUp> zz', default_opts)
-- " Переводчик рус -> eng
map('v', 't', '<Plug>(VTranslate)', {})
-- fzf
map('n', '<C-a>', [[ <cmd>lua require('telescope.builtin').find_files()<cr> ]], default_opts)
map('n', '<C-p>', [[ <cmd>lua require('telescope.builtin').buffers()<cr> ]], default_opts)

-----------------------------------------------------------
-- Фн. клавиши по F1 .. F12
-----------------------------------------------------------
-- По F1 очищаем последний поиск с подсветкой
map('n', '<F1>', ':nohl<CR>', default_opts)
-- shift + F1 = удалить пустые строки
map('n', '<S-F1>', ':g/^$/d<CR>', default_opts)
-- <F2> для временной вставки из буфера, чтобы отключить авто идент
vim.o.pastetoggle='<F2>'
-- <F3> перечитать конфигурацию nvim Может не работать, если echo $TERM  xterm-256color
map('n', '<F3>', ':so ~/.config/nvim/init.lua<CR>:so ~/.config/nvim/lua/plugins.lua<CR>:so ~/.config/nvim/lua/settings.lua<CR>:so ~/.config/nvim/lua/keymaps.lua<CR>', { noremap = true })
-- <S-F3> Открыть всю nvim конфигурацию для редактирования
map('n', '<S-F3>', ':e ~/.config/nvim/init.lua<CR>:e ~/.config/nvim/lua/plugins.lua<CR>:e ~/.config/nvim/lua/settings.lua<CR>:e ~/.config/nvim/lua/keymaps.lua<CR>', { noremap = true })
-- <F4> Поиск слова под курсором
map('n', '<F4>', [[<cmd>lua require('telescope.builtin').grep_string()<cr>]], default_opts)
-- <S-F4> Поиск слова в модальном окошке
map('n', '<S-F4>', [[<cmd>lua require('telescope.builtin').live_grep()<cr>]], default_opts)
-- <F5> разные вариации нумераций строк, можно переключаться
map('n', '<F5>', ':exec &nu==&rnu? "se nu!" : "se rnu!"<CR>', default_opts)
-- <F6> дерево файлов.
map('n', '<F6>', ':NvimTreeRefresh<CR>:NvimTreeToggle<CR>', default_opts)
-- <F8>  Показ дерева классов и функций, плагин majutsushi/tagbar
map('n', '<F8>', ':TagbarToggle<CR>', default_opts)
-- <F11> Проверка орфографии  для русского и английского языка
map('n', '<F11>', ':set spell!<CR>', default_opts)
map('i', '<F11>', '<C-O>:set spell!<CR>', default_opts)

Единственная проблема возникла с перечитыванием конфигов. В старом init.vim надо было перечитать всего один файл, я это и делал так:

noremap <F3> :source ~/.config/nvim/init.vim<CR>

А тут файлов уже больше получается. Полез в инет, начал гуглить. Нашел вот такое обсуждение, но у меня не взлетело ничего из того, что там предлагается. Очередной показатель, что lua за 15 минут - это цирк. Надо разбираться. И короче, я просто захардкодил в итоге релоад этих 4-х файлов, но сдаваться не буду, попробую найти адекватное решение.

Файл settings.lua

Файл с настройками получился таким:

settings.lua
local cmd = vim.cmd             -- execute Vim commands
local exec = vim.api.nvim_exec  -- execute Vimscript
local g = vim.g                 -- global variables
local opt = vim.opt             -- global/buffer/windows-scoped options
-- Направление перевода с русского на английский
g.translate_source = 'ru'
g.translate_target = 'en'
-- Компактный вид у тагбара и Отк. сортировка по имени у тагбара
g.tagbar_compact = 1
g.tagbar_sort = 0

-- Конфиг ale + eslint
g.ale_fixers = { javascript= { 'eslint' } }
g.ale_sign_error = '❌'
g.ale_sign_warning = '⚠️'
g.ale_fix_on_save = 1
-- Запуск линтера, только при сохранении
g.ale_lint_on_text_changed = 'never'
g.ale_lint_on_insert_leave = 0

-----------------------------------------------------------
-- Главные
-----------------------------------------------------------
opt.colorcolumn = '80'              -- Разделитель на 80 символов
opt.cursorline = true               -- Подсветка строки с курсором
opt.spelllang= { 'en_us', 'ru' }    -- Словари рус eng
opt.number = true                   -- Включаем нумерацию строк
opt.relativenumber = true           -- Вкл. относительную нумерацию строк
opt.so=999                          -- Курсор всегда в центре экрана
opt.undofile = true                 -- Возможность отката назад
opt.splitright = true               -- vertical split вправо
opt.splitbelow = true               -- horizontal split вниз
-----------------------------------------------------------
-- Цветовая схема
-----------------------------------------------------------
opt.termguicolors = true      --  24-bit RGB colors
cmd'colorscheme onedark'
-----------------------------------------------------------
-- Табы и отступы
-----------------------------------------------------------
cmd([[
filetype indent plugin on
syntax enable
]])
opt.expandtab = true      -- use spaces instead of tabs
opt.shiftwidth = 4        -- shift 4 spaces when tab
opt.tabstop = 4           -- 1 tab == 4 spaces
opt.smartindent = true    -- autoindent new lines
-- don't auto commenting new lines
cmd [[au BufEnter * set fo-=c fo-=r fo-=o]]
-- remove line lenght marker for selected filetypes
cmd [[autocmd FileType text,markdown,html,xhtml,javascript setlocal cc=0]]
-- 2 spaces for selected filetypes
cmd [[
autocmd FileType xml,html,xhtml,css,scss,javascript,lua,yaml,htmljinja setlocal shiftwidth=2 tabstop=2
]]
-- С этой строкой отлично форматирует html файл, который содержит jinja2
cmd[[ autocmd BufNewFile,BufRead *.html set filetype=htmldjango ]]
-----------------------------------------------------------
-- Полезные фишки
-----------------------------------------------------------
-- Запоминает где nvim последний раз редактировал файл
cmd [[
autocmd BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
]]
-- Подсвечивает на доли секунды скопированную часть текста
exec([[
augroup YankHighlight
autocmd!
autocmd TextYankPost * silent! lua vim.highlight.on_yank{higroup="IncSearch", timeout=700}
augroup end
]], false)

-----------------------------------------------------------
-- Установки для плагинов
-----------------------------------------------------------
-- LSP settings
local lsp_installer = require("nvim-lsp-installer")
lsp_installer.on_server_ready(function(server)
    local opts = {}
    if server.name == "sumneko_lua" then
        -- only apply these settings for the "sumneko_lua" server
        opts.settings = {
            Lua = {
                diagnostics = {
                    -- Get the language server to recognize the 'vim', 'use' global
                    globals = {'vim', 'use'},
                },
                workspace = {
                    -- Make the server aware of Neovim runtime files
                    library = vim.api.nvim_get_runtime_file("", true),
                },
                -- Do not send telemetry data containing a randomized but unique identifier
                telemetry = {
                    enable = false,
                },
            },
        }
    end
    server:setup(opts)
end)


-- nvim-cmp supports additional completion capabilities
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities = require('cmp_nvim_lsp').update_capabilities(capabilities)
vim.o.completeopt = 'menuone,noselect'
-- luasnip setup
local luasnip = require 'luasnip'
-- nvim-cmp setup
local cmp = require 'cmp'
cmp.setup {
    snippet = {
        expand = function(args)
            luasnip.lsp_expand(args.body)
        end,
    },
    sources = {
        { name = 'nvim_lsp' },
        { name = 'luasnip' },
        { name = 'path' },
        { name = 'buffer', opts = {
            get_bufnrs = function()
                return vim.api.nvim_list_bufs()
            end
        },
    },
},
}

С файлом никаких проблем не возникло, все легко переписалось. Добавились настройки для плагинов: LSP и nvim-cmp, но о плагинах дальше...

Файл plugins.lua

Мой файл с плагинами после "ревизии" получился таким:

plugins.lua

vim.cmd [[packadd packer.nvim]]

return require('packer').startup(function()
    -- Packer сам себя
    use 'wbthomason/packer.nvim'

    -----------------------------------------------------------
    -- ПЛАГИНЫ ВНЕШНЕГО ВИДА
    -----------------------------------------------------------

    -- Цветовая схема
    use 'joshdick/onedark.vim'
    --- Информационная строка внизу
    use { 'nvim-lualine/lualine.nvim',
    requires = {'kyazdani42/nvim-web-devicons', opt = true},
    config = function()
        require('lualine').setup()
    end, }
    -- Табы вверху
    use {'akinsho/bufferline.nvim', requires = 'kyazdani42/nvim-web-devicons',
    config = function()
        require("bufferline").setup{}
    end, }


    -----------------------------------------------------------
    -- НАВИГАЦИЯ
    -----------------------------------------------------------
    -- Файловый менеджер
    use { 'kyazdani42/nvim-tree.lua',
    requires = 'kyazdani42/nvim-web-devicons',
    config = function() require'nvim-tree'.setup {} end, }
    -- Навигация внутри файла по классам и функциям
    use 'majutsushi/tagbar'
    -- Замена fzf и ack
    use { 'nvim-telescope/telescope.nvim',
    requires = { {'nvim-lua/plenary.nvim'} },
    config = function() require'telescope'.setup {} end, }


    -----------------------------------------------------------
    -- LSP и автодополнялка
    -----------------------------------------------------------


    -- Highlight, edit, and navigate code using a fast incremental parsing library
    use 'nvim-treesitter/nvim-treesitter'
    -- Collection of configurations for built-in LSP client
    use 'neovim/nvim-lspconfig'
    use 'williamboman/nvim-lsp-installer'
    -- Автодополнялка
    use 'hrsh7th/nvim-cmp'
    use 'hrsh7th/cmp-nvim-lsp'
    use 'hrsh7th/cmp-buffer'
    use 'saadparwaiz1/cmp_luasnip'
    --- Автодополнлялка к файловой системе
    use 'hrsh7th/cmp-path'
    -- Snippets plugin
    use 'L3MON4D3/LuaSnip'



    -----------------------------------------------------------
    -- PYTHON
    -----------------------------------------------------------
    --- Шапка с импортами приводим в порядок
    use 'fisadev/vim-isort'
    -- Поддержка темплейтом jinja2
    use 'mitsuhiko/vim-jinja'


    -----------------------------------------------------------
    -- HTML и CSS
    -----------------------------------------------------------
    -- Подсвечивает закрывающий и откры. тэг. Если, где-то что-то не закрыто, то не подсвечивает.
    use 'idanarye/breeze.vim'
    -- Закрывает автоматом html и xml тэги. Пишешь <h1> и он автоматом закроется </h1>
    use 'alvan/vim-closetag'
    -- Подсвечивает #ffffff
    use 'ap/vim-css-color'

    -----------------------------------------------------------
    -- РАЗНОЕ
    -----------------------------------------------------------
    -- Даже если включена русская раскладка vim команды будут работать
    use 'powerman/vim-plugin-ruscmd'
    -- 'Автоформатирование' кода для всех языков
    use 'Chiel92/vim-autoformat'
    -- ]p - вставить на строку выше, [p - ниже
    use 'tpope/vim-unimpaired'
    -- Переводчик рус - англ
    use 'skanehira/translate.vim'
    --- popup окошки
    use 'nvim-lua/popup.nvim'
    -- Обрамляет или снимает обрамление. Выдели слово, нажми S и набери <h1>
    use 'tpope/vim-surround'
    -- Считает кол-во совпадений при поиске
    use 'google/vim-searchindex'
    -- Может повторять через . vimsurround
    use 'tpope/vim-repeat'
    -- Стартовая страница, если просто набрать vim в консоле
    use 'mhinz/vim-startify'
    -- Комментирует по gc все, вне зависимости от языка программирования
    use { 'numToStr/Comment.nvim',
    config = function() require('Comment').setup() end }
    -- Обрамляет строку в теги по ctrl- y + ,
    use 'mattn/emmet-vim'
    -- Закрывает автоматом скобки
    use 'cohama/lexima.vim'
    -- Линтер, работает для всех языков
    use 'dense-analysis/ale'

end)

За установку плагинов для lua отвечает менеджер packer.nvim. Принцип работы такой же, как и у обычных менеджеров.

О плагинах

Некоторые плагины я удалил, которые были в init.vim, некоторые добавил или заменил. Об этом и пойдет дальше речь.

nvim-lspconfig и nvim-lsp-installer

Работа плагина nvim-lsp-installer
Работа плагина nvim-lsp-installer

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

Допустим, вы открыли два файла, один написан на Rust, а другой на Typescript. На гиф-ке сверху видно, как плагин nvim-lsp-installer устанавливает сервера для этих языков, а как только сервера были установлены, мгновенно заработали линтеры с критикой кода. Для работы nvim-lsp-installer требуется плагин nvim-lspconfig. Если ввести команду :LspInstallInfo , то можно увидеть список поддерживаемых на данный момент языков (сейчас, когда я это пишу, их 57).

nvim-cmp

Nvim-cmp - это движок, на котором строятся любые автодополнения. Движок написан на lua. Можно посмотреть в моем файле plugins.lua, какие я еще использую встроенные исходники. Например, чтобы работал автокомплит по путям в файловой системе, используется cmp-path, для lsp - cmp-nvim-lsp и т.д.

telescope.nvim

telescope.nvim
telescope.nvim

Telescope.nvim - модная по нынешним временам штуковина. В своей прошлой статье, я писал о плагинах fzf и ack.vim. Плагин fzf отвечал за нечеткий поиск по файлам, а ack - когда нужно грепнуть какое-нибудь слово. Так вот Телескоп делает обе эти вещи в одном флаконе. Умеет делать нечеткий поиск по файлам и умеет искать слово внутри файлов. И делает это все в модальном всплывающем окошке.

Comment.nvim

Comment.nvim
Comment.nvim

Я на гиф-ке выше выделяю код, нажимаю gc , и он закоменчен. Прелесть Comment.nvim в том, что не надо думать, с каким на данный момент я имею дело языком, будь то php, perl или js и т.д. Плагин может закомментарить любой язык по gc. До этого использовал плагин nerdcommenter, но вот перешел на новый, который, как вы уже поняли, написан на lua.

lualine.nvim

lualine.nvim
lualine.nvim

Многим людям в nvim нравилась строчка внизу экрана со всякой там информацией, называлась она airline (в старом init.vim она у меня была). Переписали ее на lua и назвали lualine.nvim. Автор даже не поленился и выложил что-то вроде бечмарка, на сколько у него быстрее эта строчка работает.

bufferline.nvim

bufferline.nvim
bufferline.nvim
Скрин кликабельный (работа плагина bufferline.nvim)
Скрин кликабельный (работа плагина bufferline.nvim)

Плагин bufferline.nvim отвечает за работу с табами (буферами) открытых файлов. Я повесил следующие настройки в горячие клавиши, чтобы переключать вкладочки с помощью tab и shift-tab

-- Переключение вкладок с помщью TAB или shift-tab (akinsho/bufferline.nvim)
map('n', '<Tab>', ':BufferLineCycleNext<CR>', default_opts)
map('n', '<S-Tab>', ':BufferLineCyclePrev<CR>', default_opts)

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

Для работы плагина нужны специальные шрифты. Если заходите по ssh с windows, например, используя securecrt или putty, то на винде надо поставить терминальный шрифт nerd, чтобы работали иконки на вкладках.

Комментарии (30)


  1. pcdesign
    03.11.2021 16:12
    +3

    Я тоже прошел этим путем и переписал свой конфиг на lua.

    Полезные ссылки, которые мне помогли при этом:

    1) Гайд на русском языке (есть и английский там же) о том как переехать https://github.com/kuator/nvim-lua-guide-ru

    2) Удобный кик-старт. Да, там все в одном файле, но зато можно сразу запустить и разобраться что к чему https://github.com/nvim-lua/kickstart.nvim

    3) Толковый видео ролик на эту тему: https://www.youtube.com/watch?v=ppMX4LHIuy4

    Всего 10 минут. Очень понятно объясняет.

    4) Я сторонник с нуля собирать, но полезно смотреть за чужим опытом. Отличные готовые сборки:

    https://github.com/NvChad/NvChad

    https://github.com/LunarVim/LunarVim


  1. pmcode
    03.11.2021 17:23
    +1

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

    В VimL тоже можно.

    $ cat ~/.vim/vimrc
    set nocompatible
    
    silent function! IsUnix()
        return has('unix') && !has('macunix') && !has('win32unix')
    endfunction
    
    silent function! IsWindows()
        return has('win16') || has('win32') || has('win64')
    endfunction
    
    if IsWindows()
        let g:root_dir = "~/vimfiles"
    elseif IsUnix()
        let g:root_dir = "~/.vim"
    endif
    
    let g:conf_dir = root_dir . "/vimrc.d"
    exec "source" . g:conf_dir . "/_init.vim"
    
    $ cat ~/.vim/vimrc.d/_init.vim 
    exec "source" . g:conf_dir . "/plug.vim"
    exec "source" . g:conf_dir . "/plugin-settings.vim"
    exec "source" . g:conf_dir . "/commands.vim"
    exec "source" . g:conf_dir . "/settings.vim"
    exec "source" . g:conf_dir . "/autocommands.vim"
    exec "source" . g:conf_dir . "/mappings.vim"
    exec "source" . g:conf_dir . "/colors.vim"

    Для себя пока смыла в neovim не вижу. Пока на серверах vim и bash, модные штуки типа neovim и fish останутся уделом гиков. А vim, как и bash, пока никуда уходить не собираются. Даже не знаю, к счастью это или к сожалению.


  1. rehci
    03.11.2021 17:25

    Я рад, что у vim появится более-менее сносный язык программирования, но вот конфиг на lua, как по мне, вообще нечитаемый.


  1. saidelman
    03.11.2021 19:27
    +2

    -- ]p - вставить на строку выше, [p - ниже
    use 'tpope/vim-unimpaired'

    К слову, это очень классный плагин, который много чего другого делает удобным.
    Я из него часто пользуюсь переходами по объектам из quickfix ([q, ]q), файлами и буферами (f и b соответственно, с теми же префиксами).
    Ещё есть полезные "переключатели": нумерация строк, относительная нумерация строк (удобно для демок отключать, чтобы не шокировать публику), подсветка строки и колонки (опять же на демо удобно включить, чтобы все видели положение курсора), проверка орфографии и ещё пачка.


    1. Rilkener Автор
      03.11.2021 19:56

      Спасибо. Я в свое время поставил его ради "строка выше/ниже", а оказывается многое упустил.


  1. Valery_Kondakoff
    03.11.2021 19:55

    А куда делся ‘set keymap=russian-jcukenwin’?


    1. Rilkener Автор
      03.11.2021 20:02

      А что-то и без этой строки работает :)


  1. borisxm
    04.11.2021 12:43

    Переназначение клавиш удобно делать через b0o/mapx.nvim — он эмулирует семантику VimL и добавляет новые фишки.


    1. Rilkener Автор
      04.11.2021 12:48

      Спасибо. Попробую через этот плагин сделать кнопку для релоада конфига и для открытия конфига.


  1. romwhite
    05.11.2021 22:20
    +1

    Очень классная статья, спасибо! Читая про Vim, всегда найдёшь для себя новое - полезное. Кстати, на прошлой неделе прошёл двухдневный VimConf 2021 - трансляция велась на Твитче. С помощью yt-dlp можно легко скачать и посмотреть оффлайн. Несколько выступлений были как раз по Lua.


    1. pcdesign
      05.11.2021 23:10

      Читая про Vim, всегда найдёшь для себя новое - полезное

      https://habr.com/ru/post/586946/

      Не всегда :) . Вот вроде читал про вим, но уши в трубочку сворачивались от такой статьи и бреда.


      1. romwhite
        06.11.2021 10:41

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


        1. pcdesign
          06.11.2021 11:03

          Да, ладно если бы просто не любил, но был бы при этом профессионалом в лошадях. Тогда было бы любопытно почитать. Но тут ведь и знания равны нуля.

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


  1. CrazyOpossum
    08.11.2021 16:33

    Literate lua для этого нет? Для vim был проект https://github.com/thcipriani/literate-vimrc. Можно сочетать плюсы от хранения конфига в одном файле с удобством навигации по markdown?


  1. mitar843
    09.11.2021 16:31

    На самом деле в Lua/Neovim есть только три хорошие вещи:

    1. Выучить новый язык - это весело. Если для автора этот пункт действительно стоит на первом месте, то мое почтение. Хотя может стоило тогда поучить Lua и без привязки к Neovim'у?

    2. Можно писать по-настоящему большие и сложные плагины (а никакой не "init", который что на Lua, что на VimScript будет работать одинаково). Вот только я с ужасом представляю как кто-нибудь теперь возьмет да и напишет builtin web browser, "чтобы было как в emacs'е". Вот такого нам точно не надо!

    3. Можно обращаться к OS API напрямую из модулей расширения Lua. Сам такое делал, чтобы работать с системным clipboard'ом без костылей типа xclip/xsel/wl-copy и разный прочий win32yank. Классная штука, но редко кому нужная. Плюс 99% кода будет на том же C, так что под пункт "изучить Lua" влезает с очень большой натяжкой.

    Все остальное - это действительно "мода для гиков". Использовать разные плагины, держать свой код в удобочитаемом состоянии и т.п. можно хоть на Lua, хоть на VimScript. А если не получается, то виноваты во всем руки, но никак не язык.

    >Единственная проблема возникла с перечитыванием конфигов

    Ну так require же имеет свой кэш и просто так повторно ничего читать не хочет. Можно его, конечно, принудительно вычищать как рекомендуют по ссылке, но правильнее, наверное, в init'е все сразу сделать через dofile. Но тогда придется указывать путь полностью.


  1. Mitai
    26.11.2021 13:48

    как в luа прописать noswapfile?


    1. Rilkener Автор
      26.11.2021 15:08

      vim.opt.noswapfile = true

      Может так?


      1. Mitai
        26.11.2021 16:23

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


        1. Rilkener Автор
          26.11.2021 17:03

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

          На счет ваших вопросов. Думаю, что поддержка мышки не включена:

          vim.opt.mouse = 'a' 

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


          1. Mitai
            27.11.2021 14:00

            Cогласен полнотью, НО буду поэтапно пробовать юзать) пока сложно отказаться от мышки))


      1. Mitai
        27.11.2021 16:33

        Not a valid option name: noswapfile


        1. Rilkener Автор
          27.11.2021 22:19

          vim.cmd('set noswapfile')  

          Можно вот так запускать. Но мне кажется в этой команде больше нет нужды.


  1. Rilkener Автор
    26.11.2021 17:02

    del


  1. Mitai
    27.11.2021 21:06

    Простите что я вам надоедаю, а можно как то в неовим отображать цвет и иконки? используемые в коде?))


    1. Rilkener Автор
      27.11.2021 22:21

      Не очень понял о каких конкретно цветах и иконках идет речь.


      1. Mitai
        29.11.2021 20:06

        те что идут перед номерацией строк, белый квадратик.зеленый квадритик, и на нижнем слайде иконка +


        1. pcdesign
          02.12.2021 09:19

          Надо понять какой плагин у вас отвечает за это. Покажите список плагинов, которые вы используете.


          1. Mitai
            02.12.2021 12:21

            скрины из вскода, были сделанны, как такое можно сделать в неовим?


            1. pcdesign
              02.12.2021 12:46

              Лично я этим плагином пользуюсь

              https://github.com/ap/vim-css-color


  1. luvs
    02.12.2021 21:13

    В bufferline есть удобная функция BufferLinePick, выбор вкладки одной буквой, получается даже быстрее чем искать через fzf (и close еще так же умеет делать).