¿Cómo mover el cursor de forma persistente en un búfer diferente al actual?

8

NB: La publicación ¿Cómo mover el punto al final de otro búfer, usando `with-current-buffer` y` goto-char`? presumiblemente hace la misma pregunta que esta, pero las respuestas que se le dan no se aplican fácilmente a mi caso aquí. Por ejemplo, esas respuestas implican insertar texto en el otro búfer, etc. La pregunta que hago aquí es considerablemente más simple, y espero que la respuesta también sea correspondientemente simple.


Suponer que

  • el marco de Emacs se divide en dos ventanas, donde una de las ventanas contiene un búfer llamado *whatever*y el otro contiene el *scratch*búfer estándar ;
  • el *whatever*búfer contiene varias líneas de texto;
  • el cursor en el *whatever*búfer está al comienzo de ese búfer (es decir, en su (point-min));
  • el *scratch*búfer es el actual;

Si ahora evalúo alguno de los siguientes en el *scratch*búfer, la posición del cursor en el *whatever*búfer permanece sin cambios:

 (with-current-buffer "*whatever*"
   (goto-char (point-max)))
 (with-current-buffer "*whatever*"
   (end-of-buffer))
 (save-excursion
   (set-buffer "*whatever*")
   (goto-char (point-max)))
 (save-excursion
   (set-buffer "*whatever*")
   (end-of-buffer))

Me imagino que, sea lo que sea (goto-char (point-max))o (end-of-buffer)haga *whatever*, la posición del cursor se descarta posteriormente.

  1. ¿Cómo debo modificar cualquiera de los fragmentos anteriores para que el cursor*whatever* del búfer se posicione (¡persistentemente!) Al final de ese búfer.

  2. ¿Qué debería haber hecho para responder esta pregunta yo mismo usando los documentos de Emacs? Intenté todo lo que se me ocurrió.


Después de leer la respuesta iluminadora de Jules Tamagnan, me di cuenta de que necesito hacer una estipulación adicional explícita:

Estoy buscando una solución que funcione independientemente de si el búfer en cuestión es visible en una ventana o no.

Después de todo, si veo el búfer B en una ventana W , muevo el cursor a una ubicación particular L , luego veo algún otro búfer C en la misma ventana W y finalmente apunto W nuevamente al búfer B , espero ver el cursor en el mismo lugar L donde lo dejé. IOW, debe haber una manera para que un búfer recuerde dónde está su punto, independientemente de si está asociado con una ventana o no.

¿Qué pasa con el caso en el que el búfer de destino está actualmente visible en dos o más ventanas ( W1 , W2 , W3 , ...)? Hay muchas posibilidades razonables para este caso. La solución propuesta podría, por ejemplo, cambiar la posición del cursor

  • en la ventana activa más reciente entre W1 , W2 , W3 , ...;
  • en todas las ventanas W1 , W2 , W3 , ...; o
  • etcétera etcétera.

(No tengo una opinión sólida sobre este caso de esquina, ya que espero que sea extremadamente raro en la práctica).

kjo
fuente
1
Las secciones clave en el manual con respecto a esto son Punto y Punto de ventana .
cjm

Respuestas:

9

Esta fue una pregunta genial, aprendí mucho que no sabía al tratar de resolver esto. Lo que aprendí fue que cada ventana tiene su propio valor point. Esto es importante porque significa que el punto no está asociado con el búfer sino con la ventana real. Como hemos visto, esto hace una gran diferencia.

Lo que debemos hacer es establecer el valor del punto en la ventana, la función para eso es set-window-point(encontré esto a través de google, encuentro que si no sé por dónde empezar a buscar en la compilación en emacs-docs mirar en google puede arrojar algo de luz). Luego necesitamos decir set-window-pointqué ventana seleccionar. Para hacer eso usé get-buffer-window(una vez más usé google para encontrar esto).

Este código solo funcionará si el búfer está abierto en una ventana. Se debe poder crear otra versión donde abra el búfer en una ventana, establezca el punto y luego vuelva a la configuración original de la ventana. Sin embargo, el código a continuación es mucho más simple.

(set-window-point (get-buffer-window "*whatever*") (point-max))

Espero que esto ayude, si tiene alguna otra pregunta o si no funciona exactamente como lo desea, hágamelo saber.

Jules
fuente
Esto tiene sentido; Si abre un búfer en 2 ventanas (por ejemplo, a través de una ventana dividida), tiene 2 puntos independientes.
Juancho
@Juancho Sí, en el fondo sabía que así era como funcionaba, pero nunca se hundió hasta ahora
Jules
6

( La respuesta de Jules Tamagnan identifica el problema, lo ampliaré ).

¡Sus soluciones con save-excursiono save-excursionrealmente funcionan! Puede verlo comprobando el valor de (point)en ese búfer después, por ejemplo

(progn
  (with-current-buffer "*whatever*"
    (goto-char 42))
  (with-current-buffer "*whatever*"
    (point)))

siempre devuelve 42 (siempre que sea una posición válida en el búfer. Eso incluso se menciona como un problema en la documentación de save-excursion: restaura solo la posición en el búfer original, no la posición en ningún otro búfer.

Si encuentra que la posición del búfer no es la que configuró, eso se debe a que algo más la está cambiando, y lo más probable es que sea una ventana (o un gancho en alguna parte, pero la mayoría de los ganchos no tienen problemas con el punto, aún así, podría ser, por ejemplo, un enlace de salida del proceso). En la documentación sobre el punto , hay una nota:

Cada búfer tiene su propio valor de punto, que es independiente del valor del punto en otros búferes. Cada ventana también tiene un valor de punto, que es independiente del valor de punto en otras ventanas en el mismo búfer. Es por eso que el punto puede tener diferentes valores en varias ventanas que muestran el mismo búfer. Cuando un búfer aparece en una sola ventana, el punto del búfer y el punto de la ventana normalmente tienen el mismo valor, por lo que la distinción rara vez es importante. Ver Window Point , para más detalles.

Si el búfer se muestra en una ventana, entonces el punto del búfer se actualiza al punto de la ventana cada vez que el punto cambia o se vuelve a mostrar la ventana. Como consecuencia, establecer el punto básicamente solo dura el tiempo que dura su código Lisp: tan pronto como el bucle de comando de nivel superior toma el control, la ventana se vuelve a mostrar (incluso si no es visible, por lo que puedo decir) y el la posición del búfer se anula. En efecto, la posición elegida por el usuario prevalece sobre la posición elegida por el programa.

Si desea actualizar también el punto de cualquier ventana que muestre el búfer, puede llamar get-buffer-window-listpara enumerar las ventanas:

(with-current-buffer "*whatever*"
  (goto-char …)
  (cl-dolist (window (get-buffer-window-list nil nil t))
    (set-window-point window (point))))

Pero tenga en cuenta que si el usuario visitaba el búfer, es posible que no aprecie que cambien el punto bajo sus narices.

Por lo que sé, Emacs no rastrea cuándo se seleccionaron las ventanas (eso es "activo" en la terminología de Emacs), solo puede saber si están seleccionadas actualmente. Si comienza a preocuparse por las ventanas seleccionadas, tenga en cuenta que cada marco tiene una ventana seleccionada, y Emacs no siempre sabe cuándo se seleccionan los marcos ( (selected-frame)no coincide completamente con la experiencia del usuario final, especialmente con los marcos dentro de los emuladores de terminal ya que Emacs no tiene forma saber cuándo el usuario tiene activa la ventana del emulador de terminal).

Gilles 'SO- deja de ser malvado'
fuente