Bueno, para tener una función de ejecutar una sola vez en un rango, añada la palabra clave range
. P.ej.
fun Foo() range
...
endfun
Luego, su función puede hacerse cargo de la estufa misma con los parámetros especiales un lugar de primera línea: y un: lastline. (Ver :help a:firstline
para más detalles.)
Sin embargo creo que en este caso sus requisitos son justo lo suficientemente simple para ser logrado con una sola línea usando :global
.
Podríamos hacer realmente con mejores entradas y salidas especificadas. Pero suponiendo un archivo que contiene
Item a: <total>
Subitem: 10 min
Subitem 2: 20 min
Item b: <total>
Subitem: 10 min
Subitem 2: 23 min
Item c: <total>
Subitem: 10 min
Subitem 2: 23 min
Subitem 3: 43 min
y una función definida como
fun! Sum(n)
let g:s += a:n
return a:n
endfun
entonces esto va a resumir los subelementos (una sola línea)
:g/^Item/ let g:s = 0 | mark a | +,-/\nItem\|\%$/ s/\v(\d+)\ze\s+min$/\=Sum(submatch(0))/g | 'a s/<total>/\=(g:s . ' min')/
y producir esta salida
Item a: 30 min
Subitem: 10 min
Subitem 2: 20 min
Item b: 33 min
Subitem: 10 min
Subitem 2: 23 min
Item c: 76 min
Subitem: 10 min
Subitem 2: 23 min
Subitem 3: 43 min
Por cierto, el comando anterior actúa en todo el búfer. Si primero resalta un rango y luego presiona la tecla :
, vim precederá automáticamente a su comando con '<,'>
, lo que significa que el siguiente comando funcionará desde el principio hasta el final del rango resaltado.
E.g. destacando las líneas 1 a 5 y después de ejecutar el comando (:'<,'> g/...
) produce esta salida
Item a: 30 min
Subitem: 10 min
Subitem 2: 20 min
Item b: 33 min
Subitem: 10 min
Subitem 2: 23 min
Item c: <total>
Subitem: 10 min
Subitem 2: 23 min
Subitem 3: 43 min
Una nota final. Si uno de los grupos no tiene subtemas, p.
Item a: <total>
Subitem: 10 min
Subitem 2: 20 min
Item b: <total>
Item c: <total>
Subitem: 10 min
Subitem 2: 23 min
Subitem 3: 43 min
y el comando abortará con un error de 'Rango no válido' cuando llegue al segundo elemento. Puede hacer que Vim ignore este y continuar independientemente al agregar todo el comando al :silent!
.
EDITAR
Sólo una explicación rápida de mi flujo de trabajo y por qué el largo de una sola línea.
- Me gusta
:g
y ex comandos mucho.
- Creé el comando de forma interactiva usando el historial de línea de comandos y la ventana de línea de comandos para editar.
- Cuando termino, pego comandos únicos como este en el búfer: tengo una asignación para ejecutar la línea actual como un comando ex. De esa forma, el comando siempre está disponible fácilmente cuando lo necesito. Para un uso más regular, es posible que desee un comando, función o ftplugin.
es hermosa ... ... En serio, gracias por la mejor respuesta, así que he probablemente he recibido. –
Por cierto, para cualquiera que piense que el comando: g anterior parece complejo, en realidad no lo es. La sintaxis es muy escueta y podría darle esa apariencia, pero las operaciones son bastante sencillas; no hay trucos inteligentes. Simplemente busque los bits que no encuentra en la maravillosa documentación, o pregunte en SO o en el grupo de vim_use Google. – 1983
Me tomó mucho tiempo entender ... así que aquí es una explicación: : g se inicia un comando global /^/elemento se ejecuta el comando en cada línea que coincide con^artículo Sea G: s = 0 marque un Almacena la posición del cursor en +, -/\ nArtículo \ | \% $/s/\ v (\ d +) \ ze \ s + min $/\ = Suma (submatch (0))/g Esta es una bestia masiva de un comando sustituto. La parte hasta la primera 's' es el rango, la parte entre la 's' y '$' es el patrón y la llamada de función es la sustitución (nada es realmente reemplazado) 'a Regrese a la posición marcó un s//\ = (g: s 'min')/ finalmente reemplaza el –