¿Cómo usar un comando externo en Vim para modificar palabras y líneas seleccionadas?


22

Algo que he encontrado útil en otros editores es la capacidad de:

  • tomar el texto seleccionado
  • ejecutar un comando externo y pasar la selección a su stdin
  • tome los comandos externos stdouty reemplace la selección actual con él.

De esta forma, puede escribir herramientas de texto útiles que operan en la selección utilizando cualquier idioma que pueda hacer io básico.

¿Cómo se puede hacer esto con vim usando la selección? ... un solo carácter, palabra, párrafo ... etc.

(¿Directamente en la línea de comando o mediante un enlace de teclas?)


Nota

Comandos como !sorttrabajar en el nivel de línea, la razón por la que hago esta pregunta es porque me gustaría operar en la selección. (es decir, el texto que se eliminaría si xse presionara).

Respuestas:


17

Creo que a menudo la forma más fácil es usar el modo visual con v(o mayúsculas Vpara seleccionar líneas enteras) y seleccionar el texto que desea canalizar.

Luego escriba:

:!cat

Esto no hace nada útil, como tal. Un comando útil que uso a menudo es:

:!python -m json.tool

para formatear JSON.

También puede simplemente escribir (sin modo visual):

:<range>!command

Por ejemplo, para todo el archivo:

:%!python -m json.tool

O para la línea actual:

:.!python -m json.tool

Otra herramienta realmente útil para usar con esto es el sortcomando.
Cody Poll

44
@CodyPoll ¿Qué pasa con Vim's :sort?
Martin Tournoij

55
@Carpetsmoker El comando de ordenamiento externo tiene muchas más opciones y (dependiendo de la configuración regional, etc.) produce un orden diferente.
derobert

1
Esto no funciona para seleccionar una sola palabra en una línea. (véase la pregunta menciona selección de nivel de palabra)
ideasman42

@ ideasman42 Correcto ... Creo que originalmente leí esta pregunta como "líneas o palabras" en lugar de "líneas y palabras" ... En cualquier caso, hacer esto con palabras no es obvio, los programas UNIX funcionan en líneas, y Vim no es una excepción. Experimenté un poco y de alguna manera tengo una solución, pero no funciona muy bien ... Tal vez mi enfoque es incorrecto, así que lo dejaré por unos días y volveré a ello más tarde.
Martin Tournoij

7

Escribí un complemento llamado express.vim que puede ayudar con esto. El complemento define un operador g=que le permite evaluar una expresión de VimScript sobre un movimiento (o selección visual). Solicita una expresión, en la que puede usar v:valcomo marcador de posición para el texto cubierto por el movimiento (o, de nuevo, la selección Visual).

En este caso, una expresión útil usaría la system()función, que ejecuta un comando externo.

system('tr a-z A-Z', v:val)

(Aquí utilicé trcomo ejemplo un comando externo simple).

La forma de usar express.vim para este problema sería seleccionar el texto con el modo Visual, luego escribir g=seguido de esa expresión, luego presionar Enter:

g=system('tr a-z A-Z', v:val)<CR>

Lo admito, no es fácil de usar. (De hecho, ¡rara vez uso este complemento yo mismo!) Estoy considerando agregar un acceso directo para invocar un comando externo, como comenzar la expresión con !. Publicaré una actualización aquí si termino haciendo eso.

EDITAR

Modifiqué express.vim para tratar expresiones que comienzan !como comandos externos. Entonces, siguiendo el trejemplo, lo anterior se vuelve mucho más simple. Después de una selección visual, escriba lo siguiente:

g=!tr a-z A-Z<CR>

Explicación:

  1. Invoque al operador express con g=
  2. Ingrese !tr a-z A-Zcomo la expresión
  3. prensa Enter

4

Está buscando los comandos de filtro en Vim. Ver :help filter. Aquí está la documentación relevante:

!{motion}{filter}   Filter {motion} text lines through the external
                    program {filter}.
!!{filter}          Filter [count] lines through the external program
                    {filter}.
{Visual}!{filter}   Filter the highlighted lines through the external
                    program {filter} (for {Visual} see |Visual-mode|).
                    {not in Vi}

:{range}![!]{filter} [!][arg]               *:range!*
                    Filter {range} lines through the external program
                   {filter}.  ...[See documentation for details]

Por lo tanto, al escribir 5!!sortse ordenarán las siguientes 5 líneas a partir del cursor.


¿Es posible filtrar una sola palabra? (no nivel de línea)
ideasman42

Sí. La tercera opción (modo visual) funciona para lo que esté resaltado (palabras, línea parcial, líneas múltiples, bloque rectangular, etc.).
Sameer

1
La tercera opción también filtra líneas enteras. Si selecciona una sola palabra y la filtra, por ejemplo, a través tr [:lower:] [:upper], entonces vim mostrará no solo esta palabra sino toda la línea.
Maria s

0

Tenga en cuenta que se puede hacer con:

  1. selecciona visualmente lo que quieras
  2. s^R=system('tr a-z A-Z', @")[:-2]^M(con ^RCTRL + R y ^ M siendo ENTER)

También podría funcionar con cualquier cosa que haga selección + reemplazar como ci"^R=....


Cuando ejecuto esto en una selección de texto de varias líneas (después de presionar vy mover el cursor) me sale el error E16: Invalid range\nE16: Invalid range\nE476: Invalid command(en Linux try existen otros comandos básicos).
ideasman42

¿Has presionado sque entra en modo de inserción o :sel comando?
Luc Hermitte

Sospechoso no, pero tampoco estoy seguro de cómo te refieres, ¿tal vez el ejemplo podría mostrar cómo vincular esto a una tecla?
ideasman42

¿Golpea directamente sdesde el modo visual, o golpea :primero? No hay nada :involucrado en la secuencia de teclas que he escrito. Un mapeo sería: vnoremap µ s<c-r>=system('tr a-z A-Z', @")[:-2]<cr>.
Luc Hermitte
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.