From 27aa5bf4452a9da91d6a8f52cb32eb82ae95e015 Mon Sep 17 00:00:00 2001 From: krapjost Date: Wed, 17 Aug 2022 00:45:48 +0900 Subject: [PATCH] Add Korean translation --- README.html | 1 - README.md | 610 ++++++++++----------- README.md.tmp | 1401 ------------------------------------------------- 3 files changed, 287 insertions(+), 1725 deletions(-) delete mode 100644 README.html delete mode 100644 README.md.tmp diff --git a/README.html b/README.html deleted file mode 100644 index a5d4406..0000000 --- a/README.html +++ /dev/null @@ -1 +0,0 @@ -/usr/bin/pandoc: error while loading shared libraries: libHSyaml-0.11.8.0-5AS3EkKRYJNMdpDppUxYf-ghc9.0.2.so: cannot open shared object file: No such file or directory diff --git a/README.md b/README.md index 3a59cdd..86c8b07 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ :arrow_upper_left: (Feeling lost? Use the GitHub TOC!) -# Neovim에서 Lua 사용 시작하기 +# Getting started using Lua in Neovim -## 번역 +## Translations - [:cn: Chinese version](https://github.com/glepnir/nvim-lua-guide-zh) - [:es: Spanish version](https://github.com/RicardoRien/nvim-lua-guide/blob/master/README.esp.md) @@ -10,35 +10,33 @@ - [:jp: Japanese version](https://github.com/willelz/nvim-lua-guide-ja/blob/master/README.ja.md) - [:ru: Russian version](https://github.com/kuator/nvim-lua-guide-ru) - [🇺🇦 Ukrainian version](https://github.com/famiclone/nvim-lua-guide-ua) +- [:kr: Korean version](https://github.com/krapjost/nvim-lua-guide-kr) -## 소개 +## Introduction -[네오빔에서 first-class 언어](https://github.com/neovim/neovim/wiki/FAQ#why-embed-lua-instead-of-x)로서 [통합된 루아](https://www.youtube.com/watch?v=IP3J56sKtn0)는 킬러 피쳐들 중 하나로 자리잡고 있습니다. -하지만 루아로 플러그인 작성하는 방법에 대해 배울 수 있는 자료는 빔스크립트로 작성하는 방법에 비해 많지 않습니다. -그래서 사람들이 좀 더 쉽게 시작할 수 있도록 기본적인 정보를 제공하려고 합니다. +The [integration of Lua](https://www.youtube.com/watch?v=IP3J56sKtn0) as a [first-class language inside Neovim](https://github.com/neovim/neovim/wiki/FAQ#why-embed-lua-instead-of-x) is shaping up to be one of its killer features. +However, the amount of teaching material for learning how to write plugins in Lua is not as large as what you would find for writing them in Vimscript. This is an attempt at providing some basic information to get people started. -이 가이드는 당신이 최소 Neovim 0.5 버전 이상을 사용하고 있다고 가정합니다. +This guide assumes you are using at least version 0.5 of Neovim. -### 루아 배우기 +### Learning Lua -루아에 익숙하지 않다면 여기 시작하기에 좋은 자료들이 많이 있습니다. +If you are not already familiar with the language, there are plenty of resources to get started: -- ['X를 Y분 만에 배우자'의 루아 페이지](https://learnxinyminutes.com/docs/lua/)에서는 기본적인 것들을 빠르게 훑어볼 수 있습니다. -- [이 가이드](https://github.com/medwatt/알림s/blob/main/Lua/Lua_Quick_Guide.ipynb)도 빠르게 시작하기 좋은 자료입니다. -- 당신이 비디오로 배우는 것을 더 선호한다면 Derek Banas의 [1 시간짜리 튜토리얼](https://www.youtube.com/watch?v=iMacxZQMPXs)도 있습니다. -- 실행 가능한 예제와 함께 좀 더 인터랙티브하게 배우고 싶다면 [루아 스크립트 튜토리얼](https://www.luascript.dev/learn)도 있습니다. -- [루아 유저 위키](http://lua-users.org/wiki/LuaDirectory)에는 루아와 관련된 유용한 정보들이 많이 있습니다. -- [루아 공식 레퍼런스 매뉴얼](https://www.lua.org/manual/5.1/)은 가장 광범위한 자료를 둘러볼 수 있습니다.(빔 에디터 내에서 읽고 싶다면 Vimdoc 플러그인으로도 있습니다.: [milisims/nvim-luaref](https://github.com/milisims/nvim-luaref)) +- The [Learn X in Y minutes page about Lua](https://learnxinyminutes.com/docs/lua/) should give you a quick overview of the basics +- [This guide](https://github.com/medwatt/Notes/blob/main/Lua/Lua_Quick_Guide.ipynb) is also a good resource for getting started quickly +- If videos are more to your liking, Derek Banas has a [1-hour tutorial on the language](https://www.youtube.com/watch?v=iMacxZQMPXs) +- Want something a little more interactive with runnable examples? Try [the LuaScript tutorial](https://www.luascript.dev/learn) +- The [lua-users wiki](http://lua-users.org/wiki/LuaDirectory) is full of useful information on all kinds of Lua-related topics +- The [official reference manual for Lua](https://www.lua.org/manual/5.1/) should give you the most comprehensive tour of the language (exists as a Vimdoc plugin if you want to read it from the comfort of your editor: [milisims/nvim-luaref](https://github.com/milisims/nvim-luaref)) -먼저 루아는 정말 깔끔하고 단순한 언어라는 것을 말하고 시작하고 싶습니다. 배우기 쉬운 언어이고, -특히 자바스크립트같은 스트립팅 언어에 대한 경험이 있다면 더욱 쉽게 배울 수 있습니다. -아마 이미 생각보다 루아에 대해 더 많은 것을 알고 있을지도 모릅니다. +It should also be noted that Lua is a very clean and simple language. It is easy to learn, especially if you have experience with similar scripting languages like JavaScript. You may already know more Lua than you realise! -알림: 네오빔에 내장된 루아 컴파일러는 [LuaJIT](https://staff.fnwi.uva.nl/h.vandermeer/docs/lua/luajit/luajit_intro.html) 2.1.0 버전입니다. 루아 5.1 버전과 호환 가능합니다. +Note: the version of Lua that Neovim embeds is [LuaJIT](https://staff.fnwi.uva.nl/h.vandermeer/docs/lua/luajit/luajit_intro.html) 2.1.0, which maintains compatibility with Lua 5.1. -### 네오빔에서 루아 작성하기에 대한 튜토리얼들 +### Existing tutorials for writing Lua in Neovim -루아로 네오빔 설정하기에 관해 다음 튜토리얼들이 이미 있습니다. 그 중에서 이 가이드를 쓰는데 도움 받은 것도 있습니다. 작성자들에게 정말 감사합니다. +A few tutorials have already been written to help people write plugins in Lua. Some of them helped quite a bit when writing this guide. Many thanks to their authors. - [teukka.tech - From init.vim to init.lua](https://teukka.tech/luanvim.html) - [dev.to - How to write neovim plugins in Lua](https://dev.to/2nit/how-to-write-neovim-plugins-in-lua-5cca) @@ -49,33 +47,33 @@ - [Configuring Neovim using Lua](https://icyphox.sh/blog/nvim-lua/) - [Devlog | Everything you need to know to configure neovim using lua](https://vonheikemen.github.io/devlog/tools/configuring-neovim-using-lua/) -### 도움 될만한 플러그인들 +### Companion plugins -- [Vimpeccable](https://github.com/svermeulen/vimpeccable) - 루아로 .vimrc 작성할 때 도와주는 플러그인 -- [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) - 여러 번 작성하기 싫은 루아 함수들 (헬퍼 함수) -- [popup.nvim](https://github.com/nvim-lua/popup.nvim) - vim 팝업 API를 Neovim에서 구현한 것 +- [Vimpeccable](https://github.com/svermeulen/vimpeccable) - Plugin to help write your .vimrc in Lua +- [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) - All the lua functions I don't want to write twice +- [popup.nvim](https://github.com/nvim-lua/popup.nvim) - An implementation of the Popup API from vim in Neovim - [nvim_utils](https://github.com/norcalli/nvim_utils) -- [nvim-luadev](https://github.com/bfredl/nvim-luadev) - 루아 플러그인들을 위한 REPL/debug 콘솔 -- [nvim-luapad](https://github.com/rafcamlet/nvim-luapad) - 내장된 루아 엔진과 실시간으로 상호작용 할 수 있는 네오빔 스크래치패드 -- [nlua.nvim](https://github.com/tjdevries/nlua.nvim) - Neovim을 위한 루아 개발 도구 -- [BetterLua.vim](https://github.com/euclidianAce/BetterLua.vim) - 더 나은 루아 구문(syntax) 하이라이팅 +- [nvim-luadev](https://github.com/bfredl/nvim-luadev) - REPL/debug console for nvim lua plugins +- [nvim-luapad](https://github.com/rafcamlet/nvim-luapad) - Interactive real time neovim scratchpad for embedded lua engine +- [nlua.nvim](https://github.com/tjdevries/nlua.nvim) - Lua Development for Neovim +- [BetterLua.vim](https://github.com/euclidianAce/BetterLua.vim) - Better Lua syntax highlighting in Vim/NeoVim -## Lua 파일들은 어디에 넣나요 +## Where to put Lua files ### init.lua -Neovim은 `init.vim` 대신 `init.lua` 파일을 설정(configuration) 파일로 로딩할 수도 있습니다. +Neovim supports loading an `init.lua` file for configuration instead of the usual `init.vim`. -알림: `init.lua` 파일을 사용하는 것은 물론 _완전히_ 선택 가능합니다. `init.vim`을 사용해도 상관 없으며 여전히 유효한 설정입니다. vim의 기능들 중 몇몇은 아직 루아로 접근할 수 없다는 것도 기억하면 좋습니다. +Note: `init.lua` is of course _completely_ optional. Support for `init.vim` is not going away and is still a valid option for configuration. Do keep in mind that some features are not 100% exposed to Lua yet. -자세한 정보: +See also: - [`:help config`](https://neovim.io/doc/user/starting.html#config) -### 모듈 +### Modules -루아 모듈들은 Neovim의 `runtimepath` (대부분의 \*nix 시스템 [*맥 | 리눅스*] 에서는 `~/.config/nvim/lua`, 윈도우에서는 `~/AppData/Local/nvim/lua` ) 안의 `lua/` 폴더 안에 위치합니다. 이 폴더 안에 있는 루아 파일들은 모듈로서 `require()` 할 수 있습니다. +Lua modules are found inside a `lua/` folder in your `'runtimepath'` (for most users, this will mean `~/.config/nvim/lua` on \*nix systems and `~/AppData/Local/nvim/lua` on Windows). You can `require()` files in this folder as Lua modules. -다음 폴더 구조를 예시로 한 번 봐봅시다: +Let's take the following folder structure as an example: ```text 📂 ~/.config/nvim @@ -92,15 +90,15 @@ Neovim은 `init.vim` 대신 `init.lua` 파일을 설정(configuration) 파일로 └── 🇻 init.vim ``` -다음 루아 코드는 `myloamodule.lua` 파일을 불러옵니다: +The following Lua code will load `myluamodule.lua`: ```lua require('myluamodule') ``` -`.lua` 확장자가 없는 것을 볼 수 있습니다. +Notice the absence of a `.lua` extension. -비슷하게, `other_modules/anothermodule.lua` 파일을 불러오는 것도 다음과 같습니다: +Similarly, loading `other_modules/anothermodule.lua` is done like so: ```lua require('other_modules.anothermodule') @@ -108,16 +106,16 @@ require('other_modules.anothermodule') require('other_modules/anothermodule') ``` -경로 구분자는 `.`이나 `/`로 표기됩니다. +Path separators are denoted by either a dot `.` or a slash `/`. -`init.lua` 파일을 포함하고 있는 폴더는 파일 이름을 지정하지 않아도 바로 불러올 수 있습니다. +A folder containing an `init.lua` file can be required directly, without having to specify the name of the file. ```lua require('other_modules') -- loads other_modules/init.lua ``` -존재하지 않는 모듈이나 구문 에러를 포함하고 있는 모듈을 불러오게 되면 현재 실행 중인 스크립트가 종료됩니다. -`pcall()` 함수를 사용하면 에러로 인해 스크립트가 종료되는 것을 방지할 수 있습니다. +Requiring a nonexistent module or a module which contains syntax errors aborts the currently executing script. +`pcall()` may be used to prevent errors. ```lua local ok, _ = pcall(require, 'module_with_error') @@ -126,22 +124,20 @@ if not ok then end ``` -자세한 정보: +See also: - [`:help lua-require`](https://neovim.io/doc/user/lua.html#lua-require) #### Tips -루아 플러그인들 중 몇몇은 그 플러그인의 `lua/` 폴더 안에 동일한 파일 이름이 존재할 수도 있습니다. 그럴 경우 이름공간([namespace](https://ko.wikipedia.org/wiki/%EC%9D%B4%EB%A6%84%EA%B3%B5%EA%B0%84)) 충돌로 이어질 수 있습니다. +Several Lua plugins might have identical filenames in their `lua/` folder. This could lead to namespace clashes. -만약 두개의 다른 플러그인이 `lua/main.lua` 파일을 가지고 있다면, `require('main')` 을 실행할 때 어떤 파일을 불러야 하는지 알기 힘듭니다. - -그래서 당신의 설정 파일이나 플러그인들의 namespace를 최상위 폴더와 같이 관리하는 것도 좋은 아이디어일 수 있습니다. 다음과 같이요: -`lua/plugin_name/main.lua` +If two different plugins have a `lua/main.lua` file, then doing `require('main')` is ambiguous: which file do we want to source? +It might be a good idea to namespace your config or your plugin with a top-level folder, like so: `lua/plugin_name/main.lua` ### Runtime files -Vimscript 파일들과 마찬가지로, 루아 파일들도 당신의 `runtimepath`에 지정된 특별한 폴더들에서 자동적으로 불러와질 수 있습니다. 현재는 다음 폴더들이 지원되고 있습니다: +Much like Vimscript files, Lua files can be loaded automatically from special folders in your `runtimepath`. Currently, the following folders are supported: - `colors/` - `compiler/` @@ -151,27 +147,27 @@ Vimscript 파일들과 마찬가지로, 루아 파일들도 당신의 `runtimepa - `plugin/` - `syntax/` -알림: runtime 디렉터리에서는 모든 `*.vim*` 파일들이 `*.lua` 파일들보다 먼저 불러와집니다. +Note: in a runtime directory, all `*.vim` files are sourced before `*.lua` files. -자세한 정보: +See also: - [`:help 'runtimepath'`](https://neovim.io/doc/user/options.html#'runtimepath') - [`:help load-plugins`](https://neovim.io/doc/user/starting.html#load-plugins) #### Tips -runtime 파일들이 Lua 모듈 시스템을 기반으로 하지 않기 때문에 두 플러그인들이 문제 없이 `plugin/main.lua` 파일을 가지고 있을 수 있습니다. +Since runtime files aren't based on the Lua module system, two plugins can have a `plugin/main.lua` file without it being an issue. -## Vimscript에서 Lua 사용하기 +## Using Lua from Vimscript ### :lua -이 명령어는 루아 코드 조각을 실행합니다. +This command executes a chunk of Lua code. ```vim :lua require('myluamodule') ``` -여러 줄의 스크립트는 [heredoc](https://ko.wikipedia.org/wiki/%ED%9E%88%EC%96%B4_%EB%8F%84%ED%81%90%EB%A8%BC%ED%8A%B8)구문을 사용해 실행할 수 있습니다: +Multi-line scripts are possible using heredoc syntax: ```vim echo "Here's a bigger chunk of Lua code" @@ -188,7 +184,7 @@ print(tbl) EOF ``` -알림: `:lua` 명령어는 각각의 scope를 가지고 있으며 `local` 키워드로 선언된 변수들은 명령어 밖에서 접근할 수 없습니다. 다음은 작동하지 않습니다: +Note: each `:lua` command has its own scope and variables declared with the `local` keyword are not accessible outside of the command. This won't work: ```vim :lua local foo = 1 @@ -196,42 +192,42 @@ EOF " prints 'nil' instead of '1' ``` -알림 2: 루아의 `print()` 함수는 `:echomsg` 명령어와 비슷하게 작동합니다. 실행 결과가 message-history에 저장되며 이는 `:silent` 커맨드를 사용해 보이지 않게 할수도 있습니다. +Note 2: the `print()` function in Lua behaves similarly to the `:echomsg` command. Its output is saved in the message-history and can be suppressed by the `:silent` command. -자세한 정보: +See also: - [`:help :lua`](https://neovim.io/doc/user/lua.html#Lua) - [`:help :lua-heredoc`](https://neovim.io/doc/user/lua.html#:lua-heredoc) ### :luado -이 명령어는 현재 버퍼에 라인들의 특정한 범위에 루아 코드를 실행합니다. 만약 범위가 지정되지 않았다면 버퍼 전체에서 실행됩니다. 어떤 string이든 루아 코드에서 `return`되면, 어떤 라인들이 바뀌어야 할지 정해집니다. +This command executes a chunk of Lua code that acts on a range of lines in the current buffer. If no range is specified, the whole buffer is used instead. Whatever string is `return`ed from the chunk is used to determine what each line should be replaced with. -다음 명령은 현재 버퍼의 모든 라인을 `hello world`로 변경합니다: +The following command would replace every line in the current buffer with the text `hello world`: ```vim :luado return 'hello world' ``` -`line`과 `linenr` 변수도 제공됩니다. 각 라인들을 하나씩 반복하는 중에 `linenr`의 숫자는 라인의 인덱스, 그 라인의 내용이 `line` 입니다. 다음 명령어는 2로 나눠질 수 있는 라인들을 대문자로 변경합니다. +Two implicit `line` and `linenr` variables are also provided. `line` is the text of the line being iterated upon whereas `linenr` is its number. The following command would make every line whose number is divisible by 2 uppercase: ```vim :luado if linenr % 2 == 0 then return line:upper() end ``` -자세한 정보: +See also: - [`:help :luado`](https://neovim.io/doc/user/lua.html#:luado) -### 루아 파일 가져오기 (Sourcing Lua files) +### Sourcing Lua files -Neovim은 루아 파일을 가져오기 위해 다음 3개의 실행 명령어들을 제공합니다. +Neovim provides 3 Ex commands to source Lua files - `:luafile` - `:source` - `:runtime` -`:luafile`과 `:source`는 비슷합니다: +`:luafile` and `:source` are very similar: ```vim :luafile ~/foo/bar/baz/myluafile.lua @@ -240,43 +236,42 @@ Neovim은 루아 파일을 가져오기 위해 다음 3개의 실행 명령어 :source % ``` -`:source`는 범위도 지정할 수 있습니다. 스크립트 파일의 일부분만 실행하고 싶을 때 유용합니다: +`:source` also supports ranges, which can be useful to only execute part of a script: ```vim :1,10source ``` -`:runtime`은 조금 다릅니다: `runtimepath` 옵션을 사용해서 어떤 파일을 가져올지 정할 수 있습니다. 더 많은 정보는 [`:help :runtime`](https://neovim.io/doc/user/repeat.html#:runtime)에서 확인할 수 있습니다. +`:runtime` is a little different: it uses the `'runtimepath'` option to determine which files to source. See [`:help :runtime`](https://neovim.io/doc/user/repeat.html#:runtime) for more details. -자세한 정보: +See also: - [`:help :luafile`](https://neovim.io/doc/user/lua.html#:luafile) - [`:help :source`](https://neovim.io/doc/user/repeat.html#:source) - [`:help :runtime`](https://neovim.io/doc/user/repeat.html#:runtime) -#### 루아 파일 가져오기 (sourcing) vs require() 호출하기: +#### Sourcing a lua file vs calling require(): -`require()` 함수를 호출하는 것과 직접 루아 파일을 소싱하는 것의 차이와 어떤 것을 언제 사용해야 할지 궁금할 겁니다. 둘은 다음과 같은 서로 다른 사용 사례들이 있습니다: +You might be wondering what the difference between calling the `require()` function and sourcing a Lua file is and whether you should prefer one way over the other. They have different use cases: - `require()`: - - 루아의 기본 빌트인 함수입니다. 루아 모듈 시스템의 장점을 이용할 수 있게 해줍니다. - - `runtimepath`의 `lua/` 폴더 안에 위치한 모듈들을 검색합니다. - - 어떤 모듈들이 불러와졌는지 계속 추적하여 스크립트가 두 번 파싱되거나 실행되는 것을 방지합니다. 만약 네오빔이 실행되고 있는 중에 모듈의 코드 파일을 수정하고 다시 `require()`를 실행한다면 모듈이 업데이트 되지 않을 것입니다. + - is a built-in Lua function. It allows you to take advantage of Lua's module system + - searches for modules in `lua/` folders in your `'runtimepath'` + - keeps track of what modules have been loaded and prevents a script from being parsed and executed a second time. If you change the file containing the code for a module and try to `require()` it a second time while Neovim is running, the module will not actually update - `:luafile`, `:source` and `:runtime`: - are Ex commands. They do not support modules - - Ex 명령어들입니다. 모듈을 지원하지 않습니다. - - 이전에 실행되었었는지 여부와 상관없이 스크립트의 내용을 실행합니다. - - `:luafile`과 `:source`는 현재 창의 작업 디렉터리(cwd)에서 상대 경로 혹은 절대 경로를 받습니다. - - `:runtime`은 `'runtimepath'` 옵션을 사용하여 파일들을 찾습니다. + - execute the contents of a script regardless of whether it has been executed before + - `:luafile` and `:source` take a path that is either absolute or relative to the working directory of the current window + - `:runtime` uses the `'runtimepath'` option to find files -`:source`, `:runtime`로 불러와졌거나 런타임 디렉터리들에서 자동적으로 불러와진 파일들은 `:scriptnames`와 `--startuptime`에서 볼 수 있습니다. +Files sourced via `:source`, `:runtime` or automatically from runtime directories will also show up in `:scriptnames` and `--startuptime` ### luaeval() -이 빔스크립트 빌트인 함수는 루아 표현식(expression) 문자열의 값을 도출하고 그 값을 리턴합니다. 루아의 데이터 타입들은 자동적으로 빔스크립트 타입들로 변환됩니다. +This built-in Vimscript function evaluates a Lua expression string and returns its value. Lua data types are automatically converted to Vimscript types (and vice versa). ```vim -" 결과값을 변수에 담을 수 있습니다. +" You can store the result in a variable let variable = luaeval('1 + 1') echo variable " 2 @@ -284,39 +279,38 @@ let concat = luaeval('"Lua".." is ".."awesome"') echo concat " 'Lua is awesome' -" 루아의 List-like 테이블은 빔의 리스트로 변환됩니다. +" List-like tables are converted to Vim lists let list = luaeval('{1, 2, 3, 4}') echo list[0] " 1 echo list[1] " 2 -" 알림 루아의 테이블은 1부터 인덱싱 되지만 빔의 리스트는 0부터입니다. +" Note that unlike Lua tables, Vim lists are 0-indexed -" Dict-like 테이블은 빔의 딕셔너리로 변환됩니다. +" Dict-like tables are converted to Vim dictionaries let dict = luaeval('{foo = "bar", baz = "qux"}') echo dict.foo " 'bar' -" booleans과 nil도 마찬가지입니다. +" Same thing for booleans and nil echo luaeval('true') " v:true echo luaeval('nil') " v:null -" 루아 함수들을 빔스크립트에서 alias를 만들어 사용할 수도 있습니다. +" You can create Vimscript aliases for Lua functions let LuaMathPow = luaeval('math.pow') echo LuaMathPow(2, 2) " 4 let LuaModuleFunction = luaeval('require("mymodule").myfunction') call LuaModuleFunction() -" 루아 함수를 빔 함수에 값으로서 전달하는 것도 가능합니다. +" It is also possible to pass Lua functions as values to Vim functions lua X = function(k, v) return string.format("%s:%s", k, v) end echo map([1, 2, 3], luaeval("X")) ``` `luaeval()` takes an optional second argument that allows you to pass data to the expression. You can then access that data from Lua using the magic global `_A`: -`luaeval()`의 두 번째 인자로 루아 표현식에 데이터를 전달하는 것도 가능합니다. 그 데이터는 루아 전역 변수인 `_A`를 사용해 접근할 수 있습니다. ```vim echo luaeval('_A[1] + _A[2]', [1, 1]) @@ -326,12 +320,12 @@ echo luaeval('string.format("Lua is %s", _A)', 'awesome') " 'Lua is awesome' ``` -자세한 정보: +See also: - [`:help luaeval()`](https://neovim.io/doc/user/lua.html#luaeval()) ### v:lua -이 빔의 전역 변수는 루아의 전역 이름공간(namespace)([`_G`](https://www.lua.org/manual/5.1/manual.html#pdf-_G))에 있는 함수들을 빔스크립트에서 직접 접근할 수 있게 해줍니다. 빔의 데이터 타입들은 루아 타입들로 변환되고 반대도 마찬가지입니다. +This global Vim variable allows you to call Lua functions in the global namespace ([`_G`](https://www.lua.org/manual/5.1/manual.html#pdf-_G)) directly from Vimscript. Again, Vim data types are converted to Lua types and vice versa. ```vim call v:lua.print('Hello from Lua!') @@ -342,7 +336,6 @@ echo scream " 'AAAAAAAAAA' " How about a nice statusline? -" 멋진 상태창을 만들어봅시다. lua << EOF function _G.statusline() local filepath = '%f' @@ -360,7 +353,6 @@ EOF set statusline=%!v:lua.statusline() " Also works in expression mappings -" 표현식 매핑들에서도 작동합니다. lua << EOF function _G.check_back_space() local col = vim.api.nvim_win_get_cursor(0)[2] @@ -374,54 +366,51 @@ inoremap \ completion#trigger_completion() " Call a function from a Lua module by using single quotes and omitting parentheses: -" 생략된 괄호와 작은 따옴표를 사용하여 루아 모듈에서 함수를 호출하기: call v:lua.require'module'.foo() ``` -자세한 정보: +See also: - [`:help v:lua`](https://neovim.io/doc/user/eval.html#v:lua) - [`:help v:lua-call`](https://neovim.io/doc/user/lua.html#v:lua-call) -#### 경고 +#### Caveats -이 변수는 함수들을 호출하는 데에만 쓰여질 수 있습니다. 다음 예시들에서는 항상 에러가 발생할 것입니다: +This variable can only be used to call functions. The following will always throw an error: ```vim -" 함수들을 aliasing 하는 것은 작동하지 않습니다. +" Aliasing functions doesn't work let LuaPrint = v:lua.print -" 딕셔너리에 접근하는 것은 작동하지 않습니다. +" Accessing dictionaries doesn't work echo v:lua.some_global_dict['key'] -" 함수를 값으로 사용하는 것은 작동하지 않습니다. +" Using a function as a value doesn't work echo map([1, 2, 3], v:lua.global_callback) ``` ### Tips -.vim 파일들 안에서 루아 신택스 하이라이팅을 보려면 `let g:vimsyn_enbed = 'l'`을 설정 파일에 적으면 됩니다. -더 자세한 정보는 [`:help g: vimsyn_embed`](https://neovim.io/doc/user/syntax.html#g:vimsyn_embed)를 보세요. +You can get Lua syntax highlighting inside .vim files by putting `let g:vimsyn_embed = 'l'` in your configuration file. See [`:help g:vimsyn_embed`](https://neovim.io/doc/user/syntax.html#g:vimsyn_embed) for more on this option. -## 빔 이름공간 (The vim namespace) +## The vim namespace -루아로 vim의 API와 소통하기 위해 네오빔은 전역 변수 `vim`을 진입점으로서 제공하고 있습니다. 이는 사용자들에게 확장된 "standard library" 함수들과 다양한 서브모듈들을 제공합니다. +Neovim exposes a global `vim` variable which serves as an entry point to interact with its APIs from Lua. It provides users with an extended "standard library" of functions as well as various sub-modules. Some notable functions and modules include: -알아둘만한 함수와 모듈들: -- `vim.inspect`: 루아 오브젝트를 읽기 편한 문자열로 변환합니다. (table 값을 봐야할 때 유용합니다) -- `vim.regex`: 루아에서 빔의 regex를 사용할 수 있습니다. -- `vim.api`: API 함수들을 사용할 수 있는 모듈입니다. (원격 플러그인들이 사용하는 API와 동일합니다) -- `vim.ui`: override 가능한 UI 함수들입니다. 플러그인에서 사용하면 좋습니다. -- `vim.loop`: 네오빔의 event-loop의 기능을 사용할 수 있는 모듈입니다. (libUV를 사용하고 있습니다) -- `vim.lsp`: 내장 LSP 클라이언트를 컨트롤할 수 있는 모듈입니다. -- `vim.treesitter`: tree-sitter 라이브러리의 기능을 사용할 수 있는 모듈입니다. +- `vim.inspect`: transform Lua objects into human-readable strings (useful for inspecting tables) +- `vim.regex`: use Vim regexes from Lua +- `vim.api`: module that exposes API functions (the same API used by remote plugins) +- `vim.ui`: overridable UI functions that can be leveraged by plugins +- `vim.loop`: module that exposes the functionality of Neovim's event-loop (using LibUV) +- `vim.lsp`: module that controls the built-in LSP client +- `vim.treesitter`: module that exposes the functionality of the tree-sitter library -이 목록이 전부는 아닙니다. `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)로 문서를 보실 수 있습니다. +This list is by no means comprehensive. If you wish to know more about what's made available by the `vim` variable, [`:help lua-stdlib`](https://neovim.io/doc/user/lua.html#lua-stdlib) and [`:help lua-vim`](https://neovim.io/doc/user/lua.html#lua-vim) are the way to go. Alternatively, you can do `:lua print(vim.inspect(vim))` to get a list of every module. API functions are documented under [`:help api-global`](https://neovim.io/doc/user/api.html#api-global). #### Tips -오브젝트를 확인하고 싶을 때마다 `print(vim.inspect(x))`를 적어야 하는 것은 조금 귀찮습니다. 설정 파일에 전역 wrapper 함수를 만들어 두는 것도 좋을 것 같습니다. (Neovim 0.7.0+ 부터는 이런 함수가 내장되어 있습니다. [`:help vim.pretty_print()`](https://neovim.io/doc/user/lua.html#vim.pretty_print())를 확인해 보세요.) +Writing `print(vim.inspect(x))` every time you want to inspect the contents of an object can get pretty tedious. It might be worthwhile to have a global wrapper function somewhere in your configuration (in Neovim 0.7.0+, this function is built-in, see [`:help vim.pretty_print()`](https://neovim.io/doc/user/lua.html#vim.pretty_print())): ```lua function _G.put(...) @@ -436,7 +425,7 @@ function _G.put(...) end ``` -이제 오브젝트의 내용물들을 쉽게 확인해볼 수 있습니다. 코드와 명령줄에서 다음과 같이 사용할 수 있습니다: +You can then inspect the contents of an object very quickly in your code or from the command-line: ```lua put({1, 2, 3}) @@ -446,24 +435,23 @@ put({1, 2, 3}) :lua put(vim.loop) ``` -또는 `:lua` 명령어 앞에 `=`를 붙이는 것으로 루아 표현식을 보기 쉽게 프린트할 수도 있습니다. (Neovim 0.7+ 이상만): +Alternatively, you can use the `:lua` command to pretty-print a Lua expression by prefixing it with `=` (Neovim 0.7+ only): ```vim :lua =vim.loop ``` -어쩔 때는 루아의 빌트인 함수들이 다른 언어들에 비해 좀 부족하게 느껴질 수도 있습니다. (예를 들면 `os.clock()`같은 경우 milliseconds가 아닌 seconds만 리턴합니다.) 그럴 때는 Neovim의 stdlib(그리고 `vim.fn` - 후에 설명합니다)을 찾아보세요. 거기 원하는 것들이 있을지도 모릅니다. - +Additionally, you may find that built-in Lua functions are sometimes lacking compared to what you would find in other languages (for example `os.clock()` only returns a value in seconds, not milliseconds). Be sure to look at the Neovim stdlib (and `vim.fn`, more on that later), it probably has what you're looking for. -## 루아에서 빔스크립트 사용하기 +## Using Vimscript from Lua ### vim.api.nvim_eval() -이 함수는 빔스크립트 표현식 문자열에서 값을 리턴합니다. 빔스크립트의 데이터 타입들은 자동적으로 루아 타입으로 변환됩니다. +This function evaluates a Vimscript expression string and returns its value. Vimscript data types are automatically converted to Lua types (and vice versa). -빔스크립트에서의 `luaeval()` 함수와 동일합니다. +It is the Lua equivalent of the `luaeval()` function in Vimscript ```lua --- 데이터 타입 변환 예 +-- Data types are converted correctly print(vim.api.nvim_eval('1 + 1')) -- 2 print(vim.inspect(vim.api.nvim_eval('[1, 2, 3]'))) -- { 1, 2, 3 } print(vim.inspect(vim.api.nvim_eval('{"foo": "bar", "baz": "qux"}'))) -- { baz = "qux", foo = "bar" } @@ -471,13 +459,13 @@ print(vim.api.nvim_eval('v:true')) -- true print(vim.api.nvim_eval('v:null')) -- nil ``` -#### 경고 +#### Caveats -`luaeval()`과 다르게 `vim.api.nvim_eval()`은 표현식에 데이터를 넘길 수 있는 변수 `_A`를 제공하지 않습니다. +Unlike `luaeval()`, `vim.api.nvim_eval()` does not provide an implicit `_A` variable to pass data to the expression. ### vim.api.nvim_exec() -이 함수는 빔스크립트 코드 조각을 평가합니다. 실행할 소스 코드 문자열과 코드의 결과가 리턴할지 지정하는 boolean 값을 인자로 받습니다. (결과값을 변수에 할당하는 것도 가능합니다). +This function evaluates a chunk of Vimscript code. It takes in a string containing the source code to execute and a boolean to determine whether the output of the code should be returned by the function (you can then store the output in a variable, for example). ```lua local result = vim.api.nvim_exec( @@ -495,13 +483,13 @@ true) print(result) -- 'hello world' ``` -#### 경고 +#### Caveats -Neovim 0.6.0 이전 버전의 경우 `nvim_exec`이 script-local 변수 (`s:`)를 지원하지 않습니다. +`nvim_exec` does not support script-local variables (`s:`) prior to Neovim 0.6.0 ### vim.api.nvim_command() -이 함수는 ex 커맨드를 실행합니다. 인자로 실행할 명령어를 포함한 문자열을 받습니다. +This function executes an ex command. It takes in a string containing the command to execute. ```lua vim.api.nvim_command('new') @@ -512,7 +500,7 @@ vim.api.nvim_command('%s/foo/bar/g') ### vim.cmd() -`vim.api.nvim_exec()`의 alias입니다. 커맨드 인자만 필요로 합니다. `output`은 항상 `false`로 지정되어 있습니다. +Alias for `vim.api.nvim_exec()`. Only the command argument is needed, `output` is always set to `false`. ```lua vim.cmd('buffers') @@ -529,13 +517,13 @@ echo g:multiline_list #### Tips -이 함수들에는 문자열을 넘겨야 함으로, 종종 다음과 같이 백슬래시를 같이 사용해야 하는 경우가 있습니다: +Since you have to pass strings to these functions, you often end up having to escape backslashes: ```lua vim.cmd('%s/\\Vfoo/bar/g') ``` -하지만 이중 중괄호를 사용한 문자열은 특수 문자 앞에 백슬래시를 넣지 않아도 되기 때문에 조금 더 쉬워집니다: +Double bracketed strings are easier to use as they do not require escaping characters: ```lua vim.cmd([[%s/\Vfoo/bar/g]]) @@ -543,15 +531,15 @@ vim.cmd([[%s/\Vfoo/bar/g]]) ### vim.api.nvim_replace_termcodes() -이 API 함수는 터미널 코드와 빔 키코드를 escape 할 수 있게 해줍니다. +This API function allows you to escape terminal codes and Vim keycodes. -빔스크립트로 씌여진 다음과 같은 키 매핑이 있습니다: +You may have come across mappings like this one: ```vim inoremap pumvisible() ? "\" : "\" ``` -같은 기능을 하는 루아 함수를 만들어봅시다. 다음과 같이 작성하고 싶을 수 있습니다: +Trying to do the same in Lua can prove to be a challenge. You might be tempted to do it like this: ```lua function _G.smart_tab() @@ -561,30 +549,30 @@ end vim.api.nvim_set_keymap('i', '', 'v:lua.smart_tab()', {expr = true, noremap = true}) ``` -매핑이 문자 그대로 `\`과 `\`를 입력하는지 알아내기만 하면 됩니다. +only to find out that the mapping inserts `\` and `\` literally... -키코드를 escape 할 수 있는 것은 빔스크립트의 기능입니다. 많은 프로그래밍 언어에서 흔히 볼 수 있는 `\r`, `\42`, `\x10` 같은 보통의 escape 시퀀스들를 제외하고, 빔스크립트의 `expr-quotes` (큰 따옴표로 둘러쌓인 문자열)은 빔 키코드들을 사람이 읽을 수 있게 표기할 수 있습니다. +Being able to escape keycodes is actually a Vimscript feature. Aside from the usual escape sequences like `\r`, `\42` or `\x10` that are common to many programming languages, Vimscript `expr-quotes` (strings surrounded with double quotes) allow you to escape the human-readable representation of Vim keycodes. -루아는 이와 같은 기능을 빌트인으로 가지고 있지 않습니다. 하지만 Neovim에는 같은 기능을 할 수 있는 API 함수가 있습니다: `nvim_replace_termcodes()` +Lua doesn't have such a feature built-in. Fortunately, Neovim has an API function for escaping terminal codes and keycodes: `nvim_replace_termcodes()` ```lua print(vim.api.nvim_replace_termcodes('', true, true, true)) ``` -조금 장황합니다. 다시 사용하기 쉽게 한 번 더 감싸면 편할 것 같습니다: +This is a little verbose. Making a reusable wrapper can help: ```lua --- 이 함수는 `termcodes`의 `t`로 부르기로 했습니다. --- 저와 똑같이 이름 지을 필요는 없습니다. 저는 간결한 것이 편했습니다. +-- The function is called `t` for `termcodes`. +-- You don't have to call it that, but I find the terseness convenient local function t(str) - -- 필요한대로 boolean 인자들을 조정합니다. + -- Adjust boolean arguments as needed return vim.api.nvim_replace_termcodes(str, true, true, true) end print(t'') ``` -이전의 예시로 다시 돌아와보면, 이제 우리가 원하는대로 작동해야 할 것입니다: +Coming back to our earlier example, this should now work as expected: ```lua local function t(str) @@ -598,7 +586,7 @@ end vim.api.nvim_set_keymap('i', '', 'v:lua.smart_tab()', {expr = true, noremap = true}) ``` -`vim.keymap.set()`를 사용할 때 opts의 expr이 true일 경우(default) 자동적으로 키코드들을 변환해주기 때문에 위의 과정들이 필요 없습니다: +This is not necessary with `vim.keymap.set()` as it automatically transforms vim keycodes returned by Lua functions in `expr` mappings by default: ```lua vim.keymap.set('i', '', function() @@ -606,17 +594,17 @@ vim.keymap.set('i', '', function() end, {expr = true}) ``` -자세한 정보: +See also: - [`:help keycodes`](https://neovim.io/doc/user/intro.html#keycodes) - [`:help expr-quote`](https://neovim.io/doc/user/eval.html#expr-quote) - [`:help nvim_replace_termcodes()`](https://neovim.io/doc/user/api.html#nvim_replace_termcodes()) -## 빔 옵션 관리하기 +## Managing vim options -### api 함수들 사용하기 +### Using api functions -Neovim은 옵션을 지정하거나 현재 지정된 값을 가져오는 API 함수들을 제공하고 있습니다: +Neovim provides a set of API functions to either set an option or get its current value: - Global options: - [`vim.api.nvim_set_option()`](https://neovim.io/doc/user/api.html#nvim_set_option()) @@ -628,30 +616,30 @@ Neovim은 옵션을 지정하거나 현재 지정된 값을 가져오는 API 함 - [`vim.api.nvim_win_set_option()`](https://neovim.io/doc/user/api.html#nvim_win_set_option()) - [`vim.api.nvim_win_get_option()`](https://neovim.io/doc/user/api.html#nvim_win_get_option()) -set/get할 옵션의 이름을 포함한 문자열과 set하고 싶은 값을 인자로 받습니다. +They take a string containing the name of the option to set/get as well as the value you want to set it to. -`(no)number`와 같은 boolean 옵션들은 `true`나 `false`를 받습니다: +Boolean options (like `(no)number`) have to be set to either `true` or `false`: ```lua vim.api.nvim_set_option('smarttab', false) print(vim.api.nvim_get_option('smarttab')) -- false ``` -당연히 문자열 옵션들은 문자열을 인자로 받습니다: +Unsurprisingly, string options have to be set to a string: ```lua vim.api.nvim_set_option('selection', 'exclusive') print(vim.api.nvim_get_option('selection')) -- 'exclusive' ``` -숫자 옵션들은 숫자를 받습니다: +Number options accept a number: ```lua vim.api.nvim_set_option('updatetime', 3000) print(vim.api.nvim_get_option('updatetime')) -- 3000 ``` -버퍼-로컬, 윈도우-로컬 옵션들은 버퍼 넘버나 윈도우 넘버를 옵션으로 받습니다. (`0`를 사용하면 현재 buffer/window로 set/get할 수 있습니다): +Buffer-local and window-local options also need a buffer number or a window number (using `0` will set/get the option for the current buffer/window): ```lua vim.api.nvim_win_set_option(0, 'number', true) @@ -660,15 +648,14 @@ print(vim.api.nvim_win_get_option(0, 'number')) -- true print(vim.api.nvim_buf_get_option(10, 'shiftwidth')) -- 4 ``` -### 메타-접근자(meta-accessors)들 사용하기 +### Using meta-accessors A few meta-accessors are available if you want to set options in a more "idiomatic" way. They essentially wrap the above API functions and allow you to manipulate options as if they were variables: -몇몇 메타-접근자는 옵션 세팅을 좀 더 "관용적"으로 할 수 있게 도와줍니다. 이것들은 본질적으로 위의 API 함수들을 감싸둔 것과 같으며 옵션들을 변수처럼 조작할 수 있게 합니다. -- [`vim.o`](https://neovim.io/doc/user/lua.html#vim.o): `:let &{option-name}`과 같습니다. -- [`vim.go`](https://neovim.io/doc/user/lua.html#vim.go): `:let &g:{option-name}`과 같습니다. -- [`vim.bo`](https://neovim.io/doc/user/lua.html#vim.bo): 버퍼-로컬 `:let &l:{option-name}`과 같습니다. -- [`vim.wo`](https://neovim.io/doc/user/lua.html#vim.wo): 윈도우-로컬 `:let &l:{option-name}`과 같습니다. +- [`vim.o`](https://neovim.io/doc/user/lua.html#vim.o): behaves like `:let &{option-name}` +- [`vim.go`](https://neovim.io/doc/user/lua.html#vim.go): behaves like `:let &g:{option-name}` +- [`vim.bo`](https://neovim.io/doc/user/lua.html#vim.bo): behaves like `:let &l:{option-name}` for buffer-local options +- [`vim.wo`](https://neovim.io/doc/user/lua.html#vim.wo): behaves like `:let &l:{option-name}` for window-local options ```lua vim.o.smarttab = false -- let &smarttab = v:false @@ -680,14 +667,14 @@ vim.bo.shiftwidth = 4 print(vim.bo.shiftwidth) -- 4 ``` -버퍼-로컬과 윈도우-로컬 옵션의 경우 숫자를 지정할 수 있습니다. 숫자가 주어지지 않으면 현재 버퍼/윈도우가 사용됩니다: +You can specify a number for buffer-local and window-local options. If no number is given, the current buffer/window is used: ```lua vim.bo[4].expandtab = true -- same as vim.api.nvim_buf_set_option(4, 'expandtab', true) vim.wo.number = true -- same as vim.api.nvim_win_set_option(0, 'number', true) ``` -이들 wrapper들 중에는 좀 더 정교한 조작을 할 수 있는 `vim.opt*` 변수들이 있습니다. 루아에서 옵션을 세팅하기 조금 더 편리한 메카니즘을 제공합니다. 이는 `init.vim`에서 작성하던 방식과 유사할 수 있습니다. +These wrappers also have more sophisticated `vim.opt*` variants that provide convenient mechanisms for setting options in Lua. They're similar to what you might be used to in your `init.vim`: - `vim.opt`: behaves like `:set` - `vim.opt_global`: behaves like `:setglobal` @@ -698,14 +685,14 @@ vim.opt.smarttab = false print(vim.opt.smarttab:get()) -- false ``` -몇몇 옵션들은 루아 테이블을 사용해 세팅됩니다: +Some options can be set using Lua tables: ```lua vim.opt.completeopt = {'menuone', 'noselect'} print(vim.inspect(vim.opt.completeopt:get())) -- { "menuone", "noselect" } ``` -리스트, 맵, 셋과 비슷한 옵션들을 위한 wrapper들도 제공됩니다. 빔스크립트의 `:set+=`, `:set^=`, `:set-=`와 비슷하게 동작하는 메소드와 메타메소드들이 있습니다. +Wrappers for list-like, map-like and set-like options also come with methods and metamethods that work similarly to their `:set+=`, `:set^=` and `:set-=` counterparts in Vimscript. ```lua vim.opt.shortmess:append({ I = true }) @@ -717,16 +704,16 @@ vim.opt.whichwrap:remove({ 'b', 's' }) vim.opt.whichwrap = vim.opt.whichwrap - { 'b', 's' } ``` -더 자세한 정보는 [`:help vim.opt`](https://neovim.io/doc/user/lua.html#vim.opt)를 확인해보세요. +Be sure to look at [`:help vim.opt`](https://neovim.io/doc/user/lua.html#vim.opt) for more information. -자세한 정보: +See also: - [`:help lua-vim-options`](https://neovim.io/doc/user/lua.html#lua-vim-options) -## 빔의 내부 변수들을 관리하기 +## Managing vim internal variables -### api 함수들 사용하기 +### Using api functions -옵션들과 같이, 내부 변수들도 다음과 같은 API 함수들이 있습니다: +Much like options, internal variables have their own set of API functions: - Global variables (`g:`): - [`vim.api.nvim_set_var()`](https://neovim.io/doc/user/api.html#nvim_set_var()) @@ -749,12 +736,10 @@ vim.opt.whichwrap = vim.opt.whichwrap - { 'b', 's' } - [`vim.api.nvim_get_vvar()`](https://neovim.io/doc/user/api.html#nvim_get_vvar()) With the exception of predefined Vim variables, they can also be deleted (the `:unlet` command is the equivalent in Vimscript). Local variables (`l:`), script variables (`s:`) and function arguments (`a:`) cannot be manipulated as they only make sense in the context of a Vim script, Lua has its own scoping rules. -미리 정의된 빔 변수들을 제외하고는 삭제할 수도 있습니다(빔스크립트에서는 `:unlet` 커맨드와 같습니다). 로컬 변수 (`l:`), 스크립트 변수 (`s:`), -함수 인자 (`a:`)는 조작할 수 없습니다. 이것들은 빔스크립트의 문맥에서만 의미가 있고, 루아에서는 루아의 스코핑 규칙이 있습니다. -이런 변수들과 친숙하지 않다면 [`:help internal-variables`](https://neovim.io/doc/user/eval.html#internal-variables)를 보시면 좀 더 자세한 설명을 읽을 수 있습니다. +If you are unfamiliar with what these variables do, [`:help internal-variables`](https://neovim.io/doc/user/eval.html#internal-variables) describes them in detail. -이 함수들은 set/get/delete 할 변수명을 포함한 문자열, 할당할 값을 인자로 받습니다. +These functions take a string containing the name of the variable to set/get/delete as well as the value you want to set it to. ```lua vim.api.nvim_set_var('some_global_variable', { key1 = 'value', key2 = 300 }) @@ -762,7 +747,7 @@ print(vim.inspect(vim.api.nvim_get_var('some_global_variable'))) -- { key1 = "va vim.api.nvim_del_var('some_global_variable') ``` -버퍼 로컬 변수들, 창이나 탭 로컬 변수들은 숫자를 받습니다 (`0`을 사용하면 현재 buffer/window/tabpage에 set/get/delete 될 것입니다): +Variables that are scoped to a buffer, a window or a tabpage also receive a number (using `0` will set/get/delete the variable for the current buffer/window/tabpage): ```lua vim.api.nvim_win_set_var(0, 'some_window_variable', 2500) @@ -773,9 +758,9 @@ vim.api.nvim_win_del_var(0, 'some_window_variable') vim.api.nvim_buf_del_var(3, 'some_tabpage_variable') ``` -### 메타-접근자 사용하기 +### Using meta-accessors -내부 변수들은 다음과 같은 meta-accessor들로 좀 더 직관적으로 조작할 수 있습니다. +Internal variables can be manipulated more intuitively using these meta-accessors: - [`vim.g`](https://neovim.io/doc/user/lua.html#vim.g): global variables - [`vim.b`](https://neovim.io/doc/user/lua.html#vim.b): buffer variables @@ -793,24 +778,23 @@ vim.g.some_global_variable = { print(vim.inspect(vim.g.some_global_variable)) -- { key1 = "value", key2 = 300 } -- target a specific buffer/window/tabpage (Neovim 0.6+) --- 특정 buffer/window/tabpage를 지정하기 (Neovim 0.6+) vim.b[2].myvar = 1 ``` -몇몇 변수 이름들은 루아에서 식별자로 사용될 수 없는 문자들을 포함하고 있을수도 있습니다. 그래도 다음 문법을 사용하면 조작할 수 있습니다:`vim.g['my#variable']`. +Some variable names may contain characters that cannot be used for identifiers in Lua. You can still manipulate these variables by using this syntax: `vim.g['my#variable']`. -다음 변수들을 삭제하기 위해서는 단순히 `nil`을 할당하면 됩니다: +To delete one of these variables, simply assign `nil` to it: ```lua vim.g.some_global_variable = nil ``` -자세한 정보: +See also: - [`:help lua-vim-variables`](https://neovim.io/doc/user/lua.html#lua-vim-variables) -#### 경고 +#### Caveats -이 변수들에 저장된 딕셔너리의 키들은 add/update/delete 할 수 없습니다. 예를 들어 다음 빔스크립트 snippet 코드는 예상한대로 작동하지 않습니다: +You cannot add/update/delete keys from a dictionary stored in one of these variables. For example, this snippet of Vimscript code does not work as expected: ```vim let g:variable = {} @@ -819,7 +803,7 @@ echo g:variable " {} ``` -하지만 임시 변수를 사용하여 돌아갈 수 있습니다. +You can use a temporary variable as a workaround: ```vim let g:variable = {} @@ -833,15 +817,14 @@ echo g:variable ``` This is a known issue: -알려진 이슈입니다: - [Issue #12544](https://github.com/neovim/neovim/issues/12544) -## 빔스크립트 함수 호출하기 +## Calling Vimscript functions ### vim.fn.{function}() -`vim.fn`는 빔스크립트 함수를 호출하는데 사용됩니다. 데이터 타입들은 루아, 빔스크립트 양측으로 자동 변환됩니다. +`vim.fn` can be used to call a Vimscript function. Data types are converted back and forth from Lua to Vimscript. ```lua print(vim.fn.printf('Hello from %s', 'Lua')) @@ -856,30 +839,28 @@ end vim.fn.jobstart('ls', { on_stdout = print_stdout }) ``` -해시(`#`)는 루아에서 식별자로 사용할 수 없는 문자이기 때문에 autoload 함수들은 다음 문법으로 불러야 합니다. +Hashes (`#`) are not valid characters for identifiers in Lua, so autoload functions have to be called with this syntax: ```lua vim.fn['my#autoload#function']() ``` -`vim.fn`과 `vim.call`은 기능상으로 동일하지만 좀 더 루아같은 문법을 사용할 수 있습니다. - +The functionality of `vim.fn` is identical to `vim.call`, but allows a more Lua-like syntax. -Vim/Lua 오브젝트 변환이 자동적이란 점에 있어서 `vim.api.nvim_call_function`과는 구별됩니다: -`vim.api.nvim_call_function`은 부동 소수점 숫자 테이블을 리턴하며 루아의 클로저를 받지 않습니다. 반면 `vim.fn`는 이러한 타입들을 투명하게 다룹니다. +It is distinct from `vim.api.nvim_call_function` in that converting Vim/Lua objects is automatic: `vim.api.nvim_call_function` returns a table for floating point numbers and does not accept Lua closures while `vim.fn` handles these types transparently. -자세한 정보: +See also: - [`:help vim.fn`](https://neovim.io/doc/user/lua.html#vim.fn) #### Tips -네오빔에는 플러그인을 위해 유용하고 강력한 빌트인 함수 라이브러리가 있습니다. [`:help vim-function`](https://neovim.io/doc/user/eval.html#vim-function)를 보면 알파벳 순의 함수들을 확인할 수 있고 [`:help function-list`](https://neovim.io/doc/user/usr_41.html#function-list)를 보면 주제별로 구분된 함수 리스트를 확인할 수 있습니다. +Neovim has an extensive library of powerful built-in functions that are very useful for plugins. See [`:help vim-function`](https://neovim.io/doc/user/eval.html#vim-function) for an alphabetical list and [`:help function-list`](https://neovim.io/doc/user/usr_41.html#function-list) for a list of functions grouped by topic. -네오빔 API 함수들은 `vim.api.{..}`를 통해 직접 사용 가능합니다. [:help api](https://neovim.io/doc/user/api.html#API)로 확인하실 수 있습니다. +Neovim API functions can be used directly through `vim.api.{..}`. See [`:help api`](https://neovim.io/doc/user/api.html#API) for information. -#### 경고 +#### Caveats -boolean을 반환해야 하는 일부 빔 함수들은 `1` 또는 `0` 을 반환합니다. 빔스크립트에서 `1`은 참(truthy), `0`은 거짓(falsy)이기 때문에 문제되지 않습니다. 다음과 같이 구성할 수 있습니다: +Some Vim functions that should return a boolean return `1` or `0` instead. This isn't a problem in Vimscript as `1` is truthy and `0` falsy, enabling constructs like these: ```vim if has('nvim') @@ -887,7 +868,7 @@ if has('nvim') endif ``` -하지만 루아에서는 `false`와 `nil`을 제외한 모든 타입이 `true`입니다. 따라서 명시적으로 `1`과 `0`을 체크해줘야 합니다. +In Lua however, only `false` and `nil` are considered falsy, numbers always evaluate to `true` no matter their value. You have to explicitly check for `1` or `0`: ```lua if vim.fn.has('nvim') == 1 then @@ -895,11 +876,11 @@ if vim.fn.has('nvim') == 1 then end ``` -## 키 매핑 정의하기 +## Defining mappings -### API 함수들 +### API functions -네오빔은 키 매핑을 set, get, delete 하기 위한 API 함수들을 제공합니다: +Neovim provides a list of API functions to set, get and delete mappings: - Global mappings: - [`vim.api.nvim_set_keymap()`](https://neovim.io/doc/user/api.html#nvim_set_keymap()) @@ -910,9 +891,9 @@ end - [`vim.api.nvim_buf_get_keymap()`](https://neovim.io/doc/user/api.html#nvim_buf_get_keymap()) - [`vim.api.nvim_buf_del_keymap()`](https://neovim.io/doc/user/api.html#nvim_buf_del_keymap()) -`vim.api.nvim_set_keymap()`과 `vim.api.nvim_buf_set_keymap()`부터 시작합시다. +Let's start with `vim.api.nvim_set_keymap()` and `vim.api.nvim_buf_set_keymap()` -함수에 전달된 첫 번째 인수는 매핑이 적용될 모드의 이름을 포함하는 문자열입니다. +The first argument passed to the function is a string containing the name of the mode for which the mapping will take effect: | String value | Help page | Affected modes | Vimscript equivalent | | ---------------------- | ------------- | ---------------------------------------- | -------------------- | @@ -928,13 +909,13 @@ end | `'c'` | `mapmode-c` | Command-line | `:cmap` | | `'t'` | `mapmode-t` | Terminal | `:tmap` | -두 번째 인수는 왼쪽편의 매핑(매핑에 정의된 명령을 트리거할 키나 키조합)을 포함한 문자열을 받습니다. 빈 문자열은 키를 비활성화 하는 ``과 동일합니다. +The second argument is a string containing the left-hand side of the mapping (the key or set of keys that trigger the command defined in the mapping). An empty string is equivalent to ``, which disables a key. -셋 째 인수는 오른편의 매핑(실행할 명령)을 포함한 문자열입니다. +The third argument is a string containing the right-hand side of the mapping (the command to execute). -마지막 인수는 boolean 옵션들을 포함한 테이블입니다. 상세한 옵션은 [`:help :map-arguments`](https://neovim.io/doc/user/map.html#:map-arguments)에 정의되어 있습니다. (`noremap` 포함 `buffer` 제외). Neovim 0.7.0 버전부터는 매핑을 실행할 때 오른편 매핑 대신 `callback` 옵션으로 루아 함수를 부를 수도 있습니다. +The final argument is a table containing boolean options for the mapping as defined in [`:help :map-arguments`](https://neovim.io/doc/user/map.html#:map-arguments) (including `noremap` and excluding `buffer`). Since Neovim 0.7.0, you can also pass a `callback` option to invoke a Lua function instead of the right-hand side when executing the mapping. -버퍼-로컬 매핑들은 버퍼 숫자를 첫 번째 인수로 받습니다 (`0`은 현재 버퍼로 지정됩니다). +Buffer-local mappings also take a buffer number as their first argument (`0` sets the mapping for the current buffer). ```lua vim.api.nvim_set_keymap('n', '', ':set hlsearch!', { noremap = true, silent = true }) @@ -950,35 +931,33 @@ vim.api.nvim_set_keymap('n', 'ex', '', { callback = function() print('My example') end, - -- 루아 함수에는 유용한 문자열 표현이 없기 때문에, "desc" 옵션을 통해 매핑을 문서화 할 수 있습니다. + -- Since Lua function don't have a useful string representation, you can use the "desc" option to document your mapping desc = 'Prints "My example" in the message area', }) ``` -`vim.api.nvim_get_keymap()`은 모드의 짧은 이름 문자열(위의 테이블)을 인수로 받고 해당 모드에 포함된 매핑들을 테이블로 반환합니다. - +`vim.api.nvim_get_keymap()` takes a string containing the shortname of the mode for which you want the list of mappings (see table above). The return value is a table containing all global mappings for the mode. ```lua print(vim.inspect(vim.api.nvim_get_keymap('n'))) -- :verbose nmap ``` -`vim.api.nvim_buf_get_keymap()`는 추가로 버퍼 숫자를 첫 번째 인수에 받습니다. (`0`은 현재 버퍼의 모든 매핑을 불러옵니다) - +`vim.api.nvim_buf_get_keymap()` takes an additional buffer number as its first argument (`0` will get mapppings for the current bufffer) ```lua print(vim.inspect(vim.api.nvim_buf_get_keymap(0, 'i'))) -- :verbose imap ``` -`vim.api.nvim_del_keymap()`는 모드와 지우고 싶은 매핑(키)를 인수로 받습니다. +`vim.api.nvim_del_keymap()` takes a mode and the left-hand side of a mapping. ```lua vim.api.nvim_del_keymap('n', '') -- :nunmap ``` -또 `vim.api.nvim_buf_del_keymap()`는 첫 번째 인수로 버퍼 숫자를 받고 `0`은 현재 버퍼를 의미합니다. +Again, `vim.api.nvim_buf_del_keymap()`, takes a buffer number as its first argument, with `0` representing the current buffer. ```lua vim.api.nvim_buf_del_keymap(0, 'i', '') @@ -987,78 +966,78 @@ vim.api.nvim_buf_del_keymap(0, 'i', '') ### vim.keymap -:주의: 이 섹션에서 이야기되는 함수들은 Neovim 0.7.0+ 버전부터 사용할 수 있습니다. +:warning: The functions discussed in this section are only available in Neovim 0.7.0+ -네오빔은 다음 두 함수들을 매핑을 set/del 하는 작업에 제공합니다. +Neovim provides two functions to set/del mappings: - [`vim.keymap.set()`](https://neovim.io/doc/user/lua.html#vim.keymap.set()) - [`vim.keymap.del()`](https://neovim.io/doc/user/lua.html#vim.keymap.del()) -이것들은 위 API 함수들과 비슷하지만 약간의 구문 설탕(syntactic sugar)가 추가되어 있습니다. +These are similar to the above API functions with added syntactic sugar. -`vim.keymap.set()`는 문자열을 첫번째 인수로 받습니다. 여러 모드를 한 번에 정의하기 위해서는 문자열 테이블(List-like)을 사용합니다: +`vim.keymap.set()` takes a string as its first argument. It can also be a table of strings to define mappings for multiple modes at once: ```lua vim.keymap.set('n', 'ex1', 'lua vim.notify("Example 1")') vim.keymap.set({'n', 'c'}, 'ex2', 'lua vim.notify("Example 2")') ``` -두 번째 인수로는 매핑할 키(lhs)를 받습니다. +The second argument is the left-hand side of the mapping. -세 번째 인수는 실행할 명령(rhs)으로 문자열 혹은 루아 함수를 받습니다. +The third argument is the right-hand side of the mapping, which can either be a string or a Lua function: ```lua vim.keymap.set('n', 'ex1', 'echomsg "Example 1"') vim.keymap.set('n', 'ex2', function() print("Example 2") end) vim.keymap.set('n', 'pl1', require('plugin').plugin_action) --- 모듈을 require 할 때 드는 시작 비용을 피하기 위해서 function으로 감싸 매핑을 부를 때 (layzily) require 할 수 있게 합니다: +-- To avoid the startup cost of requiring the module, you can wrap it in a function to require it lazily when invoking the mapping: vim.keymap.set('n', 'pl2', function() require('plugin').plugin_action() end) ``` -네 번째 (optional) 인수는 `vim.api.nvim_set_keymap()`에 전해지는 옵션 테이블에 대응되며, 몇 가지 추가된 것([`:help vim.keymap.set()`](https://neovim.io/doc/user/lua.html#vim.keymap.set())에 전체 리스트)들이 있습니다. +The fourth (optional) argument is a table of options that correspond to the options passed to `vim.api.nvim_set_keymap()`, with a few additions (see [`:help vim.keymap.set()`](https://neovim.io/doc/user/lua.html#vim.keymap.set()) for the full list). ```lua vim.keymap.set('n', 'ex1', 'echomsg "Example 1"', {buffer = true}) vim.keymap.set('n', 'ex2', function() print('Example 2') end, {desc = 'Prints "Example 2" to the message area'}) ``` -루아 함수로 키맵을 정의하는 것은 문자열을 사용하는 것과 다릅니다. `:nmap ex1` 과 같은 키맵에 대한 정보를 보는 보통의 방법은 유용한 정보(문자열 자체)를 보여주지 않습니다. `Lua function`만 보여줍니다. 키맵을 설명하는 `desc` 키를 추가하는 것이 권장됩니다. 특히 플러그인 매핑들은 사용자들이 키맵을 좀 더 쉽게 이해할 수 있게 돕기 때문에 중요합니다. +Defining keymaps with a Lua function is different from using a string. The usual way to show information about a keymap like `:nmap ex1` will not output useful information (the string itself), but instead only show `Lua function`. It is recommended to add a `desc` key to describe the behavior of your keymap. This is especially important for documenting plugin mappings so users can understand the usage of the keymap more easily. -이 API에는 기존 빔 키맵의 역사적인 단점을 개선하는 흥미로운 기능이 있습니다: -- 매핑은 `rhs`가 `` 매핑일 때를 제외하고는 `noremap`이 기본입니다. 이 말은 매핑이 재귀적이어야 하는지 아닌지를 생각할 일이 잘 없다는 뜻입니다: +An interesting feature of this API is that it irons out some historical quirks of Vim mappings: +- Mappings are `noremap` by default, except when the `rhs` is a `` mapping. This means you rarely have to think about whether a mapping should be recursive or not: ```lua vim.keymap.set('n', 'test1', 'echo "test"') -- :nnoremap test echo "test" - -- 이 매핑이 재귀적으로 적용되길 바란다면 "remap" 옵션을 "true"로 적으면 됩니다. + -- If you DO want the mapping to be recursive, set the "remap" option to "true" vim.keymap.set('n', '>', ']', {remap = true}) -- :nmap > ] - -- 매핑들은 재귀적이지 않으면 작동하지 않습니다. vim.keymap.set()은 이를 자동으로 처리합니다. + -- mappings don't work unless they're recursive, vim.keymap.set() handles that for you automatically vim.keymap.set('n', 'plug', '(plugin)') -- :nmap plug (plugin) ``` -- `expr` 매핑에서는, `nvim_replace_termcodes()`는 루아 함수에서 반환된 문자열에 자동으로 적용됩니다: +- In `expr` mappings, `nvim_replace_termcodes()` is automatically applied to strings returned from Lua functions: ```lua vim.keymap.set('i', '', function() return vim.fn.pumvisible == 1 and '' or '' end, {expr = true}) ``` -자세한 정보: +See also: - [`:help recursive_mapping`](https://neovim.io/doc/user/map.html#recursive_mapping) -`vim.keymap.del()` 같은 방식으로 작동하지만 매핑을 삭제합니다: +`vim.keymap.del()` works the same way but deletes mappings instead: ```lua vim.keymap.del('n', 'ex1') vim.keymap.del({'n', 'c'}, 'ex2', {buffer = true}) ``` -## 사용자 커맨드 정의하기 +## Defining user commands -:주의: 이 섹션에서 이야기되는 API 함수들은 Neovim 0.7.0+ 에서만 사용할 수 있습니다. +:warning: The API functions discussed in this section are only available in Neovim 0.7.0+ -Neovim은 사용자 정의 커맨드를 위한 API 함수들을 제공합니다: +Neovim provides API functions for user-defined commands: - Global user commands: - [`vim.api.nvim_create_user_command()`](https://neovim.io/doc/user/api.html#nvim_create_user_command()) @@ -1067,14 +1046,13 @@ Neovim은 사용자 정의 커맨드를 위한 API 함수들을 제공합니다: - [`vim.api.nvim_buf_create_user_command()`](https://neovim.io/doc/user/api.html#nvim_buf_create_user_command()) - [`vim.api.nvim_buf_del_user_command()`](https://neovim.io/doc/user/api.html#nvim_buf_del_user_command()) -`vim.api.nvim_create_user_command()`부터 시작해봅시다. +Let's start with `vim.api.nvim_create_user_command()` -첫 번째 인수는 커맨드의 (대문자로 시작하는) 이름입니다. +The first argument passed to this function is the name of the command (which must start with an uppercase letter). -두 번째 인수는 커맨드를 불러왔을 때 실행할 코드입니다. 이는 둘 중 하나입니다: - -문자열(일 경우 빔스크립트로 실행). `:command`처럼 ``, `` 등과 같은 escape 시퀀스를 사용할 수 있습니다. +The second argument is the code to execute when invoking said command. It can either be: +A string (in which case it will be executed as Vimscript). You can use escape sequences like ``, ``, etc. like you would with `:command` ```lua vim.api.nvim_create_user_command('Upper', 'echo toupper()', { nargs = 1 }) -- :command! -nargs=1 Upper echo toupper() @@ -1082,8 +1060,7 @@ vim.api.nvim_create_user_command('Upper', 'echo toupper()', { nargs = 1 vim.cmd('Upper hello world') -- prints "HELLO WORLD" ``` -혹은 루아 함수. 루아 함수는 보통 escape 시퀀스에서 제공되는 데이터를 포함한 딕셔너리 테이블을 받습니다. ([`:help nvim_create_user_command()`](https://neovim.io/doc/user/api.html#nvim_create_user_command())에서 가능한 키 목록을 볼 수 있습니다) - +Or a Lua function. It receives a dictionary-like table that contains the data normally provided by escape sequences (see [`:help nvim_create_user_command()`](https://neovim.io/doc/user/api.html#nvim_create_user_command()) for a list of available keys) ```lua vim.api.nvim_create_user_command( 'Upper', @@ -1094,53 +1071,51 @@ vim.api.nvim_create_user_command( ) ``` -세 번째 인수는 커맨드 속성을 테이블로 받습니다([`:help command-attributes`](https://neovim.io/doc/user/map.html#command-attributes)). -이미 `vim.api.nvim_buf_create_user_command()`로 버퍼-로컬 사용자 커맨드를 정의할 수 있기 때문에 `-buffer`는 유효한 속성이 아닙니다. +The third argument lets you pass command attributes as a table (see [`:help command-attributes`](https://neovim.io/doc/user/map.html#command-attributes)). Since you can already define buffer-local user commands with `vim.api.nvim_buf_create_user_command()`, `-buffer` is not a valid attribute. -두 개의 추가적으로 가능한 속성들: -- `desc`는 루아 콜백으로 정의된 명령에서 `:command {cmd}`를 실행할 때 표시될 내용을 제어합니다. 키맵과 비슷한 이유로 `desc` 키를 추가하는 것이 권장됩니다. +Two additional attributes are available: +- `desc` allows you to control what gets displayed when you run `:command {cmd}` on a command defined as a Lua callback. Similarly to keymaps, it is recommended to add a `desc` key to commands defined as Lua functions. +- `force` is equivalent to calling `:command!` and replaces a command if one with the same name already exists. It is true by default, unlike its Vimscript equivalent. -- `force`는 `:command!`와 같습니다. 그리고 같은 이름의 커맨드가 이미 있다면 교체합니다. 대응되는 빔스크립트와 다르게 기본적으로 true입니다. - -`-comlpete` 속성은 [`:help :command-complete`](https://neovim.io/doc/user/map.html#:command-complete)에 있는 속성 리스트에 추가로 루아 함수를 받습니다. +The `-complete` attribute can take a Lua function in addition to the attributes listed in [`:help :command-complete`](https://neovim.io/doc/user/map.html#:command-complete). ```lua vim.api.nvim_create_user_command('Upper', function() end, { nargs = 1, complete = function(ArgLead, CmdLine, CursorPos) - -- 완성 후보들을 리스트 테이브로 반환합니다. + -- return completion candidates as a list-like table return { 'foo', 'bar', 'baz' } end, }) ``` -버퍼 로컬 유저 커맨드는 버퍼 숫자를 첫 번째 인수로 받습니다. 이는 `-buffer`가 현재 버퍼에만 커맨드를 정의할 수 있는 것에 비해 장점이 있습니다. +Buffer-local user commands also take a buffer number as their first argument. This is an advantage over `-buffer` which can only define a command for the current buffer. ```lua vim.api.nvim_buf_create_user_command(4, 'Upper', function() end, {}) ``` -`vim.api.nvim_del_user_command()`는 커맨드 이름을 받습니다. +`vim.api.nvim_del_user_command()` takes a command name. ```lua vim.api.nvim_del_user_command('Upper') -- :delcommand Upper ``` -`vim.api.nvim_buf_del_user_command()`는 버퍼 숫자를 첫 번째 인수로 받고, `0`은 현 버퍼를 의미합니다. +Again, `vim.api.nvim_buf_del_user_command()`, takes a buffer number as its first argument, with `0` representing the current buffer. ```lua vim.api.nvim_buf_del_user_command(4, 'Upper') ``` -자세한 정보: +See also: - [`:help nvim_create_user_command()`](https://neovim.io/doc/user/api.html#nvim_create_user_command()) - [`:help 40.2`](https://neovim.io/doc/user/usr_40.html#40.2) - [`:help command-attributes`](https://neovim.io/doc/user/map.html#command-attributes) -### 경고 +### Caveats -`-complete=custom` 속성은 자동완성 후보들을 자동적으로 필터링 하고 빌트인 와일드 카드([`:help wildcard`](https://neovim.io/doc/user/editing.html#wildcard))를 지원합니다: +The `-complete=custom` attribute automatically filters completion candidates and has built-in wildcard ([`:help wildcard`](https://neovim.io/doc/user/editing.html#wildcard)) support: ```vim function! s:completion_function(ArgLead, CmdLine, CursorPos) abort @@ -1155,7 +1130,7 @@ command! -nargs=1 -complete=custom,s:completion_function Test echo " Typing `:Test st[ae]` returns "star" and "stellar" ``` -루아 함수를 `complete`에 넘기는 것은 `customplist`처럼 작동합니다. 이는 필터링을 사용자에게 맡깁니다: +Passing a Lua function to `complete` makes it behave like `customlist` which leaves filtering up to the user: ```lua vim.api.nvim_create_user_command('Test', function() end, { @@ -1172,57 +1147,54 @@ vim.api.nvim_create_user_command('Test', function() end, { -- Typing `:Test z` returns all the completion results because the list was not filtered ``` -## autocommands 정의하기 +## Defining autocommands -(이 섹션은 현재 작업 중입니다) +(this section is a work in progress) -네오빔 0.7.0+ 에는 autocommands를 위한 API 함수들이 있습니다. (`:help api-autocmd`에 상세한 설명) +Neovim 0.7.0 has API functions for autocommands. See `:help api-autocmd` for details - [Pull request #14661](https://github.com/neovim/neovim/pull/14661) (lua: autocmds take 2) -## highlights 정의하기 +## Defining highlights -(이 섹션은 현재 작업 중입니다) +(this section is a work in progress) -네오빔 0.7.0+ 에는 highlight 그룹을 위한 API 함수들이 있습니다. 자세한 정보: +Neovim 0.7.0 has API functions for highlight groups. See also: - [`:help nvim_set_hl()`](https://neovim.io/doc/user/api.html#nvim_set_hl()) - [`:help nvim_get_hl_by_id()`](https://neovim.io/doc/user/api.html#nvim_get_hl_by_id()) - [`:help nvim_get_hl_by_name()`](https://neovim.io/doc/user/api.html#nvim_get_hl_by_name()) -## 일반적인 팁과 추천 사항들 +## General tips and recommendations -### 캐시 모듈들 리로딩하기 +### Reloading cached modules -루아에서 `require()` 함수는 모듈을 캐시합니다. 퍼포먼스를 위해서는 좋지만 플러그인을 만들때는 조금 성가실 수 있습니다. `require()`를 다시 부를 때 모듈이 업데이트 되지 않기 때문입니다. +In Lua, the `require()` function caches modules. This is a good thing for performance, but it can make working on plugins a bit cumbersome because modules are not updated on subsequent `require()` calls. -만약 특정 모듈의 캐시를 새로고침 하고 싶다면 전역 테이블인 `package.loaded`를 수정해야 합니다: +If you'd like to refresh the cache for a particular module, you have to modify the `package.loaded` global table: ```lua package.loaded['modname'] = nil -require('modname') -- 'modname' 모듈의 업데이트된 버전을 로드합니다. +require('modname') -- loads an updated version of module 'modname' ``` -[nvim-lua/plenary.nvim](https://github.com/nvim-lua/plenary.nvim) 플러그인에는 이걸 대신해주는 [커스텀 함수](https://github.com/nvim-lua/plenary.nvim/blob/master/lua/plenary/reload.lua)가 있습니다. - +The [nvim-lua/plenary.nvim](https://github.com/nvim-lua/plenary.nvim) plugin has a [custom function](https://github.com/nvim-lua/plenary.nvim/blob/master/lua/plenary/reload.lua) that does this for you. ### Don't pad Lua strings! -### 루아 문자열에 공백을 채우지 마세요! -이중 중괄호 스트링을 사용할 때 양 끝에 공백 문자를 넣지 마세요. 스페이스가 무시되는 맥락에서는 괜찮지만, whitespace가 의미있을 때는 디버깅 하기 어려운 문제를 일으킬 수 있습니다: +When using double bracketed strings, resist the temptation to pad them! While it is fine to do in contexts where spaces are ignored, it can cause hard to debug issues when whitespace is significant: ```lua vim.api.nvim_set_keymap('n', 'f', [[ call foo() ]], {noremap = true}) ``` -위의 예에서 `f`는 `call foo()` 대신 `call foo()`로 매핑됩니다. +In the above example, `f` is mapped to `call foo()` instead of `call foo()`. -### 빔스크립트 <-> 루아 타입 변환에 대해 알아둘 점 +### Notes about Vimscript <-> Lua type conversion -#### 변수를 변환하는 것은 copy를 생성합니다: -빔스크립트에서 루아 오브젝트, 혹은 루아에서 빔 오브젝트에 대한 참조와 직접 상호 작용할 수 없습니다. - -예를 들어, 빔스크립트의 `map()` 함수는 변수를 그 자리에서 수정합니다: +#### Converting a variable creates a copy: +You can't directly interact with the reference to a Vim object from Lua or a Lua object from Vimscript. +For example, the `map()` function in Vimscript modifies a variable in place: ```vim let s:list = [1, 2, 3] @@ -1236,7 +1208,7 @@ echo s:list is# s:newlist " 1 ``` -루아에서 이 함수를 사용할 때는 카피를 만듭니다: +Using this function from Lua creates a copy instead: ```lua local tbl = {1, 2, 3} @@ -1247,17 +1219,17 @@ print(vim.inspect(newtbl)) -- { 2, 4, 6 } print(tbl == newtbl) -- false ``` -#### 변환이 항상 가능한 것은 아닙니다 -이는 보통 함수와 테이블에 영향을 줍니다: +#### Conversion is not always possible +This mostly affects functions and tables: -리스트와 딕셔너리가 같이 혼합된 루아 테이블은 변환될 수 없습니다: +Lua tables that are a mix between a List and a Dictionary can't be converted: ```lua print(vim.fn.count({1, 1, number = 1}, 1)) -- E5100: Cannot convert given lua table: table should either have a sequence of positive integer keys or contain only string keys ``` -루아에서 빔 함수를 `vim.fn`으로 호출할 수 있지만 참조를 갖고 있을 수는 없습니다. 이로 인해 다음과 같은 이상한 동작이 발생할 수 있습니다: +While you can call Vim functions in Lua with `vim.fn`, you can't hold references to them. This can cause surprising behaviors: ```lua local FugitiveHead = vim.fn.funcref('FugitiveHead') @@ -1268,21 +1240,21 @@ print(vim.g.test_dict.test_lambda) -- nil print(vim.inspect(vim.g.test_dict)) -- {} ``` -빔 함수에 루아 함수를 넘기는 것은 됩니다. 하지만 빔 변수에 저장하는 것은 안됩니다. (Neovim 0.7.0+ 에서 고쳐짐): +Passing Lua functions to Vim functions is OK, storing them in Vim variables is not (fixed in Neovim 0.7.0+): ```lua --- 이건 작동하지만: +-- This works: vim.fn.jobstart({'ls'}, { on_stdout = function(chan_id, data, name) print(vim.inspect(data)) end }) --- 이건 안됩니다: +-- This doesn't: vim.g.test_dict = {test_lambda = function() return 1 end} -- Error: Cannot convert given lua type ``` -하지만 빔스크립트에서 `luaeval()`을 사용할 때는 동일한 작업을 하면 **잘** 작동합니다: +Note however that doing the same from Vimscript with `luaeval()` **does** work: ```vim let g:test_dict = {'test_lambda': luaeval('function() return 1 end')} @@ -1291,9 +1263,9 @@ echo g:test_dict ``` #### Vim booleans -빔 스크립트에서 흔한 패턴은 `1`이나 `0`을 제대로 된 boolean 값 대신 사용하는 것입니다. 사실 빔에는 7.4.1154 버전까지 별도의 boolean 타입이 없었습니다. +A common pattern in Vim scripts is to use `1` or `0` instead of proper booleans. Indeed, Vim did not have a separate boolean type until version 7.4.1154. -루아 boolean은 빔스크립트의 실제 boolean 타입으로 변환됩니다. 숫자가 아니라요: +Lua booleans are converted to actual booleans in Vimscript, not numbers: ```vim lua vim.g.lua_true = true @@ -1304,13 +1276,13 @@ echo g:lua_false " v:false ``` -### Linters/Lanuage servers 설정하기 +### Setting up linters/language servers -루아 프로젝트에 diagnostics와 autocompletion를 적용하기 위해 린터나 랭귀지 서버를 사용한다면 네오빔 특정 세팅을 설정해줘야 합니다. 여기 유명한 도구들을 위한 추천하는 세팅이 몇 개 있습니다: +If you're using linters and/or language servers to get diagnostics and autocompletion for Lua projects, you may have to configure Neovim-specific settings for them. Here are a few recommended settings for popular tools: #### luacheck -[luacheck](https://github.com/mpeterv/luacheck/)은 `vim` 전역 변수를 인식할 수 있게 해줍니다. 다음 설정을 `~/.luacheckrc` (혹은 `$XDG_CONFIG_HOME/luacheck/.luacheckrc`)에 넣어주세요: +You can get [luacheck](https://github.com/mpeterv/luacheck/) to recognize the `vim` global by putting this configuration in `~/.luacheckrc` (or `$XDG_CONFIG_HOME/luacheck/.luacheckrc`): ```lua globals = { @@ -1318,35 +1290,29 @@ globals = { } ``` -[Alloyed/lua-lsp](https://github.com/Alloyed/lua-lsp/) language server는 `luacheck`을 사용하여 linting을 제공하고 같은 파일을 읽습니다. - - -`luacheck`에 대한 더 자세한 정보는 이 [문서](https://luacheck.readthedocs.io/en/stable/config.html)를 보시면 됩니다. +The [Alloyed/lua-lsp](https://github.com/Alloyed/lua-lsp/) language server uses `luacheck` to provide linting and reads the same file. +For more information on how to configure `luacheck`, please refer to its [documentation](https://luacheck.readthedocs.io/en/stable/config.html) #### sumneko/lua-language-server +The [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig/) repository contains [instructions to configure sumneko/lua-language-server](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#sumneko_lua) (the example uses the built-in LSP client but the configuration should be identical for other LSP client implementations). -[nvim-lspconfig](https://github.com/neovim/nvim-lspconfig/) 리포지터리는 [sumneko/lua-language-server 구성 지침](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#sumneko_lua)을 포함하고 있습니다(이 예시는 빌트인 LSP 클라이언트를 사용하고 있지만 구성은 다른 LSP 클라이언트 구현체들과 동일할 겁니다). - -[sumneko/lua-language-server](https://github.com/sumneko/lua-language-server/) 설정하는 더 상세한 설명은 ["Setting"](https://github.com/sumneko/lua-language-server/wiki/Setting)를 보세요. - +For more information on how to configure [sumneko/lua-language-server](https://github.com/sumneko/lua-language-server/) see ["Setting"](https://github.com/sumneko/lua-language-server/wiki/Setting) #### coc.nvim -[rafcamlet/coc-nvim-lua](https://github.com/rafcamlet/coc-nvim-lua/)는 [coc.nvim](https://github.com/neoclide/coc.nvim/)을 위한 자동완성 소스입니다. - -### 루아 코드 디버깅하기 +The [rafcamlet/coc-nvim-lua](https://github.com/rafcamlet/coc-nvim-lua/) completion source for [coc.nvim](https://github.com/neoclide/coc.nvim/) provides completion items for the Neovim stdlib. -[jbyuki/one-small-step-for-vimkind](https://github.com/jbyuki/one-small-step-for-vimkind)로 루아 코드를 별도의 네오빔 인스턴스로 실행하여 디버깅할 수 있습니다. +### Debugging Lua code +You can debug Lua code running in a separate Neovim instance with [jbyuki/one-small-step-for-vimkind](https://github.com/jbyuki/one-small-step-for-vimkind) -이 플러그인은 [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/)을 사용합니다. 디버그 어댑터에 연결하는 것은 [mfussenegger/nvim-dap](https://github.com/mfussenegger/nvim-dap/)이나 [puremourning/vimspector](https://github.com/puremourning/vimspector/) 같은 DAP 클라이언트를 필요로 합니다. +The plugin uses the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/). Connecting to a debug adapter requires a DAP client like [mfussenegger/nvim-dap](https://github.com/mfussenegger/nvim-dap/) or [puremourning/vimspector](https://github.com/puremourning/vimspector/). +### Debugging Lua mappings/commands/autocommands -### 루아 매핑/커맨드/오토커맨드 디버깅 - -`:verbose` 커맨드는 어디에 mapping/command/autocommand가 정의되어 있는지 확인할 수 있게 해줍니다: +The `:verbose` command allows you to see where a mapping/command/autocommand was defined: ```vim :verbose map m @@ -1357,81 +1323,79 @@ n m_ * echo 'example' Last set from ~/.config/nvim/init.vim line 26 ``` -루아에서 이 기능은 성능 상의 이유 때문에 기본적으로 비활성화 되어 있습니다. Neovim을 시작할 때 verbose 레벨을 0보다 크게 줌으로서 활성화시킬 수 있습니다: +By default, this feature is disabled in Lua for performance reasons. You can enable it by starting Neovim with a verbose level greater than 0: ```sh nvim -V1 ``` -자세한 정보: +See also: - [`:help 'verbose'`](https://neovim.io/doc/user/options.html#'verbose') - [`:help -V`](https://neovim.io/doc/user/starting.html#-V) - [neovim/neovim#15079](https://github.com/neovim/neovim/pull/15079) -### 루아 코드 테스팅 +### Testing Lua code - [plenary.nvim: test harness](https://github.com/nvim-lua/plenary.nvim/#plenarytest_harness) - [notomo/vusted](https://github.com/notomo/vusted) -### Luarocks 패키지 사용하기 +### Using Luarocks packages -[wbthomason/packer.nvim](https://github.com/wbthomason/packer.nvim)는 Luarocks 패키지를 지원합니다. [README](https://github.com/wbthomason/packer.nvim/#luarocks-support)에 세팅 방법에 대한 지침이 있습니다. +[wbthomason/packer.nvim](https://github.com/wbthomason/packer.nvim) supports Luarocks packages. Instructions for how to set this up are available in the [README](https://github.com/wbthomason/packer.nvim/#luarocks-support) -## 잡다 +## Miscellaneous ### vim.loop -`vim.loop` 은 LibUV API를 사용할 수 있는 모듈입니다. 리소스들: +`vim.loop` is the module that exposes the LibUV API. Some resources: - [Official documentation for LibUV](https://docs.libuv.org/en/v1.x/) - [Luv documentation](https://github.com/luvit/luv/blob/master/docs.md) - [teukka.tech - Using LibUV in Neovim](https://teukka.tech/posts/2020-01-07-vimloop/) -자세한 정보: +See also: - [`:help vim.loop`](https://neovim.io/doc/user/lua.html#vim.loop) ### vim.lsp -`vim.lsp`는 빌트인 LSP 클라이언트를 제어하는 모듈입니다. [neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig/) 리포지터리에 유명한 language server들의 기본 설정 방법을 설명하고 있습니다. +`vim.lsp` is the module that controls the built-in LSP client. The [neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig/) repository contains default configurations for popular language servers. -클라이언트 동작은 "lap-handlers"를 사용해 구성할 수 있습니다. 자세한 정보: +The behavior of the client can be configured using "lsp-handlers". For more information: - [`:help lsp-handler`](https://neovim.io/doc/user/lsp.html#lsp-handler) - [neovim/neovim#12655](https://github.com/neovim/neovim/pull/12655) - [How to migrate from diagnostic-nvim](https://github.com/nvim-lua/diagnostic-nvim/issues/73#issue-737897078) -[lsp client를 중심으로 개발된 플러그인](https://github.com/rockerBOO/awesome-neovim#lsp)들은 여기서 확인하실 수 있습니다. +You may also want to take a look at [plugins built around the LSP client](https://github.com/rockerBOO/awesome-neovim#lsp) -자세한 정보: +See also: - [`:help lsp`](https://neovim.io/doc/user/lsp.html#LSP) ### vim.treesitter `vim.treesitter` is the module that controls the integration of the [Tree-sitter](https://tree-sitter.github.io/tree-sitter/) library in Neovim. If you want to know more about Tree-sitter, you may be interested in this [presentation (38:37)](https://www.youtube.com/watch?v=Jes3bD6P0To). -`vim.treesitter`는 Neovim [Tree-sitter](https://tree-sitter.github.io/tree-sitter/) 라이브러리의 통합을 제어하는 모듈입니다. Tree-sitter에 대해 더 자세히 알고 싶다면 다음 [프레젠테이션 (38:37)](https://www.youtube.com/watch?v=Jes3bD6P0To)을 참조하세요. - -[nvim-treesitter](https://github.com/nvim-treesitter/) 조직은 이 라이브러리를 활용한 다양한 플러그인들을 제공합니다. +The [nvim-treesitter](https://github.com/nvim-treesitter/) organisation hosts various plugins taking advantage of the library. -자세한 정보: +See also: - [`:help lua-treesitter`](https://neovim.io/doc/user/treesitter.html#lua-treesitter) ### Transpilers -루아를 사용하는 것의 이점 중 하나는 루아 코드로 작성하지 않아도 된다는 것입니다! 루아를 위한 다양한 트랜스파일러들이 있습니다. +One advantage of using Lua is that you don't actually have to write Lua code! There is a multitude of transpilers available for the language. - [Moonscript](https://moonscript.org/) -아마 가장 잘 알려진 루아 트랜스파일러입니다. 클래스, 배열 이해(list comprehension), 함수 리터럴 같은 편리한 기능들을 많이 제공하고 있습니다. [svermeulen/nvim-moonmaker](https://github.com/svermeulen/nvim-moonmaker) 플러그인은 네오빔 플러그인과 설정을 Moonscript에서 바로 할 수 있도록 해줍니다. +Probably one of the most well-known transpilers for Lua. Adds a lots of convenient features like classes, list comprehensions or function literals. The [svermeulen/nvim-moonmaker](https://github.com/svermeulen/nvim-moonmaker) plugin allows you to write Neovim plugins and configuration directly in Moonscript. - [Fennel](https://fennel-lang.org/) -루아로 컴파일되는 리습입니다. [Olical/aniseed](https://github.com/Olical/aniseed) 혹은 [Hotpot](https://github.com/rktjmp/hotpot.nvim) 플러그인을 사용하면 네오빔을 위한 구성과 플러그인 작성을 Fennel로 할 수 있습니다. 추가적으로 [Olical/conjure](https://github.com/Olical/conjure) 플러그인은 Fennel을(다른 리습 계열 언어들과 함께) 지원하는 IDE를 제공합니다. +A lisp that compiles to Lua. You can write configuration and plugins for Neovim in Fennel with the [Olical/aniseed](https://github.com/Olical/aniseed) or the [Hotpot](https://github.com/rktjmp/hotpot.nvim) plugin. Additionally, the [Olical/conjure](https://github.com/Olical/conjure) plugin provides an interactive development environment that supports Fennel (among other languages). - [Teal](https://github.com/teal-language/tl) -Teal은 TL(typed lua)로 발음됩니다. 스탠다드 루아 구문을 그대로 유지하면서 강타입 시스템을 지원하는 언어입니다. [nvim-teal-maker](https://github.com/svermeulen/nvim-teal-maker) 플러그인으로 Teal을 사용해 네오빔 플러그인, 구성을 작성할 수 있습니다. +The name Teal comes from pronouncing TL (typed lua). This is exactly what it tries to do - add strong typing to lua while otherwise remaining close to standard lua syntax. The [nvim-teal-maker](https://github.com/svermeulen/nvim-teal-maker) plugin can be used to write Neovim plugins or configuration files directly in Teal -다른 흥미로운 프로젝트들: +Other interesting projects: - [TypeScriptToLua/TypeScriptToLua](https://github.com/TypeScriptToLua/TypeScriptToLua) - [Haxe](https://haxe.org/) - [SwadicalRag/wasm2lua](https://github.com/SwadicalRag/wasm2lua) diff --git a/README.md.tmp b/README.md.tmp deleted file mode 100644 index d413b29..0000000 --- a/README.md.tmp +++ /dev/null @@ -1,1401 +0,0 @@ -:arrow_upper_left: (Feeling lost? Use the GitHub TOC!) - -# Neovim에서 Lua 사용 시작하기 - -## 번역 - -- [:cn: Chinese version](https://github.com/glepnir/nvim-lua-guide-zh) -- [:es: Spanish version](https://github.com/RicardoRien/nvim-lua-guide/blob/master/README.esp.md) -- [:brazil: Portuguese version](https://github.com/npxbr/nvim-lua-guide/blob/master/README.pt-br.md) -- [:jp: Japanese version](https://github.com/willelz/nvim-lua-guide-ja/blob/master/README.ja.md) -- [:ru: Russian version](https://github.com/kuator/nvim-lua-guide-ru) -- [🇺🇦 Ukrainian version](https://github.com/famiclone/nvim-lua-guide-ua) - -## 소개 - -The [integration of Lua](https://www.youtube.com/watch?v=IP3J56sKtn0) as a [first-class language inside Neovim](https://github.com/neovim/neovim/wiki/FAQ#why-embed-lua-instead-of-x) is shaping up to be one of its killer features. -However, the amount of teaching material for learning how to write plugins in Lua is not as large as what you would find for writing them in Vimscript. This is an attempt at providing some basic information to get people started. - -This guide assumes you are using at least version 0.5 of Neovim. - -### Learning Lua - -If you are not already familiar with the language, there are plenty of resources to get started: - -- The [Learn X in Y minutes page about Lua](https://learnxinyminutes.com/docs/lua/) should give you a quick overview of the basics -- [This guide](https://github.com/medwatt/Notes/blob/main/Lua/Lua_Quick_Guide.ipynb) is also a good resource for getting started quickly -- If videos are more to your liking, Derek Banas has a [1-hour tutorial on the language](https://www.youtube.com/watch?v=iMacxZQMPXs) -- Want something a little more interactive with runnable examples? Try [the LuaScript tutorial](https://www.luascript.dev/learn) -- The [lua-users wiki](http://lua-users.org/wiki/LuaDirectory) is full of useful information on all kinds of Lua-related topics -- The [official reference manual for Lua](https://www.lua.org/manual/5.1/) should give you the most comprehensive tour of the language (exists as a Vimdoc plugin if you want to read it from the comfort of your editor: [milisims/nvim-luaref](https://github.com/milisims/nvim-luaref)) - -It should also be noted that Lua is a very clean and simple language. It is easy to learn, especially if you have experience with similar scripting languages like JavaScript. You may already know more Lua than you realise! - -Note: the version of Lua that Neovim embeds is [LuaJIT](https://staff.fnwi.uva.nl/h.vandermeer/docs/lua/luajit/luajit_intro.html) 2.1.0, which maintains compatibility with Lua 5.1. - -### Existing tutorials for writing Lua in Neovim - -A few tutorials have already been written to help people write plugins in Lua. Some of them helped quite a bit when writing this guide. Many thanks to their authors. - -- [teukka.tech - From init.vim to init.lua](https://teukka.tech/luanvim.html) -- [dev.to - How to write neovim plugins in Lua](https://dev.to/2nit/how-to-write-neovim-plugins-in-lua-5cca) -- [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) -- [ms-jpq - Neovim Async Tutorial](https://github.com/ms-jpq/neovim-async-tutorial) -- [oroques.dev - Neovim 0.5 features and the switch to init.lua](https://oroques.dev/notes/neovim-init/) -- [Building A Vim Statusline from Scratch - jdhao's blog](https://jdhao.github.io/2019/11/03/vim_custom_statusline/) -- [Configuring Neovim using Lua](https://icyphox.sh/blog/nvim-lua/) -- [Devlog | Everything you need to know to configure neovim using lua](https://vonheikemen.github.io/devlog/tools/configuring-neovim-using-lua/) - -### Companion plugins - -- [Vimpeccable](https://github.com/svermeulen/vimpeccable) - Plugin to help write your .vimrc in Lua -- [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) - All the lua functions I don't want to write twice -- [popup.nvim](https://github.com/nvim-lua/popup.nvim) - An implementation of the Popup API from vim in Neovim -- [nvim_utils](https://github.com/norcalli/nvim_utils) -- [nvim-luadev](https://github.com/bfredl/nvim-luadev) - REPL/debug console for nvim lua plugins -- [nvim-luapad](https://github.com/rafcamlet/nvim-luapad) - Interactive real time neovim scratchpad for embedded lua engine -- [nlua.nvim](https://github.com/tjdevries/nlua.nvim) - Lua Development for Neovim -- [BetterLua.vim](https://github.com/euclidianAce/BetterLua.vim) - Better Lua syntax highlighting in Vim/NeoVim - -## Where to put Lua files - -### init.lua - -Neovim supports loading an `init.lua` file for configuration instead of the usual `init.vim`. - -Note: `init.lua` is of course _completely_ optional. Support for `init.vim` is not going away and is still a valid option for configuration. Do keep in mind that some features are not 100% exposed to Lua yet. - -See also: -- [`:help config`](https://neovim.io/doc/user/starting.html#config) - -### Modules - -Lua modules are found inside a `lua/` folder in your `'runtimepath'` (for most users, this will mean `~/.config/nvim/lua` on \*nix systems and `~/AppData/Local/nvim/lua` on Windows). You can `require()` files in this folder as Lua modules. - -Let's take the following folder structure as an example: - -```text -📂 ~/.config/nvim -├── 📁 after -├── 📁 ftplugin -├── 📂 lua -│ ├── 🌑 myluamodule.lua -│ └── 📂 other_modules -│ ├── 🌑 anothermodule.lua -│ └── 🌑 init.lua -├── 📁 pack -├── 📁 plugin -├── 📁 syntax -└── 🇻 init.vim -``` - -The following Lua code will load `myluamodule.lua`: - -```lua -require('myluamodule') -``` - -Notice the absence of a `.lua` extension. - -Similarly, loading `other_modules/anothermodule.lua` is done like so: - -```lua -require('other_modules.anothermodule') --- or -require('other_modules/anothermodule') -``` - -Path separators are denoted by either a dot `.` or a slash `/`. - -A folder containing an `init.lua` file can be required directly, without having to specify the name of the file. - -```lua -require('other_modules') -- loads other_modules/init.lua -``` - -Requiring a nonexistent module or a module which contains syntax errors aborts the currently executing script. -`pcall()` may be used to prevent errors. - -```lua -local ok, _ = pcall(require, 'module_with_error') -if not ok then - -- not loaded -end -``` - -See also: -- [`:help lua-require`](https://neovim.io/doc/user/lua.html#lua-require) - -#### Tips - -Several Lua plugins might have identical filenames in their `lua/` folder. This could lead to namespace clashes. - -If two different plugins have a `lua/main.lua` file, then doing `require('main')` is ambiguous: which file do we want to source? - -It might be a good idea to namespace your config or your plugin with a top-level folder, like so: `lua/plugin_name/main.lua` - -### Runtime files - -Much like Vimscript files, Lua files can be loaded automatically from special folders in your `runtimepath`. Currently, the following folders are supported: - -- `colors/` -- `compiler/` -- `ftplugin/` -- `ftdetect/` -- `indent/` -- `plugin/` -- `syntax/` - -Note: in a runtime directory, all `*.vim` files are sourced before `*.lua` files. - -See also: -- [`:help 'runtimepath'`](https://neovim.io/doc/user/options.html#'runtimepath') -- [`:help load-plugins`](https://neovim.io/doc/user/starting.html#load-plugins) - -#### Tips - -Since runtime files aren't based on the Lua module system, two plugins can have a `plugin/main.lua` file without it being an issue. - -## Using Lua from Vimscript - -### :lua - -This command executes a chunk of Lua code. - -```vim -:lua require('myluamodule') -``` - -Multi-line scripts are possible using heredoc syntax: - -```vim -echo "Here's a bigger chunk of Lua code" - -lua << EOF -local mod = require('mymodule') -local tbl = {1, 2, 3} - -for k, v in ipairs(tbl) do - mod.method(v) -end - -print(tbl) -EOF -``` - -Note: each `:lua` command has its own scope and variables declared with the `local` keyword are not accessible outside of the command. This won't work: - -```vim -:lua local foo = 1 -:lua print(foo) -" prints 'nil' instead of '1' -``` - -Note 2: the `print()` function in Lua behaves similarly to the `:echomsg` command. Its output is saved in the message-history and can be suppressed by the `:silent` command. - -See also: - -- [`:help :lua`](https://neovim.io/doc/user/lua.html#Lua) -- [`:help :lua-heredoc`](https://neovim.io/doc/user/lua.html#:lua-heredoc) - -### :luado - -This command executes a chunk of Lua code that acts on a range of lines in the current buffer. If no range is specified, the whole buffer is used instead. Whatever string is `return`ed from the chunk is used to determine what each line should be replaced with. - -The following command would replace every line in the current buffer with the text `hello world`: - -```vim -:luado return 'hello world' -``` - -Two implicit `line` and `linenr` variables are also provided. `line` is the text of the line being iterated upon whereas `linenr` is its number. The following command would make every line whose number is divisible by 2 uppercase: - -```vim -:luado if linenr % 2 == 0 then return line:upper() end -``` - -See also: - -- [`:help :luado`](https://neovim.io/doc/user/lua.html#:luado) - -### Sourcing Lua files - -Neovim provides 3 Ex commands to source Lua files - -- `:luafile` -- `:source` -- `:runtime` - -`:luafile` and `:source` are very similar: - -```vim -:luafile ~/foo/bar/baz/myluafile.lua -:luafile % -:source ~/foo/bar/baz/myluafile.lua -:source % -``` - -`:source` also supports ranges, which can be useful to only execute part of a script: - -```vim -:1,10source -``` - -`:runtime` is a little different: it uses the `'runtimepath'` option to determine which files to source. See [`:help :runtime`](https://neovim.io/doc/user/repeat.html#:runtime) for more details. - -See also: - -- [`:help :luafile`](https://neovim.io/doc/user/lua.html#:luafile) -- [`:help :source`](https://neovim.io/doc/user/repeat.html#:source) -- [`:help :runtime`](https://neovim.io/doc/user/repeat.html#:runtime) - -#### Sourcing a lua file vs calling require(): - -You might be wondering what the difference between calling the `require()` function and sourcing a Lua file is and whether you should prefer one way over the other. They have different use cases: - -- `require()`: - - is a built-in Lua function. It allows you to take advantage of Lua's module system - - searches for modules in `lua/` folders in your `'runtimepath'` - - keeps track of what modules have been loaded and prevents a script from being parsed and executed a second time. If you change the file containing the code for a module and try to `require()` it a second time while Neovim is running, the module will not actually update -- `:luafile`, `:source` and `:runtime`: - - are Ex commands. They do not support modules - - execute the contents of a script regardless of whether it has been executed before - - `:luafile` and `:source` take a path that is either absolute or relative to the working directory of the current window - - `:runtime` uses the `'runtimepath'` option to find files - -Files sourced via `:source`, `:runtime` or automatically from runtime directories will also show up in `:scriptnames` and `--startuptime` - -### luaeval() - -This built-in Vimscript function evaluates a Lua expression string and returns its value. Lua data types are automatically converted to Vimscript types (and vice versa). - -```vim -" You can store the result in a variable -let variable = luaeval('1 + 1') -echo variable -" 2 -let concat = luaeval('"Lua".." is ".."awesome"') -echo concat -" 'Lua is awesome' - -" List-like tables are converted to Vim lists -let list = luaeval('{1, 2, 3, 4}') -echo list[0] -" 1 -echo list[1] -" 2 -" Note that unlike Lua tables, Vim lists are 0-indexed - -" Dict-like tables are converted to Vim dictionaries -let dict = luaeval('{foo = "bar", baz = "qux"}') -echo dict.foo -" 'bar' - -" Same thing for booleans and nil -echo luaeval('true') -" v:true -echo luaeval('nil') -" v:null - -" You can create Vimscript aliases for Lua functions -let LuaMathPow = luaeval('math.pow') -echo LuaMathPow(2, 2) -" 4 -let LuaModuleFunction = luaeval('require("mymodule").myfunction') -call LuaModuleFunction() - -" It is also possible to pass Lua functions as values to Vim functions -lua X = function(k, v) return string.format("%s:%s", k, v) end -echo map([1, 2, 3], luaeval("X")) -``` - -`luaeval()` takes an optional second argument that allows you to pass data to the expression. You can then access that data from Lua using the magic global `_A`: - -```vim -echo luaeval('_A[1] + _A[2]', [1, 1]) -" 2 - -echo luaeval('string.format("Lua is %s", _A)', 'awesome') -" 'Lua is awesome' -``` - -See also: -- [`:help luaeval()`](https://neovim.io/doc/user/lua.html#luaeval()) - -### v:lua - -This global Vim variable allows you to call Lua functions in the global namespace ([`_G`](https://www.lua.org/manual/5.1/manual.html#pdf-_G)) directly from Vimscript. Again, Vim data types are converted to Lua types and vice versa. - -```vim -call v:lua.print('Hello from Lua!') -" 'Hello from Lua!' - -let scream = v:lua.string.rep('A', 10) -echo scream -" 'AAAAAAAAAA' - -" How about a nice statusline? -lua << EOF -function _G.statusline() - local filepath = '%f' - local align_section = '%=' - local percentage_through_file = '%p%%' - return string.format( - '%s%s%s', - filepath, - align_section, - percentage_through_file - ) -end -EOF - -set statusline=%!v:lua.statusline() - -" Also works in expression mappings -lua << EOF -function _G.check_back_space() - local col = vim.api.nvim_win_get_cursor(0)[2] - return (col == 0 or vim.api.nvim_get_current_line():sub(col, col):match('%s')) and true -end -EOF - -inoremap - \ pumvisible() ? "\" : - \ v:lua.check_back_space() ? "\" : - \ completion#trigger_completion() - -" Call a function from a Lua module by using single quotes and omitting parentheses: -call v:lua.require'module'.foo() -``` - -See also: -- [`:help v:lua`](https://neovim.io/doc/user/eval.html#v:lua) -- [`:help v:lua-call`](https://neovim.io/doc/user/lua.html#v:lua-call) - -#### Caveats - -This variable can only be used to call functions. The following will always throw an error: - -```vim -" Aliasing functions doesn't work -let LuaPrint = v:lua.print - -" Accessing dictionaries doesn't work -echo v:lua.some_global_dict['key'] - -" Using a function as a value doesn't work -echo map([1, 2, 3], v:lua.global_callback) -``` - -### Tips - -You can get Lua syntax highlighting inside .vim files by putting `let g:vimsyn_embed = 'l'` in your configuration file. See [`:help g:vimsyn_embed`](https://neovim.io/doc/user/syntax.html#g:vimsyn_embed) for more on this option. - -## The vim namespace - -Neovim exposes a global `vim` variable which serves as an entry point to interact with its APIs from Lua. It provides users with an extended "standard library" of functions as well as various sub-modules. - -Some notable functions and modules include: - -- `vim.inspect`: transform Lua objects into human-readable strings (useful for inspecting tables) -- `vim.regex`: use Vim regexes from Lua -- `vim.api`: module that exposes API functions (the same API used by remote plugins) -- `vim.ui`: overridable UI functions that can be leveraged by plugins -- `vim.loop`: module that exposes the functionality of Neovim's event-loop (using LibUV) -- `vim.lsp`: module that controls the built-in LSP client -- `vim.treesitter`: module that exposes the functionality of the tree-sitter library - -This list is by no means comprehensive. If you wish to know more about what's made available by the `vim` variable, [`:help lua-stdlib`](https://neovim.io/doc/user/lua.html#lua-stdlib) and [`:help lua-vim`](https://neovim.io/doc/user/lua.html#lua-vim) are the way to go. Alternatively, you can do `:lua print(vim.inspect(vim))` to get a list of every module. API functions are documented under [`:help api-global`](https://neovim.io/doc/user/api.html#api-global). - -#### Tips - -Writing `print(vim.inspect(x))` every time you want to inspect the contents of an object can get pretty tedious. It might be worthwhile to have a global wrapper function somewhere in your configuration (in Neovim 0.7.0+, this function is built-in, see [`:help vim.pretty_print()`](https://neovim.io/doc/user/lua.html#vim.pretty_print())): - -```lua -function _G.put(...) - local objects = {} - for i = 1, select('#', ...) do - local v = select(i, ...) - table.insert(objects, vim.inspect(v)) - end - - print(table.concat(objects, '\n')) - return ... -end -``` - -You can then inspect the contents of an object very quickly in your code or from the command-line: - -```lua -put({1, 2, 3}) -``` - -```vim -:lua put(vim.loop) -``` - -Alternatively, you can use the `:lua` command to pretty-print a Lua expression by prefixing it with `=` (Neovim 0.7+ only): -```vim -:lua =vim.loop -``` - -Additionally, you may find that built-in Lua functions are sometimes lacking compared to what you would find in other languages (for example `os.clock()` only returns a value in seconds, not milliseconds). Be sure to look at the Neovim stdlib (and `vim.fn`, more on that later), it probably has what you're looking for. - -## Using Vimscript from Lua - -### vim.api.nvim_eval() - -This function evaluates a Vimscript expression string and returns its value. Vimscript data types are automatically converted to Lua types (and vice versa). - -It is the Lua equivalent of the `luaeval()` function in Vimscript - -```lua --- Data types are converted correctly -print(vim.api.nvim_eval('1 + 1')) -- 2 -print(vim.inspect(vim.api.nvim_eval('[1, 2, 3]'))) -- { 1, 2, 3 } -print(vim.inspect(vim.api.nvim_eval('{"foo": "bar", "baz": "qux"}'))) -- { baz = "qux", foo = "bar" } -print(vim.api.nvim_eval('v:true')) -- true -print(vim.api.nvim_eval('v:null')) -- nil -``` - -#### Caveats - -Unlike `luaeval()`, `vim.api.nvim_eval()` does not provide an implicit `_A` variable to pass data to the expression. - -### vim.api.nvim_exec() - -This function evaluates a chunk of Vimscript code. It takes in a string containing the source code to execute and a boolean to determine whether the output of the code should be returned by the function (you can then store the output in a variable, for example). - -```lua -local result = vim.api.nvim_exec( -[[ -let s:mytext = 'hello world' - -function! s:MyFunction(text) - echo a:text -endfunction - -call s:MyFunction(s:mytext) -]], -true) - -print(result) -- 'hello world' -``` - -#### Caveats - -`nvim_exec` does not support script-local variables (`s:`) prior to Neovim 0.6.0 - -### vim.api.nvim_command() - -This function executes an ex command. It takes in a string containing the command to execute. - -```lua -vim.api.nvim_command('new') -vim.api.nvim_command('wincmd H') -vim.api.nvim_command('set nonumber') -vim.api.nvim_command('%s/foo/bar/g') -``` - -### vim.cmd() - -Alias for `vim.api.nvim_exec()`. Only the command argument is needed, `output` is always set to `false`. - -```lua -vim.cmd('buffers') -vim.cmd([[ -let g:multiline_list = [ - \ 1, - \ 2, - \ 3, - \ ] - -echo g:multiline_list -]]) -``` - -#### Tips - -Since you have to pass strings to these functions, you often end up having to escape backslashes: - -```lua -vim.cmd('%s/\\Vfoo/bar/g') -``` - -Double bracketed strings are easier to use as they do not require escaping characters: - -```lua -vim.cmd([[%s/\Vfoo/bar/g]]) -``` - -### vim.api.nvim_replace_termcodes() - -This API function allows you to escape terminal codes and Vim keycodes. - -You may have come across mappings like this one: - -```vim -inoremap pumvisible() ? "\" : "\" -``` - -Trying to do the same in Lua can prove to be a challenge. You might be tempted to do it like this: - -```lua -function _G.smart_tab() - return vim.fn.pumvisible() == 1 and [[\]] or [[\]] -end - -vim.api.nvim_set_keymap('i', '', 'v:lua.smart_tab()', {expr = true, noremap = true}) -``` - -only to find out that the mapping inserts `\` and `\` literally... - -Being able to escape keycodes is actually a Vimscript feature. Aside from the usual escape sequences like `\r`, `\42` or `\x10` that are common to many programming languages, Vimscript `expr-quotes` (strings surrounded with double quotes) allow you to escape the human-readable representation of Vim keycodes. - -Lua doesn't have such a feature built-in. Fortunately, Neovim has an API function for escaping terminal codes and keycodes: `nvim_replace_termcodes()` - -```lua -print(vim.api.nvim_replace_termcodes('', true, true, true)) -``` - -This is a little verbose. Making a reusable wrapper can help: - -```lua --- The function is called `t` for `termcodes`. --- You don't have to call it that, but I find the terseness convenient -local function t(str) - -- Adjust boolean arguments as needed - return vim.api.nvim_replace_termcodes(str, true, true, true) -end - -print(t'') -``` - -Coming back to our earlier example, this should now work as expected: - -```lua -local function t(str) - return vim.api.nvim_replace_termcodes(str, true, true, true) -end - -function _G.smart_tab() - return vim.fn.pumvisible() == 1 and t'' or t'' -end - -vim.api.nvim_set_keymap('i', '', 'v:lua.smart_tab()', {expr = true, noremap = true}) -``` - -This is not necessary with `vim.keymap.set()` as it automatically transforms vim keycodes returned by Lua functions in `expr` mappings by default: - -```lua -vim.keymap.set('i', '', function() - return vim.fn.pumvisible() == 1 and '' or '' -end, {expr = true}) -``` - -See also: - -- [`:help keycodes`](https://neovim.io/doc/user/intro.html#keycodes) -- [`:help expr-quote`](https://neovim.io/doc/user/eval.html#expr-quote) -- [`:help nvim_replace_termcodes()`](https://neovim.io/doc/user/api.html#nvim_replace_termcodes()) - -## Managing vim options - -### Using api functions - -Neovim provides a set of API functions to either set an option or get its current value: - -- Global options: - - [`vim.api.nvim_set_option()`](https://neovim.io/doc/user/api.html#nvim_set_option()) - - [`vim.api.nvim_get_option()`](https://neovim.io/doc/user/api.html#nvim_get_option()) -- Buffer-local options: - - [`vim.api.nvim_buf_set_option()`](https://neovim.io/doc/user/api.html#nvim_buf_set_option()) - - [`vim.api.nvim_buf_get_option()`](https://neovim.io/doc/user/api.html#nvim_buf_get_option()) -- Window-local options: - - [`vim.api.nvim_win_set_option()`](https://neovim.io/doc/user/api.html#nvim_win_set_option()) - - [`vim.api.nvim_win_get_option()`](https://neovim.io/doc/user/api.html#nvim_win_get_option()) - -They take a string containing the name of the option to set/get as well as the value you want to set it to. - -Boolean options (like `(no)number`) have to be set to either `true` or `false`: - -```lua -vim.api.nvim_set_option('smarttab', false) -print(vim.api.nvim_get_option('smarttab')) -- false -``` - -Unsurprisingly, string options have to be set to a string: - -```lua -vim.api.nvim_set_option('selection', 'exclusive') -print(vim.api.nvim_get_option('selection')) -- 'exclusive' -``` - -Number options accept a number: - -```lua -vim.api.nvim_set_option('updatetime', 3000) -print(vim.api.nvim_get_option('updatetime')) -- 3000 -``` - -Buffer-local and window-local options also need a buffer number or a window number (using `0` will set/get the option for the current buffer/window): - -```lua -vim.api.nvim_win_set_option(0, 'number', true) -vim.api.nvim_buf_set_option(10, 'shiftwidth', 4) -print(vim.api.nvim_win_get_option(0, 'number')) -- true -print(vim.api.nvim_buf_get_option(10, 'shiftwidth')) -- 4 -``` - -### Using meta-accessors - -A few meta-accessors are available if you want to set options in a more "idiomatic" way. They essentially wrap the above API functions and allow you to manipulate options as if they were variables: - -- [`vim.o`](https://neovim.io/doc/user/lua.html#vim.o): behaves like `:let &{option-name}` -- [`vim.go`](https://neovim.io/doc/user/lua.html#vim.go): behaves like `:let &g:{option-name}` -- [`vim.bo`](https://neovim.io/doc/user/lua.html#vim.bo): behaves like `:let &l:{option-name}` for buffer-local options -- [`vim.wo`](https://neovim.io/doc/user/lua.html#vim.wo): behaves like `:let &l:{option-name}` for window-local options - -```lua -vim.o.smarttab = false -- let &smarttab = v:false -print(vim.o.smarttab) -- false -vim.o.isfname = vim.o.isfname .. ',@-@' -- on Linux: let &isfname = &isfname .. ',@-@' -print(vim.o.isfname) -- '@,48-57,/,.,-,_,+,,,#,$,%,~,=,@-@' - -vim.bo.shiftwidth = 4 -print(vim.bo.shiftwidth) -- 4 -``` - -You can specify a number for buffer-local and window-local options. If no number is given, the current buffer/window is used: - -```lua -vim.bo[4].expandtab = true -- same as vim.api.nvim_buf_set_option(4, 'expandtab', true) -vim.wo.number = true -- same as vim.api.nvim_win_set_option(0, 'number', true) -``` - -These wrappers also have more sophisticated `vim.opt*` variants that provide convenient mechanisms for setting options in Lua. They're similar to what you might be used to in your `init.vim`: - -- `vim.opt`: behaves like `:set` -- `vim.opt_global`: behaves like `:setglobal` -- `vim.opt_local`: behaves like `:setlocal` - -```lua -vim.opt.smarttab = false -print(vim.opt.smarttab:get()) -- false -``` - -Some options can be set using Lua tables: - -```lua -vim.opt.completeopt = {'menuone', 'noselect'} -print(vim.inspect(vim.opt.completeopt:get())) -- { "menuone", "noselect" } -``` - -Wrappers for list-like, map-like and set-like options also come with methods and metamethods that work similarly to their `:set+=`, `:set^=` and `:set-=` counterparts in Vimscript. - -```lua -vim.opt.shortmess:append({ I = true }) --- alternative form: -vim.opt.shortmess = vim.opt.shortmess + { I = true } - -vim.opt.whichwrap:remove({ 'b', 's' }) --- alternative form: -vim.opt.whichwrap = vim.opt.whichwrap - { 'b', 's' } -``` - -Be sure to look at [`:help vim.opt`](https://neovim.io/doc/user/lua.html#vim.opt) for more information. - -See also: -- [`:help lua-vim-options`](https://neovim.io/doc/user/lua.html#lua-vim-options) - -## Managing vim internal variables - -### Using api functions - -Much like options, internal variables have their own set of API functions: - -- Global variables (`g:`): - - [`vim.api.nvim_set_var()`](https://neovim.io/doc/user/api.html#nvim_set_var()) - - [`vim.api.nvim_get_var()`](https://neovim.io/doc/user/api.html#nvim_get_var()) - - [`vim.api.nvim_del_var()`](https://neovim.io/doc/user/api.html#nvim_del_var()) -- Buffer variables (`b:`): - - [`vim.api.nvim_buf_set_var()`](https://neovim.io/doc/user/api.html#nvim_buf_set_var()) - - [`vim.api.nvim_buf_get_var()`](https://neovim.io/doc/user/api.html#nvim_buf_get_var()) - - [`vim.api.nvim_buf_del_var()`](https://neovim.io/doc/user/api.html#nvim_buf_del_var()) -- Window variables (`w:`): - - [`vim.api.nvim_win_set_var()`](https://neovim.io/doc/user/api.html#nvim_win_set_var()) - - [`vim.api.nvim_win_get_var()`](https://neovim.io/doc/user/api.html#nvim_win_get_var()) - - [`vim.api.nvim_win_del_var()`](https://neovim.io/doc/user/api.html#nvim_win_del_var()) -- Tabpage variables (`t:`): - - [`vim.api.nvim_tabpage_set_var()`](https://neovim.io/doc/user/api.html#nvim_tabpage_set_var()) - - [`vim.api.nvim_tabpage_get_var()`](https://neovim.io/doc/user/api.html#nvim_tabpage_get_var()) - - [`vim.api.nvim_tabpage_del_var()`](https://neovim.io/doc/user/api.html#nvim_tabpage_del_var()) -- Predefined Vim variables (`v:`): - - [`vim.api.nvim_set_vvar()`](https://neovim.io/doc/user/api.html#nvim_set_vvar()) - - [`vim.api.nvim_get_vvar()`](https://neovim.io/doc/user/api.html#nvim_get_vvar()) - -With the exception of predefined Vim variables, they can also be deleted (the `:unlet` command is the equivalent in Vimscript). Local variables (`l:`), script variables (`s:`) and function arguments (`a:`) cannot be manipulated as they only make sense in the context of a Vim script, Lua has its own scoping rules. - -If you are unfamiliar with what these variables do, [`:help internal-variables`](https://neovim.io/doc/user/eval.html#internal-variables) describes them in detail. - -These functions take a string containing the name of the variable to set/get/delete as well as the value you want to set it to. - -```lua -vim.api.nvim_set_var('some_global_variable', { key1 = 'value', key2 = 300 }) -print(vim.inspect(vim.api.nvim_get_var('some_global_variable'))) -- { key1 = "value", key2 = 300 } -vim.api.nvim_del_var('some_global_variable') -``` - -Variables that are scoped to a buffer, a window or a tabpage also receive a number (using `0` will set/get/delete the variable for the current buffer/window/tabpage): - -```lua -vim.api.nvim_win_set_var(0, 'some_window_variable', 2500) -vim.api.nvim_tab_set_var(3, 'some_tabpage_variable', 'hello world') -print(vim.api.nvim_win_get_var(0, 'some_window_variable')) -- 2500 -print(vim.api.nvim_buf_get_var(3, 'some_tabpage_variable')) -- 'hello world' -vim.api.nvim_win_del_var(0, 'some_window_variable') -vim.api.nvim_buf_del_var(3, 'some_tabpage_variable') -``` - -### Using meta-accessors - -Internal variables can be manipulated more intuitively using these meta-accessors: - -- [`vim.g`](https://neovim.io/doc/user/lua.html#vim.g): global variables -- [`vim.b`](https://neovim.io/doc/user/lua.html#vim.b): buffer variables -- [`vim.w`](https://neovim.io/doc/user/lua.html#vim.w): window variables -- [`vim.t`](https://neovim.io/doc/user/lua.html#vim.t): tabpage variables -- [`vim.v`](https://neovim.io/doc/user/lua.html#vim.v): predefined Vim variables -- [`vim.env`](https://neovim.io/doc/user/lua.html#vim.env): environment variables - -```lua -vim.g.some_global_variable = { - key1 = 'value', - key2 = 300 -} - -print(vim.inspect(vim.g.some_global_variable)) -- { key1 = "value", key2 = 300 } - --- target a specific buffer/window/tabpage (Neovim 0.6+) -vim.b[2].myvar = 1 -``` - -Some variable names may contain characters that cannot be used for identifiers in Lua. You can still manipulate these variables by using this syntax: `vim.g['my#variable']`. - -To delete one of these variables, simply assign `nil` to it: - -```lua -vim.g.some_global_variable = nil -``` - -See also: -- [`:help lua-vim-variables`](https://neovim.io/doc/user/lua.html#lua-vim-variables) - -#### Caveats - -You cannot add/update/delete keys from a dictionary stored in one of these variables. For example, this snippet of Vimscript code does not work as expected: - -```vim -let g:variable = {} -lua vim.g.variable.key = 'a' -echo g:variable -" {} -``` - -You can use a temporary variable as a workaround: - -```vim -let g:variable = {} -lua << EOF -local tmp = vim.g.variable -tmp.key = 'a' -vim.g.variable = tmp -EOF -echo g:variable -" {'key': 'a'} -``` - -This is a known issue: - -- [Issue #12544](https://github.com/neovim/neovim/issues/12544) - -## Calling Vimscript functions - -### vim.fn.{function}() - -`vim.fn` can be used to call a Vimscript function. Data types are converted back and forth from Lua to Vimscript. - -```lua -print(vim.fn.printf('Hello from %s', 'Lua')) - -local reversed_list = vim.fn.reverse({ 'a', 'b', 'c' }) -print(vim.inspect(reversed_list)) -- { "c", "b", "a" } - -local function print_stdout(chan_id, data, name) - print(data[1]) -end - -vim.fn.jobstart('ls', { on_stdout = print_stdout }) -``` - -Hashes (`#`) are not valid characters for identifiers in Lua, so autoload functions have to be called with this syntax: - -```lua -vim.fn['my#autoload#function']() -``` - -The functionality of `vim.fn` is identical to `vim.call`, but allows a more Lua-like syntax. - -It is distinct from `vim.api.nvim_call_function` in that converting Vim/Lua objects is automatic: `vim.api.nvim_call_function` returns a table for floating point numbers and does not accept Lua closures while `vim.fn` handles these types transparently. - -See also: -- [`:help vim.fn`](https://neovim.io/doc/user/lua.html#vim.fn) - -#### Tips - -Neovim has an extensive library of powerful built-in functions that are very useful for plugins. See [`:help vim-function`](https://neovim.io/doc/user/eval.html#vim-function) for an alphabetical list and [`:help function-list`](https://neovim.io/doc/user/usr_41.html#function-list) for a list of functions grouped by topic. - -Neovim API functions can be used directly through `vim.api.{..}`. See [`:help api`](https://neovim.io/doc/user/api.html#API) for information. - -#### Caveats - -Some Vim functions that should return a boolean return `1` or `0` instead. This isn't a problem in Vimscript as `1` is truthy and `0` falsy, enabling constructs like these: - -```vim -if has('nvim') - " do something... -endif -``` - -In Lua however, only `false` and `nil` are considered falsy, numbers always evaluate to `true` no matter their value. You have to explicitly check for `1` or `0`: - -```lua -if vim.fn.has('nvim') == 1 then - -- do something... -end -``` - -## Defining mappings - -### API functions - -Neovim provides a list of API functions to set, get and delete mappings: - -- Global mappings: - - [`vim.api.nvim_set_keymap()`](https://neovim.io/doc/user/api.html#nvim_set_keymap()) - - [`vim.api.nvim_get_keymap()`](https://neovim.io/doc/user/api.html#nvim_get_keymap()) - - [`vim.api.nvim_del_keymap()`](https://neovim.io/doc/user/api.html#nvim_del_keymap()) -- Buffer-local mappings: - - [`vim.api.nvim_buf_set_keymap()`](https://neovim.io/doc/user/api.html#nvim_buf_set_keymap()) - - [`vim.api.nvim_buf_get_keymap()`](https://neovim.io/doc/user/api.html#nvim_buf_get_keymap()) - - [`vim.api.nvim_buf_del_keymap()`](https://neovim.io/doc/user/api.html#nvim_buf_del_keymap()) - -Let's start with `vim.api.nvim_set_keymap()` and `vim.api.nvim_buf_set_keymap()` - -The first argument passed to the function is a string containing the name of the mode for which the mapping will take effect: - -| String value | Help page | Affected modes | Vimscript equivalent | -| ---------------------- | ------------- | ---------------------------------------- | -------------------- | -| `''` (an empty string) | `mapmode-nvo` | Normal, Visual, Select, Operator-pending | `:map` | -| `'n'` | `mapmode-n` | Normal | `:nmap` | -| `'v'` | `mapmode-v` | Visual and Select | `:vmap` | -| `'s'` | `mapmode-s` | Select | `:smap` | -| `'x'` | `mapmode-x` | Visual | `:xmap` | -| `'o'` | `mapmode-o` | Operator-pending | `:omap` | -| `'!'` | `mapmode-ic` | Insert and Command-line | `:map!` | -| `'i'` | `mapmode-i` | Insert | `:imap` | -| `'l'` | `mapmode-l` | Insert, Command-line, Lang-Arg | `:lmap` | -| `'c'` | `mapmode-c` | Command-line | `:cmap` | -| `'t'` | `mapmode-t` | Terminal | `:tmap` | - -The second argument is a string containing the left-hand side of the mapping (the key or set of keys that trigger the command defined in the mapping). An empty string is equivalent to ``, which disables a key. - -The third argument is a string containing the right-hand side of the mapping (the command to execute). - -The final argument is a table containing boolean options for the mapping as defined in [`:help :map-arguments`](https://neovim.io/doc/user/map.html#:map-arguments) (including `noremap` and excluding `buffer`). Since Neovim 0.7.0, you can also pass a `callback` option to invoke a Lua function instead of the right-hand side when executing the mapping. - -Buffer-local mappings also take a buffer number as their first argument (`0` sets the mapping for the current buffer). - -```lua -vim.api.nvim_set_keymap('n', '', ':set hlsearch!', { noremap = true, silent = true }) --- :nnoremap :set hlsearch -vim.api.nvim_set_keymap('n', 'tegf', [[lua require('telescope.builtin').git_files()]], { noremap = true, silent = true }) --- :nnoremap tegf lua require('telescope.builtin').git_files() - -vim.api.nvim_buf_set_keymap(0, '', 'cc', 'line(".") == 1 ? "cc" : "ggcc"', { noremap = true, expr = true }) --- :noremap cc line('.') == 1 ? 'cc' : 'ggcc' - -vim.api.nvim_set_keymap('n', 'ex', '', { - noremap = true, - callback = function() - print('My example') - end, - -- Since Lua function don't have a useful string representation, you can use the "desc" option to document your mapping - desc = 'Prints "My example" in the message area', -}) -``` - -`vim.api.nvim_get_keymap()` takes a string containing the shortname of the mode for which you want the list of mappings (see table above). The return value is a table containing all global mappings for the mode. - -```lua -print(vim.inspect(vim.api.nvim_get_keymap('n'))) --- :verbose nmap -``` - -`vim.api.nvim_buf_get_keymap()` takes an additional buffer number as its first argument (`0` will get mapppings for the current bufffer) - -```lua -print(vim.inspect(vim.api.nvim_buf_get_keymap(0, 'i'))) --- :verbose imap -``` - -`vim.api.nvim_del_keymap()` takes a mode and the left-hand side of a mapping. - -```lua -vim.api.nvim_del_keymap('n', '') --- :nunmap -``` - -Again, `vim.api.nvim_buf_del_keymap()`, takes a buffer number as its first argument, with `0` representing the current buffer. - -```lua -vim.api.nvim_buf_del_keymap(0, 'i', '') --- :iunmap -``` - -### vim.keymap - -:warning: The functions discussed in this section are only available in Neovim 0.7.0+ - -Neovim provides two functions to set/del mappings: -- [`vim.keymap.set()`](https://neovim.io/doc/user/lua.html#vim.keymap.set()) -- [`vim.keymap.del()`](https://neovim.io/doc/user/lua.html#vim.keymap.del()) - -These are similar to the above API functions with added syntactic sugar. - -`vim.keymap.set()` takes a string as its first argument. It can also be a table of strings to define mappings for multiple modes at once: - -```lua -vim.keymap.set('n', 'ex1', 'lua vim.notify("Example 1")') -vim.keymap.set({'n', 'c'}, 'ex2', 'lua vim.notify("Example 2")') -``` - -The second argument is the left-hand side of the mapping. - -The third argument is the right-hand side of the mapping, which can either be a string or a Lua function: - -```lua -vim.keymap.set('n', 'ex1', 'echomsg "Example 1"') -vim.keymap.set('n', 'ex2', function() print("Example 2") end) -vim.keymap.set('n', 'pl1', require('plugin').plugin_action) --- To avoid the startup cost of requiring the module, you can wrap it in a function to require it lazily when invoking the mapping: -vim.keymap.set('n', 'pl2', function() require('plugin').plugin_action() end) -``` - -The fourth (optional) argument is a table of options that correspond to the options passed to `vim.api.nvim_set_keymap()`, with a few additions (see [`:help vim.keymap.set()`](https://neovim.io/doc/user/lua.html#vim.keymap.set()) for the full list). - -```lua -vim.keymap.set('n', 'ex1', 'echomsg "Example 1"', {buffer = true}) -vim.keymap.set('n', 'ex2', function() print('Example 2') end, {desc = 'Prints "Example 2" to the message area'}) -``` - -Defining keymaps with a Lua function is different from using a string. The usual way to show information about a keymap like `:nmap ex1` will not output useful information (the string itself), but instead only show `Lua function`. It is recommended to add a `desc` key to describe the behavior of your keymap. This is especially important for documenting plugin mappings so users can understand the usage of the keymap more easily. - -An interesting feature of this API is that it irons out some historical quirks of Vim mappings: -- Mappings are `noremap` by default, except when the `rhs` is a `` mapping. This means you rarely have to think about whether a mapping should be recursive or not: - ```lua - vim.keymap.set('n', 'test1', 'echo "test"') - -- :nnoremap test echo "test" - - -- If you DO want the mapping to be recursive, set the "remap" option to "true" - vim.keymap.set('n', '>', ']', {remap = true}) - -- :nmap > ] - - -- mappings don't work unless they're recursive, vim.keymap.set() handles that for you automatically - vim.keymap.set('n', 'plug', '(plugin)') - -- :nmap plug (plugin) - ``` -- In `expr` mappings, `nvim_replace_termcodes()` is automatically applied to strings returned from Lua functions: - ```lua - vim.keymap.set('i', '', function() - return vim.fn.pumvisible == 1 and '' or '' - end, {expr = true}) - ``` - -See also: -- [`:help recursive_mapping`](https://neovim.io/doc/user/map.html#recursive_mapping) - -`vim.keymap.del()` works the same way but deletes mappings instead: - -```lua -vim.keymap.del('n', 'ex1') -vim.keymap.del({'n', 'c'}, 'ex2', {buffer = true}) -``` - -## Defining user commands - -:warning: The API functions discussed in this section are only available in Neovim 0.7.0+ - -Neovim provides API functions for user-defined commands: - -- Global user commands: - - [`vim.api.nvim_create_user_command()`](https://neovim.io/doc/user/api.html#nvim_create_user_command()) - - [`vim.api.nvim_del_user_command()`](https://neovim.io/doc/user/api.html#nvim_del_user_command()) -- Buffer-local user commands: - - [`vim.api.nvim_buf_create_user_command()`](https://neovim.io/doc/user/api.html#nvim_buf_create_user_command()) - - [`vim.api.nvim_buf_del_user_command()`](https://neovim.io/doc/user/api.html#nvim_buf_del_user_command()) - -Let's start with `vim.api.nvim_create_user_command()` - -The first argument passed to this function is the name of the command (which must start with an uppercase letter). - -The second argument is the code to execute when invoking said command. It can either be: - -A string (in which case it will be executed as Vimscript). You can use escape sequences like ``, ``, etc. like you would with `:command` -```lua -vim.api.nvim_create_user_command('Upper', 'echo toupper()', { nargs = 1 }) --- :command! -nargs=1 Upper echo toupper() - -vim.cmd('Upper hello world') -- prints "HELLO WORLD" -``` - -Or a Lua function. It receives a dictionary-like table that contains the data normally provided by escape sequences (see [`:help nvim_create_user_command()`](https://neovim.io/doc/user/api.html#nvim_create_user_command()) for a list of available keys) -```lua -vim.api.nvim_create_user_command( - 'Upper', - function(opts) - print(string.upper(opts.args)) - end, - { nargs = 1 } -) -``` - -The third argument lets you pass command attributes as a table (see [`:help command-attributes`](https://neovim.io/doc/user/map.html#command-attributes)). Since you can already define buffer-local user commands with `vim.api.nvim_buf_create_user_command()`, `-buffer` is not a valid attribute. - -Two additional attributes are available: -- `desc` allows you to control what gets displayed when you run `:command {cmd}` on a command defined as a Lua callback. Similarly to keymaps, it is recommended to add a `desc` key to commands defined as Lua functions. -- `force` is equivalent to calling `:command!` and replaces a command if one with the same name already exists. It is true by default, unlike its Vimscript equivalent. - -The `-complete` attribute can take a Lua function in addition to the attributes listed in [`:help :command-complete`](https://neovim.io/doc/user/map.html#:command-complete). - -```lua -vim.api.nvim_create_user_command('Upper', function() end, { - nargs = 1, - complete = function(ArgLead, CmdLine, CursorPos) - -- return completion candidates as a list-like table - return { 'foo', 'bar', 'baz' } - end, -}) -``` - -Buffer-local user commands also take a buffer number as their first argument. This is an advantage over `-buffer` which can only define a command for the current buffer. - -```lua -vim.api.nvim_buf_create_user_command(4, 'Upper', function() end, {}) -``` - -`vim.api.nvim_del_user_command()` takes a command name. - -```lua -vim.api.nvim_del_user_command('Upper') --- :delcommand Upper -``` - -Again, `vim.api.nvim_buf_del_user_command()`, takes a buffer number as its first argument, with `0` representing the current buffer. - -```lua -vim.api.nvim_buf_del_user_command(4, 'Upper') -``` - -See also: -- [`:help nvim_create_user_command()`](https://neovim.io/doc/user/api.html#nvim_create_user_command()) -- [`:help 40.2`](https://neovim.io/doc/user/usr_40.html#40.2) -- [`:help command-attributes`](https://neovim.io/doc/user/map.html#command-attributes) - -### Caveats - -The `-complete=custom` attribute automatically filters completion candidates and has built-in wildcard ([`:help wildcard`](https://neovim.io/doc/user/editing.html#wildcard)) support: - -```vim -function! s:completion_function(ArgLead, CmdLine, CursorPos) abort - return join([ - \ 'strawberry', - \ 'star', - \ 'stellar', - \ ], "\n") -endfunction - -command! -nargs=1 -complete=custom,s:completion_function Test echo -" Typing `:Test st[ae]` returns "star" and "stellar" -``` - -Passing a Lua function to `complete` makes it behave like `customlist` which leaves filtering up to the user: - -```lua -vim.api.nvim_create_user_command('Test', function() end, { - nargs = 1, - complete = function(ArgLead, CmdLine, CursorPos) - return { - 'strawberry', - 'star', - 'stellar', - } - end, -}) - --- Typing `:Test z` returns all the completion results because the list was not filtered -``` - -## Defining autocommands - -(this section is a work in progress) - -Neovim 0.7.0 has API functions for autocommands. See `:help api-autocmd` for details - -- [Pull request #14661](https://github.com/neovim/neovim/pull/14661) (lua: autocmds take 2) - -## Defining highlights - -(this section is a work in progress) - -Neovim 0.7.0 has API functions for highlight groups. See also: - -- [`:help nvim_set_hl()`](https://neovim.io/doc/user/api.html#nvim_set_hl()) -- [`:help nvim_get_hl_by_id()`](https://neovim.io/doc/user/api.html#nvim_get_hl_by_id()) -- [`:help nvim_get_hl_by_name()`](https://neovim.io/doc/user/api.html#nvim_get_hl_by_name()) - -## General tips and recommendations - -### Reloading cached modules - -In Lua, the `require()` function caches modules. This is a good thing for performance, but it can make working on plugins a bit cumbersome because modules are not updated on subsequent `require()` calls. - -If you'd like to refresh the cache for a particular module, you have to modify the `package.loaded` global table: - -```lua -package.loaded['modname'] = nil -require('modname') -- loads an updated version of module 'modname' -``` - -The [nvim-lua/plenary.nvim](https://github.com/nvim-lua/plenary.nvim) plugin has a [custom function](https://github.com/nvim-lua/plenary.nvim/blob/master/lua/plenary/reload.lua) that does this for you. - -### Don't pad Lua strings! - -When using double bracketed strings, resist the temptation to pad them! While it is fine to do in contexts where spaces are ignored, it can cause hard to debug issues when whitespace is significant: - -```lua -vim.api.nvim_set_keymap('n', 'f', [[ call foo() ]], {noremap = true}) -``` - -In the above example, `f` is mapped to `call foo()` instead of `call foo()`. - -### Notes about Vimscript <-> Lua type conversion - -#### Converting a variable creates a copy: -You can't directly interact with the reference to a Vim object from Lua or a Lua object from Vimscript. -For example, the `map()` function in Vimscript modifies a variable in place: - -```vim -let s:list = [1, 2, 3] -let s:newlist = map(s:list, {_, v -> v * 2}) - -echo s:list -" [2, 4, 6] -echo s:newlist -" [2, 4, 6] -echo s:list is# s:newlist -" 1 -``` - -Using this function from Lua creates a copy instead: - -```lua -local tbl = {1, 2, 3} -local newtbl = vim.fn.map(tbl, function(_, v) return v * 2 end) - -print(vim.inspect(tbl)) -- { 1, 2, 3 } -print(vim.inspect(newtbl)) -- { 2, 4, 6 } -print(tbl == newtbl) -- false -``` - -#### Conversion is not always possible -This mostly affects functions and tables: - -Lua tables that are a mix between a List and a Dictionary can't be converted: - -```lua -print(vim.fn.count({1, 1, number = 1}, 1)) --- E5100: Cannot convert given lua table: table should either have a sequence of positive integer keys or contain only string keys -``` - -While you can call Vim functions in Lua with `vim.fn`, you can't hold references to them. This can cause surprising behaviors: - -```lua -local FugitiveHead = vim.fn.funcref('FugitiveHead') -print(FugitiveHead) -- vim.NIL - -vim.cmd("let g:test_dict = {'test_lambda': {-> 1}}") -print(vim.g.test_dict.test_lambda) -- nil -print(vim.inspect(vim.g.test_dict)) -- {} -``` - -Passing Lua functions to Vim functions is OK, storing them in Vim variables is not (fixed in Neovim 0.7.0+): - -```lua --- This works: -vim.fn.jobstart({'ls'}, { - on_stdout = function(chan_id, data, name) - print(vim.inspect(data)) - end -}) - --- This doesn't: -vim.g.test_dict = {test_lambda = function() return 1 end} -- Error: Cannot convert given lua type -``` - -Note however that doing the same from Vimscript with `luaeval()` **does** work: - -```vim -let g:test_dict = {'test_lambda': luaeval('function() return 1 end')} -echo g:test_dict -" {'test_lambda': function('4714')} -``` - -#### Vim booleans -A common pattern in Vim scripts is to use `1` or `0` instead of proper booleans. Indeed, Vim did not have a separate boolean type until version 7.4.1154. - -Lua booleans are converted to actual booleans in Vimscript, not numbers: - -```vim -lua vim.g.lua_true = true -echo g:lua_true -" v:true -lua vim.g.lua_false = false -echo g:lua_false -" v:false -``` - -### Setting up linters/language servers - -If you're using linters and/or language servers to get diagnostics and autocompletion for Lua projects, you may have to configure Neovim-specific settings for them. Here are a few recommended settings for popular tools: - -#### luacheck - -You can get [luacheck](https://github.com/mpeterv/luacheck/) to recognize the `vim` global by putting this configuration in `~/.luacheckrc` (or `$XDG_CONFIG_HOME/luacheck/.luacheckrc`): - -```lua -globals = { - "vim", -} -``` - -The [Alloyed/lua-lsp](https://github.com/Alloyed/lua-lsp/) language server uses `luacheck` to provide linting and reads the same file. - -For more information on how to configure `luacheck`, please refer to its [documentation](https://luacheck.readthedocs.io/en/stable/config.html) - -#### sumneko/lua-language-server - -The [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig/) repository contains [instructions to configure sumneko/lua-language-server](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#sumneko_lua) (the example uses the built-in LSP client but the configuration should be identical for other LSP client implementations). - -For more information on how to configure [sumneko/lua-language-server](https://github.com/sumneko/lua-language-server/) see ["Setting"](https://github.com/sumneko/lua-language-server/wiki/Setting) - -#### coc.nvim - -The [rafcamlet/coc-nvim-lua](https://github.com/rafcamlet/coc-nvim-lua/) completion source for [coc.nvim](https://github.com/neoclide/coc.nvim/) provides completion items for the Neovim stdlib. - -### Debugging Lua code - -You can debug Lua code running in a separate Neovim instance with [jbyuki/one-small-step-for-vimkind](https://github.com/jbyuki/one-small-step-for-vimkind) - -The plugin uses the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/). Connecting to a debug adapter requires a DAP client like [mfussenegger/nvim-dap](https://github.com/mfussenegger/nvim-dap/) or [puremourning/vimspector](https://github.com/puremourning/vimspector/). - -### Debugging Lua mappings/commands/autocommands - -The `:verbose` command allows you to see where a mapping/command/autocommand was defined: - -```vim -:verbose map m -``` - -```text -n m_ * echo 'example' - Last set from ~/.config/nvim/init.vim line 26 -``` - -By default, this feature is disabled in Lua for performance reasons. You can enable it by starting Neovim with a verbose level greater than 0: - -```sh -nvim -V1 -``` - -See also: -- [`:help 'verbose'`](https://neovim.io/doc/user/options.html#'verbose') -- [`:help -V`](https://neovim.io/doc/user/starting.html#-V) -- [neovim/neovim#15079](https://github.com/neovim/neovim/pull/15079) - -### Testing Lua code - -- [plenary.nvim: test harness](https://github.com/nvim-lua/plenary.nvim/#plenarytest_harness) -- [notomo/vusted](https://github.com/notomo/vusted) - -### Using Luarocks packages - -[wbthomason/packer.nvim](https://github.com/wbthomason/packer.nvim) supports Luarocks packages. Instructions for how to set this up are available in the [README](https://github.com/wbthomason/packer.nvim/#luarocks-support) - -## Miscellaneous - -### vim.loop - -`vim.loop` is the module that exposes the LibUV API. Some resources: - -- [Official documentation for LibUV](https://docs.libuv.org/en/v1.x/) -- [Luv documentation](https://github.com/luvit/luv/blob/master/docs.md) -- [teukka.tech - Using LibUV in Neovim](https://teukka.tech/posts/2020-01-07-vimloop/) - -See also: -- [`:help vim.loop`](https://neovim.io/doc/user/lua.html#vim.loop) - -### vim.lsp - -`vim.lsp` is the module that controls the built-in LSP client. The [neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig/) repository contains default configurations for popular language servers. - -The behavior of the client can be configured using "lsp-handlers". For more information: -- [`:help lsp-handler`](https://neovim.io/doc/user/lsp.html#lsp-handler) -- [neovim/neovim#12655](https://github.com/neovim/neovim/pull/12655) -- [How to migrate from diagnostic-nvim](https://github.com/nvim-lua/diagnostic-nvim/issues/73#issue-737897078) - -You may also want to take a look at [plugins built around the LSP client](https://github.com/rockerBOO/awesome-neovim#lsp) - -See also: -- [`:help lsp`](https://neovim.io/doc/user/lsp.html#LSP) - -### vim.treesitter - -`vim.treesitter` is the module that controls the integration of the [Tree-sitter](https://tree-sitter.github.io/tree-sitter/) library in Neovim. If you want to know more about Tree-sitter, you may be interested in this [presentation (38:37)](https://www.youtube.com/watch?v=Jes3bD6P0To). - -The [nvim-treesitter](https://github.com/nvim-treesitter/) organisation hosts various plugins taking advantage of the library. - -See also: -- [`:help lua-treesitter`](https://neovim.io/doc/user/treesitter.html#lua-treesitter) - -### Transpilers - -One advantage of using Lua is that you don't actually have to write Lua code! There is a multitude of transpilers available for the language. - -- [Moonscript](https://moonscript.org/) - -Probably one of the most well-known transpilers for Lua. Adds a lots of convenient features like classes, list comprehensions or function literals. The [svermeulen/nvim-moonmaker](https://github.com/svermeulen/nvim-moonmaker) plugin allows you to write Neovim plugins and configuration directly in Moonscript. - -- [Fennel](https://fennel-lang.org/) - -A lisp that compiles to Lua. You can write configuration and plugins for Neovim in Fennel with the [Olical/aniseed](https://github.com/Olical/aniseed) or the [Hotpot](https://github.com/rktjmp/hotpot.nvim) plugin. Additionally, the [Olical/conjure](https://github.com/Olical/conjure) plugin provides an interactive development environment that supports Fennel (among other languages). - -- [Teal](https://github.com/teal-language/tl) - -The name Teal comes from pronouncing TL (typed lua). This is exactly what it tries to do - add strong typing to lua while otherwise remaining close to standard lua syntax. The [nvim-teal-maker](https://github.com/svermeulen/nvim-teal-maker) plugin can be used to write Neovim plugins or configuration files directly in Teal - -Other interesting projects: -- [TypeScriptToLua/TypeScriptToLua](https://github.com/TypeScriptToLua/TypeScriptToLua) -- [Haxe](https://haxe.org/) -- [SwadicalRag/wasm2lua](https://github.com/SwadicalRag/wasm2lua) -- [hengestone/lua-languages](https://github.com/hengestone/lua-languages)