8

What's the best way to detect keystrokes (e.g. via a hook) which don't edit the buffer? I mean things like arrow-keys for point motion, calls to beginning-of-buffer, etc.

The reason for this is that I'm working on some ycmd bindings for emacs, and I'd like to be able to detect (at least heuristically) when the user has stopped editing and is moving around the buffer. This is a good time for shipping the buffer contents off for parsing. The vim client does this when the user exits insertion mode, and I'm trying to emulate that behavior.

  • 8
    You may be interested in idle timers for this kind of stuff: gnu.org/software/emacs/manual/html_node/elisp/Idle-Timers.html – giordano Nov 3 '14 at 7:28
  • 2
    Another idea (or a refinement of the idea with idle timers): advise self-insert-command to cancel and reschedule a timer instead of using an idle timer. This way, even if the user does something, the timer is not reset unless the "something" is text insertion. – mbork Nov 3 '14 at 8:08
  • 2
    mbork: after-change-functions is a general mechanism for reacting to text changes. – phils Nov 3 '14 at 9:36
  • 1
    Use a post-command-hook. That will trigger on everything, so you may need to do some filtering on what triggered it before taking whatever action you want. – Malabarba Nov 3 '14 at 9:43
  • 1
    Not sure it's relevant for this particular problem, but the buffer-chars-modified-tick function may be useful. – Jon O. Nov 3 '14 at 20:03
2

Add the following hooks:

  • To pre-command-hook, set some sentinel variable to t – this signals the command was non-changing.
  • To after-change-functions, set this sentinel value to nil. (It is a hook, it just doesn't sound like one; thanks to @phils for pointing this out.)
  • To post-command-hook, check this sentinel value and run your function.

This may or may not work depending on the order of execution. If it doesn't, let me know in the comments below.


When I get off work, I will post an example.

  • I have to go to work now… – Sean Allred Nov 3 '14 at 13:48
  • 2
    Don't advise self insert. Use after-change-functions – Malabarba Nov 3 '14 at 16:09
  • I'll give this a shot when I've got a chance. – abingham Nov 3 '14 at 16:17
  • 4
    @abingham As a general rule, hooks are preferable to advices. Hooks are specifically designed for you to attach functions, while advices are ways to attach something in unexpected places. In this particular case, it's also not advisable to advise some very fundamental functions, because it interacts unreliably with byte compilation. – Malabarba Nov 3 '14 at 17:04
  • 2
    I think Sean meant to refer to post-self-insert-hook (that bit of the answer seems to be confusing that hook with advising self-insert-command). In any case, I think you would generally prefer after-change-functions because it actually does what you want (as self-insert is not the only kind of key stroke which modifies the buffer). – phils Nov 3 '14 at 21:13
0

Just a thought -

This should not really be about "keystrokes", but about commands - no matter how they are executed, no? If I understand correctly, you are really looking for a way to tell whether a given command that gets invoked modifies the buffer.

If so, then maybe do something like this:

  • Put a function on pre-command-hook that (1) records the current value of (buffer-modified-p) and then (2) uses set-modified-p to make the buffer unmodified.

  • Put a function on post-command-hook that (1) checks whether the command modified the buffer (by comparing the recorded value against the new current value of (buffer-modified-p)), then acts accordingly, and (2) if the new value is nil then resets to the pre-change value using set-modified-p.

Kind of heavy-handed (it checks for each command that is invoked), but it might be worth a try.

If the "acts accordingly" part is just a no-op for all buffer modifying commands, and if it is also a no-op for many non-modifying commands (e.g. because you just did it on a previous non-modifying command), then at least you will not be doing that "acts accordingly" action more than necessary. But the checking part alone might be expensive/overkill (slow things down too much) - try it to see.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.