Como mover persistentemente o cursor em um buffer diferente do atual?

8

Nota: O post Como mover o ponto para o final de outro buffer, usando `with-current-buffer` e` goto-char`? presumivelmente, faz a mesma pergunta que esta, mas as respostas dadas a ela não se aplicam prontamente ao meu caso aqui. Por exemplo, essas respostas envolvem a inserção de texto no outro buffer, etc. A pergunta que estou fazendo aqui é consideravelmente mais simples, e espero que a resposta seja igualmente simples.


Suponha que

  • o quadro do Emacs é dividido em duas janelas, onde uma das janelas contém um buffer chamado *whatever*e a outra contém o *scratch*buffer padrão ;
  • o *whatever*buffer contém várias linhas de texto;
  • o cursor no *whatever*buffer está no início desse buffer (ou seja, no seu (point-min));
  • o *scratch*buffer é o atual;

Se agora eu avaliar qualquer um dos seguintes no *scratch*buffer, a posição do cursor no *whatever*buffer permanecerá inalterada:

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

Eu acho que, o que (goto-char (point-max))quer que (end-of-buffer)faça ou a *whatever*posição do cursor seja descartado posteriormente.

  1. Como devo modificar qualquer um dos trechos acima para que o cursor*whatever* do buffer seja posicionado (persistentemente!) No final desse buffer.

  2. O que eu deveria ter feito para responder a essa pergunta usando os documentos do Emacs? Eu tentei tudo o que conseguia pensar.


Depois de ler a resposta esclarecedora de Jules Tamagnan, percebi que precisava explicitar mais uma estipulação:

Estou procurando uma solução que funcione independentemente do buffer em questão ser visível em uma janela ou não.

Afinal, se eu visualizar o buffer B em uma janela W , mover o cursor para um local específico L , exibir outro buffer C na mesma janela W e finalmente apontar W de volta para o buffer B , espero ver o cursor em o mesmo local L onde eu o deixei. IOW, deve haver uma maneira de um buffer lembrar onde está o seu ponto, independentemente de estar associado a uma janela ou não.

E o caso em que o buffer de destino está atualmente visível em duas ou mais janelas ( W1 , W2 , W3 , ...)? Existem muitas possibilidades razoáveis ​​para este caso. A solução proposta pode, por exemplo, alterar a posição do cursor

  • na janela ativa mais recente entre W1 , W2 , W3 , ...;
  • em todas as janelas W1 , W2 , W3 , ...; ou
  • etc etc.

(Não tenho uma opinião forte sobre esse caso de canto, pois espero que seja extremamente raro na prática.)

kjo
fonte
11
As seções principais deste manual são Ponto e Ponto da janela .
Cjm 06/04

Respostas:

9

Essa foi uma pergunta bem legal, eu aprendi muita coisa que não sabia ao tentar descobrir isso. O que eu aprendi foi que cada janela tem seu próprio valor point. Isso é importante porque significa que o ponto não está associado ao buffer, mas à janela real. Como vimos, isso faz uma grande diferença.

O que precisamos fazer então é definir o valor do ponto na janela, a função para isso é set-window-point(eu encontrei isso no google, acho que se não souber por onde começar a procurar na compilação no emacs-docs procurando no google pode lançar alguma luz). Precisamos então dizer set-window-pointqual janela selecionar. Para fazer isso eu usei get-buffer-window(mais uma vez eu usei o google para encontrar isso).

Este código só funcionará se o buffer estiver aberto em uma janela. É possível criar outra versão onde você abre o buffer em uma janela, define o ponto e volta à configuração original da janela. O código abaixo é muito mais simples.

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

Espero que isso ajude, se você tiver outras perguntas ou se não funcionar exatamente como deseja, deixe-me saber.

Jules
fonte
Isso faz sentido; se você abrir um buffer em 2 janelas (por exemplo, através da janela dividida), você terá 2 pontos independentes.
196 Juancho
@ Juancho Sim, no fundo eu sabia que era assim que funcionava, mas que nunca realmente afundou até agora
Jules
6

( A resposta de Jules Tamagnan identifica o problema, eu o expandirei.)

Suas soluções com save-excursionou de save-excursionfato funcionam! Você pode vê-lo verificando o valor (point)desse buffer posteriormente, por exemplo,

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

sempre retorna 42 (desde que seja uma posição válida no buffer. Isso é mencionado ainda como uma pegadinha na documentação de save-excursion: restaura apenas a posição no buffer original, não a posição em qualquer outro buffer.

Se você achar que a posição do buffer não é a que você definiu, é porque outra coisa está mudando, e essa coisa provavelmente é uma janela (ou um gancho em algum lugar, mas a maioria dos ganchos não tem nada a ver com isso - ainda assim, poderia ser um gancho de saída do processo, por exemplo). Na documentação sobre o ponto , há uma observação:

Cada buffer possui seu próprio valor de point, que é independente do valor de point em outros buffers. Cada janela também possui um valor de point, que é independente do valor de point em outras janelas no mesmo buffer. É por isso que point pode ter valores diferentes em várias janelas que exibem o mesmo buffer. Quando um buffer aparece em apenas uma janela, o ponto do buffer e o ponto da janela normalmente têm o mesmo valor; portanto, a distinção raramente é importante. Consulte Ponto da janela , para mais detalhes.

Se o buffer for mostrado em uma janela, o ponto do buffer será atualizado para o ponto da janela toda vez que o ponto for alterado ou a janela for exibida novamente. Como conseqüência, definir o ponto basicamente dura apenas enquanto o código Lisp durar: assim que o loop de comando de nível superior assume o controle, a janela é exibida novamente (mesmo que não seja visível, tanto quanto eu saiba) e o a posição do buffer é substituída. Com efeito, a posição escolhida pelo usuário supera a posição escolhida pelo programa.

Se você também deseja atualizar o ponto de qualquer janela que exibe o buffer, pode chamar get-buffer-window-listpara enumerar as janelas:

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

Mas considere que, se o usuário estava visitando o buffer, talvez não gostasse de mudar o ponto debaixo do nariz.

Até onde eu sei, o Emacs não rastreia quando as janelas foram selecionadas (isso é "ativo" na terminologia do Emacs), você só pode saber se elas estão atualmente selecionadas. Se você começar a se preocupar com as janelas selecionadas, lembre-se de que cada quadro tem uma janela selecionada, e o Emacs nem sempre sabe quando os quadros são selecionados ( (selected-frame)não corresponde completamente à experiência do usuário final, especialmente com quadros dentro de emuladores de terminal, pois o Emacs não tem como para saber quando o usuário tem a janela do emulador de terminal ativa).

Gilles 'SO- parar de ser mau'
fonte