# Primeiros passos usando Lua no Neovim

## Introdução

A integração do Lua como uma linguagem de primeira classe dentro do Neovim está se configurando para ser uma de suas características matadoras. No entanto, a quantidade de material didático para aprender a escrever plug-ins em Lua não é tão grande quanto você encontraria para escrevê-los em Vimscript. Esta é uma tentativa de fornecer algumas informações básicas para ajudar e incentivar quem está começando agora.

Este guia assume que você está usando o [build noturno](https://github.com/neovim/neovim/releases/tag/nightly) mais recente do Neovim. Como a versão 0.5 do Neovim é uma versão em desenvolvimento, tenha em mente que algumas APIs nas quais estão sendo trabalhadas ativamente não são muito estáveis e podem mudar antes do lançamento.

### Aprendendo Lua

Se você ainda não está familiarizado com a linguagem, existem muitos recursos para começar:

- A página [Aprenda X em Y minutos sobre Lua](https://learnxinyminutes.com/docs/lua/) deve fornecer uma visão geral rápida dos fundamentos
- Se os vídeos são mais do seu agrado, Derek Banas tem um [tutorial de 1 hora sobre a linguagem](https://www.youtube.com/watch?v=iMacxZQMPXs)
- O [wiki de usuários do lua](http://lua-users.org/wiki/LuaDirectory) está cheio de informações úteis sobre todos os tipos de tópicos relacionados ao Lua
- O [manual oficial de referência para o Lua](https://www.lua.org/manual/5.1/) deve fornecer uma visão mais completo da linguagem

Deve-se notar também que o Lua é uma linguagem muito limpa e simples. É fácil de aprender, especialmente se você tiver experiência com linguagens de script semelhantes, como JavaScript. Você já deve conhecer mais o Lua do que imagina!

Nota: a versão do Lua que o Neovim embute é LuaJIT 2.1.0, que mantém a compatibilidade com Lua 5.1 (com algumas extensões 5.2)

### Tutoriais existentes para escrever códigos Lua para o Neovim

Alguns tutoriais já foram criados para ajudar as pessoas a escrever plug-ins em Lua. Alguns deles ajudaram bastante na redação deste guia. Muito obrigado aos seus autores.

- [teukka.tech - Do init.vim para init.lua](https://teukka.tech/luanvim.html)
- [2n.pl - Como escrever plug-ins neovim em Lua](https://www.2n.pl/blog/how-to-write-neovim-plugins-in-lua.md)
- [2n.pl - Como fazer interface do usuário para plug-ins neovim em Lua](https://www.2n.pl/blog/how-to-make-ui-for-neovim-plugins-in-lua)
- [ms-jpq - Tutorial Neovim Async](https://ms-jpq.github.io/neovim-async-tutorial/)

### Plugins complementares

- [Vimpeccable](https://github.com/svermeulen/vimpeccable) - Plugin para ajudar a escrever seu .vimrc em Lua
- [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) - Todas as funções lua que não quero escrever duas vezes
- [popup.nvim](https://github.com/nvim-lua/popup.nvim) - Uma implementação da API Popup do vim no Neovim
- [nvim_utils](https://github.com/norcalli/nvim_utils)
- [nvim-luadev](https://github.com/bfredl/nvim-luadev) - console REPL / debug para plug-ins nvim lua
- [nvim-luapad](https://github.com/rafcamlet/nvim-luapad) - Bloco de rascunho neovim interativo em tempo real para mecanismo lua integrado
- [nlua.nvim](https://github.com/tjdevries/nlua.nvim) - Desenvolvimento Lua para Neovim
- [BetterLua.vim](https://github.com/euclidianAce/BetterLua.vim) - Melhor destaque da sintaxe Lua no Vim / NeoVim

## Onde colocar os arquivos Lua

Os arquivos Lua são normalmente encontrados dentro de uma pasta `lua/` em seu `runtimepath` (para a maioria dos usuários, isso significará `~/.config/nvim/lua` em sistemas *nix e `~/AppData/Local/nvim/lua` no Windows). Os globais `package.path` e `package.cpath` são ajustados automaticamente para incluir arquivos Lua nesta pasta. Isso significa que você pode `require()` esses arquivos como módulos Lua.

Vamos pegar a seguinte estrutura de pastas como exemplo:

```texto
📂 ~/.config/nvim
├── 📁 after
├── 📁 ftplugin
├── 📂 lua
│  ├── 🌑 myluamodule.lua
│  └── 📂 other_modules
│     ├── 🌑 anothermodule.lua
│     └── 🌑 init.lua
├── 📁 pack
├── 📁 plugin
├── 📁 syntax
└── 🇻 init.vim
```

O seguinte código Lua carregará `myluamodule.lua`:

```lua
require('myluamodule')
```

Observe a ausência de uma extensão `.lua`.

Da mesma forma, o carregamento de `other_modules/anothermodule.lua` é feito assim:

```lua
require('other_modules.anothermodule')
- ou
require('other_modules/anothermodule')
```

Os separadores de caminho são indicados por um ponto `.` ou por uma barra `/`.

Uma pasta contendo um arquivo `init.lua` pode ser solicitada diretamente, sem ter que especificar o nome do arquivo.

```lua
require('other_modules') -- loads other_modules/init.lua
```

Para mais informações: `:help lua-require`

#### Ressalvas

Ao contrário dos arquivos .vim, os arquivos .lua não são originados automaticamente de diretórios em seu `runtimepath`. Em vez disso, você deve obtê-los/solicitá-los do Vimscript. Existem planos para adicionar a opção de carregar um arquivo `init.lua` como uma alternativa para` init.vim`:

- [Problema nº 7895](https://github.com/neovim/neovim/issues/7895)
- [solicitação pull correspondente](https://github.com/neovim/neovim/pull/12235)

#### Dicas

Vários plug-ins Lua podem ter nomes de arquivo idênticos em sua pasta `lua/`. Isso pode levar a conflitos de espaço de nomes.

Se dois plug-ins diferentes têm um arquivo `lua/main.lua`, então fazer `require('main')` é ambíguo: qual arquivo fonte nós queremos?

Pode ser uma boa ideia atribuir um namespace à sua configuração ou ao seu plugin com uma pasta de nível superior, como: `lua/plugin_name/main.lua`

## Usando Lua a partir de Vimscript

### :lua

Esse comando executa um trecho do código Lua.

```vim
:lua require('myluamodule')
```

Scripts multilinhas são possíveis usando a sintaxe heredoc:

```vim
echo "Aqui está um pedaço maior do código Lua"

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
```


Veja também:

- `:help :lua`
- `:help :lua-heredoc`

#### Ressalvas

Você não obtém o realce de sintaxe correto ao escrever Lua em um arquivo .vim. Pode ser mais conveniente usar o comando `:lua` como um ponto de entrada para solicitar arquivos Lua externos.

### :luado

Este comando executa um pedaço de código Lua que atua em um intervalo de linhas no buffer atual. Se nenhum intervalo for especificado, todo o buffer será usado. Qualquer string que seja retornada (`return`) do pedaço de código é usada para determinar com o que cada linha deve ser substituída.

O seguinte comando substituiria todas as linhas no buffer atual com o texto `hello world`:

```vim
:luado return 'hello world'
```

Duas variáveis implícitas `line` e `linenr` também são fornecidas. `line` é o texto da linha sendo iterada, enquanto `linenr` é o seu número. O comando a seguir tornaria cada linha cujo número é divisível por 2 maiúsculas:

```vim
:luado if linenr % 2 == 0 then return line:upper() end
```

Veja também:

- `:help :luado`

### :luafile

Este comando fornece um arquivo Lua.

```vim
:luafile ~/foo/bar/baz/myluafile.lua
```

É análogo ao comando `:source` para arquivos .vim ou à função incorporada `dofile()` em Lua.

Veja também:

- `:help :luafile`

#### luafile vs require():

Você pode estar se perguntando qual é a diferença entre `lua require()` e `luafile` e se você deve usar um em vez do outro. Eles têm diferentes casos de uso:

- `require()`:
    - é uma função Lua embutida. Ele permite que você aproveite as vantagens do sistema de módulos de Lua
    - busca por módulos usando a variável `package.path` (como observado anteriormente, você pode `require()` scripts Lua localizados dentro da pasta `lua/` em seu `runtimepath`)
    - mantém registro de quais módulos foram carregados e evita que um script seja analisado e executado uma segunda vez. Se você alterar o arquivo que contém o código de um módulo e tentar `require()` uma segunda vez enquanto o Neovim está em execução, o módulo não será atualizado
- `:luafile`:
    - é um Ex command. Não suporta módulos
    - pega um caminho que é absoluto ou relativo ao diretório de trabalho da janela atual
    - executa o conteúdo de um script independentemente de ele ter sido executado antes

`:luafile` também pode ser útil se você deseja executar um arquivo Lua no qual está trabalhando:

```vim
:luafile %
```

### luaeval()

Essa função Vimscript embutida avalia uma string de expressão matemática Lua e retorna seu valor. Os tipos de dados Lua são convertidos automaticamente em tipos Vimscript (e vice-versa).

```vim
" Você pode armazenar o resultado em uma variável
let variable = luaeval('1 + 1')
echo variable
" 2
let concat = luaeval('"Lua".." eh ".."incrivel"')
echo concat
" 'Lua eh incrivel'

" Tabelas semelhantes a listas são convertidas para listas Vim
let list = luaeval('{1, 2, 3, 4}')
echo list[0]
" 1
echo list[1]
" 2
" Observe que, ao contrário das tabelas Lua, as listas do Vim são indexadas em 0

" Tabelas semelhantes a Dict são convertidas em dicionários Vim
let dict = luaeval('{foo = "bar", baz = "qux"}')
echo dict.foo
" 'bar'

" O mesmo vale para booleanas e nulidade
echo luaeval('true')
" v:true
echo luaeval('nil')
" v:null

" Você pode criar pseudônimos Vimscript para funções Lua
let LuaMathPow = luaeval('math.pow')
echo LuaMathPow(2, 2)
" 4
let LuaModuleFunction = luaeval('require("mymodule").myfunction')
call LuaModuleFunction()

" Também é possível passar funções Lua como valores para funções Vim
lua X = function(k, v) return string.format("%s:%s", k, v) end
echo map([1, 2, 3], luaeval("X"))
```

`luaeval()` recebe um segundo argumento opcional que permite que você passe dados para uma expressão matemática. Você pode então acessar esses dados de Lua usando o mágico `_A` global:

```vim
echo luaeval('_A[1] + _A[2]', [1, 1])
" 2

echo luaeval('string.format("Lua eh %s", _A)', 'incrivel')
" 'Lua eh incrivel'
```

Veja também:
- `:help luaeval()`

### v:lua

Essa variável global do Vim permite chamar funções Lua globais diretamente do Vimscript. Novamente, os tipos de dados do Vim são convertidos em tipos Lua e vice-versa.

```vim
call v:lua.print('Ola da Lua!')
" 'Ola da Lua!'

let scream = v:lua.string.rep('A', 10)
echo scream
" 'AAAAAAAAAA'

" Podemos requerir módulos
call v:lua.require('mymodule').myfunction()

" Que tal um bom 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()

" Também funciona em mapeamentos de expressões
lua << EOF
function _G.check_back_space()
    local col = vim.fn.col('.') - 1
    if col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') then
        return true
    else
        return false
    end
end
EOF

inoremap <silent> <expr> <Tab>
    \ pumvisible() ? '\<C-n>' :
    \ v:lua.check_back_space() ? '\<Tab>' :
    \ completion#trigger_completion()
```

Veja também:
- `:help v:lua`
- `:help v:lua-call`


#### Ressalvas

Esta variável só pode ser usada para chamar funções. O seguinte sempre gerará um erro:

```vim
" As funções de pseudônimo não funcionam
let LuaPrint = v:lua.print

" Acessar dicionários não funciona
echo v:lua.some_global_dict['key']

" Usar uma função como valor não funciona
echo map([1, 2, 3], v:lua.global_callback)
```

## O namespace do vim

Neovim expõe uma variável global `vim` que serve como um ponto de entrada para interagir com suas APIs de Lua. Ele fornece aos usuários uma "biblioteca padrão" estendida de funções, bem como vários submódulos.

Algumas funções e módulos notáveis incluem:

- `vim.inspect`: objetos Lua de impressão bonita (útil para inspecionar tabelas)
- `vim.regex`: use regexes do Vim através do Lua
- `vim.api`: módulo que expõe funções da API (a mesma API usada por plug-ins remotos)
- `vim.loop`: módulo que expõe a funcionalidade do loop de evento do Neovim (usando LibUV)
- `vim.lsp`: módulo que controla o cliente LSP integrado
- `vim.treesitter`: módulo que expõe a funcionalidade da biblioteca tree-sitter

Esta lista não é abrangente. Se você deseja saber mais sobre o que é disponibilizado pela variável `vim`, utilize `:help lua-stdlib` e `:help lua-vim`. Alternativamente, você pode fazer `:lua print(vim.inspect(vim))` para obter uma lista de cada módulo.

#### Dicas

Escrever `print(vim.inspect(x))` toda vez que você deseja inspecionar o conteúdo de um objeto pode ser muito tedioso. Pode valer a pena ter uma função de wrapper global em algum lugar da sua configuração:

```lua
function _G.dump(...)
    local objects = vim.tbl_map(vim.inspect, {...})
    print(unpack(objects))
end
```

Você pode então inspecionar o conteúdo de um objeto muito rapidamente em seu código ou na linha de comando:

```lua
dump({1, 2, 3})
```

```vim
:lua dump(vim.loop)
```


Além disso, você pode descobrir que às vezes faltam funções nativas do Lua em comparação com o que você encontraria em outras linguagens (por exemplo, `os.clock()` retorna apenas um valor em segundos, não milissegundos). Certifique-se de verificar o stdlib do Neovim (e `vim.fn`, falaremos mais sobre isso depois), ele provavelmente tem o que você está procurando.

## Usando Vimscript através do Lua

### vim.api.nvim_eval()

Esta função avalia uma string de expressão Vimscript e retorna seu valor. Os tipos de dados Vimscript são convertidos automaticamente em tipos Lua (e vice-versa).

É o equivalente em Lua da função `luaeval()` em Vimscript

```lua
-- Os tipos de dados são convertidos corretamente
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
```

**A FAZER**: é possível que `vim.api.nvim_eval ()` retorne um `funcref`?

#### Ressalvas

Ao contrário de `luaeval()`, a utilização de `vim.api.nvim_eval()` não fornece uma variável `_A` implícita para passar dados para a expressão.

### vim.api.nvim_exec()

Esta função avalia um pedaço do código Vimscript. Leva em uma string contendo o código-fonte para ser executado e um booleano para determinar se a saída do código deve ser retornada pela função (você pode então armazenar a saída em uma variável, por exemplo).

```lua
local result = vim.api.nvim_exec(
[[
let mytext = 'hello world'

function! MyFunction(text)
    echo a:text
endfunction

call MyFunction(mytext)
]],
true)

print(result) -- 'hello world'
```

**A FAZER**: A documentação diz que o escopo do script (`s:`) é suportado, mas executar este trecho com uma variável com escopo do script gera um erro. Por quê?

### vim.api.nvim_command()

Esta função executa um comando ex. Ele recebe uma string contendo o comando a ser executado.

```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')
```

Nota: `vim.cmd` é um pseudônimo mais curto para esta função

```lua
vim.cmd('buffers')
```

#### Dicas

Como você precisa passar strings para essas funções, muitas vezes acaba tendo que escapar das barras invertidas:

```lua
vim.cmd('%s/\\Vfoo/bar/g')
```

Strings literais são mais fáceis de usar, pois não requerem caracteres de escape:

```lua
vim.cmd([[%s/\Vfoo/bar/g]])
```

## Gerenciando opções do vim

### Usando funções API

Neovim fornece um conjunto de funções de API para definir (set) uma opção ou obter (get) seu valor atual:

- Opções globais:
    - `vim.api.nvim_set_option()`
    - `vim.api.nvim_get_option()`
- Opções locais de buffer:
    - `vim.api.nvim_buf_set_option()`
    - `vim.api.nvim_buf_get_option()`
- Opções locais da janela:
    - `vim.api.nvim_win_set_option()`
    - `vim.api.nvim_win_get_option()`

Eles recebem uma string contendo o nome da opção para definir/obter, bem como o valor que você deseja definir.

As opções booleanas (como `(no)number`) devem ser definidas como `true` (verdadeiro) ou `false` (falso):

```lua
vim.api.nvim_set_option('smarttab', false)
print(vim.api.nvim_get_option('smarttab')) -- false
```

Não deve ser surpresa que as opções de string devam ser definidas como uma string:

```lua
vim.api.nvim_set_option('selection', 'exclusive')
print(vim.api.nvim_get_option('selection')) -- 'exclusive'
```

As opções de número aceitam um número:

```lua
vim.api.nvim_set_option('updatetime', 3000)
print(vim.api.nvim_get_option('updatetime')) -- 3000
```

As opções de buffer local e janela local também precisam de um número de buffer ou de janela (usando `0` irá definir/obter a opção para o buffer/janela atual):

```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
```

### Usando meta-acessores

Alguns meta-acessores estão disponíveis se você quiser definir opções de uma maneira mais "idiomática". Eles basicamente cobrem as funções de API acima e permitem que você manipule opções como se fossem variáveis:

- `vim.o.{option}`: opções globais
- `vim.bo.{opção}`: opções locais do buffer
- `vim.wo.{opção}`: opções locais da janela

```lua
vim.o.smarttab = false
print(vim.o.smarttab) -- false

vim.bo.shiftwidth = 4
print(vim.bo.shiftwidth) -- 4
```

Você pode especificar um número para opções locais de buffer e locais de janela. Se nenhum número for fornecido, o buffer/janela atual é usado:

```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)
```

Veja também:
- `:help lua-vim-internal-options`

#### Ressalvas

**AVISO**: a seção a seguir é baseada em alguns experimentos que fiz. Os documentos não parecem mencionar esse comportamento e eu não verifiquei o código-fonte para verificar minhas afirmações.
**A FAZER**: Alguém pode confirmar isso?

Se você sempre lidou com opções usando o comando `:set`, o comportamento de algumas opções pode surpreendê-lo.

Essencialmente, as opções podem ser globais, locais para um buffer/janela ou ter um valor global **e** local.

O comando `:setglobal` define o valor global de uma opção.
O comando `:setlocal` define o valor local de uma opção.
O comando `:set` define o valor global **e** local de uma opção.

Aqui está uma tabela útil de `:help :setglobal`:


|                 Comando | valor global | valor local |
| ----------------------: | :----------: | :---------: |
|       :set option=value |     set      |     set     |
|  :setlocal option=value |      -       |     set     |
| :setglobal option=value |     set      |      -      |

Não há equivalente ao comando `:set` em Lua, você define uma opção global ou localmente.

Você pode esperar que a opção `number` seja global, mas a documentação a descreve como sendo "local para a janela". Essas opções são, na verdade, "fixas": seu valor é copiado da janela atual quando você abre uma nova.

Portanto, se você definisse a opção em `init.lua`, faria da seguinte forma:

```lua
vim.wo.number = true
```

Opções que são "locais para buffer" como `shiftwidth`, `expandtab` ou `undofile` são ainda mais confusas. Digamos que seu `init.lua` contém o seguinte código:

```lua
vim.bo.expandtab = true
```

Quando você inicia o Neovim e começa a editar, está tudo bem: pressionar `<Tab>` insere espaços em vez de um caractere de tabulação. Abra outro buffer e você de repente está de volta às guias...

Configurá-lo globalmente tem o problema oposto:

```lua
vim.o.expandtab = true
```

Desta vez, você insere guias ao iniciar o Neovim pela primeira vez. Abra outro buffer e o pressionar do `<Tab>` fará o que você espera.

Em suma, as opções que são "locais para buffer" devem ser definidas da seguinte maneira se você quiser o comportamento correto:

```lua
vim.bo.expandtab = true
vim.o.expandtab = true
```

Veja também:
- `:help :setglobal`
- `:help global-local`

**A FAZER**: Por que isso acontece? Todas as opções locais de buffer se comportam dessa maneira? Pode estar relacionado a [neovim/neovim#7658](https://github.com/neovim/neovim/issues/7658) e a [vim/vim#2390](https://github.com/vim/vim/issues/2390). Também para opções de janela local: [neovim/neovim#11525](https://github.com/neovim/neovim/issues/11525) e [vim/vim#4945](https://github.com/vim/vim/issues/4945)

## Gerenciando variáveis internas do vim

### Usando funções API

Assim como as opções, as variáveis internas têm seu próprio conjunto de funções de API:

- Variáveis globais (`g:`):
    - `vim.api.nvim_set_var()`
    - `vim.api.nvim_get_var()`
    - `vim.api.nvim_del_var()`
- Variáveis de buffer (`b:`):
    - `vim.api.nvim_buf_set_var()`
    - `vim.api.nvim_buf_get_var()`
    - `vim.api.nvim_buf_del_var()`
- Variáveis de janela (`w:`):
    - `vim.api.nvim_win_set_var()`
    - `vim.api.nvim_win_get_var()`
    - `vim.api.nvim_win_del_var()`
- Variáveis da página de tabulação (`t:`):
    - `vim.api.nvim_tabpage_set_var()`
    - `vim.api.nvim_tabpage_get_var()`
    - `vim.api.nvim_tabpage_del_var()`
- Variáveis Vim predefinidas (`v:`):
    - `vim.api.nvim_set_vvar()`
    - `vim.api.nvim_get_vvar()`

Com exceção das variáveis Vim predefinidas, elas também podem ser excluídas (o comando `:unlet` é o equivalente no Vimscript). Variáveis locais (`l:`), variáveis de script (`s:`) e argumentos de função (`a:`) não podem ser manipulados, pois só fazem sentido no contexto de um script Vim, Lua tem suas próprias regras de escopo.

Se você não está familiarizado com o que essas variáveis fazem, `:help internal-variables` as descreve em detalhes.

Essas funções recebem uma string contendo o nome da variável para definir/obter/excluir, bem como o valor para o qual você deseja defini-la.

```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')
```

Variáveis que têm como escopo um buffer, uma janela ou uma página de tabulação também recebem um número (usando `0` irá definir/obter/excluir a variável para o buffer/janela/página de tabulação atual):

```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')
```

### Usando meta-acessores

Variáveis internas podem ser manipuladas de forma mais intuitiva usando estes meta-acessores:

- `vim.g.{name}`: variáveis globais
- `vim.b.{name}`: variáveis de buffer
- `vim.w.{name}`: variáveis de janela
- `vim.t.{name}`: variáveis da página de tabulação
- `vim.v.{name}`: variáveis Vim predefinidas

```lua
vim.g.some_global_variable = {
    key1 = 'value',
    key2 = 300
}

print(vim.inspect(vim.g.some_global_variable)) -- { key1 = "value", key2 = 300 }
```

Para excluir uma dessas variáveis, simplesmente atribua `nil` a ela:

```lua
vim.g.some_global_variable = nil
```

#### Ressalvas

Ao contrário dos meta-acessores de opções, você não pode especificar um número para variáveis com escopo de buffer/janela/página de tabulação.

Além disso, você não pode adicionar/atualizar/excluir chaves de um dicionário armazenado em uma dessas variáveis. Por exemplo, este snippet de código Vimscript não funciona conforme o esperado:

```vim
let g:variable = {}
lua vim.g.variable.key = 'a'
echo g:variable
" {}
```

Este é um problema conhecido:

- [Issue #12544](https://github.com/neovim/neovim/issues/12544)

## Chamando funções Vimscript

### vim.call()

`vim.call()` chama uma função Vimscript. Pode ser uma função integrada do Vim ou uma função do usuário. Novamente, os tipos de dados são convertidos entre Lua e Vimscript.

Leva o nome da função seguido pelos argumentos que você deseja passar para essa função:

```lua
print(vim.call('printf', 'Hello from %s', 'Lua'))

local reversed_list = vim.call('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.call('jobstart', 'ls', { on_stdout = print_stdout })

vim.call('my#autoload#function')
```

Veja também:
- `:help vim.call()`

### vim.fn.{function}()

`vim.fn` faz exatamente a mesma coisa que `vim.call()`, mas se parece mais com uma chamada de função nativa do Lua:

```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 })
```
Hashtags `#` não são caracteres válidos para identificadores em Lua, então funções de carregamento automático devem ser chamadas com esta sintaxe:

```lua
vim.fn['my#autoload#function']()
```

Veja também:
- `:help vim.fn`

#### Dicas

O Neovim possui uma extensa biblioteca de poderosas funções integradas que são muito úteis para plug-ins. Veja `:help vim-function` para uma lista alfabética e `:help function-list` para uma lista de funções agrupadas por tópico.

#### Ressalvas

Algumas funções do Vim que deveriam retornar uma booleana, retornam `1` ou` 0`. Isso não é um problema no Vimscript, já que `1` é verdadeiro e `0` falso, permitindo construções como estas:

```vim
if has('nvim')
    " do something...
endif
```

Em Lua, no entanto, apenas `false` e` nil` são considerados falsos, os números sempre avaliam como `true` independentemente de seu valor. Você deve verificar explicitamente se há `1` ou` 0`:

```lua
if vim.fn.has('nvim') == 1 then
    -- do something...
end
```

## Definindo mapeamentos

Neovim fornece uma lista de funções de API para definir, obter e excluir mapeamentos:

- Mapeamentos globais:
    - `vim.api.nvim_set_keymap()`
    - `vim.api.nvim_get_keymap()`
    - `vim.api.nvim_del_keymap()`
- Mapeamentos de buffer local:
    - `vim.api.nvim_buf_set_keymap()`
    - `vim.api.nvim_buf_get_keymap()`
    - `vim.api.nvim_buf_del_keymap()`

Vamos começar com `vim.api.nvim_set_keymap()` e `vim.api.nvim_buf_set_keymap()`

O primeiro argumento passado para a função é uma string contendo o nome do modo para o qual o mapeamento terá efeito:


| Valor da string        | Página de ajuda | Modos afetados                           | Equivalente no Vimscript  |
| ---------------------- | -------------   | ---------------------------------------- | --------------------      |
| `''` (string vazia)    | `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`                   |

O segundo argumento é uma string contendo o lado esquerdo do mapeamento (a chave ou conjunto de chaves que acionam o comando definido no mapeamento). Uma string vazia é equivalente a `<Nop>`, que desabilita uma tecla.

O terceiro argumento é uma string contendo o lado direito do mapeamento (o comando a ser executado).
 
O argumento final é uma tabela contendo opções booleanas para o mapeamento conforme definido em `:help :map-arguments` (incluindo `noremap` e excluindo `buffer`).

Os mapeamentos locais do buffer também levam um número do buffer como primeiro argumento (`0` define o mapeamento para o buffer atual).

```lua
vim.api.nvim_set_keymap('n', '<leader><Space>', ':set hlsearch!<CR>', { noremap = true, silent = true })
-- :nnoremap <silent> <leader><Space> :set hlsearch<CR>

vim.api.nvim_buf_set_keymap(0, '', 'cc', 'line(".") == 1 ? "cc" : "ggcc"', { noremap = true, expr = true })
-- :noremap <buffer> <expr> cc line('.') == 1 ? 'cc' : 'ggcc'
```

`vim.api.nvim_get_keymap()` pega uma string contendo o nome curto do modo para o qual você deseja a lista de mapeamentos (veja a tabela acima). O valor de retorno é uma tabela contendo todos os mapeamentos globais para o modo.

```lua
print(vim.inspect(vim.api.nvim_get_keymap('n')))
-- :verbose nmap
```

`vim.api.nvim_buf_get_keymap()` recebe um número de buffer adicional como seu primeiro argumento (`0` obterá mapeamentos para o buffer atual)

```lua
print(vim.inspect(vim.api.nvim_buf_get_keymap(0, 'i')))
-- :verbose imap <buffer>
```

`vim.api.nvim_del_keymap()` pega um modo e o lado esquerdo de um mapeamento.

```lua
vim.api.nvim_del_keymap('n', '<leader><Space>')
-- :nunmap <leader><Space>
```

Novamente, `vim.api.nvim_buf_del_keymap()`, recebe um número de buffer como seu primeiro argumento, com `0` representando o buffer atual.

```lua
vim.api.nvim_buf_del_keymap(0, 'i', '<Tab>')
-- :iunmap <buffer> <Tab>
```

## Definindo comandos de usuário

Atualmente não há interface para criar comandos de usuário em Lua. Mas está planejado:

- [Solicitação pull # 11613](https://github.com/neovim/neovim/pull/11613)

Por enquanto, é melhor você criar comandos no Vimscript.

## Definindo autocommands

Augroups e autocommands ainda não têm uma interface, mas está sendo trabalhada:

- [Solicitação pull # 12378](https://github.com/neovim/neovim/pull/12378)

Enquanto isso, você pode criar comandos automáticos no Vimscript ou usar [este wrapper de norcalli / nvim_utils](https://github.com/norcalli/nvim_utils/blob/master/lua/nvim_utils.lua#L554-L567)

## Definindo sintaxe/destaques

A sintaxe API ainda é um trabalho em andamento. Aqui estão algumas dicas:

- [Problema nº 9876](https://github.com/neovim/neovim/issues/9876)
- [tjdevries / colorbuddy.vim, uma biblioteca para criar esquemas de cores em Lua](https://github.com/tjdevries/colorbuddy.vim)
- `:help lua-treesitter`

## Dicas e recomendações gerais

**FAÇAM**:
- Hot-reloadings de módulos
- `vim.validate()`?
- Adicionar coisas sobre testes de unidade? Eu sei que o Neovim usa o framework [busted](https://olivinelabs.com/busted/), mas não sei como usá-lo para plug-ins
- Melhores Práticas? Não sou um mago da Lua, então não saberia
- Como usar pacotes LuaRocks ([wbthomason / packer.nvim](https://github.com/wbthomason/packer.nvim)?)

## Diversos

### vim.loop

`vim.loop` é o módulo que expõe a API LibUV. Alguns recursos:

- [Documentação oficial para LibUV](https://docs.libuv.org/en/v1.x/)
- [documentação Luv](https://github.com/luvit/luv/blob/master/docs.md)
- [teukka.tech - Usando LibUV em Neovim](https://teukka.tech/vimloop.html)

Veja também:
- `:help vim.loop`

### vim.lsp

`vim.lsp` é o módulo que controla o cliente LSP embutido. O repositório [neovim / nvim-lspconfig](https://github.com/neovim/nvim-lspconfig/) contém configurações padrão para servidores de idiomas populares.

Você também pode dar uma olhada nos plug-ins construídos em torno do cliente LSP:
- [nvim-lua / completed-nvim](https://github.com/nvim-lua/completion-nvim)
- [nvim-lua / diagnostic-nvim](https://github.com/nvim-lua/diagnostic-nvim)

Veja também:
- `:help lsp`

### vim.treesitter

`vim.treesitter` é o módulo que controla a integração da biblioteca [Tree-sitter](https://tree-sitter.github.io/tree-sitter/) no Neovim. Se você quiser saber mais sobre o Tree-sitter, pode se interessar por esta [apresentação (38:37)](https://www.youtube.com/watch?v=Jes3bD6P0To).

A organização [nvim-treesitter](https://github.com/nvim-treesitter/) hospeda vários plug-ins aproveitando a biblioteca.

Veja também:
- `:help lua-treesitter`


### Transpilers

Uma vantagem de usar Lua é que você não precisa realmente escrever código Lua! Há uma grande variedade de transpiladores disponíveis para o idioma.

- [Moonscript](https://moonscript.org/)

Provavelmente um dos transpiladores mais conhecidos para Lua. Adiciona muitos recursos convenientes, como classes, compreensões de lista ou literais de função. O plugin [svermeulen / nvim-moonmaker](https://github.com/svermeulen/nvim-moonmaker) permite que você escreva plugins Neovim e configuração diretamente no Moonscript.

- [Fennel](https://fennel-lang.org/)

Um lisp que compila para Lua. Você pode escrever configuração e plug-ins para Neovim no Fennel com o plug-in [Olical / aniseed](https://github.com/Olical/aniseed). Adicionalmente, o plugin [Olical/conjure](https://github.com/Olical/conjure) disponibiliza um ambiente interativo de desenvolvimento que da suporte a Fennel (além de outras linguagens).

Outros projetos interessantes:
- [TypeScriptToLua/TypeScriptToLua](https://github.com/TypeScriptToLua/TypeScriptToLua)
- [teal-language/tl](https://github.com/teal-language/tl)
- [Haxe](https://haxe.org/)
- [SwadicalRag/wasm2lua](https://github.com/SwadicalRag/wasm2lua)
- [hengestone/lua-languages](https://github.com/hengestone/lua-languages)