DEV Community

Ellison Leão
Ellison Leão

Posted on • Updated on

Criando plugins Lua para Neovim - Parte 2

Um plugin para o mundo real


Na segunda parte da nossa série vamos criar um plugin que poderá ser usado no dia-a-dia, onde iremos introduzir algumas funcionalidades legais do Neovim, como as floating windows e algumas funções da API lua.

Vamos começar relembrando a estrutura de um plugin. Nosso novo plugin vai possuir a seguinte estrutura:

weather.nvim
├── lua
│  └── weather.lua
└── plugin
   └── weather.lua
Enter fullscreen mode Exit fullscreen mode

A idéia do plugin é mostrar a previsão do tempo atual em uma floating window, sendo chamado a partir de um comando.

Desenhando, vamos ter algo como:

weather.nvim

Estrutura do módulo

Nosso módulo weather.lua vai conter a seguinte estrutura:

local M = {}

local function create_command()
-- vamos criar o comando :Weather aqui
end

M.create_window = function()
-- aqui vamos criar a janela, um mapping para fechá-la e mostrar o tempo
end

M.close_window = function()
-- uma função para fechar a janela atual, que sera usada em um mapping
end

return M
Enter fullscreen mode Exit fullscreen mode

Analisando uma por uma, temos:

create_command()

A função create_command() vai criar nosso comando customizado (command!). Aqui introduzimos o vim.cmd, que pode ser utilizada para chamar comandos Ex nativos do vim, mais conhecidos como os comandos :.

defininos nosso comando como:

vim.api.nvim_create_user_command("Weather", M.create_window(), {nargs=0})
Enter fullscreen mode Exit fullscreen mode

com isso, nosso commando, :Weather, vai chamar diretamente uma função do nosso módulo lua para esse plugin

create_window()

a função create_window() vai ser responsável por criar uma floating window no canto superior direito da tela e mostrar o conteúdo do tempo. Para criá-la, precisamos seguir os seguintes passos:

  1. criar um buffer “descartável”, que será usado para o conteúdo da janela
  2. criar as configurações da janela (tamanho de linhas, colunas, posicao x e y na tela, bordas)
  3. chamar o comando que “abre” a janela
  4. criar um mapping para poder fechar a janela
  5. criar o conteúdo do buffer, no nosso caso, o tempo atual.

Para o passo 1, temos:

buf = vim.api.nvim_create_buf(false, true)
Enter fullscreen mode Exit fullscreen mode

Aqui temos outra novidade também, o vim.api , um conjunto de métodos para o neovim dentro do módulo lua vim. nvim_create_buf aceita 2 parâmetros, se o buffer vai ser listado ou não (no nosso caso não, por isso o false) e se ele será descartável ou não (no nosso caso sim, por isso o true). Para saber mais sobre o método, chame :help nvim_create_buf .

O método retorna o id do novo buffer criado, e a informação desse id é importante porque ele será usado para fazer referência em outras funções mais pra frente. Note aqui também que não estamos criando a váriavel buf dentro desse método, mas uma variável “global” do módulo lua que também será usada por outros métodos dentro desse módulo.

Para o passo 2, temos:

  local columns = vim.api.nvim_get_option("columns")
  local lines = vim.api.nvim_get_option("lines")
  local win_width = math.ceil(columns * 0.3 - 10)
  local win_height = math.ceil(lines * 0.3 - 6)
  local x_pos = 1
  local y_pos = columns - win_width

  local win_opts = {
    style = "minimal",
    relative = "editor",
    width = win_width,
    height = win_height,
    row = x_pos,
    col = y_pos,
    border = "single",
  }
Enter fullscreen mode Exit fullscreen mode

Primeiro pegamos as variáveis de total de linhas e colunas do buffer atual para fazer um cálculo proporcional do tamanho da nossa floating window.

  • relative="editor" é a opção que vai dizer que iremos usar as coordenadas x e y globais, relativas ao editor, tendo tamanho inicial (0,0) até (linhas-1, colunas-1)

  • style = "minimal", vai deixar nossa janela com configurações mínimas, removendo a maioria das opções de UI. Isso é essencial para janelas temporárias, onde não iremos precisar fazer nenhuma alteração.

  • width e height é o calculo proporcional do tamanho da janela, adicionando um padding para que ela não fique simplesmente “grudada” no canto superior direito da tela. Cada unidade de medida corresponde a um caracter

  • row e col vai setar a posição x e y da nossa janela

  • border vai passar a config da nossa borda da floating window, no caso single representa linhas simples

Para o passo 3, temos:

win = vim.api.nvim_open_win(buf, true, win_opts)
Enter fullscreen mode Exit fullscreen mode

Aqui chamamos a vim.api.nvim_open_win, o método que vai abrir nossa janela, usando o buffer que criamos, com a configuração que passamos. Nos parâmetros, podemos também ver o true, que vai setar a janela como a atual. Vamos precisar disso para chamar o comando que gera o conteúdo da mesma. Note também que nossa variável win também é “global”, pois vamos precisar da informação dela para criar os mappings que vão poder fechá-la.

Para o passo 4, temos:

vim.keymap.set("n", "q", M.close_window(), {noremap = true, silent = true, buffer = buf})
Enter fullscreen mode Exit fullscreen mode

Usamos a nova api introduzida no neovim 0.7 vim.keymap para criar um nnoremap local (somente para o buffer criado), que basicamente irá chamar outro método do nosso módulo, para fechar a janela. Iremos explicar o método close_window() mais pra frente.

Como parâmetros, primeiros temos o modo, no caso o modo Normal, depois o comando que esse mapping irá chamar e finalmente temos uma table com possíveis opções para o mapping, como noremap, silent, etc. No nosso caso, só queremos que o comando não coloque nenhum output na tela e não utilize nenhum outro mapping com a letra q, caso haja algum.

Finalmente para o passo 5, temos:

local command = "curl https://wttr.in/?0"
vim.fn.termopen(command)
Enter fullscreen mode Exit fullscreen mode

Aqui fazemos uma ponte entre lua e vimscript, chamando a função termopen, que basicamente abre um terminal emulado dentro do neovim com o resultado do comando curl

close_window()

A função close window no nosso caso só vai ser uma chamada direta para o nvim_win_close:

vim.api.nvim_win_close(win, true)
Enter fullscreen mode Exit fullscreen mode

Aqui passamos a variável win, que é o id da nossa janela criada e true fala que queremos forçar o fechamento da janela.

Conclusão

Com isso, nosso primeiro plugin “para o mundo real”, está pronto. A versão do código para esse post pode ser vista clicando aqui.

Para ver a versão completa do plugin, com mais customizações, clique aqui e já manda o star!. Para a parte 3 da nossa série, vamos mostrar como portar nossa config do neovim em vimscript totalmente para Lua. Não deixem de acompanhar!

Para ouvir

Top comments (0)