Como modificar um buffer sem desfazer a notificação?

11

P: Como insiro / modifico o texto em um buffer sem undoperceber?

Aqui está o caso de uso. Eu tenho um bloco de comentários no início de cada arquivo que, entre outras coisas, atualiza um carimbo de data / hora para a alteração mais recente em um arquivo. Eu gostaria de poder modificar esse carimbo de data / hora sem que as undoinstalações percebam.

A razão pela qual eu quero undoentrar em curto-circuito aqui é devido ao seguinte caso extremo, que surge ao editar / compilar documentos LaTeX (e provavelmente outros, mas esse é o que mais me deixa louco):

  1. Faça uma pequena alteração no arquivo para ver como ele afetará o documento compilado
  2. Salve o arquivo (que atualiza o registro de data e hora)
  3. Executar latexno arquivo
  4. Decida que a mudança é ruim
  5. undo as mudanças

O problema na etapa (5) ( undo) é que ela não desfaz a alteração feita na etapa (1), mas desfaz a atualização do registro de data e hora na etapa (2). Isso não me incomodaria (eu poderia apenas undonovamente), exceto que também move o ponto até o carimbo de data / hora na parte superior do arquivo, que quase sempre está a muitas, muitas linhas da mudança substantiva real. É muito chocante e quebra completamente minha concentração.

Estou apresentando a pergunta em relação a um arquivo que estou visitando, mas geralmente trata-se de modificar buffers.

Então: como impedir que eu undoobserve uma modificação específica em um buffer?

Dan
fonte
11
Isso não está relacionado à sua pergunta de desfazer, mas pode ajudar com o problema "desfazer move o ponto": stackoverflow.com/a/20510025/1279369
nanny
2
Não seria melhor se essa alteração de carimbo de data fosse anexada ao item mais recente no histórico de desfazer? Dessa forma undo, desfaria os dois.
Malabarba
Eu acho que o que você realmente quer é atomic-change-group.
@ john: Como isso ajudaria? As duas alterações no grupo são acionadas por comandos separados: uma “pequena alteração” (por exemplo, uma inserção) e a atualização do carimbo de data / hora feito durante o salvamento.
Gilles 'SO- stop be evil'
Note-se que, por alguma razão nenhum destes métodos em respostas existentes trabalhado para mim, no entanto esta resposta define uma with-undo-collapsemacro que foi muito útil: emacs.stackexchange.com/a/7560/2418
ideasman42

Respostas:

6

A resposta de @ stsquad me colocou no caminho certo. Basicamente, as etapas são:

  1. Salve  buffer-undo-list
  2. desabilitar undo
  3. faça o seu
  4. reative undoe restaure obuffer-undo-list

Então, aqui está um esboço dessa função:

(defun disable-undo-one-off ()
  (let ((undo buffer-undo-list))        ; save the undo list
    (buffer-disable-undo)               ; disable undo
    (do-some-stuff)                     ; do your thing
    (buffer-enable-undo)                ; re-enable undo
    (setq buffer-undo-list undo)))      ; restore the undo list

Edit: na verdade, verifica-se que uma solução mais simples ainda é simplesmente let-bind, buffer-undo-listpara que as alterações na lista no corpo do clobber sejam bloqueadas letquando a lista original for restaurada:

(defun disable-undo-one-off ()
  (let (buffer-undo-list)
    (do-some-stuff)))

A principal limitação disso é que parece funcionar para modificações que não alteram o número de caracteres no buffer (por exemplo, alterando "gatinhos" para "filhotes", mas não "gatos"), porque, caso contrário, o restante A lista agora se refere aos pontos errados. Portanto, essa é apenas uma solução parcial .

Dan
fonte
Você pode querer envolvê-lo em uma proteção para relaxar, caso você interrompa a atividade no meio do caminho. Eu não sabia que você estava fazendo tudo isso em uma função que facilita o controle das coisas.
Stsquad
Você também pode adicionar na solução a atualização do carimbo de data / hora para não atualizar o histórico de desfazer (e histórico de pontos, se possível)?
precisa
@stsquad: boa ideia, tentarei fazer isso mais tarde. Agradecemos novamente pela dica sobre as funções e a lista em questão.
Dan
@kaushalmodi: pergunta esclarecedora: o que significa que você deseja ver a função de atualização do carimbo de data / hora real?
Dan
@ Dan Gostaria de ver como modificar a função de atualização do timestamp para não atualizar o histórico de desfazer ou ponto.
precisa
3

Uma operação de desfazer combina vários elementos da lista de desfazer . Uma nilentrada na lista marca o limite entre dois grupos de alterações. Ao remover o nilinício da lista que é automaticamente inserido pelo loop de nível superior¹, você pode agrupar a atualização do carimbo de data / hora com a última alteração no buffer, que tecnicamente não corresponde à sua solicitação, mas praticamente deve resolver o problema no seu cenário.

(defun time-stamp-group-undo ()
  (if (eq nil (car buffer-undo-list))
      (setq buffer-undo-list (cdr buffer-undo-list)))
  (time-stamp))

(Aviso: não testado, a lista de desfazer pode exigir mais massagens.)

Você também pode jogar com a lista de desfazer de uma maneira diferente, modificando a entrada da posição (um número inteiro) para a atualização do carimbo de data / hora.

¹ faz uma remoção semelhante para agrupar inserções. self-insert-command

Gilles 'SO- parar de ser mau'
fonte
2

O problema com o que você sugere é que a árvore de desfazer é uma lista de deltas para ir de onde você está e para onde você quer estar. Embora seja perfeitamente possível desativar o rastreamento de desfazer em um buffer, não tenho certeza de qual seria o efeito de não registrar ativamente as alterações. Atualmente, tenho uma alternância para ativar / desativar desfazer em um buffer específico, pois não faz sentido desfazer informações em um log crescente ou em uma página de atualização. No entanto, ele corrige as alterações ao alternar:

(defun my-toggle-buffer-undo ()
  "Toggle undo tracking in current buffer."
  (interactive)
  (with-current-buffer (current-buffer)
    (if (eq buffer-undo-list t)
        (setq buffer-undo-list nil)
      (buffer-disable-undo (current-buffer)))))

(define-key my-toggle-map "u" 'my-toggle-buffer-undo)

buffer-disable-undo, na verdade, apenas define buffer-undo-list para zero . Talvez se você salvou o estado de buffer-undo-list na alternância, poderia restaurá-lo depois?

stsquad
fonte