(1) Push every new this-command onto a list containing any previously pushed this-command.

(2) Limit the list to a variable length (e.g., 3 or 5), and chop off the oldest.

(3) Compare whether all elements of the list are eq.

(defvar this-command-list nil)

(defvar maximum-elements 3)

(defun pre-command-hook-fn ()
  (push this-command this-command-list)
  (if (> (length this-command-list) maximum-elements)
    (setq this-command-list (delq (last this-command-list) this-command-list)))
  (TEST IF ALL ELEMENTS of `this-command-list' ARE THE SAME))

(add-hook 'pre-command-hook 'pre-command-hook-fn)

Background (aka why): I am instituting a concept similar to the deplacement-command list used by flyspell -- i.e., if this-command is the same as last-command and it is also a memq of a list of certain deplacement commands, then don't do a costly function. The difference here is that I want to compare a variable number of previous commands with the current command -- e.g., if I move the cursor (consecutively) 3 or 5 times to the left, then skip the costly function that would ordinarily run every command loop.

EDIT:  The following is a working solution based on the answer by @phils below. I thought it important to correct the mistake above which used delq instead of nbutlast.

(require 'cl)

(defvar this-command-list nil)

(defvar maximum-elements 3)

(defun pre-command-hook-fn ()
  (push this-command this-command-list)
  (when (> (length this-command-list) maximum-elements)
    (setq this-command-list (nbutlast this-command-list)))
  (message "test:  %s" (eq (length (cl-remove-duplicates this-command-list)) 1)))

(add-hook 'pre-command-hook 'pre-command-hook-fn)
  • Are you sure you want to check if all elements of a list are the same? That would mean that your condition is only true if a function repeats itself five times in a row. Or did you want the condition to be true if this-function was one of the last five functions called? – zck Sep 2 '16 at 5:29
  • @zck -- yes, please, I would like to test whether all elements are eq -- e.g., '(left-char left-char left-char left-char left-char) -- if they are all the same, then throw a t. Essentially, I don't mind if my costly function runs a couple of times consecutively, but if I'm just repeating the same thing again and again like holding down the arrow key, then I'd like to skip the costly function -- e.g., if its 3 or 5 times in a row, then start skipping the costly function (whatever that may be). – lawlist Sep 2 '16 at 5:34

How about:

(eq (length (cl-remove-duplicates SEQ)) 1)
  • Yes, that works and it's non-destructive -- perfect! – lawlist Sep 2 '16 at 6:01

We don't actually need to keep track of the last N commands, just the last command, and how many times it's repeated. This code will send a message when a command is called too many consecutive times.

(defvar my-last-fn-repeat-count 0
  "How many consecutive times the last function has been called.")

(defvar repeat-limit 5
  "When a command has repeated this many times, consider that too much.")

(defun pre-command-hook-fn ()
  "Warn when we're repeating too much."
  (if (eq this-command last-command)
      (incf my-last-fn-repeat-count)
    (setq my-last-fn-repeat-count 0))

  (when (>= my-last-fn-repeat-count repeat-limit)
    (message "You've repeated too much.")))

(add-hook 'pre-command-hook 'pre-command-hook-fn)

This has the benefit of not needing to do any list creation or searching, so it's a bit simpler. It should be faster, but I can't imagine working with a five-element list to ever be slow, so speed isn't a real-life benefit.

  • Oh, dear, now we have two great answers and I already gave credit to phils . . . :) I gave you a +1, but don't generally take a way a check-mark once given . . . . Thank you very much -- greatly appreciated! phils answered the call of the question, but your solution to the problem posed in the question is indeed a good one. – lawlist Sep 2 '16 at 6:17
  • No worries! Glad to help out. – zck Sep 2 '16 at 12:15
  • Consider using put, one less variable to worry about. – politza Sep 2 '16 at 13:23
  • @politza To use one variable for both of my-last-fn-repeat-count and repeat-limit? I'd rather be more explicit about the meaning and have two. – zck Sep 2 '16 at 14:17
  • No, something like (put this-command ...). – politza Sep 2 '16 at 17:22

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.