Configurar Neovim para Zig
O Neovim é uma excelente escolha para desenvolvimento com Zig, oferecendo LSP nativo, Tree-sitter para syntax highlighting preciso e um ecossistema rico de plugins. Este guia mostra como configurar o Neovim para ter uma experiência de desenvolvimento completa com Zig, incluindo autocompletar, diagnósticos, formatação e navegação de código.
Antes de configurar o Neovim, certifique-se de que o Zig está instalado. Consulte o guia para sua plataforma no guia completo de instalação.
Pré-requisitos
- Neovim 0.9+ (recomendado 0.10+)
- Zig instalado e acessível no PATH
- ZLS instalado (Zig Language Server)
- Git para clonar plugins
Verificar Versões
nvim --version | head -1
zig version
zls --version
Instalar o ZLS
Se ainda não instalou o ZLS:
# Linux (x86_64)
curl -LO "https://github.com/zigtools/zls/releases/download/0.14.0/zls-x86_64-linux.tar.xz"
tar -xf "zls-x86_64-linux.tar.xz"
sudo mv zls /usr/local/bin/
# macOS
brew install zls
# Arch Linux
sudo pacman -S zls
Configuração com lazy.nvim (Recomendado)
O lazy.nvim é o gerenciador de plugins mais popular para Neovim. Vamos configurar tudo do zero.
Estrutura de Arquivos
~/.config/nvim/
├── init.lua
├── lua/
│ ├── plugins/
│ │ ├── lsp.lua
│ │ ├── cmp.lua
│ │ └── treesitter.lua
│ └── config/
│ └── keymaps.lua
init.lua Base
Crie ou edite ~/.config/nvim/init.lua:
-- Bootstrap lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
"git", "clone", "--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable", lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
-- Opções gerais
vim.g.mapleader = " "
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.tabstop = 4
vim.opt.shiftwidth = 4
vim.opt.expandtab = true
vim.opt.signcolumn = "yes"
vim.opt.termguicolors = true
-- Carregar plugins
require("lazy").setup("plugins")
-- Carregar keymaps
require("config.keymaps")
Configuração do LSP (ZLS)
Crie ~/.config/nvim/lua/plugins/lsp.lua:
return {
{
"neovim/nvim-lspconfig",
dependencies = {
"williamboman/mason.nvim",
"williamboman/mason-lspconfig.nvim",
},
config = function()
-- Configurar Mason (gerenciador de LSP servers)
require("mason").setup()
require("mason-lspconfig").setup({
ensure_installed = { "zls" },
})
local lspconfig = require("lspconfig")
-- Função para configurar keymaps quando o LSP conecta
local on_attach = function(client, bufnr)
local opts = { noremap = true, silent = true, buffer = bufnr }
-- Navegação
vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
vim.keymap.set("n", "gD", vim.lsp.buf.declaration, opts)
vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts)
vim.keymap.set("n", "gr", vim.lsp.buf.references, opts)
vim.keymap.set("n", "K", vim.lsp.buf.hover, opts)
vim.keymap.set("n", "<C-k>", vim.lsp.buf.signature_help, opts)
-- Ações
vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, opts)
vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, opts)
vim.keymap.set("n", "<leader>f", function()
vim.lsp.buf.format({ async = true })
end, opts)
-- Diagnósticos
vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, opts)
vim.keymap.set("n", "]d", vim.diagnostic.goto_next, opts)
vim.keymap.set("n", "<leader>e", vim.diagnostic.open_float, opts)
vim.keymap.set("n", "<leader>q", vim.diagnostic.setloclist, opts)
-- Formatar ao salvar
if client.supports_method("textDocument/formatting") then
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = bufnr,
callback = function()
vim.lsp.buf.format({ bufnr = bufnr })
end,
})
end
end
-- Configurar ZLS
lspconfig.zls.setup({
on_attach = on_attach,
settings = {
zls = {
enable_snippets = true,
enable_autofix = true,
enable_import_detection = true,
warn_style = true,
highlight_global_var_declarations = true,
},
},
})
-- Configuração de diagnósticos
vim.diagnostic.config({
virtual_text = true,
signs = true,
underline = true,
update_in_insert = false,
severity_sort = true,
float = {
border = "rounded",
source = true,
},
})
end,
},
}
Autocompletar com nvim-cmp
Crie ~/.config/nvim/lua/plugins/cmp.lua:
return {
{
"hrsh7th/nvim-cmp",
dependencies = {
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-path",
"L3MON4D3/LuaSnip",
"saadparwaiz1/cmp_luasnip",
},
config = function()
local cmp = require("cmp")
local luasnip = require("luasnip")
cmp.setup({
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
["<C-b>"] = cmp.mapping.scroll_docs(-4),
["<C-f>"] = cmp.mapping.scroll_docs(4),
["<C-Space>"] = cmp.mapping.complete(),
["<C-e>"] = cmp.mapping.abort(),
["<CR>"] = cmp.mapping.confirm({ select = true }),
["<Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
elseif luasnip.expand_or_jumpable() then
luasnip.expand_or_jump()
else
fallback()
end
end, { "i", "s" }),
["<S-Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif luasnip.jumpable(-1) then
luasnip.jump(-1)
else
fallback()
end
end, { "i", "s" }),
}),
sources = cmp.config.sources({
{ name = "nvim_lsp" },
{ name = "luasnip" },
}, {
{ name = "buffer" },
{ name = "path" },
}),
formatting = {
format = function(entry, vim_item)
vim_item.menu = ({
nvim_lsp = "[LSP]",
luasnip = "[Snip]",
buffer = "[Buf]",
path = "[Path]",
})[entry.source.name]
return vim_item
end,
},
})
end,
},
}
Tree-sitter para Syntax Highlighting
Crie ~/.config/nvim/lua/plugins/treesitter.lua:
return {
{
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
config = function()
require("nvim-treesitter.configs").setup({
ensure_installed = { "zig", "lua", "vim", "vimdoc", "c", "markdown" },
auto_install = true,
highlight = {
enable = true,
additional_vim_regex_highlighting = false,
},
indent = {
enable = true,
},
incremental_selection = {
enable = true,
keymaps = {
init_selection = "<C-space>",
node_incremental = "<C-space>",
scope_incremental = false,
node_decremental = "<bs>",
},
},
})
end,
},
}
Keymaps Específicos para Zig
Crie ~/.config/nvim/lua/config/keymaps.lua:
-- Atalhos gerais
local map = vim.keymap.set
-- Compilar e executar Zig
map("n", "<leader>zb", ":!zig build<CR>", { desc = "Zig build" })
map("n", "<leader>zr", ":!zig build run<CR>", { desc = "Zig build run" })
map("n", "<leader>zt", ":!zig build test<CR>", { desc = "Zig build test" })
-- Executar o arquivo atual
map("n", "<leader>zx", function()
local file = vim.fn.expand("%")
vim.cmd("!zig run " .. file)
end, { desc = "Zig run current file" })
-- Testar o arquivo atual
map("n", "<leader>zT", function()
local file = vim.fn.expand("%")
vim.cmd("!zig test " .. file)
end, { desc = "Zig test current file" })
-- Terminal integrado
map("n", "<leader>tt", ":terminal<CR>", { desc = "Abrir terminal" })
map("t", "<Esc>", "<C-\\><C-n>", { desc = "Sair do modo terminal" })
Plugins Adicionais Recomendados
Para uma experiência mais completa, adicione estes plugins ao diretório lua/plugins/:
Telescope (Fuzzy Finder)
-- lua/plugins/telescope.lua
return {
{
"nvim-telescope/telescope.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
keys = {
{ "<leader>ff", "<cmd>Telescope find_files<cr>", desc = "Buscar arquivos" },
{ "<leader>fg", "<cmd>Telescope live_grep<cr>", desc = "Buscar texto" },
{ "<leader>fb", "<cmd>Telescope buffers<cr>", desc = "Listar buffers" },
{ "<leader>fh", "<cmd>Telescope help_tags<cr>", desc = "Ajuda" },
{ "<leader>fd", "<cmd>Telescope diagnostics<cr>", desc = "Diagnósticos" },
{ "<leader>fr", "<cmd>Telescope lsp_references<cr>", desc = "Referências LSP" },
},
},
}
Lualine (Status Line)
-- lua/plugins/lualine.lua
return {
{
"nvim-lualine/lualine.nvim",
config = function()
require("lualine").setup({
sections = {
lualine_c = {
{ "filename", path = 1 },
},
lualine_x = { "encoding", "fileformat", "filetype" },
},
})
end,
},
}
Verificação da Configuração
Após configurar tudo, reinicie o Neovim e verifique:
- LSP ativo: Abra um arquivo
.zige execute:LspInfopara verificar se o ZLS está conectado - Tree-sitter: Execute
:TSInstallInfoe verifique sezigestá instalado - Autocompletar: Comece a digitar
std.em um arquivo.zige veja as sugestões
Teste com Código Zig
Crie um arquivo main.zig e abra no Neovim:
const std = @import("std");
pub fn main() !void {
const allocator = std.heap.page_allocator;
var list = std.ArrayList(u32).init(allocator);
defer list.deinit();
try list.append(42);
try list.append(100);
const stdout = std.io.getStdOut().writer();
for (list.items) |item| {
try stdout.print("{} ", .{item});
}
try stdout.print("\n", .{});
}
Verifique se:
- A sintaxe é colorida corretamente (Tree-sitter)
- Ao digitar
std., aparecem sugestões (autocompletar) - Erros são destacados em tempo real (diagnósticos)
gdsobremainvai para a definição (navegação LSP)
Problemas Comuns
ZLS não conecta
Execute :LspLog para ver os logs do LSP. Causas comuns:
- ZLS não está no PATH
- Versão do ZLS incompatível com a versão do Zig
- Falta a dependência
nvim-lspconfig
Tree-sitter não funciona para Zig
Execute :TSInstall zig manualmente e reinicie o Neovim.
Autocompletar lento
Verifique se não há muitos sources configurados no nvim-cmp e se o ZLS está na versão correta.
Para mais soluções, visite nossa página de erros comuns.
Próximos Passos
Com o Neovim configurado para Zig:
- Crie seu primeiro projeto — Primeiro projeto Zig
- Aprenda a linguagem — Introdução ao Zig
- Explore outros editores — VS Code ou Sublime/Emacs
- Configure CI/CD — GitHub Actions com Zig
- Veja exemplos — Receitas