Saltar al contenido principal

Snippets y Templates Automáticos

Los snippets y templates son herramientas poderosas para acelerar la escritura de código repetitivo. En este capítulo aprenderás a crear y usar snippets eficientemente para maximizar tu productividad.

🚀 UltiSnips: El Motor de Snippets Más Potente

UltiSnips es el sistema de snippets más avanzado para Vim, con capacidades de Python scripting y lógica compleja.

Instalación y configuración básica

" Instalación con vim-plug
Plug 'SirVer/ultisnips'
Plug 'honza/vim-snippets' " Colección grande de snippets

" Configuración básica
let g:UltiSnipsExpandTrigger="<Tab>"
let g:UltiSnipsJumpForwardTrigger="<Tab>"
let g:UltiSnipsJumpBackwardTrigger="<S-Tab>"
let g:UltiSnipsEditSplit="vertical"

" Directorios de snippets
let g:UltiSnipsSnippetsDir="~/.vim/UltiSnips" " Personal
let g:UltiSnipsSnippetDirectories=["UltiSnips", "mysnippets"]

" Mapeos adicionales
nnoremap <Leader>ue :UltiSnipsEdit<CR>
nnoremap <Leader>ur :call UltiSnips#RefreshSnippets()<CR>

Sintaxis básica de snippets

snippet trigger "description" options
snippet content with ${1:placeholder} and ${2:another}
$0 # Posición final del cursor
endsnippet

📝 Creando Snippets Personalizados

Estructura de archivos de snippets

~/.vim/UltiSnips/
├── all.snippets # Snippets globales
├── python.snippets # Específicos para Python
├── javascript.snippets # Específicos para JavaScript
├── html.snippets # Específicos para HTML
└── vim.snippets # Específicos para Vim

Ejemplos de snippets básicos

Python snippets

# ~/.vim/UltiSnips/python.snippets

# Función básica
snippet def "Function definition" b
def ${1:function_name}(${2:args}):
"""${3:Docstring for $1.}"""
${4:pass}
$0
endsnippet

# Clase básica
snippet class "Class definition" b
class ${1:ClassName}(${2:object}):
"""${3:Docstring for $1.}"""

def __init__(self${4:, args}):
"""${5:Initialize $1.}"""
${6:pass}
$0
endsnippet

# Try-except
snippet try "Try except block" b
try:
${1:pass}
except ${2:Exception} as ${3:e}:
${4:raise}
$0
endsnippet

# If main
snippet ifmain "if __name__ == '__main__'" b
if __name__ == '__main__':
${1:main()}
$0
endsnippet

# Docstring con parámetros
snippet docs "Function docstring" b
"""${1:Brief description.}

Args:
${2:param1} (${3:type}): ${4:Description}

Returns:
${5:type}: ${6:Description}

Raises:
${7:ExceptionType}: ${8:Description}
"""
$0
endsnippet

JavaScript/TypeScript snippets

# ~/.vim/UltiSnips/javascript.snippets

# Función
snippet func "Function" b
function ${1:functionName}(${2:args}) {
${3:// TODO: implement}
$0
}
endsnippet

# Arrow function
snippet arrow "Arrow function" w
(${1:args}) => {
${2:// TODO: implement}
$0
}
endsnippet

# React component
snippet rfc "React functional component" b
import React from 'react';

const ${1:ComponentName} = (${2:props}) => {
return (
<div>
${3:// Component content}
$0
</div>
);
};

export default $1;
endsnippet

# Console log
snippet cl "console.log" w
console.log('${1:message}:', ${2:variable});$0
endsnippet

# Try-catch
snippet try "Try catch block" b
try {
${1:// code}
} catch (${2:error}) {
console.error('${3:Error message}:', $2);
$0
}
endsnippet

HTML snippets

# ~/.vim/UltiSnips/html.snippets

# HTML5 template
snippet html5 "HTML5 template" b
<!DOCTYPE html>
<html lang="${1:en}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${2:Document}</title>
${3:<link rel="stylesheet" href="style.css">}
</head>
<body>
${4:<!-- Content here -->}
$0
</body>
</html>
endsnippet

# Div con clase
snippet div "Div with class" w
<div class="${1:classname}">
$0
</div>
endsnippet

# Link
snippet a "Anchor tag" w
<a href="${1:url}"${2: target="_blank"}>${3:link text}</a>$0
endsnippet

🧠 Snippets Avanzados con Python

Snippets con lógica Python

# Snippet que genera getters/setters automáticamente
snippet prop "Property with getter/setter" b
@property
def ${1:property_name}(self):
"""${2:Property docstring.}"""
return self._$1

@$1.setter
def $1(self, value):
"""Set $1."""
self._$1 = value
$0
endsnippet

# Snippet con fecha automática
snippet date "Current date" w
`!p snip.rv = datetime.now().strftime("%Y-%m-%d")`$0
endsnippet

# Snippet con nombre de archivo
snippet filename "Current filename" w
`!p snip.rv = vim.eval("expand('%:t:r')")`$0
endsnippet

# Snippet condicional
snippet init "Class __init__ method" b
def __init__(self${1:, args}):
"""Initialize ${2:`!p snip.rv = snip.basename or "instance"`}.
`!p
if len(t[1]) > 2:
snip.rv = "\n Args:"
args = [arg.strip() for arg in t[1].split(',')[1:]]
for arg in args:
if arg:
snip.rv += f"\n {arg}: Description for {arg}."
`"""
${3:pass}
$0
endsnippet

Snippets con transformaciones de texto

# Convertir a mayúsculas
snippet const "Constant definition" b
${1/(.+)/\U$1\E/} = ${2:value}$0
endsnippet

# Convertir primera letra a mayúscula
snippet class "Class from filename" b
class ${1:`!p snip.rv = snip.basename.title()`}:
"""${2:Class docstring.}"""

def __init__(self):
"""Initialize $1."""
${3:pass}
$0
endsnippet

🎨 Templates de Archivos

Templates automáticos por tipo de archivo

" En .vimrc - Auto-cargar templates
augroup templates
autocmd!
autocmd BufNewFile *.py 0r ~/.vim/templates/python_template.py
autocmd BufNewFile *.js 0r ~/.vim/templates/javascript_template.js
autocmd BufNewFile *.html 0r ~/.vim/templates/html_template.html
autocmd BufNewFile *.sh 0r ~/.vim/templates/bash_template.sh

" Ejecutar snippets automáticamente después de cargar template
autocmd BufNewFile *.py normal! Gdd/TODO<CR>:nohlsearch<CR>a
augroup END

Ejemplos de templates

Python template

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
File: {filename}
Author: {author}
Date: {date}
Description: TODO: Add description
"""

import sys
import os


def main():
"""Main function."""
# TODO: Implement main logic
pass


if __name__ == '__main__':
main()

JavaScript template

/**
* @file {filename}
* @author {author}
* @date {date}
* @description TODO: Add description
*/

'use strict';

// TODO: Add imports

/**
* Main function
*/
function main() {
// TODO: Implement main logic
}

// TODO: Add exports
module.exports = {
main
};

Templates dinámicos con funciones Vim

" Función para crear template con variables
function! LoadTemplate(template_name)
let l:template_path = expand('~/.vim/templates/' . a:template_name)
if filereadable(l:template_path)
execute '0r ' . l:template_path

" Reemplazar variables
%s/{filename}/\=expand('%:t')/g
%s/{author}/\=g:author_name/g
%s/{email}/\=g:author_email/g
%s/{date}/\=strftime('%Y-%m-%d')/g
%s/{year}/\=strftime('%Y')/g

" Ir al primer TODO
call search('TODO')
endif
endfunction

" Variables globales para templates
let g:author_name = 'Tu Nombre'
let g:author_email = 'tu.email@ejemplo.com'

" Comando para cargar templates
command! -nargs=1 Template call LoadTemplate(<q-args>)

🔧 Sistemas Alternativos de Snippets

1. vim-snipmate (Ligero)

Plug 'MarcWeber/vim-addon-mw-utils'
Plug 'tomtom/tlib_vim'
Plug 'garbas/vim-snipmate'

" Configuración básica
imap <C-J> <Plug>snipMateNextOrTrigger
smap <C-J> <Plug>snipMateNextOrTrigger

2. neosnippet (Para compatibilidad)

Plug 'Shougo/neosnippet.vim'
Plug 'Shougo/neosnippet-snippets'

" Configuración
imap <C-k> <Plug>(neosnippet_expand_or_jump)
smap <C-k> <Plug>(neosnippet_expand_or_jump)
xmap <C-k> <Plug>(neosnippet_expand_target)

3. Snippets nativos con abbrev

" Abbreviations básicas
iabbrev teh the
iabbrev waht what
iabbrev @@ tu.email@ejemplo.com

" Snippets simples con abbrev
autocmd FileType python iabbrev <buffer> def<Tab> def ():<CR>""""""<CR><CR><Esc>3kwa
autocmd FileType javascript iabbrev <buffer> func function () {<CR><CR>}<Esc>2k$i

📚 Colecciones de Snippets

Instalación de colecciones populares

" Colección oficial de vim-snippets
Plug 'honza/vim-snippets'

" Snippets específicos para frameworks
Plug 'epilande/vim-es2015-snippets' " ES6+ JavaScript
Plug 'epilande/vim-react-snippets' " React
Plug 'dsznajder/vscode-es7-javascript-react-snippets' " VSCode style

" Configurar múltiples fuentes
let g:UltiSnipsSnippetDirectories=["UltiSnips", "vim-snippets", "mysnippets"]

Snippets por framework/librería

Django snippets

# ~/.vim/UltiSnips/python.snippets

snippet model "Django model" b
class ${1:ModelName}(models.Model):
"""${2:Model docstring.}"""

${3:name} = models.${4:CharField}(${5:max_length=100})
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

class Meta:
verbose_name = "${6:$1}"
verbose_name_plural = "${7:$1s}"

def __str__(self):
return self.$3
$0
endsnippet

snippet view "Django view" b
def ${1:view_name}(request):
"""${2:View docstring.}"""
${3:# TODO: Implement view logic}

context = {
${4:'key': 'value',}
}

return render(request, '${5:template.html}', context)
$0
endsnippet

React snippets

# ~/.vim/UltiSnips/javascript.snippets

snippet usestate "useState hook" w
const [${1:state}, set${1/(.)/\u$1/}] = useState(${2:initialValue});$0
endsnippet

snippet useeffect "useEffect hook" b
useEffect(() => {
${1:// Effect logic}

${2:return () => {
// Cleanup
};}
}, [${3:dependencies}]);$0
endsnippet

📝 Ejercicios Prácticos

Ejercicio 1: Setup básico

  1. Instala UltiSnips y vim-snippets
  2. Configura triggers personalizados
  3. Prueba snippets existentes para tu lenguaje favorito
  4. Crea tu primer snippet personalizado

Ejercicio 2: Snippets avanzados

  1. Crea snippets con múltiples placeholders
  2. Implementa snippets con lógica Python
  3. Crea snippets que usen transformaciones de texto
  4. Desarrolla snippets para tu framework/librería favorita

Ejercicio 3: Templates de archivos

  1. Crea templates para diferentes tipos de archivo
  2. Implementa variables dinámicas (fecha, autor, etc.)
  3. Configura auto-carga de templates
  4. Crea comando personalizado para cargar templates

Ejercicio 4: Workflow completo

  1. Desarrolla una librería completa de snippets para tu stack
  2. Organiza snippets por categorías
  3. Crea documentación para tus snippets
  4. Comparte tus snippets con el equipo

🏆 Tips Pro

1. Organización de snippets

" Estructura recomendada
~/.vim/UltiSnips/
├── all.snippets # Globales
├── web/
│ ├── html.snippets
│ ├── css.snippets
│ └── javascript.snippets
├── backend/
│ ├── python.snippets
│ └── go.snippets
└── frameworks/
├── react.snippets
├── django.snippets
└── express.snippets

2. Snippets contextuales

" Snippets que solo funcionan en contextos específicos
snippet if "if statement" b
if ${1:condition}:
${2:pass}
$0
endsnippet

# Solo en clases
snippet method "Class method" "re.search(r'class ', snip.buffer[max(0, snip.line-10):snip.line+1])" be
def ${1:method_name}(self${2:, args}):
"""${3:Method docstring.}"""
${4:pass}
$0
endsnippet

3. Snippets con validación

# Snippet que valida entrada
snippet email "Email input" w
`!p
import re
email = t[1] if t[1] else "example@email.com"
if not re.match(r'^[^@]+@[^@]+\.[^@]+$', email):
email = "example@email.com"
snip.rv = email
`$0
endsnippet

4. Debugging de snippets

" Ver snippets disponibles
:UltiSnipsEdit

" Recargar snippets después de cambios
:call UltiSnips#RefreshSnippets()

" Debug de snippets
let g:ultisnips_debug = 1

5. Integración con completado

" Mostrar snippets en completado
let g:UltiSnipsExpandTrigger = "<C-j>"
let g:UltiSnipsJumpForwardTrigger = "<C-j>"
let g:UltiSnipsJumpBackwardTrigger = "<C-k>"

" Usar Tab para completado normal y C-j para snippets
function! TabOrComplete()
if col('.') > 1 && strpart( getline('.'), col('.')-2, 3 ) =~ '^\w'
return "\<C-N>"
else
return "\<Tab>"
endif
endfunction
inoremap <Tab> <C-R>=TabOrComplete()<CR>

🔗 Integración con Otros Plugins

Con vim-surround

" Snippet que usa surround
snippet func "Function with surround" b
function ${1:name}(${2:args}) {
${3:// TODO: implement}
$0
}
endsnippet

Con auto-pairs

" Configurar para que funcione bien con snippets
let g:AutoPairsMapCR = 0
imap <silent><CR> <C-R>=AutoPairsReturn()<CR>

¡Los snippets bien organizados pueden acelerar dramáticamente tu velocidad de desarrollo!