diff --git a/.config/nvim/init.lua b/.config/nvim/init.lua new file mode 100644 index 0000000..4c12974 --- /dev/null +++ b/.config/nvim/init.lua @@ -0,0 +1,401 @@ +-- 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) + +-- Definir leader como spacebar +vim.g.mapleader = " " +vim.g.maplocalleader = " " + +-- Configurações visuais +vim.opt.number = true +vim.opt.relativenumber = true +vim.opt.signcolumn = "yes" + +-- Habilitar popup automático de completação LSP +vim.opt.completeopt = { "menu", "menuone", "noselect" } + +-- Configurar undo persistente +vim.opt.undofile = true +vim.opt.undodir = vim.fn.stdpath("data") .. "/undo" + +-- Criar diretório de undo se não existir +vim.fn.mkdir(vim.fn.stdpath("data") .. "/undo", "p") + +-- Mostrar diagnósticos em popup flutuante ao posicionar cursor +vim.diagnostic.config({ + virtual_text = true, + signs = true, + underline = true, + update_in_insert = false, + severity_sort = true, + float = { + border = "rounded", + source = "always", + header = "", + prefix = "", + }, +}) + +-- Abrir popup de diagnóstico automaticamente ao hover +vim.api.nvim_create_autocmd("CursorHold", { + callback = function() + local opts = { + focusable = false, + close_events = { "BufLeave", "CursorMoved", "InsertEnter", "FocusLost" }, + border = "rounded", + source = "always", + prefix = " ", + scope = "cursor", + } + vim.diagnostic.open_float(nil, opts) + end +}) + +-- Reduzir tempo para mostrar o popup (padrão é 4000ms) +vim.opt.updatetime = 300 + +-- Configurar plugins +require("lazy").setup({ + -- Tema Catppuccin + { + "catppuccin/nvim", + name = "catppuccin", + priority = 1000, + config = function() + require("catppuccin").setup({ + flavour = "frappe", + }) + vim.cmd.colorscheme("catppuccin") + end, + }, + + -- Treesitter + { + "nvim-treesitter/nvim-treesitter", + build = ":TSUpdate", + config = function() + local status_ok, treesitter = pcall(require, "nvim-treesitter.configs") + if not status_ok then + return + end + treesitter.setup({ + ensure_installed = { "lua", "rust", "bash", "gdscript" }, + highlight = { enable = true }, + auto_install = false, + }) + end, + }, + + -- Telescope + { + "nvim-telescope/telescope.nvim", + tag = "0.1.8", + dependencies = { "nvim-lua/plenary.nvim" }, + config = function() + require("telescope").setup() + + -- Keybindings + local builtin = require("telescope.builtin") + vim.keymap.set("n", "ff", builtin.find_files, { desc = "Find files" }) + vim.keymap.set("n", "fg", builtin.live_grep, { desc = "Live grep" }) + vim.keymap.set("n", "fb", builtin.buffers, { desc = "Find buffers" }) + vim.keymap.set("n", "fh", builtin.help_tags, { desc = "Help tags" }) + end, + }, + + -- Yazi - Explorador de arquivos + { + "mikavilpas/yazi.nvim", + event = "VeryLazy", + keys = { + { + "e", + "Yazi", + desc = "Open yazi file explorer", + }, + { + "cw", + "Yazi cwd", + desc = "Open yazi in current working directory", + }, + }, + opts = { + open_for_directories = false, + keymaps = { + show_help = "", + }, + }, + }, + + -- Gitsigns - Símbolos de status git + -- Mostra indicadores visuais de mudanças git na coluna de sinais + -- Nota: Para suporte a Jujutsu VCS, considere plugins experimentais como jj-sign.nvim ou panda.nvim + { + "lewis6991/gitsigns.nvim", + event = { "BufReadPre", "BufNewFile" }, + config = function() + require("gitsigns").setup({ + signs = { + add = { text = "┃" }, + change = { text = "┃" }, + delete = { text = "_" }, + topdelete = { text = "‾" }, + changedelete = { text = "~" }, + untracked = { text = "┆" }, + }, + signcolumn = true, + numhl = false, + linehl = false, + word_diff = false, + watch_gitdir = { + interval = 1000, + follow_files = true, + }, + attach_to_untracked = true, + current_line_blame = false, + current_line_blame_opts = { + virt_text = true, + virt_text_pos = "eol", + delay = 1000, + }, + sign_priority = 6, + update_debounce = 100, + status_formatter = nil, + max_file_length = 40000, + preview_config = { + border = "rounded", + style = "minimal", + relative = "cursor", + row = 0, + col = 1, + }, + on_attach = function(bufnr) + local gs = package.loaded.gitsigns + + local function map(mode, l, r, opts) + opts = opts or {} + opts.buffer = bufnr + vim.keymap.set(mode, l, r, opts) + end + + -- Navegação entre hunks + map("n", "]c", function() + if vim.wo.diff then return "]c" end + vim.schedule(function() gs.next_hunk() end) + return "" + end, { expr = true, desc = "Next git hunk" }) + + map("n", "[c", function() + if vim.wo.diff then return "[c" end + vim.schedule(function() gs.prev_hunk() end) + return "" + end, { expr = true, desc = "Previous git hunk" }) + + -- Ações + map("n", "hs", gs.stage_hunk, { desc = "Stage hunk" }) + map("n", "hr", gs.reset_hunk, { desc = "Reset hunk" }) + map("v", "hs", function() gs.stage_hunk({vim.fn.line("."), vim.fn.line("v")}) end, { desc = "Stage hunk" }) + map("v", "hr", function() gs.reset_hunk({vim.fn.line("."), vim.fn.line("v")}) end, { desc = "Reset hunk" }) + map("n", "hS", gs.stage_buffer, { desc = "Stage buffer" }) + map("n", "hu", gs.undo_stage_hunk, { desc = "Undo stage hunk" }) + map("n", "hR", gs.reset_buffer, { desc = "Reset buffer" }) + map("n", "hp", gs.preview_hunk, { desc = "Preview hunk" }) + map("n", "hb", function() gs.blame_line({full=true}) end, { desc = "Blame line" }) + map("n", "tb", gs.toggle_current_line_blame, { desc = "Toggle blame line" }) + map("n", "hd", gs.diffthis, { desc = "Diff this" }) + map("n", "hD", function() gs.diffthis("~") end, { desc = "Diff this ~" }) + map("n", "td", gs.toggle_deleted, { desc = "Toggle deleted" }) + + -- Text object + map({"o", "x"}, "ih", ":Gitsigns select_hunk", { desc = "Select hunk" }) + end, + }) + end, + }, + + -- Undotree - Visualizador de undo persistente + { + "mbbill/undotree", + config = function() + vim.keymap.set("n", "u", vim.cmd.UndotreeToggle, { desc = "Toggle Undotree" }) + end, + }, + + -- Comment.nvim - Comentar código facilmente + { + "numToStr/Comment.nvim", + config = function() + require("Comment").setup() + end, + }, + + -- vim-surround - Adicionar/remover/mudar delimitadores + { + "tpope/vim-surround", + }, + + -- GitHub Copilot + { + "github/copilot.vim", + config = function() + -- Keybindings para Copilot + vim.g.copilot_no_tab_map = true + vim.keymap.set("i", "", 'copilot#Accept("\\")', { + expr = true, + replace_keycodes = false, + desc = "Copilot Accept" + }) + vim.keymap.set("i", "", "(copilot-dismiss)", { desc = "Copilot Dismiss" }) + vim.keymap.set("i", "", "(copilot-next)", { desc = "Copilot Next" }) + vim.keymap.set("i", "", "(copilot-previous)", { desc = "Copilot Previous" }) + end, + }, + + -- nvim-cmp para autocompletação LSP + { + "hrsh7th/nvim-cmp", + dependencies = { + "hrsh7th/cmp-nvim-lsp", + "hrsh7th/cmp-buffer", + "hrsh7th/cmp-path", + }, + config = function() + local cmp = require("cmp") + cmp.setup({ + mapping = cmp.mapping.preset.insert({ + [""] = cmp.mapping.scroll_docs(-4), + [""] = cmp.mapping.scroll_docs(4), + [""] = cmp.mapping.complete(), + [""] = cmp.mapping.abort(), + [""] = cmp.mapping.confirm({ select = false }), + [""] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_next_item() + else + fallback() + end + end, { "i", "s" }), + [""] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_prev_item() + else + fallback() + end + end, { "i", "s" }), + }), + sources = cmp.config.sources({ + { name = "nvim_lsp" }, + { name = "path" }, + }, { + { name = "buffer" }, + }), + completion = { + autocomplete = { require("cmp.types").cmp.TriggerEvent.TextChanged }, + }, + }) + end, + }, + + -- Lualine + { + "nvim-lualine/lualine.nvim", + config = function() + require("lualine").setup({ + options = { + theme = "catppuccin", + }, + tabline = { + lualine_a = { "buffers" }, + lualine_z = { "tabs" }, + }, + }) + end, + }, + + -- LSP + { + "neovim/nvim-lspconfig", + dependencies = { + "williamboman/mason.nvim", + "williamboman/mason-lspconfig.nvim", + }, + config = function() + require("mason").setup() + require("mason-lspconfig").setup({ + ensure_installed = {}, + automatic_installation = false, + }) + + -- Capabilities para nvim-cmp + local capabilities = require("cmp_nvim_lsp").default_capabilities() + + -- LSP Keybindings + vim.api.nvim_create_autocmd("LspAttach", { + callback = function(args) + local opts = { buffer = args.buf } + vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts) + vim.keymap.set("n", "K", vim.lsp.buf.hover, opts) + vim.keymap.set("n", "rn", vim.lsp.buf.rename, opts) + vim.keymap.set("n", "ca", vim.lsp.buf.code_action, opts) + vim.keymap.set("n", "gr", vim.lsp.buf.references, opts) + vim.keymap.set("i", "", vim.lsp.buf.signature_help, opts) + vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, opts) + vim.keymap.set("n", "]d", vim.diagnostic.goto_next, opts) + end, + }) + + -- Lua LSP (usando lua-language-server já instalado no sistema) + vim.lsp.config.lua_language_server = { + cmd = { "lua-language-server" }, + filetypes = { "lua" }, + root_markers = { ".luarc.json", ".git" }, + settings = { + Lua = { + diagnostics = { + globals = { "vim" }, + }, + }, + }, + capabilities = capabilities, + } + vim.lsp.enable("lua_language_server") + + -- Rust LSP + vim.lsp.config.rust_analyzer = { + cmd = { "rust-analyzer" }, + filetypes = { "rust" }, + root_markers = { "Cargo.toml", ".git" }, + capabilities = capabilities, + } + vim.lsp.enable("rust_analyzer") + + -- Bash LSP + vim.lsp.config.bashls = { + cmd = { "bash-language-server", "start" }, + filetypes = { "sh", "bash" }, + root_markers = { ".git" }, + capabilities = capabilities, + } + vim.lsp.enable("bashls") + + -- GDScript LSP + vim.lsp.config.gdscript = { + cmd = { "nc", "localhost", "6005" }, + filetypes = { "gd", "gdscript", "gdscript3" }, + root_markers = { "project.godot", ".git" }, + capabilities = capabilities, + } + vim.lsp.enable("gdscript") + end, + }, +})