diff options
| author | Elvis Claros Castro <elvis@claros.ar> | 2026-09-27 12:46:49 -0300 |
|---|---|---|
| committer | Elvis Claros Castro <elvis@claros.ar> | 2026-09-27 12:46:49 -0300 |
| commit | df7c711e2a49d51249350f52c63274b72aacb739 (patch) | |
| tree | 426da3b65371f857f3ee3d9893d7ff3279aac02e /lua/config | |
| parent | a0bd84df02ce235123dfc939327e8bd33dffdd7e (diff) | |
| download | nvim-conf-df7c711e2a49d51249350f52c63274b72aacb739.tar.gz nvim-conf-df7c711e2a49d51249350f52c63274b72aacb739.zip | |
Migración de plugins a funcionalidad nativa: statusline y treesitter propios, se quitan mason, lualine, mini, notify y otros
Diffstat (limited to 'lua/config')
| -rw-r--r-- | lua/config/autocmds.lua | 137 | ||||
| -rw-r--r-- | lua/config/init.lua | 3 | ||||
| -rw-r--r-- | lua/config/keymaps.lua | 51 | ||||
| -rw-r--r-- | lua/config/lazy.lua | 2 | ||||
| -rw-r--r-- | lua/config/options.lua | 6 | ||||
| -rw-r--r-- | lua/config/statusline.lua | 214 |
6 files changed, 409 insertions, 4 deletions
diff --git a/lua/config/autocmds.lua b/lua/config/autocmds.lua index ffb5d57..ccb9bd0 100644 --- a/lua/config/autocmds.lua +++ b/lua/config/autocmds.lua @@ -15,7 +15,6 @@ vim.api.nvim_create_autocmd("FileType", { "lspinfo", "spectre_panel", "startuptime", - "tsplayground", "PlenaryTestPopup", }, callback = function(event) @@ -162,6 +161,128 @@ vim.api.nvim_create_autocmd("User", { end, }) +-- Progreso LSP como notificación de snacks.notifier (reemplaza noice lsp.progress) +---@type table<number, {token:lsp.ProgressToken, msg:string, done:boolean}[]> +local lsp_progress = vim.defaulttable() +vim.api.nvim_create_autocmd("LspProgress", { + group = augroup "lsp_progress_notify", + ---@param ev {data: {client_id: integer, params: lsp.ProgressParams}} + callback = function(ev) + local client = vim.lsp.get_client_by_id(ev.data.client_id) + local value = ev.data.params.value --[[@as {percentage?: number, title?: string, message?: string, kind: "begin" | "report" | "end"}]] + if not client or type(value) ~= "table" then + return + end + local p = lsp_progress[client.id] + + for i = 1, #p + 1 do + if i == #p + 1 or p[i].token == ev.data.params.token then + p[i] = { + token = ev.data.params.token, + msg = ("[%3d%%] %s%s"):format( + value.kind == "end" and 100 or value.percentage or 100, + value.title or "", + value.message and (" **%s**"):format(value.message) or "" + ), + done = value.kind == "end", + } + break + end + end + + local msg = {} ---@type string[] + lsp_progress[client.id] = vim.tbl_filter(function(v) + return table.insert(msg, v.msg) or not v.done + end, p) + + local spinner = { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" } + vim.notify(table.concat(msg, "\n"), vim.log.levels.INFO, { + id = "lsp_progress", + title = client.name, + opts = function(notif) + notif.icon = #lsp_progress[client.id] == 0 and " " + or spinner[math.floor(vim.uv.hrtime() / (1e6 * 80)) % #spinner + 1] + end, + }) + end, +}) + +-- Formatear/minificar JSON con jq (reemplaza json-nvim) +vim.api.nvim_create_autocmd("FileType", { + group = augroup "json_jq", + pattern = "json", + callback = function(event) + vim.keymap.set("n", "<leader>jff", ":%!jq .<CR>", { buffer = event.buf, desc = "Formatear JSON con jq" }) + vim.keymap.set("n", "<leader>jmf", ":%!jq -c .<CR>", { buffer = event.buf, desc = "Minificar JSON con jq" }) + end, +}) + +-- Cerrar buffers inactivos tras 120 min (reemplaza nvim-early-retirement) +local retirement_age_mins = 120 +local buf_last_used = {} +vim.api.nvim_create_autocmd("BufEnter", { + group = augroup "early_retirement", + callback = function(event) + buf_last_used[event.buf] = os.time() + end, +}) +local retirement_timer = assert(vim.uv.new_timer()) +retirement_timer:start( + 60000, + 60000, + vim.schedule_wrap(function() + local now = os.time() + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + if + vim.api.nvim_buf_is_valid(buf) + and vim.bo[buf].buflisted + and not vim.bo[buf].modified + and #vim.fn.win_findbuf(buf) == 0 + then + local last = buf_last_used[buf] + if last == nil then + buf_last_used[buf] = now + elseif now - last > retirement_age_mins * 60 then + pcall(vim.api.nvim_buf_delete, buf, {}) + buf_last_used[buf] = nil + end + end + end + end) +) + +-- Detección simple de indentación (reemplaza indent-o-matic); editorconfig nativo tiene prioridad +vim.api.nvim_create_autocmd("BufReadPost", { + group = augroup "detect_indent", + callback = function(event) + local ec = vim.b[event.buf].editorconfig + if ec and (ec.indent_style or ec.indent_size) then + return + end + local tabs, spaces, min_spaces = 0, 0, math.huge + for _, line in ipairs(vim.api.nvim_buf_get_lines(event.buf, 0, 200, false)) do + local ws = line:match "^%s+" + if ws then + if ws:find "\t" then + tabs = tabs + 1 + else + spaces = spaces + 1 + if #ws > 1 and #ws < min_spaces then + min_spaces = #ws + end + end + end + end + if tabs > spaces then + vim.bo[event.buf].expandtab = false + elseif spaces > 0 and min_spaces ~= math.huge then + vim.bo[event.buf].expandtab = true + vim.bo[event.buf].shiftwidth = min_spaces + vim.bo[event.buf].softtabstop = min_spaces + end + end, +}) + -- vim.api.nvim_create_autocmd("User", { @@ -177,3 +298,17 @@ vim.api.nvim_create_autocmd("User", { -- end -- end, -- }) + +-- WezTerm no implementa el borrado de imágenes del protocolo kitty (snacks.image +-- usa el modo fallback sin placeholders), así que al salir de un buffer de imagen +-- quedan restos en pantalla. Forzar un repintado completo los limpia. +if vim.env.TERM_PROGRAM == "WezTerm" then + vim.api.nvim_create_autocmd("BufWinLeave", { + group = vim.api.nvim_create_augroup("wezterm_image_cleanup", { clear = true }), + callback = function(ev) + if vim.bo[ev.buf].filetype == "image" then + vim.schedule(function() vim.cmd "mode" end) + end + end, + }) +end diff --git a/lua/config/init.lua b/lua/config/init.lua index 5da196b..fe60f1f 100644 --- a/lua/config/init.lua +++ b/lua/config/init.lua @@ -7,6 +7,9 @@ require "config.options" local colorscheme = require "config.native-colorscheme" colorscheme.setup() +-- Statusline nativa (reemplaza lualine.nvim) +require("config.statusline").setup() + -- Additional UI Enhancements vim.opt.guicursor = "n-v-c:block,i-ci-ve:ver25,r-cr:hor20,o:hor50" vim.opt.cursorline = true diff --git a/lua/config/keymaps.lua b/lua/config/keymaps.lua index c1e126e..00ef762 100644 --- a/lua/config/keymaps.lua +++ b/lua/config/keymaps.lua @@ -173,3 +173,54 @@ map("n", "<leader>ft", "<CMD>FloatermToggle<CR>", { desc = "run terminal" }) map({ "n", "v" }, "<C-a>", "<cmd>CodeCompanionActions<cr>", { noremap = true, silent = true }) map({ "n", "v" }, "<LocalLeader>a", "<cmd>CodeCompanionChat Toggle<cr>", { noremap = true, silent = true }) map("v", "ga", "<cmd>CodeCompanionChat Add<cr>", { noremap = true, silent = true }) + +-- Historial de notificaciones (reemplaza :Noice history) +map("n", "<leader>nh", function() + Snacks.notifier.show_history() +end, { desc = "Historial de notificaciones" }) + +-- Abrir archivo/selección en el navegador (reemplaza vim-rhubarb :GBrowse) +map({ "n", "v" }, "<leader>go", function() + Snacks.gitbrowse() +end, { desc = "Git browse en el navegador" }) + +-- Picker de iconos/emoji (reemplaza icon-picker.nvim) +map("n", "<leader><leader>i", function() + Snacks.picker.icons() +end, { desc = "Insertar icono/emoji" }) +map("n", "<leader><leader>y", function() + Snacks.picker.icons { confirm = "yank" } +end, { desc = "Copiar icono/emoji" }) +map("i", "<C-o>", function() + Snacks.picker.icons() +end, { desc = "Insertar icono/emoji" }) + +-- Menú de acciones de Oil vía vim.ui.select (reemplaza menu.nvim) +map("n", "<leader>um", function() + local items = vim.tbl_filter(function(item) + return item.cmd ~= nil + end, require "menus.oil") + vim.ui.select(items, { + prompt = "Oil", + format_item = function(item) + return item.name .. (item.rtxt and " (" .. item.rtxt .. ")" or "") + end, + }, function(choice) + if choice then + choice.cmd() + end + end) +end, { desc = "Abrir menú de Oil" }) + +-- Animación de retipeo del buffer (antes plugin animation.nvim) +map("n", "<leader>AA", function() + require("pi.animations").redraw_buffer() +end, { desc = "Retype buffer animation" }) + +-- Buffers abiertos y navegación entre ellos (reemplaza buffer_manager.nvim, +-- roto en Neovim: usa el autocmd BufModifiedSet, que Vim soporta pero Neovim no implementa) +map("n", "<leader>o", function() + Snacks.picker.buffers() +end, { desc = "Buffers abiertos" }) +map("n", "]b", ":bnext<CR>", { desc = "Buffer siguiente" }) +map("n", "[b", ":bprevious<CR>", { desc = "Buffer anterior" }) diff --git a/lua/config/lazy.lua b/lua/config/lazy.lua index 34e034f..89a14a8 100644 --- a/lua/config/lazy.lua +++ b/lua/config/lazy.lua @@ -13,7 +13,7 @@ vim.opt.rtp:prepend(lazypath) require("lazy").setup { -- leave nil when passing the spec as the first argument to setup() - spec = { { "LazyVim/LazyVim", import = "plugins" } }, + spec = { { import = "plugins" } }, local_spec = true, -- load project specific .lazy.lua spec files. They will be added at the end of the spec. defaults = { -- Set this to `true` to have all your plugins lazy-loaded by default. diff --git a/lua/config/options.lua b/lua/config/options.lua index 2d80d08..1598c1c 100644 --- a/lua/config/options.lua +++ b/lua/config/options.lua @@ -103,8 +103,10 @@ opt.listchars = "tab:\\ ,trail:-" -- Siempre muestra la línea de estado. opt.laststatus = 3 --- Configura la altura del área de comandos. -opt.cmdheight = 1 +-- Sin fila de comandos: la cmdline la dibuja noice como popup centrado. +-- (Antes lo forzaba noice con messages activado; ahora lo seteamos nosotros.) +-- En firenvim no hay noice, así que ahí se mantiene la fila clásica. +opt.cmdheight = vim.g.started_by_firenvim and 1 or 0 -- Establece el tiempo de actualización en milisegundos. opt.updatetime = 50 diff --git a/lua/config/statusline.lua b/lua/config/statusline.lua new file mode 100644 index 0000000..c74d8d4 --- /dev/null +++ b/lua/config/statusline.lua @@ -0,0 +1,214 @@ +-- Statusline nativa (reemplaza lualine.nvim), con la paleta de config.native-colorscheme. +local M = {} + +local colors = require("config.native-colorscheme").colors + +local mode_names = { + n = "NORMAL", + no = "O-PENDING", + nt = "NORMAL", + v = "VISUAL", + V = "V-LINE", + ["\22"] = "V-BLOCK", + s = "SELECT", + S = "S-LINE", + ["\19"] = "S-BLOCK", + i = "INSERT", + R = "REPLACE", + Rv = "V-REPLACE", + c = "COMMAND", + cv = "EX", + r = "PROMPT", + ["r?"] = "CONFIRM", + ["!"] = "SHELL", + t = "TERMINAL", +} + +local mode_hl = { + n = "StlModeNormal", + i = "StlModeInsert", + v = "StlModeVisual", + V = "StlModeVisual", + ["\22"] = "StlModeVisual", + s = "StlModeVisual", + S = "StlModeVisual", + c = "StlModeCommand", + R = "StlModeReplace", + r = "StlModeReplace", + t = "StlModeTerminal", + ["!"] = "StlModeTerminal", +} + +function M.set_highlights() + local hl = function(name, fg, bg, bold) + vim.api.nvim_set_hl(0, name, { fg = fg, bg = bg, bold = bold ~= false }) + end + hl("StlModeIcon", colors.base4, colors.base03) + hl("StlModeNormal", colors.blue100, colors.base03) + hl("StlModeInsert", colors.green100, colors.base03) + hl("StlModeVisual", colors.magenta100, colors.base03) + hl("StlModeCommand", colors.yellow100, colors.base03) + hl("StlModeReplace", colors.red100, colors.base03) + hl("StlModeTerminal", colors.orange100, colors.base03) + hl("StlBranch", colors.orange100, colors.base03) + hl("StlDiffAdd", colors.green300, colors.base03) + hl("StlDiffChange", colors.yellow300, colors.base03) + hl("StlDiffDelete", colors.red300, colors.base03) + hl("StlFile", colors.yellow100, colors.base03) + hl("StlDiagError", colors.red300, colors.base03) + hl("StlDiagWarn", colors.yellow300, colors.base03) + hl("StlDiagInfo", colors.blue300, colors.base03) + hl("StlDiagHint", colors.cyan300, colors.base03) + hl("StlUpdates", colors.orange300, colors.bg_statusline, false) + hl("StlLsp", colors.base4, colors.base03) + hl("StlFt", colors.magenta100, colors.base03) + hl("StlProgress", colors.cyan100, colors.base03) + hl("StlSep", colors.base00, colors.base03, false) + hl("StlBg", colors.fg, colors.bg_statusline, false) +end + +-- Handlers de click (:h 'statusline' %@); globales porque %@ necesita un nombre simple. +function _G.StlClickFile() + Snacks.picker.files() +end + +function _G.StlClickDiag() + Snacks.picker.diagnostics() +end + +local function filename() + local name = vim.api.nvim_buf_get_name(0) + if name == "" then + return "[Sin nombre]" + end + local file = vim.fn.fnamemodify(name, ":t") + local parent = vim.fn.fnamemodify(name, ":h:t") + return parent .. "/" .. file +end + +local function git() + local out = {} + -- vim.b para el repo del buffer; vim.g como fallback (repo del cwd, ej. en oil) + local head = vim.b.gitsigns_head or vim.g.gitsigns_head + if head and head ~= "" then + out[#out + 1] = "%#StlBranch# " .. head + end + local status = vim.b.gitsigns_status_dict + if status then + if (status.added or 0) > 0 then + out[#out + 1] = "%#StlDiffAdd# " .. status.added + end + if (status.changed or 0) > 0 then + out[#out + 1] = "%#StlDiffChange# " .. status.changed + end + if (status.removed or 0) > 0 then + out[#out + 1] = "%#StlDiffDelete# " .. status.removed + end + end + if #out == 0 then + return "" + end + return table.concat(out) +end + +local diag_specs = { + { vim.diagnostic.severity.ERROR, "StlDiagError", " " }, + { vim.diagnostic.severity.WARN, "StlDiagWarn", " " }, + { vim.diagnostic.severity.INFO, "StlDiagInfo", " " }, + { vim.diagnostic.severity.HINT, "StlDiagHint", " " }, +} + +local function diagnostics() + local counts = vim.diagnostic.count(0) + local parts = {} + for _, spec in ipairs(diag_specs) do + local n = counts[spec[1]] + if n and n > 0 then + parts[#parts + 1] = "%#" .. spec[2] .. "#" .. spec[3] .. n + end + end + if #parts == 0 then + return "" + end + return "%@v:lua.StlClickDiag@" .. table.concat(parts, " ") .. "%X " +end + +local function lsp_clients() + local clients = vim.lsp.get_clients { bufnr = 0 } + if #clients == 0 then + return "No LSP" + end + local names = {} + for _, client in ipairs(clients) do + names[#names + 1] = client.name + end + return table.concat(names, ",") +end + +local function lazy_updates() + local ok, status = pcall(require, "lazy.status") + if ok and status.has_updates() then + return "%#StlUpdates#" .. status.updates() .. " " + end + return "" +end + +local function filetype() + local ft = vim.bo.filetype + if ft == "" then + return "" + end + local ok, mini = pcall(require, "mini.icons") + if ok then + local ok_get, icon, icon_hl = pcall(mini.get, "filetype", ft) + if ok_get and icon then + return "%#" .. icon_hl .. "#" .. icon .. " %#StlFt#" .. ft .. " " + end + end + return "%#StlFt#" .. ft .. " " +end + +-- Como el componente 'progress' de lualine: Top / Bot / porcentaje +local function progress() + local cur = vim.fn.line "." + local total = vim.fn.line "$" + if cur == 1 then + return "Top" + elseif cur == total then + return "Bot" + end + return string.format("%2d%%%%", math.floor(cur / total * 100)) +end + +function M.render() + local mode = vim.api.nvim_get_mode().mode + local hl = mode_hl[mode:sub(1, 1)] or "StlModeNormal" + local name = mode_names[mode] or mode_names[mode:sub(1, 1)] or mode + local left = vim.tbl_filter(function(s) + return s ~= "" + end, { + "%#StlModeIcon# %#" .. hl .. "#" .. name, + git(), + "%#StlFile#%@v:lua.StlClickFile@ " .. filename() .. "%X", + }) + + return table.concat(left, "%#StlSep# │ ") .. table.concat { + " %#StlBg#%=", + diagnostics(), + lazy_updates(), + "%#StlLsp#", lsp_clients(), " ", + filetype(), + "%#StlProgress#", progress(), " ", + } +end + +function M.setup() + M.set_highlights() + vim.api.nvim_create_autocmd("ColorScheme", { + group = vim.api.nvim_create_augroup("native_statusline", { clear = true }), + callback = M.set_highlights, + }) + vim.o.statusline = "%!v:lua.require'config.statusline'.render()" +end + +return M |