Wie bewege ich den Cursor dauerhaft in einem anderen als dem aktuellen Puffer?

8

NB: Der Beitrag Wie verschiebe ich einen Punkt an das Ende eines anderen Puffers, indem ich "with-current-buffer" und "goto-char" verwende? Vermutlich stellt sich dieselbe Frage wie diese, aber die Antworten darauf lassen sich hier nicht ohne weiteres auf meinen Fall übertragen. Diese Antworten beinhalten beispielsweise das Einfügen von Text in den anderen Puffer usw. Die Frage, die ich hier stelle, ist erheblich einfacher, und ich erwarte, dass die Antwort darauf auch entsprechend einfach sein sollte.


Nehme an, dass

  • Der Emacs-Frame ist in zwei Fenster unterteilt, wobei eines der Fenster einen aufgerufenen Puffer *whatever*und das andere den Standardpuffer enthält *scratch*.
  • Der *whatever*Puffer enthält mehrere Textzeilen.
  • der Cursor im *whatever*Puffer befindet sich am Anfang dieses Puffers (dh an seinem (point-min));
  • der *scratch*Puffer ist der aktuelle;

Wenn ich jetzt Folgendes im *scratch*Puffer auswerte , *whatever*bleibt die Position des Cursors im Puffer unverändert:

 (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))

Ich vermute , dass, was auch immer (goto-char (point-max))oder (end-of-buffer)tut *whatever*Position ‚s Cursor anschließend verworfen wird.

  1. Wie muss ich eines der obigen Snippets so ändern, dass der Cursor des *whatever*Puffers (dauerhaft!) Am Ende dieses Puffers positioniert wird?

  2. Was hätte ich tun sollen, um diese Frage mithilfe der Emacs-Dokumente selbst zu beantworten? Ich habe alles versucht, was mir einfiel.


Nachdem ich Jules Tamagnans aufschlussreiche Antwort gelesen hatte, wurde mir klar, dass ich eine weitere Bestimmung explizit machen muss:

Ich suche nach einer Lösung, die unabhängig davon funktioniert, ob der betreffende Puffer in einem Fenster sichtbar ist oder nicht.

Wenn ich Puffer B in einem Fenster W ansehe, den Cursor an eine bestimmte Stelle L bewege , dann einen anderen Puffer C im selben Fenster W ansehe und schließlich W zurück zu Puffer B zeige , erwarte ich, dass sich der Cursor an befindet der gleiche Ort L, an dem ich es verlassen habe. IOW, es muss eine Möglichkeit geben, dass sich ein Puffer daran erinnert, wo sich sein Punkt befindet, unabhängig davon, ob er einem Fenster zugeordnet ist oder nicht.

Was ist mit dem Fall, in dem der Zielpuffer derzeit in zwei oder mehr Fenstern sichtbar ist ( W1 , W2 , W3 , ...)? Für diesen Fall gibt es viele vernünftige Möglichkeiten. Die vorgeschlagene Lösung könnte beispielsweise die Position des Cursors ändern

  • im zuletzt aktiven Fenster zwischen W1 , W2 , W3 , ...;
  • in allen Fenstern W1 , W2 , W3 , ...; oder
  • usw. usw.

(Ich habe keine feste Meinung zu diesem Eckfall, da ich davon ausgehe, dass er in der Praxis äußerst selten ist.)

kjo
quelle
1
Die wichtigsten Abschnitte im Handbuch sind Punkt und Fensterpunkt .
CJM

Antworten:

9

Das war eine ziemlich coole Frage, ich habe viel gelernt, was ich nicht wusste, als ich versuchte, das herauszufinden. Was ich gelernt habe war, dass jedes Fenster seinen eigenen Wert für hat point. Dies ist wichtig, da dies bedeutet, dass der Punkt nicht dem Puffer, sondern dem eigentlichen Fenster zugeordnet ist. Wie wir gesehen haben, macht dies einen großen Unterschied.

Was wir dann tun müssen, ist den Wert des Punktes im Fenster festzulegen, die Funktion dafür ist set-window-point(ich habe dies über Google gefunden, ich finde, wenn ich nicht weiß, wo ich anfangen soll, in dem Build in emacs-docs zu suchen ein Blick auf Google kann etwas Licht ins Dunkel bringen). Wir müssen dann sagen, set-window-pointwelches Fenster wir auswählen sollen. Um das zu tun, habe ich verwendet get-buffer-window(wieder habe ich Google verwendet, um dies zu finden).

Dieser Code funktioniert nur, wenn der Puffer in einem Fenster geöffnet ist. Eine andere Version sollte erstellt werden können, in der Sie den Puffer in einem Fenster öffnen, den Punkt festlegen und dann zur ursprünglichen Fensterkonfiguration zurückkehren. Der folgende Code ist jedoch viel einfacher.

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

Ich hoffe, das hilft, wenn Sie weitere Fragen haben oder wenn es nicht genau so funktioniert, wie Sie es möchten, lassen Sie es mich einfach wissen.

Jules
quelle
Das macht Sinn; Wenn Sie einen Puffer in 2 Fenstern öffnen (z. B. über ein geteiltes Fenster), haben Sie 2 unabhängige Punkte.
Juancho
@ Juancho Ja, tief im Inneren wusste ich, dass es so funktioniert, aber es ist bis jetzt nie wirklich eingesunken
Jules
6

( Jules Tamagnans Antwort identifiziert das Problem, ich werde es erweitern.)

Ihre Lösungen mit save-excursionoder save-excursionfunktionieren tatsächlich! Sie können es sehen, indem Sie anschließend den Wert von (point)in diesem Puffer überprüfen , z

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

Gibt immer 42 zurück (vorausgesetzt, es handelt sich um eine gültige Position im Puffer. Dies wird in der Dokumentation von sogar als Gotcha erwähnt save-excursion: Es wird nur die Position im ursprünglichen Puffer wiederhergestellt, nicht die Position in einem anderen Puffer.

Wenn Sie feststellen, dass die Pufferposition nicht die von Ihnen festgelegte ist, liegt dies daran, dass etwas anderes sie ändert, und das Ding ist höchstwahrscheinlich ein Fenster (oder irgendwo ein Haken, aber die meisten Haken haben nichts damit zu tun, den Punkt zu verfälschen - immer noch, Es könnte sich beispielsweise um einen Prozessausgabehaken handeln. In der Dokumentation zu Punkt gibt es einen Hinweis:

Jeder Puffer hat seinen eigenen Punktwert, der unabhängig vom Punktwert in anderen Puffern ist. Jedes Fenster hat auch einen Punktwert, der unabhängig vom Punktwert in anderen Fenstern desselben Puffers ist. Aus diesem Grund kann point in verschiedenen Fenstern unterschiedliche Werte haben, die denselben Puffer anzeigen. Wenn ein Puffer nur in einem Fenster angezeigt wird, haben der Pufferpunkt und der Fensterpunkt normalerweise den gleichen Wert, sodass die Unterscheidung selten wichtig ist. Weitere Informationen finden Sie unter Fensterpunkt .

Wenn der Puffer in einem Fenster angezeigt wird, wird der Punkt des Puffers jedes Mal auf den Punkt des Fensters aktualisiert, wenn sich der Punkt ändert oder das Fenster erneut angezeigt wird. Infolgedessen dauert das Festlegen des Punkts im Grunde nur so lange, wie Ihr Lisp-Code gültig ist: Sobald die Befehlsschleife auf oberster Ebene die Kontrolle übernimmt, wird das Fenster erneut angezeigt (auch wenn es nicht sichtbar ist, soweit ich das beurteilen kann) und das Pufferposition wird überschrieben. Tatsächlich übertrifft die vom Benutzer gewählte Position die vom Programm gewählte Position.

Wenn Sie auch den Punkt eines Fensters aktualisieren möchten, in dem der Puffer angezeigt wird, können Sie aufrufen, get-buffer-window-listum die Fenster aufzulisten:

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

Bedenken Sie jedoch, dass der Benutzer, wenn er den Puffer besucht, es möglicherweise nicht zu schätzen weiß, wenn der Punkt unter seiner Nase geändert wird.

Soweit ich weiß, verfolgt Emacs nicht, wann Fenster ausgewählt wurden (das ist in der Emacs-Terminologie „aktiv“), Sie können nur wissen, ob sie aktuell ausgewählt sind. Wenn Sie sich um ausgewählte Fenster kümmern, achten Sie darauf, dass jeder Frame ein ausgewähltes Fenster hat und Emacs nicht immer weiß, wann Frames ausgewählt sind ( (selected-frame)entspricht nicht vollständig der Endbenutzererfahrung, insbesondere bei Frames in Terminalemulatoren, da Emacs keine Möglichkeit hat um zu wissen, wann der Benutzer das Terminalemulatorfenster aktiv hat).

Gilles 'SO - hör auf böse zu sein'
quelle