¿Qué se entiende por shell en modo "vi" o modo "emacs"?

32

Esta pregunta se sigue directamente de la respuesta . En este caso, específicamente no puedo entender la parte que dice:

En ese sentido, su comportamiento está más cerca de emacs 'que con el modo bash (readline) / ksh / zsh emacs, pero se aparta del editor de línea incorporado del controlador de terminal (en modo canónico), donde Ctrl-Welimina la palabra anterior (borrar, también en vi )

Aquí estamos hablando de shells y no editores, que son dos programas completamente diferentes. ¿Qué significa decir que Shell está en modo editor?

PD: Puede basar su respuesta en la premisa de que entiendo qué es un shell y cómo usar vim para la edición básica.

Friki
fuente
No se trata de la funcionalidad del shell central per se, sino de la edición de línea (lo que haces cuando haces un error tipográfico y vuelves y te corriges).
n. 'pronombres' m.

Respuestas:

27

En el modo "vi" puede editar / navegar en el indicador de shell actual como una línea en el editor vi. Puedes verlo como un archivo de texto de una línea. De manera análoga, en el modo "emacs" puede editar / navegar por la línea de comando actual utilizando (algunos) los accesos directos de Emacs.

Ejemplo

Por ejemplo, en modo vi puedes hacer algo como (en bash):

$ set -o vi
$ ls hello world
<ESC>
bbdw # results in
$ ls world

En el modo emacs, puede presionar, por ejemplo, Ctrl+ Apara saltar al comienzo de una línea (vi: Ctrl+ [, 0o ESC, 0). Puede activar el modo emacs mediante set -o emacs(en bash, ksh, zsh, etc.).

Readline

Muchos programas de línea de comandos interactivos (incluido bash ) usan la biblioteca readline . Por lo tanto, puede configurar qué modo de entrada usar (vi o emacs) y otras opciones en un solo lugar, de modo que cada programa que use readline tenga exactamente la misma interfaz de edición / navegación.

Por ejemplo, mi configuración de línea de lectura se ve así:

$ cat ~/.inputrc 
set editing-mode vi
set blink-matching-paren on

Por ejemplo, zsh / ksh no usa readline hasta donde yo sé, sino que también admite modos vi / emacs que son muy parecidos al bash / readline.

Por supuesto, el modo vi / emacs en un shell de línea de comandos es solo un subconjunto del conjunto completo de características del editor. No todas las características tienen sentido en una línea de comandos, y algunas características son más complicadas de soportar que otras.

Modo canónico

Antes de que se 'inventaran' los modos vi / emacs de los shells interactivos de la línea de comandos, su shell usaría solo el modo canónico de su terminal, que solo proporciona un conjunto limitado de comandos de edición (por ejemplo, Ctrl+ Wpara eliminar la última palabra.

maxschlepzig
fuente
Supongamos que no sé en qué modo de entrada estoy. ¿Puedo verificarlo ingresando un texto y presionando [Ctrl] + [A]? si el cursor se mueve para comenzar sus emacs, de lo contrario vi
limovala
2
@limovala, debería ser una buena aproximación. Depende de su shell, por supuesto; si CTL + A no funciona, otra posibilidad es que su shell no incluya ningún modo de edición. Quizás algunos shells también implementan otros modos de edición. Pero en la práctica, su método debería ser lo suficientemente bueno. También puede probar con un comando vi después de eso para estar más seguro. En bash también puedes usar algo como set -o | grep 'emacs\|vi'. Sin embargo, en zsh (donde tengo modo vi) esto no funciona.
maxschlepzig
bind -P también dará una buena indicación de en qué modo está uno
Paul
23

Notarás que cuando ejecutas catun indicador de comandos de shell en un terminal, catse supone que debes escribir para stdout lo que lee de stdin, y presionas a, ves un aeco del controlador del terminal, pero catno escribe eso a(ves solo uno a, el que hizo eco el controlador de terminal).

Sin embargo, si escribe a Backspace b Enter, no verá catsalida a\010b\015, pero b\012( by nueva línea).

Esto se debe a que el controlador de terminal (estamos hablando de software en el núcleo, no en el emulador de terminal xterm) implementa un editor de línea muy básico cuando está en modo canónico . El controlador de terminal se puede configurar mediante ioctl()llamadas al sistema, como cuando se usa el sttycomando. Por ejemplo, para salir del modo canónico, puedes hacerlo stty -icanon. Si lo haces:

stty -icanon; cat

Luego, verá tanto la echo(que podría haber deshabilitado con stty -echo) como la catsalida al mismo tiempo.

Ese editor es un editor de línea. Es decir, corresponde al usuario editar una línea de texto hasta que se envíe a la aplicación que lee el dispositivo terminal al presionar Enter.

Las capacidades de edición de ese editor son muy limitadas. En la mayoría de las implementaciones, solo hay 4 teclas de edición (en realidad caracteres) también configurables con stty:

  • borrar ( ^Ho ^?generalmente): borra el carácter anterior
  • kill ( ^Ugeneralmente): vacía (kill) la línea ingresada hasta ahora
  • werase ( ^W): borra la palabra anterior
  • lnext ( ^V): ingrese el siguiente carácter literalmente (cancele el significado especial de todo lo anterior)

En los viejos tiempos, se pensaba que ese editor de línea de controlador de terminal se ampliaría con capacidades más sofisticadas. Es por eso que ninguno de los primeros shells tiene capacidades de edición de línea de comando (obtendría las mismas capacidades de edición de línea en el indicador de shell que cuando se ejecuta catcomo lo hicimos anteriormente).

Sin embargo, eso realmente nunca sucedió, tal vez parte de la razón es el desorden con diferentes terminales que no envían los mismos caracteres al presionar algunas teclas, lo que hizo evidente que eso no debería implementarse en el espacio del núcleo.

Entonces, algunos shells comenzaron a abandonar el modo canónico del controlador de terminal e implementaron su propio editor de línea. En ese momento, emacsy vieran los editores de texto visual más populares con un modo de operación y enlace de teclas completamente diferente. En vi, tiene un modo para ingresar texto y otro para editar. En emacs, siempre está ingresando al modo de texto , pero la edición se realiza presionando combinaciones de teclas (como ^bmover el carácter hacia atrás).

No tenía sentido que los proyectiles en el momento presentaran sus propias ataduras de teclas diferentes. Eso habría provocado la frustración de que las personas tuvieran que aprender una diferente. Sin embargo, elegir un ( emacso vi) estilo sobre el otro habría sido una forma segura de alienar a los usuarios del otro editor.

De acuerdo con https://www.usenix.org/legacy/publications/library/proceedings/vhll/full_papers/korn.ksh.a :

Las populares funciones de edición en línea (modo vi y emacs) de ksh fueron creadas por los desarrolladores de software de Bell Laboratories; el modo de edición de línea vi de Pat Sullivan y el modo de edición de línea emacs de Mike Veach. Cada uno había modificado independientemente el shell Bourne para agregar estas características, y ambos estaban en organizaciones que querían usar ksh solo si ksh tenía su respectivo editor en línea. Originalmente, la idea de agregar la edición de línea de comando a ksh fue rechazada con la esperanza de que la edición de línea se moviera al controlador del terminal. Sin embargo, cuando quedó claro que no era probable que esto ocurriera pronto, ambos modos de edición de línea se integraron en ksh y se hicieron opcionales para que pudieran deshabilitarse en los sistemas que proporcionaban edición como parte de la interfaz del terminal.

Por lo tanto, implementaron ambos y una interfaz para que los usuarios elijan entre los dos. kshfue probablemente el primero a principios de los años 80 (reutilizando el código que se había escrito por separado para agregar un modo vi y un modo emacs al shell Bourne como se ve arriba) seguido de tcsh( tcshinicialmente solo tenía emacsenlace de teclas, el vimodo se agregó más tarde) y más tarde bashy zsha principios de los 90.

Cambia entre los dos modos en bash, zsho kshcon set -o vio set -o emacs, y con bindkey -eo bindkey -ven tcsho zsh.

POSIX realmente especifica el vimodo y no el emacsmodo para sh(la historia dice que Richard Stallman se opuso a que POSIX especificara el emacsmodo parash ).

El modo predeterminado para bash, las variantes de dominio público de ksh(pdksh, mksh, oksh), tcshy zshes el modo emacs (aunque con zsh, es visi $EDITORes tuyo vi), mientras que en AT&T ksh, es el modo tonto a menos $EDITORo $VISUALmenciona vio emacs.

kshTambién más tarde se agregó un gmacsmodo para acomodar a los usuarios de Gosling emacsque se manejan de manera Ctrl+Tdiferente.

Ahora, el manejo de ^Wen emacso en tcshmodo emacs probablemente sea anterior al werasepersonaje en el editor de línea de terminal, por lo que realmente no podemos culparlos por eso y mi declaración sobre "partir ..." puede verse como engañosa. Es solo que me resulta irritante cuando las cosas como emacs, tcsho se infocomportan de manera diferente a todo lo demás cuando escribes Ctrl-W. Puedes imaginar que me pareció mucho más irritante cuando algunas aplicaciones comenzaron a cerrar su ventana cuando escribías Ctrl-W.

Stéphane Chazelas
fuente
1
pdkshTambién analiza $EDITORpara viy cambia de modo durante el inicio; Lo eliminé para mksh(especialmente porque de todos modos solo mantengo el modo Emacs).
mirabilos
Muchas gracias además, especialmente con la discusión detallada del comportamiento y la historia de varios proyectiles. Como alguien a quien se requiere regularmente que trabaje en diferentes distribuciones con shells que no configuré, esto es extraordinariamente útil.
BryKKan
Gracias por el excelente contexto histórico. Es una pena que las funciones de edición en línea más sofisticadas no se hayan agregado al controlador de terminal en ese momento. No habría necesidad de que los programas incluyan bibliotecas como Readline. También me preguntaba por qué el modo Emacs no está especificado por POSIX, por lo que ese enlace a la justificación fue interesante. (También comparto tu frustración al ^Wcerrar ventanas).
Anthony G - justicia para Monica
1
@AnthonyGeoghegan, todavía necesitaríamos cosas como zle / readline ya que cosas como la finalización de nombre de archivo / comando realmente no se podían hacer en el controlador de terminal.
Stéphane Chazelas