Diseñar tu vocabulario: prefijos, colisiones y documentación
Un conjunto de atajos no es un lenguaje. Convenciones de prefijos y espacios de nombres, el contrato de teclas reservadas de este curso, cómo auditar qué está libre de verdad tras los mapeos que Neovim instala de fábrica, la trampa del retardo por prefijo compartido — timeoutlen y ttimeoutlen no son lo mismo — y cómo generar una chuleta desde tu propia tabla de mapeos.
Llegado este punto sabes crear mapeos, teclas expresivas, comandos y operadores. El problema deja de ser técnico y pasa a ser de diseño de lenguaje: cincuenta atajos sin sistema son peores que quince con gramática, porque los primeros hay que recordarlos uno a uno y los segundos se deducen. Esta lección cierra el nivel con la parte que ninguna documentación de plugin te va a enseñar: cómo repartir un espacio de teclas que es finito, ya está medio ocupado, y tiene que seguir siendo legible dentro de dos años.
- Estructurar tus mapeos con prefijos que formen un espacio de nombres deducible en lugar de memorizable.
- Conocer el contrato de teclas de este curso y auditar qué está libre de verdad, contando lo que Neovim instala de fábrica.
- Evitar el retardo por prefijo compartido y distinguir
timeoutlendettimeoutlen. - Documentar el vocabulario con
descy generar una chuleta desde la propia tabla de mapeos.
Prefijos: construir un espacio de nombres
Un prefijo convierte una tecla en un dominio. La convención que mejor escala usa dos niveles y una regla fija: el primer carácter tras la tecla líder nombra el dominio, el segundo nombra la acción dentro de él.
| Prefijo | Dominio | Ejemplos |
|---|---|---|
<leader>f |
Buscar archivos y texto | <leader>ff, <leader>fg, <leader>fr |
<leader>g |
Git | <leader>gs, <leader>gb, <leader>gd |
<leader>c |
Código y LSP | <leader>cf, <leader>cr, <leader>ca |
<leader>b |
Buffers | <leader>bd, <leader>bn |
<leader>u |
Interruptores | <leader>uw, <leader>un |
<leader>x |
Diagnósticos y listas | <leader>xx, <leader>xq |
Junto a la tecla líder conviven tres espacios de nombres nativos que deberías respetar en lugar de reinventar. Los corchetes [ y ] significan anterior y siguiente dentro de una secuencia, y Neovim ya trae de serie [q y ]q para la quickfix de la lección 1.6, [b y ]b para buffers, [d y ]d para diagnósticos. La tecla g es el cajón de acciones extendidas — ahí colocaste tu operador gz en la 11.4 —, y z gobierna pliegues, desplazamiento y ortografía. Un mapeo tuyo que respete estas convenciones se aprende solo; uno que las contradiga te cobrará una fricción diaria.
Sustantivo primero, verbo después
<leader>bd se lee «buffer, delete» y <leader>gs se lee «git, status». Fija ese orden y no lo rompas jamás: en cuanto un mapeo tuyo invierte el criterio, pierdes la capacidad de deducir atajos que nunca aprendiste, que es justamente lo que un espacio de nombres te compra. El premio adicional es which-key: con el orden coherente, cada prefijo abre un menú que es un dominio, no una miscelánea.
El contrato de teclas de este curso
Tu vocabulario no empieza en un solar vacío. A lo largo del curso se han ido firmando cesiones de territorio, y romperlas ahora significa romper lecciones enteras. Este es el mapa consolidado:
| Tecla | Dueño | Dónde se firmó |
|---|---|---|
<C-Space> y <Tab> |
El completado | 3.2 — y su fallo es silencioso si alguien las pisa |
s / S |
flash.nvim, el salto | 3.3 |
gs |
mini.surround | 2.2 y 3.3 |
gr + letra |
La familia LSP: grn, gra, grr, gri, grt |
3.1, de fábrica desde 0.11 |
[ / ] + letra |
Anterior / siguiente: quickfix, buffers, diagnósticos | 1.6 y 3.1, nativos |
<leader> |
Tus acciones, por dominios | 2.1 en adelante |
La lista no es una imposición estética: es la condición para que todo lo demás componga. Cuando en la 11.4 hubo que elegir tecla para el operador de ordenación, este mapa es lo que dictó gz y descartó gs.
Qué teclas están libres de verdad
Neovim instala mapeos por defecto que crecen con cada versión, y la lista vive en :h default-mappings. El espacio gr está ocupado por el LSP: grn renombra, gra ejecuta una acción de código, grr lista referencias, gri va a la implementación y grt al tipo. Además K muestra documentación flotante y gO lista los símbolos del documento. Antes de reclamar cualquier tecla, la pregunta correcta no es «me parece que está libre», sino:
:verbose nmap gz → qué hay y dónde se fijó por última vez:map <leader>f → todo lo que cuelga de ese prefijo:h default-mappings → qué reclama Neovim de fábrica:verbose resuelve en segundos el misterio de qué plugin te ha robado una tecla. La versión programática es más potente, porque puedes ejecutarla al arrancar y convertir una colisión en un aviso:
local function ocupada(modo, lhs) local objetivo = vim.fn.keytrans(vim.keycode(lhs)) for _, m in ipairs(vim.api.nvim_get_keymap(modo)) do if vim.fn.keytrans(m.lhs) == objetivo then return m.desc or m.rhs or 'mapeo sin descripción' end endendprint(ocupada('n', 'grn'))La opción unique = true de la 11.1 hace lo mismo de forma declarativa: si el mapeo ya existía, el arranque falla con E227 en lugar de sobrescribir en silencio. Mientras diseñas tu vocabulario es la red de seguridad más barata que existe. Y si decides quedarte con una tecla nativa, la forma limpia de liberarla es vim.keymap.del y una nota en tu config — no sobrescribirla y olvidarlo.
Territorio ocupado
Lo del contrato de arriba, más los nativos con historia: Q reproduce el último registro grabado, Y copia hasta el final de línea. Reclamar cualquiera es legítimo, pero debe ser una decisión consciente, anotada, y con vim.keymap.del de por medio.
Territorio cómodo y libre
La tecla líder con cualquier dominio, los pares con [ y ] que no pisen los nativos, y parejas bajo g que no empiecen por r ni sean gs — como el gz de la 11.4. Ahí es donde debe crecer tu vocabulario.
El retardo por prefijo compartido
Cuando un mapeo es prefijo estricto de otro, Neovim no puede saber si has terminado de teclear y espera timeoutlen milisegundos antes de decidir. Si mapeas a la vez <leader>b y <leader>bd, cada pulsación del primero arrastra medio segundo de parálisis.
La regla de diseño es sencilla: los prefijos son ramas y los mapeos son hojas; ninguna rama puede ser también una hoja. Con una excepción honrada: el operador doblado de la 11.4 (gz y gzz), donde la espera desemboca en operator-pending y no se nota — la convención nativa de dd y yy bendice el patrón.
El caso jk merece la mención porque muerde en texto en castellano, donde la j aparece con frecuencia: cada una queda retenida — sin pintar — hasta que el temporizador expira o llega la siguiente tecla. Y no confundas los dos temporizadores: timeoutlen gobierna la ambigüedad entre mapeos tuyos; ttimeoutlen gobierna la espera de las secuencias de escape del terminal, y debe ser muy pequeño para que <Esc> responda al instante.
vim.o.timeout = truevim.o.timeoutlen = 400 -- ambigüedad entre mapeos: lo que esperas túvim.o.ttimeoutlen = 10 -- códigos del terminal: cuanto más bajo, mejorPara mapeos locales de buffer que compiten con un prefijo global existe nowait = true, que corta la espera de raíz. Es la solución del caso clásico de las ventanas efímeras: en un panel de ayuda o un árbol de archivos, q debe cerrar de inmediato aunque en el ámbito global exista algún mapeo que empiece por q.
Documentar lo que has construido
Un vocabulario sin documentación se erosiona: los atajos diarios sobreviven y los quincenales se olvidan y se vuelven espacio muerto. La disciplina mínima es desc en absolutamente todos los mapeos — la 11.1 te dio la razón técnica: desc convierte la tabla en una base de datos legible por which-key, por :map y por tus propios scripts. Y si es una base de datos, se le pueden hacer informes. Este comando — de usuario, como manda la 11.3 — genera la chuleta de tu editor:
vim.api.nvim_create_user_command('Chuleta', function() local filas = { '| Modo | Tecla | Acción |', '|---|---|---|' } for _, modo in ipairs({ 'n', 'x', 'o', 'i', 't' }) do for _, m in ipairs(vim.api.nvim_get_keymap(modo)) do if m.desc and m.desc ~= '' then filas[#filas + 1] = ('| %s | %s | %s |'):format(modo, vim.fn.keytrans(m.lhs), m.desc) end end end vim.cmd('enew') vim.bo.filetype = 'markdown' vim.bo.buftype = 'nofile' vim.api.nvim_buf_set_lines(0, 0, -1, false, filas)end, { desc = 'Volcar todos los atajos documentados a un buffer' })Veinte líneas que producen una chuleta que nunca se desactualiza, porque no describe lo que creías haber configurado sino lo que hay cargado ahora mismo — en un buffer scratch como los del Nivel 10. Invierte el sentido habitual de la documentación: en lugar de escribir un archivo que envejece, interrogas al sistema.
Tu configuración es una API que le entregas a tu yo de dentro de dos años, y ese usuario no leerá el código
El error de perspectiva que arruina las configuraciones grandes es tratarlas como un artefacto personal y por tanto exento de las reglas que aplicarías a cualquier interfaz pública. Pero un vocabulario de atajos cumple todas las condiciones de una API: tiene usuarios — tú, en distintos momentos y con distintos grados de memoria —, tiene un coste de aprendizaje, tiene compatibilidad hacia atrás que romper, y tiene un espacio de nombres finito que se satura. De ahí se derivan consecuencias concretas y poco intuitivas. La primera es que la consistencia vale más que la optimalidad local: un atajo ligeramente peor pero que sigue el patrón del resto se recuerda, y uno perfecto pero excepcional se olvida, porque el coste dominante no es pulsar la tecla sino recuperarla de la memoria. La segunda es que existe un umbral de amortización: aprender un atajo cuesta del orden de decenas de repeticiones deliberadas — lo sabes por la práctica del Nivel 6 —, así que una acción que ejecutas dos veces al mes nunca amortiza una tecla, y su sitio natural es un comando de usuario con nombre descriptivo y completado, no una pulsación que tendrás que buscar cada vez. La tercera es que la escasez es real: el espacio de teclas cómodas es diminuto, Neovim reclama parte de él en cada versión y tu propio curso ya ha firmado cesiones — el contrato de arriba —, de modo que gastar una tecla buena en un capricho hoy te obliga a un realojo doloroso mañana. La cuarta, y la más incómoda, es que un vocabulario tiene que poder encogerse: revisar cada cierto tiempo qué mapeos no has usado y borrarlos es tan valioso como añadirlos, porque cada atajo muerto consume espacio de nombres, alarga los menús de which-key y ensucia la deducción. Diseña por tanto como diseñarías una biblioteca que otros van a usar: dominios coherentes, nombres deducibles, documentación generada del propio sistema y una poda periódica. La diferencia entre una configuración que se disfruta a los tres años y una que se abandona a los seis meses casi nunca está en los plugins elegidos, sino en si alguien trató sus teclas como un lenguaje o como un cajón.
La línea «Last set from» señala al culpable con archivo y línea. Hazlo parte del ritual tras instalar cualquier plugin, como aprendiste en la 3.2 con las teclas del completado.
Todo mapeo tuyo que no aparezca carece de desc. La chuleta no es solo consulta: es la auditoría de documentación más barata que existe.
nowait corta la espera del prefijo solo en ese buffer. Es la pieza que faltaba del trío local: buffer acota, la prioridad local gana, nowait responde ya.
Con dos segundos de espera, la ambigüedad se ve a simple vista. Súbelo, mide, arregla el árbol — ninguna rama puede ser hoja — y baja el valor de nuevo.
Lo esencial
Organiza tus mapeos en dominios de dos niveles con el sustantivo delante del verbo, y respeta los espacios nativos: [ y ] para anterior y siguiente, g para acciones extendidas, z para pliegues y ortografía. Respeta también el contrato del curso: <C-Space> y <Tab> del completado, s/S de flash, gs de surround, gr del LSP. Antes de reclamar una tecla, consúltala con :verbose nmap o con nvim_get_keymap. Ningún prefijo puede ser también un mapeo completo — salvo el operador doblado —, o pagarás timeoutlen en cada pulsación; ttimeoutlen es otra cosa y debe ser mínimo. Pon desc en todo, usa unique mientras diseñas, nowait en locales de buffer, y genera la chuleta desde la tabla real en lugar de escribirla a mano.
Audita tu idioma
- Ejecuta
:Chuleta, cuenta cuántos mapeos tuyos carecen dedescy déjalo a cero. - Busca en tu configuración algún prefijo que sea también un mapeo completo; mide el retardo subiendo
timeoutlena 2000, elimina la ambigüedad y comprueba que desapareció. - Verifica el contrato del curso en tu instalación:
:verbose nmap s,:verbose nmap gs,:verbose nmap grny:verbose imap <Tab>deben señalar a flash, surround, el LSP y el completado. Si alguno señala a otro sitio, decide el realojo tú — antes de que lo decida el orden de carga. - Reescribe los mapeos de un dominio entero para que sigan el patrón sustantivo-verbo y verifica en which-key que el grupo queda coherente.
- Localiza cinco atajos que no hayas usado en un mes: convierte en comandos de usuario los que merezcan sobrevivir y borra el resto. Tu vocabulario acaba de mejorar encogiendo.