emacsmodeline

Emacs mode-line highlight during macro definition


Is there as simple way to have a clear indicator when I'm defining a keyboard macro (kmacro-start-macro-or-insert-counter), e.g. by changing the mode-line background or something similar?

The "Def" indicator is hard to parse out and sometimes not visible due to many minor-mode indicators/narrow screen.

Thank you very much!


Solution

  • I used the standard functions bound to f3 and f4 and modified them by adding my-modeline-face-function, and rebound those keys to the new functions. You can change the colors of the faces in my-modeline-face-function to suit your needs. I chose to use cond because you may find that you have other similar needs for the various major and minor modes, and you can insert similar conditions for those modes. [For example, you could do this for isearch-mode, or calculcator-mode, etc.]

    The value returned by face-remap-add-relative is stored in a custom variable that I named my-face-remap-cookie, which in turn is used at the end of the macro recording phase as an argument to the function face-remap-remove-relative.

    (defun my-kmacro-start-macro-or-insert-counter (arg)
      "Record subsequent keyboard input, defining a keyboard macro.
    The commands are recorded even as they are executed.
    
    Sets the `kmacro-counter' to ARG (or 0 if no prefix arg) before defining the
    macro.
    
    With \\[universal-argument], appends to current keyboard macro (keeping
    the current value of `kmacro-counter').
    
    When defining/executing macro, inserts macro counter and increments
    the counter with ARG or 1 if missing.  With \\[universal-argument],
    inserts previous `kmacro-counter' (but do not modify counter).
    
    The macro counter can be modified via \\[kmacro-set-counter] and \\[kmacro-add-counter].
    The format of the counter can be modified via \\[kmacro-set-format]."
      (interactive "P")
      (if (or defining-kbd-macro executing-kbd-macro)
          (progn
            (my-modeline-face-function)
            (kmacro-insert-counter arg))
        (kmacro-start-macro arg)
        (my-modeline-face-function)))
    
    (defun my-kmacro-end-or-call-macro (arg &optional no-repeat)
      "End kbd macro if currently being defined; else call last kbd macro.
    With numeric prefix ARG, repeat macro that many times.
    With \\[universal-argument], call second macro in macro ring."
      (interactive "P")
      (cond
       (defining-kbd-macro
         (if kmacro-call-repeat-key
       (kmacro-call-macro arg no-repeat t)
           (kmacro-end-macro arg)))
       ((and (eq this-command 'kmacro-view-macro)  ;; We are in repeat mode!
       kmacro-view-last-item)
        (kmacro-exec-ring-item (car kmacro-view-last-item) arg))
       ((and arg (listp arg))
        (kmacro-call-ring-2nd 1))
       (t
        (kmacro-call-macro arg no-repeat)))
      (my-modeline-face-function))
    
    (defface my-recording-macro-face
      '((t (:background "yellow" :foreground "black")))
      "Face for `my-recording-macro-face`."
      :group 'my-faces)
    
    (defvar my-face-remap-cookie nil
    "The return value of `face-remap-add-relative` is a Lisp object that
    serves as a `cookie`; you can pass this object as an argument to
    `face-remap-remove-relative` if you need to remove the remapping later.")
    (make-variable-buffer-local 'my-face-remap-cookie)
    
    (defun my-modeline-face-function ()
    "Doc-string."
      (require 'face-remap)
      (cond
        (defining-kbd-macro
          (setq my-face-remap-cookie
            (face-remap-add-relative 'mode-line 'my-recording-macro-face)))
        (t
          (face-remap-remove-relative my-face-remap-cookie)
          (setq my-face-remap-cookie nil))))
    
    (define-key global-map [f3] 'my-kmacro-start-macro-or-insert-counter)
    
    (define-key global-map [f4] 'my-kmacro-end-or-call-macro)