Saltar al contenido

LazyVim para C, Rust, Swift y frontend

Los Extras de lenguaje aplicados a los cuatro stacks del curso: clangd con codelldb, rustaceanvim con crates.nvim, el frontend con vtsls, ESLint, Prettier y Tailwind — y Swift montado a mano por las dos vías, porque no hay extra. Más la IA sin pelearse con el completado.

Todo el trabajo de configuración por lenguaje del Nivel 2 —servidor LSP con sus banderas, formateo, depuración, parser, coordinados entre sí— LazyVim lo tiene empaquetado en Extras. Esta lección los aplica a nuestros cuatro stacks, y es deliberadamente un examen doble: de la distro, que resuelve tres de los cuatro con una línea cada uno, y tuyo, porque el cuarto —Swift— no tiene extra y hay que montarlo a mano. Saber hacer las dos cosas, activar el paquete y cocinar sin él, es exactamente la posición que este nivel te quiere dejar.

  • Leer la documentación de un extra antes de activarlo: qué instala, qué configura, qué mapea.
  • Activar y entender los Extras de C/C++ (clangd), Rust y el grupo de frontend (TypeScript, Tailwind, ESLint, Prettier).
  • Conocer las opciones globales de cada extra: vim.g.lazyvim_ts_lsp, vim.g.lazyvim_rust_diagnostics.
  • Añadir Swift (sourcekit-lsp) sobre LazyVim por las dos vías posibles, y saber cuándo cada una.
  • Sumar IA sin pelearse con el autocompletado.

Antes de activar: aprende a leer un extra

Cada extra tiene una página en la documentación de LazyVim (lazyvim.org, sección Extras) con una anatomía fija que conviene saber leer, porque es tu contrato con él: la lista de plugins que incluye y, para cada uno, sus opciones por defecto y su spec completa desplegable. Los marcados como (optional) solo se configuran si el plugin está instalado por otra vía — así un extra de lenguaje puede traer configuración de tests o de DAP que solo se enciende si tienes esos extras activos también.

Dos costumbres de Arquitecto al leer esas páginas. Primera: la sección de opciones te dice qué podrás sobreescribir con las técnicas de la lección 5.3 — es tu mapa de override antes de necesitarlo. Segunda: la propia página te avisa de que no copies los defaults a tu config; están ahí para leerse, no para pegarse. Copiar defaults es congelar hoy las decisiones que la distro te mantendría mañana.

Activar los Extras de lenguaje

Abre :LazyExtras y activa (tecla x) los que necesites — quedarán apuntados en tu lazyvim.json (lección 5.2) — o, si prefieres verlos en el código, añádelos a mano en la spec:

lua/config/lazy.lua (imports de Extras)LUA
spec = {  { "LazyVim/LazyVim", import = "lazyvim.plugins" },  -- Nuestros stacks  { import = "lazyvim.plugins.extras.lang.clangd" },      -- C / C++  { import = "lazyvim.plugins.extras.lang.rust" },        -- Rust  { import = "lazyvim.plugins.extras.lang.typescript" },  -- TS / JS  { import = "lazyvim.plugins.extras.lang.tailwind" },    -- Tailwind  { import = "lazyvim.plugins.extras.lang.json" },        -- JSON con schemas  { import = "lazyvim.plugins.extras.linting.eslint" },   -- ESLint  { import = "lazyvim.plugins.extras.formatting.prettier" },  -- IA  { import = "lazyvim.plugins.extras.ai.copilot" },  { import = "plugins" },},

Cada Extra trae todo coordinado: el servidor LSP con sus banderas, el parser de Treesitter, el adaptador de depuración y los atajos propios del lenguaje.

lang.clangd

clangd con banderas afinadas, clangd_extensions y el DAP con codelldb para C y C++. Añade el salto cabecera-fuente con una tecla.

lang.rust

rustaceanvim con rust-analyzer afinado, crates.nvim para el Cargo.toml y codelldb para depurar. El setup de la lección 3.6, en una línea.

lang.typescript

vtsls como servidor por defecto, acciones propias de TS y el depurador de JavaScript ya adaptado.

lang.tailwind

tailwindcss-language-server con completado de clases y los colores de las clases pintados en el menú.

C y C++: lang.clangd

El extra monta clangd con la misma filosofía que tu config del Nivel 2, pero con las banderas ya discutidas y decididas: --background-index para indexar el proyecto en segundo plano, --clang-tidy para los diagnósticos del linter integrados, --header-insertion=iwyu, --completion-style=detailed y --function-arg-placeholders. Sus root_markers reconocen compile_commands.json, compile_flags.txt, Makefiles, Meson y Ninja — y fija offsetEncoding = utf-16, un detalle de compatibilidad que en configs a mano causa avisos crípticos cuando falta.

Alrededor del servidor: clangd_extensions.nvim (inlay hints y vista del AST), el parser de C++ por ensure_installed, y la pieza que en el Nivel 2 fue una lección entera — el DAP: registra el adaptador codelldb (que Mason instala por ti) con dos configuraciones listas, Launch file y Attach to process, para C y C++. Y una tecla nueva: <leader>ch alterna entre cabecera y fuente.

Lo que el extra no puede hacer por ti: generar el compile_commands.json. Eso sigue siendo cosa de tu sistema de build (lección 3.5), porque ninguna distro puede saber cómo se compila tu proyecto.

Rust: lang.rust

Aquí el extra toma una decisión de arquitectura que conviene entender: desactiva el rust_analyzer genérico de la capa de lspconfig y entrega el lenguaje entero a rustaceanvim, que gestiona el servidor él mismo — exactamente el razonamiento de tu lección 3.6, para que no haya nunca dos servidores adjuntos al mismo buffer. El rust-analyzer que arranca viene afinado: cargo.allFeatures, procMacro.enable, clippy en el checkOnSave.

Alrededor: crates.nvim convierte el Cargo.toml en territorio inteligente — completado de versiones, acciones y hover sobre cada dependencia —; los parsers de rust y ron; codelldb vía Mason para depurar; y si usas el extra de tests, el adaptador de neotest de rustaceanvim. Teclas propias: <leader>cR para las code actions de rust-analyzer y <leader>dr para elegir qué depurar (debuggables) — binarios, tests o ejemplos del Cargo.toml, detectados solos.

Y una opción global documentada: vim.g.lazyvim_rust_diagnostics en tu options.lua permite delegar los diagnósticos en bacon-ls en vez de rust-analyzer, para proyectos donde el cargo check continuo pesa demasiado.

TypeScript y React: lang.typescript y su corte

El extra monta vtsls como servidor por defecto sobre los filetypes de JS/TS y sus variantes React (typescriptreact, javascriptreact), con inlay hints configurados y updateImportsOnFileMove — mueves un archivo y los imports del proyecto se actualizan. Las acciones propias que añade, todas ejecutando comandos del servidor:

gD definición en el código fuente, no en el .d.tsgR referencias al archivo entero<leader>cM añade los imports que faltan<leader>cD arregla todos los diagnósticos del archivo<leader>cV elige la versión de TS del workspace

También adapta el depurador: js-debug-adapter (instalado por Mason) con configuraciones pwa-node de lanzamiento y attach para los cuatro filetypes, usando tsx o ts-node para ejecutar TypeScript directamente.

El extra es en realidad una familia: la documentación lista sub-extras para elegir servidor — vtsls (el por defecto), tsgo (el compilador nativo de TypeScript, mucho más rápido, activable también con vim.g.lazyvim_ts_lsp = "tsgo" en tu options.lua) — y variantes para las toolchains biome y oxc. Para el stack React del curso, el trío completo es lang.typescript + linting.eslint + formatting.prettier, y el extra lang.json cubre los JSON de configuración del ecosistema.

Tailwind: lang.tailwind

Monta tailwindcss-language-server — completado de clases, hover con el CSS resultante — y tailwindcss-colorizer-cmp, que pinta en el menú de completado el color real de cada clase. Su configuración expone dos listas cómodas para ajustar dónde actúa: filetypes_exclude (por defecto excluye markdown) y filetypes_include para añadir los tuyos. Como con todos los extras de lenguaje, :LazyExtras tiende a sugerírtelo él mismo entre los recomendados cuando detecta un proyecto Tailwind en el directorio.

Cada Extra también reparte teclas

Un Extra no solo instala: mapea. Acabas de ver a TypeScript reclamar gD, gR y tres entradas bajo <leader>c, y a clangd quedarse <leader>ch. Después de activar varios, pasa por :map <leader>c y por <leader> con which-key para ver qué ha aparecido. Es la forma barata de descubrir que dos Extras quieren la misma tecla antes de que te pase en mitad de un trabajo — la misma auditoría de la lección 5.2, repetida tras cada alta.

Swift: el que va a mano

LazyVim no trae un Extra de Swift — puedes comprobarlo en el catálogo de lang.*, que va de Angular a Zig sin pasar por él —, así que lo añadimos nosotros. Y aquí tienes dos vías, las dos válidas, que se distinguen por una pregunta: ¿quieres que Swift viva debajo de la capa de la distro o integrado en ella?

Vía 1: la nativa de 0.12 (más simple)

Como viste en la lección 3.7, en Neovim 0.12 un servidor de lenguaje es una ficha en la carpeta lsp/ de tu runtimepath más una línea para activarlo. Y ~/.config/nvim/lsp/ está en el runtimepath también dentro de LazyVim, así que esto funciona sin escribir ninguna spec:

lsp/sourcekit.luaLUA
return {  cmd = { "xcrun", "sourcekit-lsp" },  filetypes = { "swift" },  root_markers = { "buildServer.json", "Package.swift", ".git" },}
lua/config/options.luaLUA
vim.lsp.enable("sourcekit")

Cinco líneas y un vim.lsp.enable. El servidor se adjunta, K, gd y los diagnósticos funcionan, y la distro ni se entera — lo cual es a la vez la virtud y el límite de esta vía.

Deja C y C++ a clangd

sourcekit-lsp también sabe de C, C++ y Objective-C. Si declaras esos filetypes y tienes activo lang.clangd, los dos servidores se adjuntarán al mismo buffer y verás diagnósticos duplicados. Deja filetypes en swift a secas, o añade objc y objcpp si trabajas con código mixto de Apple. Es el mismo principio que el extra de Rust aplica al desactivar el rust_analyzer genérico: un buffer, un servidor.

Vía 2: la de LazyVim (integrada con su capa)

Si prefieres que Swift entre por la misma puerta que el resto —y así herede la gestión de la distro: sus keymaps de LSP, su motor de formateo con conform, su ecosistema— declara el servidor en las opts de su capa de lspconfig, con el mismo patrón de override de la lección 5.3:

lua/plugins/lang-swift.luaLUA
return {  {    "neovim/nvim-lspconfig",    opts = {      servers = {        sourcekit = {          mason = false, -- no está en Mason: viene con la toolchain de Xcode          cmd = { "xcrun", "sourcekit-lsp" },          filetypes = { "swift" },          root_markers = { "buildServer.json", "Package.swift", ".git" },        },      },    },  },  -- formateo con swift-format vía conform (LazyVim ya lo trae)  {    "conform.nvim",    opts = { formatters_by_ft = { swift = { "swift_format" } } },  },  -- el parser, por la opción de la spec de LazyVim  {    "nvim-treesitter/nvim-treesitter",    opts = { ensure_installed = { "swift" } },  },}

El patrón para cualquier lenguaje sin Extra

Este archivo es la plantilla universal: una entrada en opts.servers para el servidor, otra en conform para el formateo y otra en ensure_installed para el parser. Sirve para Swift, para un lenguaje de nicho o para el que salga el año que viene. Fíjate en que mason = false es lo que le dice a LazyVim «de este servidor me encargo yo»: sin esa línea intentaría instalarlo con Mason, y sourcekit-lsp no está ahí porque ya viene con Xcode. Y fíjate en que el archivo entero es, en miniatura, lo que es un extra: si mañana quisieras, podrías compararlo con cualquier archivo de lazyvim/plugins/extras/lang/ y reconocer la misma estructura.

IA sobre LazyVim

El Extra ai.copilot activa copilot.lua con sugerencias en línea, y trae una integración fina que merece mirarse: la opción global vim.g.ai_cmp (activada por defecto) decide si las sugerencias de IA entran como fuente del motor de completado en vez de como texto fantasma suelto — es decir, la distro resuelve por diseño el conflicto de «quién es el dueño de aceptar la sugerencia» dándoselo al completado. Es exactamente la disciplina que predica este track.

Si prefieres el stack por capas de la lección 3.4 —copilot.lua para la sugerencia en línea, CodeCompanion para conversar y sidekick para los agentes—, añádelos como plugins propios en lua/plugins/ con las specs de esa lección: se integran igual que en tu config a mano.

Antes de aceptar cualquier atajo de IA

Ningún plugin de IA debe quedarse con <Tab> ni con <C-Space>: la primera mueve el menú de completado y la segunda lo dispara. Si un tutorial te propone <Tab> para aceptar la sugerencia, muévelo a una combinación con Alt o acepta que tu completado se vuelva impredecible. Compruébalo con :imap <Tab> — y recuerda que en la lección 5.3 ya recuperaste <C-Space> de manos de flash; no la vuelvas a regalar.

La economía del empaquetado

Lo que has usado hoy tiene setenta años de historia fuera de Neovim y se llama paquete. Un extra de LazyVim es exactamente lo que un paquete de Debian o de Homebrew: alguien tomó software de terceros (un servidor, un depurador, tres plugins), decidió versiones que funcionan juntas, escribió la integración, y publicó el conjunto con un nombre. La economía que lo sostiene es siempre la misma y es demoledora: la integración de clangd con codelldb hay que resolverla una vez, y el coste se amortiza entre todos los usuarios del paquete. Tú tardaste una lección en el Nivel 2; el mantenedor del extra tardó más; el usuario del extra tarda una tecla. El conocimiento no desapareció — se condensó en el paquete, con las decisiones dentro.

Y por eso la pregunta correcta ante cualquier ecosistema —distros de Linux, registries de npm o de crates, imágenes de contenedores, extras de LazyVim— no es «¿uso paquetes o compilo de fuentes?», porque la respuesta es obviamente «paquetes, mientras existan y sirvan». La pregunta correcta es la que Swift te ha obligado a responder hoy: ¿qué haces cuando el paquete no existe? Ahí se separan los perfiles. Quien solo sabe instalar paquetes se queda parado o abandona la herramienta; quien sabe lo que un paquete empaqueta, lo monta a mano en veinte líneas y sigue trabajando — y de paso podría, si quisiera, contribuir el paquete que faltaba, que es como los ecosistemas crecen. Ser Arquitecto es eso: usar el paquete sin devoción y cocinarlo sin drama. Hoy has hecho las dos cosas en la misma lección.

Tu IDE políglota en LazyVim

  1. Activa los Extras de clangd, rust y typescript, más linting.eslint y formatting.prettier. Comprueba en lazyvim.json que están apuntados.
  2. Antes de abrir ningún archivo, lee la página de documentación de uno de ellos entera e identifica sus tres partes: plugins incluidos, opciones y spec completa.
  3. Abre un archivo de cada lenguaje y confirma que el LSP responde (K, gd). En el buffer de Rust, comprueba que hay un solo servidor adjunto.
  4. En un proyecto TypeScript, borra un import y recupéralo con <leader>cM. Prueba gD sobre un símbolo de una librería y observa que aterrizas en el fuente, no en el .d.ts.
  5. Abre un Cargo.toml y comprueba lo que crates.nvim añade: hover sobre una dependencia, completado de versiones.
  6. Añade Swift por la vía 1 y prueba un archivo .swift. Después migra a la vía 2 y comprueba que el formateo al guardar de la distro ahora también cubre Swift.
  7. Activa ai.copilot y verifica con :imap <Tab> que la tecla sigue siendo del completado.
  8. Pasa :map <leader>c y anota qué tecla ha añadido cada extra. Si dos chocan algún día, ya sabes de qué lección es la solución.