<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Linux Sin Humo (Publicaciones sobre tutorials)</title><link>https://sergiobelkin.com/</link><description></description><atom:link href="https://sergiobelkin.com/categories/cat_tutorials.xml" rel="self" type="application/rss+xml"></atom:link><language>es</language><copyright>Contents © 2026 &lt;a href="mailto:sebelk@gmail.com"&gt;sebelk&lt;/a&gt; 
&lt;a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/"&gt;
&lt;img alt="Creative Commons License BY-NC-SA"
style="border-width:0; margin-bottom:12px;"
src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png"&gt;&lt;/a&gt;
</copyright><lastBuildDate>Mon, 01 Jun 2026 11:31:00 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>¿Cómo convertir tu configuración de init.vim a init.lua?</title><link>https://sergiobelkin.com/posts/como-convertir-tu-configuracion-de-initvim-a-initlua/</link><dc:creator>sebelk</dc:creator><description>&lt;h3 id="requisitos"&gt;Requisitos&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Curiosidad&lt;/strong&gt;. Es la condición más importante para leer este post. Si la tenés, con algo de esfuerzo sumado a algo de tiempo podrás aprender Vim, Neovim, etc.&lt;/li&gt;
&lt;li&gt;Conocimientos básicos o intermedios de Vim y haber leído el &lt;a href="https://sergiobelkin.com/posts/una-introduccion-pragmatica-al-uso-de-plugins-en-neovim/"&gt;post anterior&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Conocimientos básicos de &lt;a href="https://github.com/junegunn/vim-plug"&gt;vim-plug&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="repaso-de-conceptos-importantes"&gt;Repaso de conceptos importantes&lt;/h3&gt;
&lt;p&gt;En el &lt;a href="https://sergiobelkin.com/posts/una-introduccion-pragmatica-al-uso-de-plugins-en-neovim/"&gt;post anterior&lt;/a&gt; vimos cómo un usuario de Vim puede comenzar a usar Neovim. En el presente artículo haremos la transición de &lt;strong&gt;Vim script&lt;/strong&gt; a &lt;strong&gt;Lua&lt;/strong&gt;. Ok, booting the post 😄 ...&lt;/p&gt;
&lt;p&gt;&lt;img alt="De Vim script a Lua" class="img-izquierda-responsiva" src="https://sergiobelkin.com/images/bridge_with_Vim_script_Lua_web.webp"&gt;&lt;/p&gt;
&lt;p&gt;Recordemos que Vim usa &lt;strong&gt;Vim script&lt;/strong&gt; (aka VimL) como lenguaje de scripting nativo. Es un lenguaje específico que permite personalizar y extender su funcionalidad. Existe en dos formas: el Vim script tradicional (también llamado "legacy script") y Vim9script (introducido en Vim 9.0), que ofrece mejor rendimiento y una sintaxis más moderna. Sin embargo, &lt;em&gt;Vim9script ni siquiera se usa de manera predeterminada en Vim 9.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lua&lt;/strong&gt;, en cambio, es un lenguaje de programación ligero, de alto nivel y multiparadigma, diseñado principalmente para ser incorporado en aplicaciones. Se destaca por su simplicidad, eficiencia y portabilidad. &lt;strong&gt;Neovim&lt;/strong&gt; incorporó Lua como lenguaje de scripting de primera clase, lo que ha ganado popularidad debido a su mejor rendimiento y facilidad de uso comparado con Vim script tradicional.&lt;/p&gt;
&lt;p&gt;Neovim usa una implementación de Lua llamada &lt;strong&gt;LuaJIT&lt;/strong&gt;, que compila código Lua a código máquina nativo durante la ejecución. Es un detalle técnico relevante, pero no la razón principal para preferir Lua sobre Vim script en la configuración del editor — en ese terreno el cuello de botella suele estar en el startup time y en el diseño de los plugins, no en la velocidad del lenguaje.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Diferencia de idiosincrasia:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vim script:&lt;/strong&gt; scripting lineal, global y directo. Bueno para pequeños ajustes, pero difícil de escalar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lua (Neovim):&lt;/strong&gt; lenguaje estructurado, orientado a modularizar, reusar y escalar. Favorece el uso de variables locales, tablas y funciones que mejoran el mantenimiento de la configuración.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Por qué importa esto en la práctica:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;La &lt;strong&gt;API de Neovim en Lua&lt;/strong&gt; es estructurada y predecible (tablas, namespaces como &lt;code&gt;vim.api.*&lt;/code&gt;, &lt;code&gt;vim.opt&lt;/code&gt;), donde Vim script ofrecía variables globales y comandos planos.&lt;/li&gt;
&lt;li&gt;El &lt;strong&gt;ecosistema de plugins modernos asume Lua como lenguaje nativo&lt;/strong&gt; — los gestores actuales (&lt;code&gt;lazy.nvim&lt;/code&gt;, &lt;code&gt;packer.nvim&lt;/code&gt;), los runtime helpers, los plugins de LSP y UI conviven mejor con configs en Lua.&lt;/li&gt;
&lt;li&gt;La &lt;strong&gt;modularización con &lt;code&gt;require&lt;/code&gt;&lt;/strong&gt; permite dividir la configuración en archivos lógicos con scoping limpio, algo que Vim script soporta de forma rudimentaria.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;LuaJIT existe y es rápido, pero esa rapidez rara vez es lo que el sysadmin nota al usar Neovim — lo que nota es que su configuración escala mejor y se integra con el ecosistema sin fricciones.&lt;/p&gt;
&lt;h3 id="3-conceptos-esenciales-lo-minimo-que-siempre-debes-recordar"&gt;3 conceptos esenciales — lo mínimo que siempre debés recordar&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concepto&lt;/th&gt;
&lt;th&gt;Por qué es esencial&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tablas (&lt;code&gt;table&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Las tablas son la única estructura de datos compuesta en Lua&lt;/strong&gt;. Opciones (&lt;code&gt;vim.o&lt;/code&gt;, &lt;code&gt;vim.opt&lt;/code&gt;), autocmds, comandos, mappings y configuraciones de plugins.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Variables locales (&lt;code&gt;local&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Permiten organizar el código, evitar errores y mejorar el rendimiento. Imprescindible para no contaminar el entorno global.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API de Neovim (&lt;code&gt;vim.api.*&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Es la manera oficial y flexible de interactuar con Neovim: crear comandos, autocmds, mappings y manipular el editor desde Lua.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Si entendés estos 3 conceptos, podés crear y mantener cualquier configuración básica y muchas avanzadas.&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="que-es-una-tabla-y-que-no-en-la-configuracion-de-neovim-lua"&gt;¿Qué es una tabla y qué no en la configuración de Neovim (Lua)?&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Tablas 🆗:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;vim.g&lt;/li&gt;
&lt;li&gt;vim.opt / vim.o&lt;/li&gt;
&lt;li&gt;vim.api&lt;/li&gt;
&lt;li&gt;Configuraciones de plugins&lt;/li&gt;
&lt;li&gt;Listas/patrones&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;No son tablas ⚠:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Funciones&lt;/li&gt;
&lt;li&gt;Comandos ejecutados&lt;/li&gt;
&lt;li&gt;Strings, números, booleanos&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="el-podio-de-las-tablas-globales-mas-importantes-en-neovim"&gt;El podio de las tablas globales más importantes en Neovim&lt;/h3&gt;
&lt;p&gt;Estas son las tres tablas globales más importantes del entorno Lua en Neovim:&lt;/p&gt;
&lt;h4 id="vim"&gt;🏅 vim&lt;/h4&gt;
&lt;p&gt;Es la tabla principal y núcleo del entorno Lua en Neovim. Contiene todo lo necesario para interactuar con el editor:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Subtablas como &lt;code&gt;vim.api&lt;/code&gt;, &lt;code&gt;vim.cmd&lt;/code&gt;, &lt;code&gt;vim.opt&lt;/code&gt;, &lt;code&gt;vim.g&lt;/code&gt;, &lt;code&gt;vim.fn&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;Siempre disponible sin necesidad de importar.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="_g"&gt;🥈 _G&lt;/h4&gt;
&lt;p&gt;Es la tabla global del lenguaje Lua. Desde aquí podés definir funciones o variables globales accesibles desde cualquier parte de tu configuración:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;_G.mi_funcion = function() ... end&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;También contiene &lt;code&gt;vim&lt;/code&gt; como una de sus claves.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="package-de-lua"&gt;🥉 package (de Lua)&lt;/h4&gt;
&lt;p&gt;Maneja los módulos cargados por &lt;code&gt;require&lt;/code&gt;. Es crucial para modularizar tu configuración:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;package.loaded&lt;/code&gt; permite ver y recargar módulos.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Nota&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Tablas como &lt;code&gt;vim.api&lt;/code&gt;, &lt;code&gt;vim.opt&lt;/code&gt;, &lt;code&gt;vim.g&lt;/code&gt; son importantes, pero &lt;strong&gt;no son globales de nivel superior&lt;/strong&gt;: viven dentro de &lt;code&gt;vim&lt;/code&gt;. Lo mismo aplica para &lt;code&gt;math&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;table&lt;/code&gt;, etc., que viven en &lt;code&gt;_G&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;→ Estas 3 (&lt;code&gt;vim&lt;/code&gt;, &lt;code&gt;_G&lt;/code&gt;, &lt;code&gt;package&lt;/code&gt;) forman la base del entorno ejecutable de cualquier configuración Neovim moderna en Lua.&lt;/p&gt;
&lt;h3 id="subtablas-mas-importantes"&gt;Subtablas más importantes&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tabla&lt;/th&gt;
&lt;th&gt;Contiene&lt;/th&gt;
&lt;th&gt;Ejemplo equivalente en Vim script&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vim.o&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Opciones globales&lt;/td&gt;
&lt;td&gt;&lt;code&gt;set tabstop=4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vim.opt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Acceso a opciones con métodos (&lt;code&gt;:append&lt;/code&gt;, &lt;code&gt;:remove&lt;/code&gt;, &lt;code&gt;:prepend&lt;/code&gt;); requerido para listas&lt;/td&gt;
&lt;td&gt;&lt;code&gt;set nrformats+=alpha&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vim.cmd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Comandos que se ejecutan en modo ex&lt;/td&gt;
&lt;td&gt;&lt;code&gt;colorscheme PaperColor&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vim.g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Variables globales&lt;/td&gt;
&lt;td&gt;&lt;code&gt;let g:loaded_perl_provider = 0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vim.keymap.set&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Asignación de atajos de teclado a una función o combinación de teclas&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nnoremap ñ :wq&amp;lt;CR&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vim.api.nvim_create_user_command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creación de comandos personalizados&lt;/td&gt;
&lt;td&gt;&lt;code&gt;command Nbuild execute 'w | Silent nikola build'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="diccionario-cruzado-vim-script-lua"&gt;Diccionario cruzado Vim script / Lua&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concepto&lt;/th&gt;
&lt;th&gt;Vim script&lt;/th&gt;
&lt;th&gt;Lua&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Variable global&lt;/td&gt;
&lt;td&gt;&lt;code&gt;let g:mi_var = 10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vim.g.mi_var = 10&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Variable local&lt;/td&gt;
&lt;td&gt;&lt;code&gt;let l:var = 10&lt;/code&gt; (function-local), &lt;code&gt;s:&lt;/code&gt;, &lt;code&gt;b:&lt;/code&gt;, &lt;code&gt;w:&lt;/code&gt; por contexto&lt;/td&gt;
&lt;td&gt;&lt;code&gt;local var = 10&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lista&lt;/td&gt;
&lt;td&gt;&lt;code&gt;let lista = [1,2,3]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lista = {1, 2, 3}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Diccionario&lt;/td&gt;
&lt;td&gt;&lt;code&gt;let dict = {'a':1}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dict = {a = 1}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Función&lt;/td&gt;
&lt;td&gt;&lt;code&gt;function! Hola() ... endfunction&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;function hola() ... end&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Función anónima&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{a, b -&amp;gt; a + b}&lt;/code&gt; (lambda, desde Vim 8.0)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;function() ... end&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Autocomando&lt;/td&gt;
&lt;td&gt;&lt;code&gt;autocmd BufWrite ...&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vim.api.nvim_create_autocmd&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mapping&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nnoremap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vim.keymap.set&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comando&lt;/td&gt;
&lt;td&gt;&lt;code&gt;command ...&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vim.api.nvim_create_user_command&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="ejemplo-de-migracion-vim-script-lua"&gt;Ejemplo de migración Vim script → Lua&lt;/h3&gt;
&lt;p&gt;Bueno, con la teoría suficiente, ✋✋ a la obra 😉. Supongamos que tenemos esta configuración del archivo &lt;code&gt;init.vim&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;tabstop&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;
&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;nrformats&lt;/span&gt;&lt;span class="p"&gt;+=&lt;/span&gt;alpha

&lt;span class="nb"&gt;nnoremap&lt;/span&gt; ñ :&lt;span class="k"&gt;wq&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

command &lt;span class="p"&gt;-&lt;/span&gt;nargs&lt;span class="p"&gt;=+&lt;/span&gt; Silent execute &lt;span class="s1"&gt;'silent !&amp;lt;args&amp;gt;'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;redraw&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
command Nbuild execute &lt;span class="s1"&gt;'w | Silent nikola build'&lt;/span&gt;

&lt;span class="k"&gt;filetype&lt;/span&gt; plugin &lt;span class="k"&gt;on&lt;/span&gt;
runtime plugins.&lt;span class="k"&gt;vim&lt;/span&gt;
&lt;span class="k"&gt;colorscheme&lt;/span&gt; PaperColor
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Es un archivo pequeño, pero que sirve de punto de partida para moverse a una configuración en Lua.&lt;/p&gt;
&lt;h4 id="crear-el-entorno-para-neovim"&gt;Crear el entorno para Neovim&lt;/h4&gt;
&lt;p&gt;&lt;img alt="El sistema modular de Neovim" class="img-izquierda-responsiva" src="https://sergiobelkin.com/images/ElsistemamodulardeNeovim.webp"&gt;&lt;/p&gt;
&lt;p&gt;Como vimos en el post anterior, mi recomendación es comenzar con un archivo &lt;code&gt;init.vim&lt;/code&gt;. Una vez que ya estamos usando Neovim podemos realizar la migración a &lt;code&gt;init.lua&lt;/code&gt;. Sin embargo, tenemos que crear los directorios para que Neovim guarde su configuración. Lo único que dejaremos por ahora en Vim script es la configuración de plugins con &lt;strong&gt;vim-plug&lt;/strong&gt;. Por lo tanto ejecutamos:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.config/nvim/lua/utils
mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.local/share/nvim/site/autoload
&lt;span class="c1"&gt;# Suponiendo que usabas un archivo para gestionar plugins en Vim&lt;/span&gt;
mv&lt;span class="w"&gt; &lt;/span&gt;~/.vim/autoload/plug.vim&lt;span class="w"&gt; &lt;/span&gt;~/.local/share/nvim/site/autoload
&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;El directorio &lt;code&gt;~/.config/nvim&lt;/code&gt; es obligatorio.&lt;/li&gt;
&lt;li&gt;El directorio &lt;code&gt;~/.config/nvim/lua&lt;/code&gt; &lt;em&gt;no&lt;/em&gt; es obligatorio, pero es muy útil para modularizar la configuración de Neovim.&lt;/li&gt;
&lt;li&gt;Los nombres dados de los archivos y directorios dentro de &lt;code&gt;~/.config/nvim/lua&lt;/code&gt; son totalmente arbitrarios.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En Neovim tendremos una estructura más modular. Si bien podemos tener todo en &lt;code&gt;init.lua&lt;/code&gt;, vamos a aprovecharnos de esta configuración que es mucho más flexible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Archivo ~/.config/nvim/init.lua&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;-- Cargamos los plugins primero — algunas configuraciones&lt;/span&gt;
&lt;span class="c1"&gt;-- (como `colorscheme`) dependen de tenerlos disponibles en el runtimepath&lt;/span&gt;
&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'source ~/.config/nvim/plugins.vim'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- Cargamos nuestros módulos (el require ejecuta el archivo;&lt;/span&gt;
&lt;span class="c1"&gt;-- el efecto viene del side-effect, no del valor capturado)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'utils.commands'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'utils.extracommands'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'keymaps'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'opciones'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Archivo ~/.config/nvim/lua/keymaps.lua&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;-- Alias&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;set&lt;/span&gt;
&lt;span class="c1"&gt;-- maps&lt;/span&gt;
&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'ñ'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;':wq&amp;lt;CR&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota sobre &lt;code&gt;vim.keymap.set&lt;/code&gt;&lt;/strong&gt;: usa &lt;code&gt;remap = false&lt;/code&gt; por default, así que &lt;code&gt;map('n', 'ñ', ':wq&amp;lt;CR&amp;gt;')&lt;/code&gt; ya es equivalente a &lt;code&gt;nnoremap&lt;/code&gt; (no a &lt;code&gt;nmap&lt;/code&gt;). El "nore" que en VimL diferenciaba &lt;code&gt;nnoremap&lt;/code&gt; de &lt;code&gt;nmap&lt;/code&gt; está implícito en el default de la API Lua.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Archivo ~/.config/nvim/lua/opciones.lua&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;-- Alias&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;o&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;opt&lt;/span&gt;

&lt;span class="c1"&gt;-- Opciones&lt;/span&gt;
&lt;span class="nv"&gt;vo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;tabstop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="nv"&gt;vop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;nrformats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'alpha'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Archivo ~/.config/nvim/lua/utils/commands.lua&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;-- Comando auxiliar para correr cosas en shell silenciado&lt;/span&gt;
&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nvim_create_user_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Silent'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'silent !'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;table.concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fargs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'redraw!'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nargs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'+'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;-- Build del sitio Nikola&lt;/span&gt;
&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nvim_create_user_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Nbuild'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Silent nikola build'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Archivo ~/.config/nvim/lua/utils/extracommands.lua&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;-- Alias&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vcmd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;cmd&lt;/span&gt;

&lt;span class="c1"&gt;-- Extra commands&lt;/span&gt;
&lt;span class="nf"&gt;vcmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'filetype plugin on'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Esta configuración es innecesaria porque ya está en init.lua&lt;/span&gt;
&lt;span class="c1"&gt;-- vcmd('runtime plugins.vim')&lt;/span&gt;
&lt;span class="nf"&gt;vcmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'colorscheme PaperColor'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Archivo ~/.config/nvim/plugins.vim&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Este es el único archivo que dejamos en Vim script (con código Lua embebido):&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c"&gt;"Plugins (Plug)&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt; plug#begin&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'~/.vim/plugged'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

Plug &lt;span class="s1"&gt;'itchyny/lightline.vim'&lt;/span&gt;
Plug &lt;span class="s1"&gt;'nyngwang/NeoTerm.lua'&lt;/span&gt;
Plug &lt;span class="s1"&gt;'NLKNguyen/papercolor-theme'&lt;/span&gt;

&lt;span class="k"&gt;call&lt;/span&gt; plug#&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;lua&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;lt;&lt;/span&gt; EOF                                                       
require&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"neo-term"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;.setup {
  exclude_filetypes &lt;span class="p"&gt;=&lt;/span&gt; { &lt;span class="s2"&gt;"oil"&lt;/span&gt; }
}                          
EOF

&lt;span class="nb"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;F4&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; :NeoTermToggle&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
tnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;F4&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;\&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;n&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;:NeoTermToggle&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
tnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Esc&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;\&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;n&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;:NeoTermEnterNormal&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Y listo...&lt;/p&gt;
&lt;h4 id="explicacion"&gt;Explicación&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;¿Por qué definimos alias en los archivos de módulos?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Los alias son básicamente variables. Los definimos porque este es un ejemplo de tipo "esqueleto" de configuración. Cuando comiences a agregar más opciones, atajos de teclado y comandos personalizados, no querrás tipear tanto 😉.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nota sobre redefinición de comandos&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vim.api.nvim_create_user_command&lt;/code&gt; &lt;strong&gt;sobrescribe por default&lt;/strong&gt; un comando con el mismo nombre (la opción &lt;code&gt;force&lt;/code&gt; tiene valor &lt;code&gt;true&lt;/code&gt; por defecto, según la doc oficial de la API). Es decir: podés llamar dos veces a &lt;code&gt;nvim_create_user_command('Nbuild', ...)&lt;/code&gt; y la segunda definición reemplaza a la primera sin error. No hace falta borrar antes con &lt;code&gt;nvim_del_user_command&lt;/code&gt;. Esto es distinto del &lt;code&gt;:command&lt;/code&gt; de VimL, que sí requiere &lt;code&gt;command!&lt;/code&gt; para sobrescribir — la API Lua no hereda esa restricción.&lt;/p&gt;
&lt;p&gt;El ejemplo de &lt;code&gt;Nbuild&lt;/code&gt; deja ver diferencias más grandes entre VimL y Lua. Las analizamos en cinco dimensiones:&lt;/p&gt;
&lt;h5 id="1-brevedad-vs-mantenibilidad"&gt;1. &lt;strong&gt;Brevedad vs mantenibilidad&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;VimL:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;vim
  command -nargs=+ Silent execute 'silent !&amp;lt;args&amp;gt;' | redraw!
  command Nbuild execute 'w | Silent nikola build'&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Es breve, directo y funciona. Pero:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Es poco &lt;strong&gt;expresivo&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;No permite &lt;strong&gt;manejar errores&lt;/strong&gt; fácilmente&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No escala bien con lógica compleja&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lua:&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;lua
  vim.api.nvim_create_user_command('Silent', function(opts)
    vim.cmd('silent !' .. table.concat(opts.fargs, ' '))
    vim.cmd('redraw!')
  end, { nargs = '+' })&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Es más verboso, sí, pero:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;La función puede ser más compleja si se necesita&lt;/li&gt;
&lt;li&gt;Es &lt;strong&gt;programable&lt;/strong&gt; y &lt;strong&gt;reutilizable&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Puede integrarse con condicionales, bucles, o lógica externa&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="2-control-de-errores-y-depuracion"&gt;2. &lt;strong&gt;Control de errores y depuración&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;En VimL: si un comando falla, tenés poco margen para capturar y manejar el error.&lt;/li&gt;
&lt;li&gt;En Lua: podés usar &lt;code&gt;pcall&lt;/code&gt;, &lt;code&gt;vim.notify&lt;/code&gt;, &lt;code&gt;vim.fn.systemlist&lt;/code&gt;, y &lt;strong&gt;construir mensajes personalizados o fallback&lt;/strong&gt; si algo sale mal.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;pcall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'silent !nikola build'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Error al ejecutar nikola build'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;levels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h5 id="3-modularizacion"&gt;3. &lt;strong&gt;Modularización&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;En Lua podés agrupar comandos en módulos, con &lt;code&gt;require(...)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;En VimL tenés que recurrir a &lt;code&gt;runtime&lt;/code&gt;, &lt;code&gt;source&lt;/code&gt;, y no hay namespaces claros.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'utils.commands'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;-- registra los user commands al cargarse&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'utils.extracommands'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;-- aplica colorscheme y filetype detection&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'keymaps'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;-- registra los atajos de teclado&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'opciones'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;-- opciones generales de configuración&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Esto &lt;strong&gt;facilita dividir la configuración en archivos lógicos&lt;/strong&gt;, más fácil de leer, mantener y compartir.&lt;/p&gt;
&lt;h5 id="4-compatibilidad-futura-y-ecosistema-neovim"&gt;4. &lt;strong&gt;Compatibilidad futura y ecosistema Neovim&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Neovim ha declarado que Lua es su &lt;strong&gt;lenguaje de configuración nativo moderno&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;La mayoría de los &lt;strong&gt;plugins modernos están escritos en Lua&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;VimL sigue siendo soportado, pero está &lt;strong&gt;siendo superado funcionalmente&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="5-legibilidad-a-largo-plazo"&gt;5. &lt;strong&gt;Legibilidad a largo plazo&lt;/strong&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Aunque VimL sea más corto, en un entorno de colaboración o con configuraciones grandes, Lua:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Es más &lt;strong&gt;explícito&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Permite &lt;strong&gt;documentar&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;La API de Neovim en Lua permite &lt;strong&gt;un uso más explícito y predecible de tipos de datos&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Es más &lt;strong&gt;fácil de extender&lt;/strong&gt; con lógica externa.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="conclusion"&gt;Conclusión&lt;/h3&gt;
&lt;p&gt;Si sabés migrar opciones, mappings, comandos y cargar plugins → podés convertir el 80% o más de tu &lt;code&gt;init.vim&lt;/code&gt; (equivalente al viejo &lt;code&gt;.vimrc&lt;/code&gt;) a &lt;code&gt;init.lua&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Migrar de Vim script a Lua no es una mejora cosmética: cambia las posibilidades de la configuración. Lo que en Vim script son comandos breves, en Lua son funciones programables — más verbosas, sí, pero abiertas a control de errores con &lt;code&gt;pcall&lt;/code&gt;, modularización con &lt;code&gt;require&lt;/code&gt; y un ecosistema de plugins que ya asume Lua como lenguaje nativo.&lt;/p&gt;
&lt;p&gt;La estructura mostrada acá es una entre muchas. El esqueleto &lt;code&gt;init.lua&lt;/code&gt; + módulos en &lt;code&gt;lua/&lt;/code&gt; se sostiene porque escala: cada archivo crece sin contaminar al resto, y la configuración deja de ser una pared de líneas para volverse un conjunto de piezas que podés rearmar cuando lo necesites.&lt;/p&gt;
&lt;p&gt;Lo que no migramos en este post es la configuración de plugins, que dejamos en &lt;code&gt;plugins.vim&lt;/code&gt;. Reemplazar &lt;strong&gt;vim-plug&lt;/strong&gt; por un gestor en Lua como &lt;strong&gt;lazy.nvim&lt;/strong&gt; es el siguiente paso natural — y tema de &lt;a href="https://sergiobelkin.com/posts/como-migrar-de-vim-plug-a-lazynvim/"&gt;este otro post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Al cierre del post dejé un resumen de 10 conceptos clave para tener a mano cuando empieces a extender tu config.&lt;/p&gt;
&lt;h3 id="apendice-los-10-conceptos-fundamentales-de-lua-resumen"&gt;Apéndice: Los 10 conceptos fundamentales de Lua (resumen)&lt;/h3&gt;
&lt;p&gt;Resumen de los 10 conceptos clave de Lua en Neovim. Los 3 marcados como &lt;em&gt;(esencial)&lt;/em&gt; son los que vimos al principio; el resto extiende esa base:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concepto&lt;/th&gt;
&lt;th&gt;Descripción breve&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tablas (&lt;code&gt;table&lt;/code&gt;)&lt;/strong&gt; &lt;em&gt;(esencial)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Estructuras clave-valor o listas. Base de toda la configuración.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Variables locales (&lt;code&gt;local&lt;/code&gt;)&lt;/strong&gt; &lt;em&gt;(esencial)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Para mantener el código limpio y evitar contaminación global.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Funciones anónimas&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Permiten definir acciones sin nombre, usadas en mappings, autocmds y comandos.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API de Neovim (&lt;code&gt;vim.api.*&lt;/code&gt;)&lt;/strong&gt; &lt;em&gt;(esencial)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Puente entre Lua y Neovim: crear comandos, mappings, autocmds.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vim.opt&lt;/code&gt; vs &lt;code&gt;vim.o&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vim.o&lt;/code&gt; da acceso directo al valor; &lt;code&gt;vim.opt&lt;/code&gt; lo envuelve en un objeto type-aware con métodos (necesario para listas).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;require&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Para cargar módulos externos y dividir la configuración.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Paréntesis en llamadas&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Obligatorio usar &lt;code&gt;()&lt;/code&gt; al llamar funciones.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Asignar una tabla a otra variable sin copiarla (ejemplo: &lt;code&gt;local vg = vim.g&lt;/code&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_G (global)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tabla especial que contiene las variables y funciones globales accesibles en toda la configuración.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;package.loaded&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Permite ver o manipular qué módulos están cargados, útil para recargar configuraciones dinámicamente.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="fuentes-y-mas-recursos"&gt;Fuentes y más Recursos&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://neovim.io/doc/user/lua.html"&gt;Lua en Neovim (&lt;code&gt;:help lua&lt;/code&gt;)&lt;/a&gt; — referencia completa de la API Lua de Neovim.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://neovim.io/doc/user/lua-guide.html"&gt;Guía de Lua para Neovim (&lt;code&gt;:help lua-guide&lt;/code&gt;)&lt;/a&gt; — survival kit oficial para configurar Neovim en Lua.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.lua.org/manual/5.1/"&gt;Manual de referencia de Lua 5.1&lt;/a&gt; — definición oficial del lenguaje (LuaJIT, que usa Neovim, está basado en esta versión).&lt;/li&gt;
&lt;li&gt;&lt;a href="https://neovim.io/doc/lua-resources/"&gt;Recursos de Lua recomendados por Neovim&lt;/a&gt; — curaduría oficial de tutoriales y libros.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tolomeo/a-pragmatic-approach-to-migrating-from-vscode-to-neovim-4fae"&gt;A pragmatic approach to migrating from VSCode to Neovim&lt;/a&gt; — otra mirada sobre migración hacia Neovim+Lua, desde VSCode.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kushcreates.com/blogs/neovim-is-better-but-why-developers-arent-switching-to-it"&gt;NeoVim Is Better, But Why Developers Aren't Switching To It?&lt;/a&gt; — perspectiva crítica sobre la adopción de Neovim.&lt;/li&gt;
&lt;/ul&gt;</description><category>Lua</category><category>Neovim</category><category>vim</category><guid>https://sergiobelkin.com/posts/como-convertir-tu-configuracion-de-initvim-a-initlua/</guid><pubDate>Thu, 15 May 2025 19:01:18 GMT</pubDate></item><item><title>Una introducción pragmática al uso de plugins en Neovim</title><link>https://sergiobelkin.com/posts/una-introduccion-pragmatica-al-uso-de-plugins-en-neovim/</link><dc:creator>sebelk</dc:creator><description>&lt;p&gt;Ya me he referido a Neovim alguna vez en el pasado: &lt;a href="https://sergiobelkin.com/posts/2017/11/20/lo-viejo-lo-bueno-y-lo-nuevo-en-neovim/"&gt;Lo viejo, lo bueno y lo nuevo en Neovim &lt;/a&gt;. 
Se pueden extender las funcionalidades de neovim, mediante plugins, de manera similar a las de su predecesor, el editor Vim. 
&lt;strong&gt;En este artículo propongo un modo muy sencillo y lo más transparente posible para el uso de plugins en Neovim.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hay dos tipos de plugins:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Globales&lt;/strong&gt;: Funcionan para todo tipo de archivos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filetype&lt;/strong&gt;: Sirven para un tipo particular de archivos**.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;El siguiente listado muestra plugins globales que forman parte del core de neovim:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;ls -l /usr/share/nvim/runtime/plugin&lt;/span&gt;
&lt;span class="n"&gt;total 60&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root  411 mar 26 10:48 editorconfig.lua&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root 3677 mar 26 10:48 gzip.vim&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root  904 mar 26 10:48 man.lua&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root  138 mar 26 10:48 matchit.vim&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root 7966 mar 26 10:48 matchparen.vim&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root  152 mar 26 10:48 netrwPlugin.vim&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root 2160 mar 26 10:48 osc52.lua&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root 2017 mar 26 10:48 rplugin.vim&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root 1778 mar 26 10:48 shada.vim&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root  236 mar 26 10:48 spellfile.vim&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root 2527 mar 26 10:48 tarPlugin.vim&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root  442 mar 26 10:48 tohtml.lua&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root  202 mar 26 10:48 tutor.vim&lt;/span&gt;
&lt;span class="n"&gt;-rw-r--r-- 1 root root 2642 mar 26 10:48 zipPlugin.vim&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plugin&lt;/th&gt;
&lt;th&gt;Funcionalidad&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;editorconfig&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Busca y lee archivos .editorconfig para aplicar reglas de indentación, fines de línea  y codificación&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gzip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Editar archivos comprimidos con gzip&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;man&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Abrir páginas del manual en el editor&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;matchit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Extiende la funcionalidad del comando&lt;/em&gt; &lt;code&gt;%&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;matchparen&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Resalta paréntesis coincidentes&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;netrwPlugin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Maneja la transferencia de archivos y listado de directorios remotos a través de una red&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;osc52&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Detecta si es posible usar el código de escape ANSI para copir desde vim a otras terminales para poder copiar texto desde neovim usand el clipboard del sistema&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rplugin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Gestiona, migra, actualiza y carga remote plugins automáticamente (están escritos en otros lenguajes como Python, Ruby, Node.js, etc y que se manejan de manera independiente del editor sin afectar el rendimiento)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shada&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Datos Compartidos entre las sesiones de neovim&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spellfile&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Descarga de archivos de ortografía&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tarPlugin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Exploración de tarballs&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tohtml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Conversor a html&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tutor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Tutorial&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zipPlugin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Exploración de archivos zip&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Los scripts en vimL pueden contener comandos de edición, estructuras de control, funciones, manejo de listas, diccionarios, y puede simular objetos mediante diccionarios con referencias a funciones. El otro lenguaje nativo que incorpora neovim es &lt;strong&gt;Lua&lt;/strong&gt;. Los desarrolladores de neovim consideran que ese lenguaje es más eficiente, tiene una sintaxis más moderna y estándar, maneja mejor los errores, permite que sea extendido fácilmente con plugins y módulos complejos, sin necesidad de depender de procesos externos o hacks.&lt;/p&gt;
&lt;p&gt;Si consideramos el archivo del plugin &lt;strong&gt;man&lt;/strong&gt; contiene lo siguiente:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;loaded_man&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;return&lt;/span&gt;
&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;loaded_man&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nvim_create_user_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Man'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;man&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;bang&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;man&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init_pager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;man&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;smods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man.lua: '&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;levels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;span class="kr"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;bang&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;addr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'other'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;nargs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;complete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;man_complete&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;augroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nvim_create_augroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'nvim.man'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;

&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nvim_create_autocmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'BufReadCmd'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;group&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;augroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'man://*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;nested&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;callback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;match&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man://(.*)'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man.lua: '&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;levels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="mini-resumen-conceptual-manlua"&gt;📝 Mini resumen conceptual — man.lua&lt;/h3&gt;
&lt;h4 id="que-hace-el-plugin"&gt;✔ ¿Qué hace el plugin?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Define &lt;strong&gt;cómo abrir manpages&lt;/strong&gt; usando comandos (&lt;code&gt;:Man&lt;/code&gt;) y URIs (&lt;code&gt;man://...&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Define &lt;strong&gt;cómo manejar errores&lt;/strong&gt; (usa &lt;code&gt;vim.notify&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="como-funciona"&gt;✔ ¿Cómo funciona?&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Previene carga múltiple&lt;/strong&gt; con &lt;code&gt;vim.g.loaded_man&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Crea un comando&lt;/strong&gt; &lt;code&gt;:Man&lt;/code&gt; con opciones (bang, autocompletado, etc.).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Crea un autocmd&lt;/strong&gt; que detecta buffers con URI &lt;code&gt;man://&lt;/code&gt; y carga la manpage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Usa funciones&lt;/strong&gt; (&lt;code&gt;open_page&lt;/code&gt;, &lt;code&gt;init_pager&lt;/code&gt;, &lt;code&gt;read_page&lt;/code&gt;, &lt;code&gt;man_complete&lt;/code&gt;) definidas en el módulo &lt;code&gt;man&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Muestra errores&lt;/strong&gt; con &lt;code&gt;vim.notify&lt;/code&gt; si algo falla.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="que-flujo-sigue"&gt;✔ ¿Qué flujo sigue?&lt;/h4&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;Usuario → :Man o :edit man:// → función del módulo man → buffer con la manpage
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="el-plugin-es-100-todo-lua"&gt;✅ El plugin es 100% todo Lua&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Usa &lt;strong&gt;API moderna&lt;/strong&gt; de Neovim:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vim.api.nvim_create_user_command&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vim.api.nvim_create_autocmd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vim.notify&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Usa &lt;strong&gt;variables globales Lua&lt;/strong&gt;: &lt;code&gt;vim.g.loaded_man&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Usa funciones Lua: &lt;code&gt;string.match&lt;/code&gt;, &lt;code&gt;require&lt;/code&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Es un plugin moderno, pensado para ser usado con Neovim o Vim con soporte de Lua.&lt;/p&gt;
&lt;h3 id="api-para-plugins-y-herramientas"&gt;API para plugins y herramientas&lt;/h3&gt;
&lt;p&gt;Además, neovim posee una API con la cual se pueden hacer desarrollos en otros lenguajes de programación y por eso existen plugins y/o herramientas relacionadas que no están escritos en vimL o LUA:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/nvim-java/nvim-java"&gt;Painless Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://neovim.io/node-client/"&gt;neovimi (node.js)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/neoclide/coc.nvim"&gt;Nodejs extension host for vim &amp;amp; neovim, load extensions like VSCode and host language servers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/neovim/pynvim"&gt;Cliente de python para escribir plugins&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;El plugin &lt;strong&gt;&lt;a href="https://github.com/brooth/far.vim"&gt;far.vim&lt;/a&gt;&lt;/strong&gt; está desarrollado en python:&lt;/p&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/far-plugin.png"&gt;&lt;img src="https://sergiobelkin.com/images/far-plugin.thumbnail.png" alt=""&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Se debe ejecutar &lt;code&gt;:UpdateRemotePlugins&lt;/code&gt; cada vez que un plugin remoto se instale, se actualice, o se borre. Esto generará o actualizará un archivo manifest, por ejemplo:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;nvim&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;rplugin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="s"&gt;" node plugins&lt;/span&gt;


&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;python3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;plugins&lt;/span&gt;
&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remote&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;RegisterPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;python3&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;nvim&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;plugged&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;far&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vim&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;rplugin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;python3&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;far&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;_far_nvim_rpc_async_invoke&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;function&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}},&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;


&lt;span class="s"&gt;" ruby plugins&lt;/span&gt;


&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;plugins&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="equivalencias-entre-vim-y-neovim"&gt;Equivalencias entre Vim y Neovim&lt;/h3&gt;
&lt;p&gt;Abro un paréntesis para recordar las equivalencias entre archivos de Vim y Neovim:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Elemento&lt;/th&gt;
&lt;th&gt;Vim&lt;/th&gt;
&lt;th&gt;Neovim&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Config principal&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.vimrc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.config/nvim/init.vim&lt;/code&gt; o &lt;code&gt;init.lua&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Carpeta de configuración&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.vim/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.config/nvim/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plugins (autoload)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.vim/autoload/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.local/share/nvim/site/autoload/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plugins (paquetes)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.vim/pack/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.local/share/nvim/site/pack/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Datos de usuario (swap, undo, backup, etc.)&lt;/td&gt;
&lt;td&gt;Dentro de &lt;code&gt;~/.vim/&lt;/code&gt; o definido por el usuario&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.local/state/nvim/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Swap files&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.vim/swapfiles/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.local/state/nvim/swap/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Undo files&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.vim/undodir/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.local/state/nvim/undo/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backup files&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.vim/backup/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.local/state/nvim/backup/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;viminfo&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.viminfo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;No se usa directamente&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;shada&lt;/td&gt;
&lt;td&gt;&lt;em&gt;No aplica (usa viminfo)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.local/share/nvim/shada/main.shada&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Colorschemes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.vim/colors/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.config/nvim/colors/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;After directory (sobreescribir plugins/config)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.vim/after/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.config/nvim/after/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Nota sobre &lt;em&gt;shada&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vim usa &lt;code&gt;viminfo&lt;/code&gt; → &lt;code&gt;~/.viminfo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Neovim usa &lt;code&gt;shada&lt;/code&gt; → &lt;code&gt;~/.local/share/nvim/shada/main.shada&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No es recomendable hacer enlace simbólico entre estos dos archivos porque no son 100% compatibles.&lt;/p&gt;
&lt;h3 id="soporte-nativo-para-plugins-en-vim-8-y-en-adelante"&gt;Soporte nativo para plugins en Vim 8 (y en adelante)&lt;/h3&gt;
&lt;!--&lt;a class="image-reference" href="/images/"handy-wicaksono-brizG9kR6qI-unsplash.jpg&gt;&lt;img src="/images/handy-wicaksono-brizG9kR6qI-unsplash.thumbnail.jpg" alt="Paquetes"&gt;&lt;/a&gt;--&gt;

&lt;p&gt;&lt;img alt="Paquetes en Vim" class="img-izquierda-responsiva" src="https://sergiobelkin.com/images/handy-wicaksono-brizG9kR6qI-unsplash.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@handywicaksono?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Handy Wicaksono&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/package?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Desde Vim 8.0 el editor cuenta con soporte nativo para paquetes. En Vim un paquete no es otra cosa que un directorio de plugins. Es decir, considerando el siguiente escenario.&lt;/p&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/native-packages.png"&gt;&lt;img src="https://sergiobelkin.com/images/native-packages.thumbnail.png" alt="Estructura de directorios de sistema nativo de plugins"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;El paquete &lt;em&gt;lightline.vim&lt;/em&gt; se va a cargar automáticamente al abrir el editor, mientras que el otro plugin &lt;em&gt;toggleterm&lt;/em&gt; podrá activarse con el comando &lt;code&gt;:packadd toggleterm.nvim&lt;/code&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h4 id="guia-rapida-para-el-metodo-nativo-de-vim-8"&gt;Guía rápida para el método nativo de Vim 8+&lt;/h4&gt;
&lt;p&gt;Mostraré como usar 2 plugins.&lt;/p&gt;
&lt;h5 id="1-crear-las-carpetas-necesarias"&gt;1. Crear las carpetas necesarias&lt;/h5&gt;
&lt;p&gt;Abrí tu terminal y ejecutá:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;~/.vim/pack/misplugins/&lt;span class="o"&gt;{&lt;/span&gt;start,opt&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Explicación rápida:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/.vim/pack/&lt;/code&gt; → carpeta donde Vim busca paquetes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;misplugins&lt;/code&gt; → nombre del grupo que quieras (puede ser cualquier nombre).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;start/&lt;/code&gt; → indica que los plugins se &lt;strong&gt;cargan automáticamente&lt;/strong&gt; al abrir Vim.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opt/&lt;/code&gt;   → indica que los plugins se cargarán bajo demanda con el comando &lt;code&gt;packadd&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h5 id="2-descargar-los-plugins"&gt;2. Descargar los plugins&lt;/h5&gt;
&lt;p&gt;Ahora dentro de &lt;code&gt;start/&lt;/code&gt;, cloná los repositorios de Git de los plugins:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;~/.vim/pack/misplugins/opt

&lt;span class="c1"&gt;# vim-fugitive (permite ejecutar y gestionar comandos de Git directamente dentro de Vim, como hacer commits, ver logs, ver diferencias (diffs) y manejar ramas sin salir del editor.)&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;https://tpope.io/vim/fugitive.git
vim&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;NONE&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"helptags fugitive/doc"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;q

&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;~/.vim/pack/misplugins/start

&lt;span class="c1"&gt;# lightline.vim (barra de estado mejorada)&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;https://github.com/itchyny/lightline.vim.git
&lt;span class="c1"&gt;# Usar el comando siguiente si lightline.vim se muestre sin colores y guardarlo en algún archivo de configuración del shell.&lt;/span&gt;
&lt;span class="c1"&gt;# export TERM=xterm-256color &lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Con esto ya los tenés instalados.&lt;/p&gt;
&lt;hr&gt;
&lt;h5 id="3-configuracion-para-lightlinevim"&gt;3. Configuración para lightline.vim|&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;Podés agregar algunas líneas en tu &lt;code&gt;~/.vimrc&lt;/code&gt; para aprovechar lightline.vim:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c"&gt;" Opcional: configuración mínima para lightline&lt;/span&gt;
&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;laststatus&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h5 id="4-listo"&gt;4. Listo&lt;/h5&gt;
&lt;p&gt;¡Abrí Vim y ya podés usar el plugin lightline.vim! &lt;/p&gt;
&lt;p&gt;Si querés cargar el plugin fugitive, lo hacés con:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="p"&gt;:&lt;/span&gt;packadd fugitive
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Importante: Los plugins escritos en lua no funcionarán en Vim&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Algo interesante en Vim y Neovim es que podemos ver los plugins que ya vienen con el editor con el comando &lt;code&gt;:help standard-plugin-list&lt;/code&gt; y con &lt;code&gt;:help local-additions&lt;/code&gt; los plugins que vamos agregando:&lt;/p&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/plugin-lists.gif"&gt;&lt;img src="https://sergiobelkin.com/images/plugin-lists.thumbnail.gif" alt=""&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;O si preferimos algo más sofisticado, para ver nuestros plugins:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:echo join(keys(g:plugs), ' ')&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Si bien esta funcionalidad también existe en Neovim,  podemos administrar los plugins de manera más flexible y automatizada. Esto nos lleva a considerar el uso de gestores de plugins.&lt;/p&gt;
&lt;h3 id="gestores-de-plugins"&gt;Gestores de plugins&lt;/h3&gt;
&lt;p&gt;Existen varios gestores de plugins:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Shougo/dein.vim"&gt;Shougo/dein.vim: Dark powered Vim/Neovim plugin manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/VundleVim/Vundle.vim"&gt;VundleVim/Vundle.vim: Vundle, the plug-in manager for Vim&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/junegunn/vim-plug"&gt;junegunn/vim-plug: Minimalist Vim Plugin Manager&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Me parece muy recomendable &lt;strong&gt;vim-plug&lt;/strong&gt; porque:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Requiere muy poca configuración: una lista con los paquetes de plugins deseados.&lt;/li&gt;
&lt;li&gt;Instala y actualiza todos los paquetes de nuestra lista o los que seleccionemos.&lt;/li&gt;
&lt;li&gt;Detecta y elimina plugins que borramos de nuestra lista. &lt;/li&gt;
&lt;li&gt;Muestra el estado de los plugins.&lt;/li&gt;
&lt;li&gt;Genera instantáneas de nuestros paquetes con su configuración, con la posibilidad de restaurarlas.&lt;/li&gt;
&lt;li&gt;Posee atajos de teclado.&lt;/li&gt;
&lt;li&gt;Es compatible tanto con Vim como Neovim&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Si queremos deshabilitar todos los plugins podemos ejecutar &lt;code&gt;nvim --noplugin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Neovim sigue los lineamientos de la XDG Base Directory Specification. &lt;strong&gt;Algo que puede ser muy útil&lt;/strong&gt;: poner el listado de plugins en un archivo separado. Esto es: creando un archivo &lt;code&gt;${XDG_CONFIG_HOME:-$HOME/.config}/nvim/plugins.vim&lt;/code&gt; y en el archivo &lt;code&gt;${XDG_CONFIG_HOME:-$HOME/.config}/nvim/init.vim&lt;/code&gt; teniendo una simple línea:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;runtime plugins.vim&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Entonces, comentando esa línea es una manera alternativa para desactivarlos.&lt;/p&gt;
&lt;p&gt;Pero hay más: supongamos que tenemos esta configuración en el archivo &lt;code&gt;${XDG_CONFIG_HOME:-$HOME/.config}/nvim/plugins.vim&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nx"&gt;Plug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;nyngwang&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;NeoTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lua&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;plug&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="s"&gt;" Esta es la manera de embeber código lua en un archivo de tipo vimL&lt;/span&gt;
&lt;span class="s"&gt;lua &amp;lt;&amp;lt; EOF&lt;/span&gt;
&lt;span class="s"&gt;require("&lt;/span&gt;&lt;span class="nx"&gt;neo&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="s"&gt;").setup {&lt;/span&gt;
&lt;span class="s"&gt;  exclude_filetypes = { "&lt;/span&gt;&lt;span class="nx"&gt;oil&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;EOF&lt;/span&gt;

&lt;span class="nx"&gt;nnoremap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;F4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;NeoTermToggle&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nx"&gt;tnoremap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;F4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="nx"&gt;NeoTermToggle&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nx"&gt;tnoremap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Esc&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;:&lt;/span&gt;&lt;span class="nx"&gt;NeoTermEnterNormal&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Con esta configuración:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Al presionar &lt;strong&gt;F4&lt;/strong&gt; se abirá una terminal.&lt;/li&gt;
&lt;li&gt;Al presionar de vuelta &lt;strong&gt;F4&lt;/strong&gt; se cerrará la terminal.&lt;/li&gt;
&lt;li&gt;Con &lt;strong&gt;Esc&lt;/strong&gt; se vuelve al modo &lt;em&gt;Normal&lt;/em&gt; en la terminal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En tiempos en los que tanto se declama la agilidad, como contrasentido se ofrecen editores que consumen muchos recursos, con desarrollos no exentos de torpezas y caprichos impuestos de antemano. El minimalismo de Vim como de Neovim nos permite adaptarlo de acuerdo a lo que necesitemos, la posibilidad de agregar distintas funcionalidades, sea para desarrollo, mejor usabilidad y experiencia del usuario (sí: el desarrollador o sysadmin también es un usuario 😀).
Finalmente, si bien tanto Vim como Neovim poseen el soporte nativo para manejar paquetes de plugins, encuentro en vim-plugin una manera mucho más conveniente de hacerlo.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Carga de Plugins en Vim" class="img-izquierda-responsiva" src="https://sergiobelkin.com/images/CargaPlugins.png"&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Característica&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Sistema Nativo (Vim 8 &lt;code&gt;packages&lt;/code&gt;)&lt;/th&gt;
&lt;th style="text-align: left;"&gt;&lt;code&gt;vim-plug&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Instalación&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Manual (clonar repos en &lt;code&gt;pack/&lt;/code&gt;)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Automática vía script (&lt;code&gt;plug.vim&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Configuración&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;En &lt;code&gt;vimrc&lt;/code&gt;, usando &lt;code&gt;packadd&lt;/code&gt; o estructura &lt;code&gt;start/opt&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Declarativa en &lt;code&gt;vimrc&lt;/code&gt; con &lt;code&gt;Plug&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Carga diferida (lazy-loading)&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Manual con &lt;code&gt;packadd&lt;/code&gt; desde &lt;code&gt;opt/&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Incorporado: &lt;code&gt;on&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;cmd&lt;/code&gt;, &lt;code&gt;event&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Instalación de plugins&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Manual (&lt;code&gt;git clone&lt;/code&gt;)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;:PlugInstall&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Actualización&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Manual (&lt;code&gt;git pull&lt;/code&gt; en cada plugin)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;:PlugUpdate&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Desinstalación&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Manual (borrar carpeta)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;:PlugClean&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Gestión de dependencias&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;No soportado nativamente&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Limitada (tú defines el orden)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Soporte para branches/tags&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Manual (&lt;code&gt;git checkout&lt;/code&gt;)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Sí (&lt;code&gt;Plug 'user/repo', { 'branch': 'dev' }&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Paralelismo en instalación&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;No&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Sí (instala varios plugins a la vez)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Interfaz de usuario&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ninguna&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Básica pero útil (durante instalación/update)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Velocidad en carga&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Muy rápida (carga solo en startup)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Muy rápida con lazy loading&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Soporte oficial&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Parte de Vim 8+&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Mantenido por la comunidad&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Curva de aprendizaje&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Mayor (entender estructura &lt;code&gt;pack/&lt;/code&gt;)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Muy simple y bien documentado&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;strong&gt;Compatibilidad&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Solo Vim 8+&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Compatible con Vim 7.4+, Neovim&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="conclusion"&gt;Conclusión&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Metáfora de las bibliotecas" class="img-izquierda-responsiva" src="https://sergiobelkin.com/images/metafora-de-la-bibliotecas.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;El soporte nativo de Vim/Neovim es como una biblioteca física organizada con dos tipos de estantes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;start/&lt;/code&gt;&lt;/strong&gt;: son los libros que se abren automáticamente apenas entrás a la biblioteca —es decir, los plugins que se cargan al iniciar Vim/Neovim.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;opt/&lt;/code&gt;&lt;/strong&gt;: son libros que están en los estantes, pero que &lt;strong&gt;vos tenés que buscar y abrir manualmente&lt;/strong&gt; usando el comando &lt;code&gt;:packadd&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Este sistema te da control total, pero también requiere que te ocupes de la instalación, organización y carga de cada plugin.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Los gestores de plugins, como &lt;code&gt;vim-plug&lt;/code&gt;, funcionan como un sistema de préstamo digital moderno:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Suscripción básica:&lt;/strong&gt;
   Declarás qué libros (plugins) querés en una lista de solicitudes (&lt;code&gt;Plug 'autor/plugin'&lt;/code&gt;), y al ejecutar un comando como &lt;code&gt;PlugInstall&lt;/code&gt;, el sistema los descarga automáticamente y los organiza en las secciones correspondientes del runtimepath.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dependencias = citas bibliográficas que debés declarar manualmente:&lt;/strong&gt;
   Si el libro A necesita al libro B para entenderse correctamente, &lt;strong&gt;vos tenés que pedir ambos explícitamente&lt;/strong&gt;.
   A diferencia de gestores como &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;pip&lt;/code&gt; o &lt;code&gt;cargo&lt;/code&gt;, &lt;strong&gt;no hay resolución automática de dependencias&lt;/strong&gt;: nadie deduce relaciones por vos.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Actualizaciones periódicas:&lt;/strong&gt;
   Usando el comando &lt;code&gt;PlugUpdate&lt;/code&gt;, podés sincronizar tu colección con las últimas ediciones disponibles.
   Eso sí: estos comandos actualizan lo que ya tenés, &lt;strong&gt;pero no agregan automáticamente nuevos plugins a menos que los declares en tu configuración.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ahora cabe preguntarse dos cosas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;¿Cómo podemos empezar a usar &lt;strong&gt;Lua&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;Más allá de que &lt;code&gt;vim-plug&lt;/code&gt; es una excelente opción: ¿Es actualmente la mejor para &lt;strong&gt;Neovim&lt;/strong&gt;?&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="mas-recursos"&gt;Más Recursos&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://neovim.io/doc/user/develop.html"&gt;Nvim documentation: develop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://specifications.freedesktop.org/basedir-spec/latest/ar01s03.html"&gt;Variables de Entorno de XDG Base Directory Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/brooth/far.vim"&gt;brooth/far.vim: Find And Replace Vim plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vimawesome.com/"&gt;Vim Awesome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opensource.com/article/20/2/how-install-vim-plugins"&gt;How to install Vim plugins | Opensource.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://shapeshed.com/vim-packages/#vim-8-brings-native-third-party-package-loading"&gt;Vim: So long Pathogen, hello native package loading | George Ornbo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><category>Neovim</category><category>sysadmin</category><guid>https://sergiobelkin.com/posts/una-introduccion-pragmatica-al-uso-de-plugins-en-neovim/</guid><pubDate>Sun, 04 May 2025 19:22:12 GMT</pubDate></item><item><title>Tutorial: Cifrar $HOME con gocryptfs</title><link>https://sergiobelkin.com/posts/tutorial-cifrar-un-directorio-con-gocryptfs/</link><dc:creator>sebelk</dc:creator><description>&lt;p&gt;En un artículo anterior: &lt;strong&gt;&lt;a href="https://sergiobelkin.com/posts/tutorial-de-fscrypt-para-cifrar-archivos/"&gt;Tutorial de fscrypt para cifrar archivos&lt;/a&gt;&lt;/strong&gt;, habíamos visto como cifrar archivos con &lt;strong&gt;fscrypt&lt;/strong&gt; y ext4. Ahora aprenderemos otro método independiente del sistema de archivos utilizado, se trata de una herramienta llamada &lt;strong&gt;gocryptfs&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conocimientos previos necesarios:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Uso habitual de línea de comandos en Linux (incluyendo entre otros manejo de propietarios y permisos)&lt;/li&gt;
&lt;li&gt;Instalación y desinstalación de paquetes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En el ejemplo en cuestión estoy usando Debian Buster (te recomiendo primero instalarla en una máquina virtual para hacer pruebas), de modo que los pasos a seguir pueden ser un poco diferentes en otras distribuciones, pero los principios generales se mantienen.
&lt;strong&gt;Todos los pasos hasta que lo pruebes como usuario común deben hacerse con privilegios de superusuario.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Es muy importante contar espacio suficiente para copiar temporalmente los archivos del directorio que se desea cifrar.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;He cambiado el shell del usuario sergio que es &lt;em&gt;dash&lt;/em&gt; (predeterminado en Debian) por &lt;strong&gt;bash&lt;/strong&gt;, ya que el primero no está pensado para un uso interactivo habitual además de ser menos potente.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/rob-king-Au6eR7Yg9CY-unsplash.jpg"&gt;&lt;img src="https://sergiobelkin.com/images/rob-king-Au6eR7Yg9CY-unsplash.thumbnail.jpg" alt=""&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3 id="instalar-grocryptfs"&gt;Instalar grocryptfs&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;apt install grocryptfs&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="crear-el-directorio-para-cifrar"&gt;Crear el directorio para cifrar&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;mkdir /home/sergio_cifrado&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="inicializar-el-directorio"&gt;Inicializar el directorio&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Aquí seteamos la misma contraseña que la del usuario&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;gocryptfs --init /home/sergio_cifrado/
Choose a password for protecting your files.
Password: 
Repeat: 

Your master key is:

    9c43faf4-16a07508-42213628-50a5c55e-
    e0c17483-c41453a0-6355f9f0-897b3aa9

If the gocryptfs.conf file becomes corrupted or you ever forget your password,
there is only one hope for recovery: The master key. Print it to a piece of
paper and store it in a drawer. This message is only printed once.

The gocryptfs filesystem has been created successfully.
You can now mount it using: gocryptfs /home/sergio_cifrado MOUNTPOINT
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="montar-el-directorio"&gt;Montar el directorio&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;mkdir /home/sergio_montaje_temporario &amp;amp;&amp;amp; chmod 750 /home/sergio_montaje_temporario &amp;amp;&amp;amp; chown sergio. /home/sergio_temporario &amp;amp;&amp;amp;
gocryptfs /home/sergio_cifrado/ /home/sergio_temporario/
Password: 
Decrypting master key
Filesystem mounted and ready.
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="ajustamos-los-propietarios-y-permisos"&gt;Ajustamos los propietarios y permisos&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;chown -R sergio. /home/sergio{_cifrado} &amp;amp;&amp;amp; chmod 750 /home/sergio_cifrado&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="copiar-todos-los-archivos-del-directorio-del-usuario-al-directorio-temporal"&gt;Copiar todos los archivos del directorio del usuario al directorio temporal&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;cp -Tav /home/sergio /home/sergio_temporario&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="borrar-el-contenido-del-directorio-del-usuario-por-favor-realizar-previamente-un-backup"&gt;Borrar el contenido del directorio del usuario (por favor realizar previamente un backup)&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;rm -rf /home/sergio&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="desmontar-el-directorio-cifrado"&gt;Desmontar el directorio cifrado&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;fusermount -u /home/sergio_temporario&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="le-cambiamos-el-nombre-al-directorio-temporario-por-el-original"&gt;Le cambiamos el nombre al directorio temporario por el original&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;mv /home/sergio_temporario /home/sergio&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Todo lo que viene a continuación es necesario cuando queremos que el directorio se monte de manera automática en el momento del login.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="instalamos-el-modulo-de-pam-para-montaje-de-volumenes"&gt;Instalamos el módulo de PAM para montaje de volúmenes&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;apt install -y libpam-mount&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="ejecutamos-el-configurador-de-pam"&gt;Ejecutamos el configurador de pam&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pam-auth-update&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/pam_auth_update.png"&gt;&lt;img src="https://sergiobelkin.com/images/pam_auth_update.thumbnail.png" alt="pam-auth-update"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;y presionamos en &lt;strong&gt;Aceptar&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;En otras distribuciones y configuraciones, puede ser necesario editar otros archivos del directorio /etc/pam.d.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Luego hay que editar el archivo &lt;code&gt;/etc/security/pam_mount.conf.xml&lt;/code&gt; agregando lo siguiente antes de &lt;code&gt;&amp;lt;/pam_mount&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;volume&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sergio"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fstype&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"fuse"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"nodev,nosuid,quiet,nonempty,allow_other"&lt;/span&gt;
&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/usr/bin/gocryptfs#/home/%(USER)_cifrado"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mountpoint&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/home/%(USER)"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="configuramos-fuse"&gt;Configuramos FUSE&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="gh"&gt;#&lt;/span&gt; /etc/fuse.conf - Configuration file for Filesystem in Userspace (FUSE)

&lt;span class="gh"&gt;#&lt;/span&gt; Set the maximum number of FUSE mounts allowed to non-root users.
&lt;span class="gh"&gt;#&lt;/span&gt; The default is 1000.
&lt;span class="gh"&gt;#&lt;/span&gt;mount_max = 1000

&lt;span class="gh"&gt;#&lt;/span&gt; Allow non-root users to specify the allow_other or allow_root mount options.
&lt;span class="gh"&gt;#&lt;/span&gt; Modificamos aquí:
user_allow_other
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Eso es todo, felicitaciones si llegaste hasta aquí 😀,  podemos reiniciar y probar la configuración:&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/aFezsKg2iRY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Para login gráfico:&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/wwwVL8k_bes" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;

&lt;h3 id="conclusion"&gt;Conclusión&lt;/h3&gt;
&lt;p&gt;De esta manera pudiste configurar el cifrado automática de un directorio $HOME de un usuario. Este método es principalmente útil para equipos donde trabaja un solo usuario (podría ser tu laptop de trabajo diario por ejemplo).&lt;/p&gt;
&lt;h3 id="fuentes-y-mas-recursos"&gt;Fuentes y más recursos&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nuetzlich.net/gocryptfs/"&gt;gocryptfs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rfjakob/gocryptfs"&gt;rfjakob/gocryptfs: Encrypted overlay filesystem written in Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pam-mount.sourceforge.net/"&gt;pam_mount — Pluggable Authentication Module to mount volumes for a user session&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><category>criptografia</category><guid>https://sergiobelkin.com/posts/tutorial-cifrar-un-directorio-con-gocryptfs/</guid><pubDate>Wed, 12 May 2021 18:11:58 GMT</pubDate></item><item><title>Tutorial de fscrypt para cifrar archivos</title><link>https://sergiobelkin.com/posts/tutorial-de-fscrypt-para-cifrar-archivos/</link><dc:creator>sebelk</dc:creator><description>&lt;h4 id="conocimientos-previos-necesarios"&gt;Conocimientos previos necesarios:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Instalación de Linux.&lt;/li&gt;
&lt;li&gt;Uso habitual de línea de comandos en Linux (incluyendo entre otros manejo de propietarios y permisos).&lt;/li&gt;
&lt;li&gt;Instalación y desinstalación de paquetes.&lt;/li&gt;
&lt;li&gt;Montaje de sistemas de archivos.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/alex-motoc-Y83nsKGkxSw-unsplash.jpg"&gt;&lt;img src="https://sergiobelkin.com/images/alex-motoc-Y83nsKGkxSw-unsplash.thumbnail.jpg" alt="Cifrado de archivos"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;El sistema ext4 proporciona cifrado de bloques de datos y nombres de archivos. Veremos a continuación de algunas reglas generales para cifrar el directorio /home de un usuario.&lt;/p&gt;
&lt;p&gt;En el ejemplo en cuestión estoy usando Debian Buster (te recomiendo primero instalarla en una máquina virtual para hacer pruebas), de modo que los pasos a seguir pueden ser un poco diferentes en otras distribuciones, pero los principios generales se mantienen.&lt;/p&gt;
&lt;p&gt;¡Manos a la obra!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Los comandos precedidos por &lt;code&gt;sudo&lt;/code&gt; indican que necesitan privilegios de root. Si querés usar sudo, sencillamente ejecutá como root:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;usermod -aG sudo sergio&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Obviamente aquí y en cada caso reemplazalo con tu usuario común.&lt;/p&gt;
&lt;h3 id="preparacion-del-sistema-de-archivos"&gt;Preparación del sistema de archivos&lt;/h3&gt;
&lt;p&gt;Algo que tendremos que hacer es habilitar la funcionalidad de cifrado, suponiendo que la partición de cifrado es /dev/sda1, haríamos:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo tune2fs -O encrypt /dev/sda1&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="descarga-y-compilacion"&gt;Descarga y compilación&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt build-dep fscrypt&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;do apt -y install git &amp;amp;&amp;amp; go get -d github.com/google/fscrypt/...&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cd go/src/github.com/google/fscrypt/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;make &amp;amp;&amp;amp; sudo make install PREFIX=/usr&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="configuracion"&gt;Configuración&lt;/h3&gt;
&lt;p&gt;Tenemos que actualizar la configuración de PAM, que servirán para desbloquear directorios al loguearse, bloquear al desloguearse, y cambiar contraseñas de acceso a los recursos cifrados.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo pam-auth-update&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/pam-auth-update-fscrypt.png"&gt;&lt;img src="https://sergiobelkin.com/images/pam-auth-update-fscrypt.thumbnail.png" alt="pam-auth-update"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Para configurar globalmente:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo fscrypt setup&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;No se puede cifrar un directorio que ya tiene contenido, de manera que hay que crear un nuevo directorio, y luego migrar el contenido del directorio del usuario:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo mkdir /home/sergio_temp &amp;amp;&amp;amp; sudo chown sergio.sergio /home/sergio_temp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fscrypt encrypt /home/sergio_temp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Allí podríamos elegir entre la contraseña del usuario, una passphrase o bien un archivo con clave 256-bit. En nuestro elegimos la primera opción, siempre teniendo en cuenta lo importante que es contar con una buena contraseña.&lt;/p&gt;
&lt;p&gt;Luego chequeamos que esté todo en orden:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fscrypt status /home/sergio_temp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Ahora sí, migramos el contenido:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cp -av -T /home/sergio /home/sergio_temp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Bloqueamos el contenido del directorio&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo fscrypt lock /home/sergio_temp --user=/home/sergio_temp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Probamos desbloquear&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fscrypt unlock /home/sergio_temp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Si funciona podemos reemplazarlo por el nuevo directorio:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo su -&lt;/code&gt;
&lt;code&gt;mv /home/sergio{,_para-borrar}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mv /home/sergio{_temp,}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Luego al reiniciar podemos probar:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;reboot&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;¿Cómo se ven los archivos cifrados?&lt;/p&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/fscrypt-access.png"&gt;&lt;img src="https://sergiobelkin.com/images/fscrypt-access.thumbnail.png" alt=""&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h4 id="mas-recursos"&gt;Más Recursos&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/google/fscrypt"&gt;fscrypt: Go tool for managing Linux filesystem encryption&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.archlinux.org/index.php/Fscrypt"&gt;fscrypt - ArchWiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kernel.org/doc/html/v4.18/filesystems/fscrypt.html"&gt;Filesystem-level encryption (fscrypt) — The Linux Kernel documentation&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;</description><category>criptografia</category><category>seguridad</category><guid>https://sergiobelkin.com/posts/tutorial-de-fscrypt-para-cifrar-archivos/</guid><pubDate>Sat, 24 Apr 2021 13:30:29 GMT</pubDate></item><item><title>Tutorial de LXC</title><link>https://sergiobelkin.com/posts/tutorial-de-lxc/</link><dc:creator>sebelk</dc:creator><description>&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/frank-mckenna-tjX_sniNzgQ-unsplash.jpg"&gt;&lt;img src="https://sergiobelkin.com/images/frank-mckenna-tjX_sniNzgQ-unsplash.thumbnail.jpg" alt="Containers"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Photo by frank mckenna on Unsplash&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;LXC es una herramienta extraordinaria, algo intermedio entre un chroot y una máquina virtualizada completamente. Usando el mismo kernel que el sistema anfitrión podemos tener sistemas operativos invitados en el propio filesystem. Es decir, cada SO invitado en un directorio. Pero la documentación y la interacción de los distintos componentes puede tornar algo &lt;em&gt;tricky&lt;/em&gt; el proceso. Cansado de lidiar con documentación desperdigada por aquí y por allá decidí crear mi propio tutorial. Intentando en lo posible ser distro-agnóstico.&lt;/p&gt;
&lt;p&gt;Aquí está:&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/lkcu8o8gus8" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;¡Espero que lo disfruten!&lt;/p&gt;</description><category>contenedores</category><guid>https://sergiobelkin.com/posts/tutorial-de-lxc/</guid><pubDate>Mon, 15 Jun 2020 00:59:38 GMT</pubDate></item><item><title>Tutorial: Autenticación en SSH con clave pública</title><link>https://sergiobelkin.com/posts/tutorial-autenticacion-con-clave-publica/</link><dc:creator>sebelk</dc:creator><description>&lt;p&gt;Este es un tutorial para que empecemos a usar claves públicas para autenticarnos. El único requisito es que hayamos ingresado a un servidor o host remoto con ssh. En nuestro ejemplo ese host tiene la ip 10.0.3.11.&lt;/p&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/jametlene-reskp-9DdOrQpMsUs-unsplash.jpg"&gt;&lt;img src="https://sergiobelkin.com/images/jametlene-reskp-9DdOrQpMsUs-unsplash.thumbnail.jpg" alt=""&gt;&lt;/a&gt;i
&lt;br&gt;
&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="https://sergiobelkin.com/posts/tutorial-autenticacion-con-clave-publica/#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;El uso de autenticación por clave pública, tal como vimos en el &lt;a href="https://sergiobelkin.com/posts/guia-breve-ssh-con-clave-publica/"&gt;post anterior&lt;/a&gt; tiene la ventaja de no tener que ingresar usuario y contraseña. Esto puede ser útil en casos en que necesitemos realizar alguna tarea en un host remoto de manera no interactiva. Por ejemplo podríamos crear una tarea programada que ejecute todos los días un script de backup.
Veremos paso a paso como conseguirlo.
Lo primero que tendremos que hacer es generar un par de claves. Para ellos ejecutaremos el siguiente comando:
&lt;code&gt;ssh-keygen&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Como se ve en la imagen de abajo se nos preguntará la ruta de la clave privada, aceptamos la predeterminada presionando la tecla Enter.
&lt;a class="image-reference" href="https://sergiobelkin.com/images/ssh-keygen.png"&gt;&lt;img src="https://sergiobelkin.com/images/ssh-keygen.thumbnail.png" alt=""&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;y además se nos pedirá una passphrase. La passphrase es una frase que sea fácil de recordar para uno mismo, pero a la vez difícil de adivinar para otros. El propósito es cifrar la clave privada. Si te estás preguntando ¿para qué hacer todo esto si de todas maneras tendré que ingresa una passphrase para autenticarme. La respuesta es que tenemos técnicas como veremos un poco más abajo, para evitar la necesidad del ingreso de la frase una y otra vez.
Ingresamos la frase una vez después de la otra:&lt;/p&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/ssh-keygen-2.png"&gt;&lt;img src="https://sergiobelkin.com/images/ssh-keygen-2.thumbnail.png" alt=""&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Esto generará dos archivos en el directorio &lt;code&gt;~/.ssh&lt;/code&gt;: &lt;code&gt;id_rsa&lt;/code&gt; y &lt;code&gt;id_rsa.pub&lt;/code&gt; que son la clave privada y la clave pública respectivamente. Como sus nombres lo indican la clave privada no debe compartirse, en cambio la clave pública es la que nosirve para identificarnos como usuarios frente a otros hosts y se puede compartir.&lt;/p&gt;
&lt;p&gt;En este momento tenemos que copiar la clave pública al host que funciona como servidor ssh. La manera más fácil y ráṕida de hacerlo es con el comando siguiente:&lt;/p&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/ssh-copy-id.png"&gt;&lt;img src="https://sergiobelkin.com/images/ssh-copy-id.thumbnail.png" alt="ssh-copy-id"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Ingresamos la contraseña de root y luego presionamos la tecla Enter. Lo que hace este comando es agregar la clave pública del archivo &lt;code&gt;id_rsa.pub&lt;/code&gt; al archivo /root/.ssh/authorized_keys del servidor ssh.&lt;/p&gt;
&lt;p&gt;Ahora lo que hacemos es reemplazar la shell actual con el agente de ssh y re-ejecutando la shell bash. El agente de ssh será el encargado de guardar las claves privadas en memoria para que no tengamos que ingresar más de una vez la passphrase:&lt;/p&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/ssh-agent.png"&gt;&lt;img src="https://sergiobelkin.com/images/ssh-agent.thumbnail.png" alt="ssh-agent"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Luego ejecutamos el comando &lt;code&gt;ssh-add&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/ssh-add.png"&gt;&lt;img src="https://sergiobelkin.com/images/ssh-add.thumbnail.png" alt="ssh-add"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Se nos pedirá la frase, la ingresamos y le damos Enter.&lt;/p&gt;
&lt;p&gt;&lt;a class="image-reference" href="https://sergiobelkin.com/images/ssh-passwordless.png"&gt;&lt;img src="https://sergiobelkin.com/images/ssh-passwordless.thumbnail.png" alt="ssh sin contraseña"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;A través de este tutorial mencionamos varios conceptos que podés ampliar recurriendo a los siguientes enlaces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.unixwiz.net/techtips/ssh-agent-forwarding.html"&gt;An Illustrated Guide to SSH Agent Forwarding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blakesmith.me/2010/02/08/understanding-public-key-private-key-concepts.html"&gt;understanding public key private key concepts » Blake Smith&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.learningtree.com/ways-manage-ssh-keys-identities/"&gt;Ways to Manage Your SSH Keys and Identities | Learning Tree Blog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Photo by Jametlene Reskp on Unsplash &lt;a class="footnote-backref" href="https://sergiobelkin.com/posts/tutorial-autenticacion-con-clave-publica/#fnref:1" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>criptografia</category><category>SSH</category><guid>https://sergiobelkin.com/posts/tutorial-autenticacion-con-clave-publica/</guid><pubDate>Fri, 08 Nov 2019 12:12:36 GMT</pubDate></item></channel></rss>