725 - ¿Es este el FUTURO del autocompletado en Neovim?

725 - ¿Es este el FUTURO del autocompletado en Neovim?

Transforma Neovim con plugins clave: blink.cmp (autocompletado), LSP, neominimap y tu propia wiki. ¡Maximiza tu productividad!

1:25
-3:15

Hace algunos meses que dejé de utilizar Obisidian como gestor de notas y he vuelto a Neovim, de donde, probablemente, nunca debí salir, como suelen decir. La cuestión es que me siento infinitamente más cómodo trabajando con Neovim. Esto unido a que como te voy contando, estoy muy metido en el tema de programación, han hecho que esté casi mas tiempo en Neovim, que en la terminal, y eso ya es mucho decir. Con el incremento de uso de Neovim, me he puesto un poco mas al día, si cabe, con los plugin que vengo utilizando, he probado algunos nuevos, he desinstalado y he reemplazado. Como te conté en un reciente episodio, esto de la configuración de Neovim, como la de Niri, etc, es un proceso, que sabes cuando empieza, pero no cuando termina. Sin embargo, en esta ocasión, he cambiado uno de los plugin fundamentales, el del autocompletado. Algo que en ningún caso se me pasaba por la cabeza.

Es este el FUTURO del autocompletado en Neovim?

Un poquito de trasfondo

Si eres de los que sigues el podcast, atareao con Linux, o el canal de YouTube, ya estarás hasta harto de oírme decir que Neovim es una de mis herramientas favoritas. La razón para decir esto es sencilla, la capacidad de personalizarlo al extremo. Neovim te permite que tu entorno de trabajo se adapta a ti en lugar de al revés. Lo mismo que me sucede con Linux o con Niri, el gestor de ventanas que estoy utilizando actualmente.

La cuestión es que cuanto mas tiempo pasas en Neovim, mas tiempo inviertes en adecentarlo. En ir modificando poco a poco Neovim, puliendo pequeños detalles, o cambiando la configuración para adaptarlo mejor a su flujo de trabajo. Como te decía, es un proceso que empieza pero no sabes cuando termina.

Así, en estas últimas semanas he ido reemplazando algunos de los plugin que he estado utilizando hasta el momento. Algunos de esos plugins que inicialmente pensaba que serían completamente irremplazables, como por ejemplo el del autocompletado, han sido sustituidos por otros que me ofrecen una mejor experiencia de usuario.

El autocompletado

El primero de los plugin del que te quiero hablar es blink. Este plugin es el que ha venido a reemplazar al clásico nvim-cmp, el que es considerado el estándar de facto para el autocompletado.

Sin lugar a dudas, el autocompletado es fundamental, ya sea que te dediques a programar, a escribir, o prácticamente a cualquier cosa que quieras hacer con Neovim, o con cualquier editor, hoy en día.

Te preguntarás porque reemplazo nvim-cmp, pues simplemente por otros plugins. En los últimos tiempos ando probando, sobre todo, complementos de IA, y lo que he visto es que muchos han empezado a reemplazar al que yo usaba por este.

Sin embargo, nvim-cmp, lo llevo utilizando bastante tiempo, y lo cierto es que funcionaba bien, salvo el problema de la integración. Y esto de que me estuviera funcionando ha sido básicamente el mayor obstáculo para decidirme por probar blink, y al final ha sido un acierto, porque he conseguido un mejor integración que la que tenía con nvim-cmp.

En algún sitio he leído que la configuración de blink es mas sencilla que la de nvim-cmp, y puede ser que sea algo mas sencilla, pero vamos, que no es una bicoca. En cualquier caso, una vez que lo tienes funcionando, la experiencia de usuario es mucho mejor, o por lo menos es lo que a mi me parece.

Tengo que decirte, que finalmente no me he quedado con ninguna de los complementos de IA que he probado, pero si que he conseguido una mejor experiencia de autocompletado, así que, definitivamente, se queda conmigo.

Mi configuración de blink la puedes ver en mis dotfiles. Pero, te la dejo aquí también para tu comodidad,

return {
    'saghen/blink.cmp',
    -- optional: provides snippets for the snippet source
    dependencies = {
        "rafamadriz/friendly-snippets",
        "mikavilpas/blink-ripgrep.nvim",
        "fang2hou/blink-copilot",
        "onsails/lspkind.nvim",
        "saghen/blink.compat",
    },
    -- use a release tag to download pre-built binaries
    version = '1.*',
    -- AND/OR build from source, requires nightly: https://rust-lang.github.io/rustup/concepts/channels.html#working-with-nightly-rust
    -- build = 'cargo build --release',
    -- If you use nix, you can build from source using latest nightly rust with:
    -- build = 'nix run .#build-plugin',

    ---@module 'blink.cmp'
    opts = {
        cmdline = { enabled = true },
        fuzzy = {
            implementation = "prefer_rust_with_warning",
            sorts = {
                "exact",
                "score",
                "sort_text"
            }
        },
        keymap = {
            ['<tab>'] = { 'select_and_accept', 'fallback' },
            ['<CR>'] = { 'select_and_accept', 'fallback' }
        },
        sources = {
            default = { "minuet", "copilot", "lsp", "path", "snippets", "buffer", "ripgrep" },
            providers = {
                minuet = {
                    name = 'minuet',
                    module = 'minuet.blink',
                    async = true,
                    -- Should match minuet.config.request_timeout * 1000,
                    -- since minuet.config.request_timeout is in seconds
                    timeout_ms = 3000,
                    score_offset = 50, -- Gives minuet higher priority among suggestions
                },
                copilot = {
                    name = "copilot",
                    module = "blink-copilot",
                    score_offset = 100,
                    async = true,
                    transform_items = function(_, items)
                        for _, item in ipairs(items) do
                            item.kind_icon = ''
                            item.kind_name = 'Copilot'
                        end
                        return items
                    end
                },
                ripgrep = {
                    module = "blink-ripgrep",
                    name = "Ripgrep",
                    -- see the full configuration below for all available options
                    ---@module "blink-ripgrep"
                    opts = {},
                },
                buffer = {
                    opts = {
                        -- get all buffers, even ones like neo-tree
                        -- get_bufnrs = vim.api.nvim_list_bufs
                        -- or (recommended) filter to only "normal" buffers
                        get_bufnrs = function()
                            return vim.tbl_filter(function(bufnr)
                                return vim.bo[bufnr].buftype == ''
                            end, vim.api.nvim_list_bufs())
                        end
                    }
                }
            },
        },
        appearance = {
            -- Blink does not expose its default kind icons so you must copy them all (or set your custom ones) and add Copilot
            kind_icons = {
                Copilot = "",
            }
        },
        signature = { enabled = true },
        completion = {
            documentation = {
                auto_show = true,
                auto_show_delay_ms = 500,
                window = { border = "single" },
            },
            ghost_text = {
                enabled = true,
            },
            trigger = {
                --show_on_keyword = true,
                prefetch_on_insert = false
            },
            list = {
                selection = { preselect = true, auto_insert = true }
            },
            menu = {
                border = "single",
                draw = {
                    padding = { 1, 1 }, -- padding only on right side
                    treesitter = { "lsp" },
                    columns = { { "kind_icon" }, { "label", gap = 1 } },
                    components = {
                        kind_icon = {
                            text = function(ctx)
                                local icon = ctx.kind_icon
                                if vim.tbl_contains({ "Path" }, ctx.source_name) then
                                    local dev_icon, _ = require("nvim-web-devicons").get_icon(ctx.label)
                                    if dev_icon then
                                        icon = dev_icon
                                    end
                                elseif ctx.source_name == "copilot" then
                                    icon = "😺"
                                elseif ctx.source_name == "Ripgrep" then
                                    icon = "🔍"
                                elseif ctx.source_name == "minuet" then
                                    icon = "💃🏻"
                                else
                                    icon = require("lspkind").symbolic(ctx.kind, {
                                        mode = "symbol",
                                    })
                                end
                                return icon .. ctx.icon_gap
                            end,

                            -- Optionally, use the highlight groups from nvim-web-devicons
                            -- You can also add the same function for `kind.highlight` if you want to
                            -- keep the highlight groups in sync with the icons.
                            highlight = function(ctx)
                                local hl = ctx.kind_hl
                                if vim.tbl_contains({ "Path" }, ctx.source_name) then
                                    local dev_icon, dev_hl = require("nvim-web-devicons").get_icon(ctx.label)
                                    if dev_icon then
                                        hl = dev_hl
                                    end
                                end
                                return hl
                            end,
                        },
                        label = {
                            text = function(ctx)
                                return require("colorful-menu").blink_components_text(ctx)
                            end,
                            highlight = function(ctx)
                                return require("colorful-menu").blink_components_highlight(ctx)
                            end,
                        },
                    }
                }
            }
        }
    },
    opts_extend = { "sources.default" }
}

Dicho esto, no tengo nada claro, pero que nada claro, que este vaya a ser la solución de autocompletado definitiva, ni mucho menos. Es mas, cada día que pasa, lo que tengo claro es que el autocompletado terminará por ser algo integrado en el propio Neovim.

LSP

Desde hace ya algunas versiones que Neovim es compatible con el Protocolo de servidor de Lenguage (LSP), lo que significa que Neovim funciona como un cliente para los servidores LSP e incluye un framework en Lua llamado vim.lsp para crear herramientas mejoras.

El LSP facilite funciones como ir a la definición, encontrar referencias, autocompletado, resaltar símbolos, formateo de código, y mucho más, todo ello de una manera estandarizada y consistente a través de diferentes lenguajes de programación.

Hasta la fecha, he estado utilizando distintos complementos para conseguir toda la funcionalidad necesaria. Pero, he visto que no es necesario nada de esto, de forma que he hecho una auténtica limpieza, y me he quedado únicamente con los archivos de configuración necesarios para los lenguajes que actualmente estoy utilizando, y que visto lo visto voy a tener que ir modificando, poco a poco (como de costumbre).

Así, ahora la estructura de los archivos de configuración de LSP, es un primer archivo, lsp.lua, que se encuentra dentro del directorio lua, y en ~/.config/nvim/lsp se encuentran todos los archivos de configuración correspondientes a cada uno de los LSP.

El método Zettelkasten

Bueno, realmente ya no es tanto el método Zettelkasten, porque era mas bien la herramienta que estaba utilizando hasta hace unos meses y que la he reemplazado por lervag/wiki.vim. Esta es una herramienta fundamental, porque como te contado en alguna que otra ocasión, utilizo Neovim para gestionar mis notas, y wiki.vim es la herramienta que me permite hacerlo de una manera sencilla y eficaz.

Mas o menos esto es lo mismo que lo que tienes con Obsidian pero de una manera mucho mas simplificada.

Justo estaba escuchando precisamente el último episodio de Sobre la marcha, titulado Vuelvo a Obsidan, y no es por las Bases, en el que el mencionaba su regreso desde LogSeq a Obsidian, y me resultó muy curiosa la coincidencia.

El Mini mapa

Algo que llevaba pendiente hacer en Neovim desde hace tiempo, era el tener un mini mapa, algo que me permitiera tener una visión general del archivo que estoy editando. Creo que en algunas ocasiones he incorporado alguno, pero te puedo asegurar que ninguno como el que tengo ahora mismo, Isrothy/neominimap.nvim.

Es muy sencillo, tremendamente fácil de configurar y que te da gusto eso que comento, un minimapa.


Más información,

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *