Gancho que indica quando o cursor foi movido rolando

7

Inspirado por esta pergunta: Deixe o Emacs mover o cursor para fora da tela , estou pensando em escrever um modo secundário que manterá o cursor em uma posição fixa que não seja afetada pelas operações de rolagem. Tenho algumas idéias de como implementar isso, mas seria necessário um gancho para me informar quando o cursor está sendo "empurrado" para fora da tela.

Em algum lugar dentro das entranhas do Emacs, existe um código chamado quando a localização de pointé removida da tela. Embora tenha sido dito que o código que controla esse comportamento vive profundamente com o código-fonte C, eu gostaria de saber se há alguma maneira de ser notificado quando estiver prestes a acontecer.

Existe alguma maneira de ser notificado quando um comando de rolagem estiver prestes a mover o cursor? Ou pelo menos, existe uma maneira de eu ser notificado quando a tela estiver prestes a ser rolada?


Atualização: não estou mais planejando escrever um modo menor para conseguir isso, porque um novo pacote foi lançado no GNU ELPA chamado scroll-restoreque fornece exatamente os recursos que eu estava pensando em me implementar!

nispio
fonte

Respostas:

5

Sim .

As funções em window-scroll-functionssão chamadas imediatamente antes de uma nova exibição que causaria rolagem. Cada função retorna dois argumentos, a janela windowe a nova posição inicial da janela new-start. Você pode ligar para obter a posição inicial da janela atual, obter a posição final da janela atual e obter a nova posição final da janela. Se o ponto não estiver entre e , está prestes a ser movido. Até onde eu sei, essas funções são chamadas em todos os casos que alteram a extensão de uma janela, incluindo rolagem e redimensionamento. Eles também são chamados quando uma janela começa a mostrar um buffer (porque ele acabou de ser criado ou porque agora está mostrando um novo buffer).(window-start window)(window-end window)(window-end window t)new-start(window-end window t)

Para fazer com que os comandos de rolagem pareçam não mover o ponto, você provavelmente desejará salvar o ponto atual neste gancho e fazer alguma coisa post-command-hook. Como o ponto precisará se mover devido à rolagem, você provavelmente o salvará e o restaurará pre-command-hook.

Gilles 'SO- parar de ser mau'
fonte
11
Excelente! Devo admitir que não esperava que a resposta fosse "sim".
Nispio 15/10
Existe algo parecido (window-start)com rolagem horizontal? (observe que window-hscrollnão realiza o trabalho quando a fonte no buffer é diferente da fonte padrão).
AlwaysLearning
1

A resposta do @Gilles é o caminho certo a seguir. Vou manter este aqui para obter informações e hacks.

Eu acredito que o pointmovimento é realizado pelas funções C window_scroll_line_basede window_scroll_pixel_based(dependendo dos parâmetros do seu quadro). Essas funções não estão expostas à máquina lisp, portanto você não pode aconselhá-las. Você precisaria aconselhar as funções que os chamam.

Duas das funções (acessíveis pelo Lisp) que podem fazer isso são scroll-upe scroll-down. Aqui está como eu descobri sobre eles:

  1. Vá para algum buffer longo.
  2. Selecione uma pequena região.
  3. Ligue para M-x (put-text-property (region-beginning) (region-end) 'point-left (lambda (&rest _) (error "Point leaving"))). Isso gerará um erro quando o ponto sair da região.
  4. Ative M-x toggle-debug-on-error.
  5. Verifique se o ponto está dentro desta região.
  6. Role com a roda do mouse até que o ponto seja arrastado para fora da região.

Você receberá um buffer de backtrace como este, que indica claramente a scroll-downfunção.

Debugger entered--Lisp error: (error "Point leaving")
  signal(error ("Point leaving"))
  error("Point leaving")
  (lambda (&rest _) (error "Point leaving"))(1508 1192)
  scroll-down(10)
  funcall(scroll-down 10)
  mwheel-scroll((double-mouse-4 (#<window 50 on *Backtrace*> 1299 (578 . 545) 77086296 nil 1299 (57 . 25) nil (398 . 20) (10 . 21)) 2))
  funcall-interactively(mwheel-scroll (double-mouse-4 (#<window 50 on *Backtrace*> 1299 (578 . 545) 77086296 nil 1299 (57 . 25) nil (398 . 20) (10 . 21)) 2))
  call-interactively(mwheel-scroll nil nil)
  command-execute(mwheel-scroll)

Eu segui scroll-downa sua definição C, que me levou a window_scroll, o que me levou a essas duas funções acima.

O que você pode fazer

Você pode aconselhar scroll-down/upcom um aroundconselho (assim como outras funções que também possam resultar em movimento de pontos). Use este conselho para verificar se a posição de pointmudou e registre a posição antiga. E então faça o que quiser com ele.

Esteja avisado, os conselhos não são muito confiáveis ​​quando se trata de funções C. Algumas funções importantes têm endereços especiais no código compilado em bytes, o que significa que conselhos sobre eles não são chamados quando o código é compilado. Acho que não será o caso aqui, mas achei que você não deveria.

Malabarba
fonte
Eu não acho aconselhar scroll-downe scroll-upseria útil aqui. Existem muitas outras maneiras pelas quais a rolagem pode acontecer. Pelo menos todos os comandos que possuem a isearch-scrollpropriedade devem ser considerados comandos de rolagem.
Gilles 'SO- stop be evil'
@Gilles é por isso que eu disse "assim como quaisquer outras funções que também possam resultar em movimento de pontos" . Mas sua resposta definitivamente parece melhor!
Malabarba 15/10
Essa é uma depuração bastante inteligente!
Nispio 15/10