└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # Початок роботи з Lua в Neovim 2 | 3 | ## Інші переклади 4 | 5 | - [:uk: English version](https://github.com/nanotee/nvim-lua-guide) 6 | - [:cn: Chinese version](https://github.com/glepnir/nvim-lua-guide-zh) 7 | - [:es: Spanish version](https://github.com/RicardoRien/nvim-lua-guide/blob/master/README.esp.md) 8 | - [:brazil: Portuguese version](https://github.com/npxbr/nvim-lua-guide/blob/master/README.pt-br.md) 9 | - [:jp: Japanese version](https://github.com/willelz/nvim-lua-guide-ja/blob/master/README.ja.md) 10 | - [:ru: Russian version](https://github.com/kuator/nvim-lua-guide-ru) 11 | 12 | ## Зміст 13 | 14 | - [Початок](#початок) 15 | - [Вивчення Lua](#вивчення-lua) 16 | - [Існуючі туторіали](#існуючі-туторіали-по-написанню-lua-в-neovim) 17 | - [Допоміжні плагіни](#допоміжні-плагіни) 18 | - [Куди класти Lua файли](#куди-класти-lua-файли) 19 | - [init.lua](#initlua) 20 | - [Модулі](#модулі) 21 | - [Поради](#поради) 22 | - [Файли рантайму](#файли-рантайму) 23 | - [Поради](#поради) 24 | - [Використання Lua у Vimscript](#використання-lua-у-vimscript) 25 | - [:lua](#lua) 26 | - [:luado](#luado) 27 | - [Підключення Lua файлів](#підключення-lua-файлів) 28 | - [Різниця між підключенням та викликом require()](#різниця-між-підключенням-та-викликом-require) 29 | - [luaeval()](#luaeval) 30 | - [v:lua](#vlua) 31 | - [Застереження](#застереження) 32 | - [Поради](#поради) 33 | - [Простір імен vim](#простір-імен-vim) 34 | - [Поради](#поради) 35 | 36 | ## Початок 37 | 38 | [Інтеграція Lua](https://www.youtube.com/watch?v=IP3J56sKtn0) в якості [першокласної мови всередині Neovim](https://github.com/neovim/neovim/wiki/FAQ#why-embed-lua-instead-of-x) перетворює її в одну із найважливіших особливостей. Тим не менш, кількість учбових матеріалів по розробці плагінів на Lua значно менше ніж аналогічних матеріалів на Vimscript. Цей довідник спроба надати базову інформацію для початку. 39 | 40 | > Довідник написаний з припущенням, що ви використовуєте що найменш 0.5 версію Neovim. 41 | 42 | ### Вивчення Lua 43 | 44 | Якщо ви ще не знайомі з цією мовою програмування, є велике різноманіття ресурсів щоб почати: 45 | 46 | - [Learn X in Y minutes page about Lua](https://learnxinyminutes.com/docs/lua/) надасть вам швидкий огляд основи мови 47 | - [Цей гайд](https://github.com/medwatt/Notes/blob/main/Lua/Lua_Quick_Guide.ipynb) також добрий ресурс для швидкого початку 48 | - Якщо вам більше подобаються відео, [1-hour tutorial on the language](https://www.youtube.com/watch?v=iMacxZQMPXs) 49 | - Потрібно більше інтерактивних прикладів? Спробуй [the LuaScript tutorial](https://www.luascript.dev/learn) 50 | - [Lua-users wiki](http://lua-users.org/wiki/LuaDirectory) великий обсяг корисної інформації по Lua 51 | - [Official reference manual for Lua](https://www.lua.org/manual/5.1/) може дати тобі найкомплексний огляд мови (Є Vimdoc плагін для читання всередині Neovim: [milisims/nvim-luaref](https://github.com/milisims/nvim-luaref)) 52 | 53 | Слід зазначити що Lua дуже проста мова програмування. Її легко вчити, особливо якщо ви маєте досвід зі схожими мовами - наприклад Javscript. Ви можете знати Lua більше ніж вважаєте! 54 | 55 | > Інтегрована версія Lua у Neovim [LuaJIT](https://staff.fnwi.uva.nl/h.vandermeer/docs/lua/luajit/luajit_intro.html) 2.1.0, що підтримує сумісність з Lua 5.1. 56 | 57 | ### Існуючі туторіали по написанню Lua в Neovim 58 | 59 | Декілька туторіалів вже написані щоб допомогти розроблювати Lua плагіни для Neovim. Деякі з них трохи допомогли написати цей довідник. Велика вдячність авторам. 60 | 61 | - [teukka.tech - From init.vim to init.lua](https://teukka.tech/luanvim.html) 62 | - [dev.to - How to write neovim plugins in Lua](https://dev.to/2nit/how-to-write-neovim-plugins-in-lua-5cca) 63 | - [dev.to - How to make UI for neovim plugins in Lua](https://dev.to/2nit/how-to-make-ui-for-neovim-plugins-in-lua-3b6e) 64 | - [ms-jpq - Neovim Async Tutorial](https://github.com/ms-jpq/neovim-async-tutorial) 65 | - [oroques.dev - Neovim 0.5 features and the switch to init.lua](https://oroques.dev/notes/neovim-init/) 66 | - [Building A Vim Statusline from Scratch - jdhao's blog](https://jdhao.github.io/2019/11/03/vim_custom_statusline/) 67 | - [Configuring Neovim using Lua](https://icyphox.sh/blog/nvim-lua/) 68 | - [Devlog | Everything you need to know to configure neovim using lua](https://vonheikemen.github.io/devlog/tools/configuring-neovim-using-lua/) 69 | 70 | ### Допоміжні плагіни 71 | 72 | - [Vimpeccable](https://github.com/svermeulen/vimpeccable) - Допоміжний плагін для написання `.vimrc` на Lua 73 | - [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) - Плагін, щоб не писати всі функції Lua двічі 74 | - [popup.nvim](https://github.com/nvim-lua/popup.nvim) - Імплементація Popup API з vim 75 | - [nvim_utils](https://github.com/norcalli/nvim_utils) - Допоміжні утіліти 76 | - [nvim-luadev](https://github.com/bfredl/nvim-luadev) - REPL/дебаг консоль для розробки Lua плагінів 77 | - [nvim-luapad](https://github.com/rafcamlet/nvim-luapad) - Інтерактивна пісочниця для вбудованого Lua 78 | - [nlua.nvim](https://github.com/tjdevries/nlua.nvim) - Lua розробка для Neovim 79 | - [BetterLua.vim](https://github.com/euclidianAce/BetterLua.vim) - Краще підсвічування синтаксису Lua у Vim/NeoVim 80 | 81 | ## Куди класти Lua файли 82 | 83 | ### init.lua 84 | 85 | Neovim підтримує здатність використовувати конфіги написані на Lua - `init.lua`, окрім звичного `init.vim` 86 | 87 | > `init.lua` звісно **опціональний** формат для конфігурації. Підтримка `init.vim` не зникла, та може використовуватись разом з Lua-конфігом. Також поки що не всі функції редактора підтримуються через Lua. 88 | 89 | Дивіться також: 90 | 91 | - [`:help config`](https://neovim.io/doc/user/starting.html#config) 92 | 93 | ### Модулі 94 | 95 | Lua модулі можна знайти всередині `lua/` директорії в вашому `'runtimepath'` (для більшості юзерів це буде `~/.config/nvim/lua` на \*nix системах та `~/AppData/Local/nvim/lua` на Windows. За допомогою функції `require()` ви можете імпортити модулі з ціеї директорії. 96 | 97 | Давайте розглянемо структуру директорій: 98 | 99 | ```text 100 | 📂 ~/.config/nvim 101 | ├── 📁 after 102 | ├── 📁 ftplugin 103 | ├── 📂 lua 104 | │ ├── 🌑 myluamodule.lua 105 | │ └── 📂 other_modules 106 | │ ├── 🌑 anothermodule.lua 107 | │ └── 🌑 init.lua 108 | ├── 📁 pack 109 | ├── 📁 plugin 110 | ├── 📁 syntax 111 | └── 🇻 init.vim 112 | ``` 113 | 114 | Наступний код завантажить `myluamodule.lua`: 115 | 116 | ```lua 117 | require('myluamodule') 118 | ``` 119 | 120 | Можете не вказувати розширення `.lua`. 121 | Схожим чином завантаження `other_modules/anothermodule.lua` виглядає так: 122 | 123 | ```lua 124 | require('other_modules.anothermodule') 125 | ``` 126 | 127 | або 128 | 129 | ```lua 130 | require('other_modules/anothermodule') 131 | ``` 132 | 133 | Розділителі шляху можуть бути крапкою `.` або слешем `/`. 134 | 135 | Якщо ви намагаєтесь завантажити не існуючий модуль, це призведе до помилки та відміни виконання скрипта. 136 | `pcall()` функція може бути використана для запобігання помилок. 137 | 138 | ```lua 139 | local ok, _ = pcall(require, 'module_with_error') 140 | if not ok then 141 | -- не заванжувати 142 | end 143 | ``` 144 | 145 | Дивіться також: 146 | 147 | - [`:help lua-require`](https://neovim.io/doc/user/lua.html#lua-require) 148 | 149 | #### Поради 150 | 151 | Деякі плагіни можуть мати однакові імена файлів у `lua/` директорії. Це може призвести до конфлікту простору імен. 152 | 153 | Якщо два різних плагіни мають файл `lua/main.lua`, а потім завантажуються шляхом `require('main')`, то який з них буде використаний? 154 | 155 | Тому буде гарною ідеєю покласти кожен `main.lua` файл у діректорію з назвою плагіну: `lua/plugin_name/main.lua` 156 | 157 | ### Файли рантайму 158 | 159 | Як і Vimscript файли, Lua файли можуть бути завантажені автоматично зі спеціальної директорії `runtimepath`. На даний час підтримуються наступні назви директорій: 160 | 161 | - `colors/` 162 | - `compiler/` 163 | - `ftplugin/` 164 | - `ftdetect/` 165 | - `indent/` 166 | - `plugin/` 167 | - `syntax/` 168 | 169 | > У рантайм директорії, усі `*.vim` файли мають бути визвані після `*.lua` файлів. 170 | 171 | Дивіться також: 172 | 173 | - [`:help 'runtimepath'`](https://neovim.io/doc/user/options.html#'runtimepath') 174 | - [`:help load-plugins`](https://neovim.io/doc/user/starting.html#load-plugins) 175 | 176 | #### Поради 177 | 178 | Поки файли рантайму не базуються на системі модулів Lua, два плагіни можуть мати файл `plugin/main.lua` без проблем. 179 | 180 | ## Використання Lua у Vimscript 181 | 182 | ### :lua 183 | 184 | Ця команда виконує шматок Lua коду. 185 | 186 | ```lua 187 | :lua require('myluamodule') 188 | ``` 189 | 190 | За допомогою heredoc синтаксису можливо виконувати багаторядкові скріпти: 191 | 192 | ```vim 193 | echo "Here's a bigger chunk of Lua code" 194 | 195 | lua << EOF 196 | local mod = require('mymodule') 197 | local tbl = {1, 2, 3} 198 | 199 | for k, v in ipairs(tbl) do 200 | mod.method(v) 201 | end 202 | 203 | print(tbl) 204 | EOF 205 | ``` 206 | 207 | > Кожна `lua` команда має свою область бачення та змінні оголошені з ключовим словом `local` не будуть доступні за межами команди. Приклад: 208 | 209 | ```vim 210 | :lua local foo = 1 211 | :lua print(foo) 212 | " виведе 'nil' замість '1' 213 | ``` 214 | 215 | > Lua функція `print()` поводиться схоже до `:echomsg` команди. Вихідні дані будуть збережені у історіі повідомлень. 216 | 217 | Дивіться також: 218 | 219 | - [`:help :lua`](https://neovim.io/doc/user/lua.html#Lua) 220 | - [`:help :lua-heredoc`](https://neovim.io/doc/user/lua.html#:lua-heredoc) 221 | 222 | ### :luado 223 | 224 | Ця команда виконує шматок Lua коду який діє на діапазон рядків у поточному буфері. Якщо рядки не зазначені, то для цілого буферу. Будь-який рядок який повернувся з блоку, використовується для визначення того, чим слід замінити кожен рядок. 225 | 226 | Наступна команда замінила би кожен рядок у поточному буфері текстом `hello world`: 227 | 228 | ```vim 229 | :luado return 'hello world' 230 | ``` 231 | 232 | Дві неявні змінні `line` та `linenr` також доступні. `line` – це текст рядка, а `linenr` – номер. Наступна команда зробить кожен рядок у верхньому регістрі, якщо номер рядка ділиться на 2 без залишку: 233 | 234 | ```vim 235 | :luado if linenr % 2 == 0 then return line:upper() end 236 | ``` 237 | 238 | Дивіться також: 239 | 240 | - [`:help :luado`](https://neovim.io/doc/user/lua.html#:luado) 241 | 242 | ### Підключення Lua файлів 243 | 244 | Neovim надає 3 Ex команди щоб підключити Lua файли: 245 | 246 | - `:luafile` 247 | - `:source` 248 | - `:runtime` 249 | 250 | `:luafile` та `:source` дуже схожі: 251 | 252 | ```vim 253 | :luafile ~/foo/bar/baz/myluafile.lua 254 | :luafile % 255 | :source ~/foo/bar/baz/myluafile.lua 256 | :source % 257 | ``` 258 | 259 | `:source` також підтримує діапазони, котрі будуть корисні для виконання частини скрипту: 260 | 261 | ```vim 262 | :1,10source 263 | ``` 264 | 265 | Команда `runtime` дещо відрізняється: вона використовує `'runtimepath'` опцію для визначення директорії звідки будуть підключені файли. Більшe деталей: [`:help :runtime`](https://neovim.io/doc/user/repeat.html#:runtime). 266 | 267 | Дивіться також: 268 | 269 | - [`:help :luafile`](https://neovim.io/doc/user/lua.html#:luafile) 270 | - [`:help :source`](https://neovim.io/doc/user/repeat.html#:source) 271 | - [`:help :runtime`](https://neovim.io/doc/user/repeat.html#:runtime) 272 | 273 | #### Різниця між підключенням та викликом require(): 274 | 275 | Можливо вам цікаво у чому різниця та чи варто віддавати перевагу одному способу над іншим. Вони мають різні випадки використання: 276 | 277 | - `require()`: 278 | - вбудована функція Lua. Дозволяє користуватися перевагами модульної системи Lua 279 | - шукає модулі у директорії `lua/` у вашому `'runtimepath'` 280 | - дозволяє слідкувати за тим які модулі були завантажені та запобігає повторному парсингу та виконанню скрипта. Якщо ви зміните код у вже завантаженому модулі та спробуєте завантажити його через `require()` ще раз, то зміни не застосуються. 281 | - `:luafile`, `:source`, `:runtime`: 282 | - Ex команди. Не підтримують модулі 283 | - повторно виконують раніше виконані скрипти 284 | - `:luafile` та `:source` приймають шлях до файлу як абсолютний так і відносний до робочої директорії поточного вікна 285 | - `:runtime` використовує `'runtimepath'` опцію щоб знайти файли 286 | 287 | ### luaeval() 288 | 289 | Ця вбудована Vimscript функція виконує Lua вираження та повертає результат. Типи данних Lua автоматично конвертуються у Vimscript типи (і навпаки). 290 | 291 | ```vim 292 | " You can store the result in a variable 293 | let variable = luaeval('1 + 1') 294 | echo variable 295 | " 2 296 | let concat = luaeval('"Lua".." is ".."awesome"') 297 | echo concat 298 | " 'Lua is awesome' 299 | 300 | " List-like tables are converted to Vim lists 301 | let list = luaeval('{1, 2, 3, 4}') 302 | echo list[0] 303 | " 1 304 | echo list[1] 305 | " 2 306 | " Note that unlike Lua tables, Vim lists are 0-indexed 307 | 308 | " Dict-like tables are converted to Vim dictionaries 309 | let dict = luaeval('{foo = "bar", baz = "qux"}') 310 | echo dict.foo 311 | " 'bar' 312 | 313 | " Same thing for booleans and nil 314 | echo luaeval('true') 315 | " v:true 316 | echo luaeval('nil') 317 | " v:null 318 | 319 | " You can create Vimscript aliases for Lua functions 320 | let LuaMathPow = luaeval('math.pow') 321 | echo LuaMathPow(2, 2) 322 | " 4 323 | let LuaModuleFunction = luaeval('require("mymodule").myfunction') 324 | call LuaModuleFunction() 325 | 326 | " It is also possible to pass Lua functions as values to Vim functions 327 | lua X = function(k, v) return string.format("%s:%s", k, v) end 328 | ``` 329 | 330 | `luaeval()` приймає опціональний другий аргумент який дозволяє передавати дані до вираження. Потім у вас буде доступ до данних через магічну глобальну змінну `_A`: 331 | 332 | ```vim 333 | echo luaeval('_A[1] + _A[2]', [1, 1]) 334 | " 2 335 | 336 | echo luaeval('string.format("Lua is %s", _A)', 'awesome') 337 | " 'Lua is awesome' 338 | ``` 339 | 340 | Дивіться також: 341 | 342 | - [`:help luaeval()`]() 343 | 344 | ### v:lua 345 | 346 | Це глобальна Vim змінна дозволяє вам викликати Lua функції у глобальному просторі імен ([`_G`](https://www.lua.org/manual/5.1/manual.html#pdf-_G)) напряму з Vimscript. І знову типи данних Vim будуть сконвертовані у Lua типи і навпаки. 347 | 348 | ```vim 349 | call v:lua.print('Hello from Lua!') 350 | " 'Hello from Lua!' 351 | 352 | let scream = v:lua.string.rep('A', 10) 353 | echo scream 354 | " 'AAAAAAAAAA' 355 | 356 | " How about a nice statusline? 357 | lua << EOF 358 | 359 | " How about a nice statusline? 360 | lua << EOF 361 | function _G.statusline() 362 | local filepath = '%f' 363 | local align_section = '%=' 364 | local percentage_through_file = '%p%%' 365 | return string.format( 366 | '%s%s%s', 367 | filepath, 368 | align_section, 369 | percentage_through_file 370 | ) 371 | end 372 | EOF 373 | 374 | set statusline=%!v:lua.statusline() 375 | 376 | " Also works in expression mappings 377 | lua << EOF 378 | function _G.check_back_space() 379 | local col = vim.api.nvim_win_get_cursor(0)[2] 380 | return (col == 0 or vim.api.nvim_get_current_line():sub(col, col):match('%s')) and true 381 | end 382 | EOF 383 | 384 | inoremap 385 | \ pumvisible() ? "\" : 386 | \ v:lua.check_back_space() ? "\" : 387 | \ completion#trigger_completion() 388 | 389 | " Call a function from a Lua module by using single quotes and omitting parentheses: 390 | call v:lua.require'module'.foo() 391 | ``` 392 | 393 | Дивіться також: 394 | 395 | - [`:help v:lua`](https://neovim.io/doc/user/eval.html#v:lua) 396 | - [`:help v:lua-call`](https://neovim.io/doc/user/lua.html#v:lua-call) 397 | 398 | #### Застереження 399 | 400 | Ця змінна може бути використана тільки для виклику функцій. Наступний код завжди буде викидувати помилку: 401 | 402 | ```vim 403 | " Aliasing functions doesn't work 404 | let LuaPrint = v:lua.print 405 | 406 | " Accessing dictionaries doesn't work 407 | echo v:lua.some_global_dict['key'] 408 | 409 | " Using a function as a value doesn't work 410 | echo map([1, 2, 3], v:lua.global_callback) 411 | ``` 412 | 413 | ### Поради 414 | 415 | Ви можете увімкнути підсвічення синтаксису Lua всередині `.vim` файлів. Додайте `let g:vimsyn_embed = 'l'` до вашого файлу конфігурації. Більше інформаціЇ [`:help g:vimsyn_embed`](https://neovim.io/doc/user/syntax.html#g:vimsyn_embed). 416 | 417 | ## Простір імен vim 418 | 419 | Neovim має глобальну змінну `vim` яка є вхідною точкою до API з Lua коду. Це надає користувачам розширену стандартну бібліотеку функцій, а також різноманітні підмодулі. 420 | 421 | Деякі важливі функції та модулі: 422 | 423 | - `vim.inspect`: трансформує Lua обʼєкти до людино-зрозумілий вигляду (корисно для інспектування Lua таблиць) 424 | - `vim.regex`: використовуйте регулярні вираження vim із Lua 425 | - `vim.api`: модуль який надає доступ до API функцій (також використовується віддаленими плагінами) 426 | - `vim.ui`: UI функції 427 | - `vim.loop`: модуль для доступу до event-loop (використовує LibUV) 428 | - `vim.lsp`: модуль що контролює вбудований LSP клієнт 429 | - `vim.treesitter`: модуль для доступу до функціоналу бібліотеки tree-sitter 430 | 431 | Цей список не є вичерпним. Якщо ви бажаєте знати що доступно через `vim` змінну, [`:help lua-stdlib`](https://neovim.io/doc/user/lua.html#lua-stdlib) та [`:help lua-vim`](https://neovim.io/doc/user/lua.html#lua-vim). Додатково, ви можете використовувати команду `:lua print(vim.inspect(vim))` щоб отримати повний список модулів. API функції теж документовані [`:help api-global`](https://neovim.io/doc/user/api.html#api-global). 432 | 433 | #### Поради 434 | 435 | Писати `print(vim.inspect(x))` кожен раз коли треба проінспектувати вміст обʼєкта може бути нудним процесом. Можливо, варто мати глобальну обгортку десь у файлі конфігурації (у Neovim 0.7.9+, ця функція вбудована, більше інформації [`:help vim.pretty_print()`]()): 436 | 437 | ```lua 438 | function _G.put(...) 439 | local objects = {} 440 | for i = 1, select('#', ...) do 441 | local v = select(i, ...) 442 | table.insert(objects, vim.inspect(v)) 443 | end 444 | 445 | print(table.concat(objects, '\n')) 446 | return ... 447 | end 448 | ``` 449 | 450 | You can then inspect the contents of an object very quickly in your code or from the command-line: 451 | Тепер ви можете інспектувати вміст обʼєкту швидко у вашому коді чи через командний рядок: 452 | 453 | ```lua 454 | put({1, 2, 3}) 455 | ``` 456 | 457 | ```vim 458 | :lua put(vim.loop) 459 | ``` 460 | 461 | Додатково ви можете використовувати `:lua` команду для красиво вивести вираження додавши до нього префікс `=` (Neovim 0.7+) 462 | 463 | ```vim 464 | :lua =vim.loop 465 | ``` 466 | --------------------------------------------------------------------------------