1

The following function named my-modeline-face-function causes Emacs to pause for approximately one-half to one full second, and I'm looking for some suggestions please to significantly increase the speed.

It doesn't seem like much, but this function is used a lot. For example, every time I enable multiple-cursors mode (aka mc-mode), I end up twiddling my thumbs before I can get down to business -- the same thing happens when exiting multiple-cursors mode.

Adding (redisplay t) at the tail end of the function does nothing to increase the speed.

Using (force-mode-line-update) following this function does not increase the speed.

(defun my-modeline-face-function ()
  (cond
    ((minibufferp)
      (set-face-attribute 'mode-line nil :height 140 :foreground "gray70"
        :background "black" :box '(:line-width 1 :color "black"))
      (set-face-attribute 'minibuffer-prompt nil :background "black"
        :foreground "cyan" :bold t)
      (set (make-local-variable 'face-remapping-alist)
        '((default :background "black" :foreground "yellow"))))
    (save-as-variable
      (set-face-attribute 'mode-line nil :height 140
        :foreground "black" :background "#eab700" :box nil))
    (insert-variable
      (set-face-attribute 'mode-line nil :height 140
        :foreground "black" :background "orange" :box nil))
    ((or multi-extract-variable multi-attach-variable)
      (set-face-attribute 'mode-line nil :height 140
        :foreground "black" :background "magenta" :box nil))
    (open-with-variable
      (set-face-attribute 'mode-line nil :height 140
        :foreground "black" :background "ForestGreen" :box nil))
    (mc-mode
      (set-face-attribute 'mode-line nil :height 140
        :foreground "black" :background "cyan" :box nil))
    (isearch-mode
      (set-face-attribute 'mode-line nil :height 140
        :foreground "black" :background "yellow" :box nil))
    ((eq major-mode 'lawlist-calculator-mode)
      (set-face-attribute 'mode-line nil :height 140
        :foreground "black" :background "firebrick" :box nil))
    (t
      (set-face-attribute 'mode-line nil :height 140
        :foreground "black" :background "gray70" :box nil)
      (set-face-attribute 'minibuffer-prompt nil
        :background "black" :foreground "white"))) )

EDIT (August 5, 2014):

● Using a measure-time macro (i.e., http://lists.gnu.org/archive/html/help-gnu-emacs/2008-06/msg00087.html ), I verified that the run-time for the function internal-set-lisp-face-attribute within set-face-attribute occurs within mere fractions of a second. However, it takes up to one full second for me to see the visual effect. The same holds true whether it is the initial call of the function or subsequent calls within the same buffer.

● As to the first call of face-remapping-alist within a buffer, the visual effect takes up to one full second for me to see. However, subsequent calls using the face-remapping-alist within that same buffer occur within fractions of the second. I have not been able to eliminate the time needed to see the visual effect following the first call. This may be as good as it gets -- i.e., up to one full second for the first call, and light speed for subsequent calls within that same buffer.

(defun my-modeline-face-function ()
  (cond
    ((minibufferp)
      (set 'face-remapping-alist '(
        (mode-line modeline-inactive-face)
        (minibuffer-prompt minibuffer-prompt-active-face))) )
    (save-as-variable
      (set 'face-remapping-alist '((mode-line save-as-modeline-face))))
    (insert-variable
      (set 'face-remapping-alist '((mode-line insert-modeline-face))))
    ((or multi-extract-variable multi-attach-variable)
      (set 'face-remapping-alist '((mode-line multi-attach-extract-modeline-face))))
    (open-with-variable
      (set 'face-remapping-alist '((mode-line open-with-modeline-face))))
    (mc-mode
      (set 'face-remapping-alist '((mode-line mc-modeline-face))))
    (isearch-mode
      (set 'face-remapping-alist '((mode-line isearch-modeline-face))))
    ((eq major-mode 'lawlist-calculator-mode)
      (set 'face-remapping-alist '((mode-line lawlist-calculator-modeline-face))))
    (t
      (set 'face-remapping-alist '(
        (mode-line modeline-active-face)
        (minibuffer-prompt minibuffer-prompt-inactive-face))) )))
lawlist
  • 13,099
  • 3
  • 49
  • 158
  • Have you byte-compiled the function? – Dan Aug 03 '14 at 22:08
  • @Dan -- thank you for the suggestion. I just tried separating it from my non-byte-compiled library and I created a separate library and byte-compiled it and gz-compressed the *.el file and restarted Emacs. However, the same delay is still present. I'm thinking that the function `set-face-attribute` in conjunction with `'mode-line` is just a time consuming process and perhaps it has nothing to do with my custom function which is just a few simple conditions. Ordinarily, a function with a few conditions should run much faster than is humanly perceptible. – lawlist Aug 03 '14 at 22:21
  • It seems odd that `set-face-attribute` would be such a bottleneck. Without knowing what the `*-variable` clauses are for it's hard to guess if there's a bottleneck there. Perhaps try profiling the code ([manual node](https://www.gnu.org/software/emacs/manual/html_node/elisp/Profiling.html), [wiki page](http://www.emacswiki.org/emacs/EmacsLispProfiler), [SO thread](http://stackoverflow.com/questions/568150/tips-for-profiling-misbehaving-emacs-lisp)). – Dan Aug 03 '14 at 22:46
  • I could be quite wrong, but I think you might be asking for trouble by trying to set face attributes during redisplay (which is presumably when your function is called, if it is part of the mode-line format stuff). I suspect it might be hard to profile this in situ (things like debug are turned off during redisplay, and profiling might be too - dunno). But you could profile it as is, outside of redisplay. That's the place to start, to see if it is your function that is slow or the slowness comes from trying to do it during redisplay. – Drew Aug 03 '14 at 23:45
  • @Drew -- thank you for the suggestions. To do my subsequent testing today, I completely eliminated my custom function from the equation. `set-face-attribute` just takes a lot of time when changing the mode-line color. `set-face-background` and `set-face-foreground` also take a long time. Interestingly, `face-remap-add-relative` takes the same long amount of time the first time it is called, but then it works at light speed every time thereafter. So the eventual solution to this issue will likely entail figuring out why `face-remap-add-relative` works at light speed for subsequent calls. – lawlist Aug 04 '14 at 06:50
  • Here is a link to a related thread discussing `face-remap-add-relative`: http://stackoverflow.com/questions/15906332/change-emacs-mode-line-color-based-on-major-mode – lawlist Aug 04 '14 at 06:51

1 Answers1

2

Changing faces dynamically is going to be slow because the redisplay code is written under the assumption that faces don't change (if they change, we basically redo a lot of work). Using face-remapping-alist will result in much better performance because the redisplay code does expect it to change and know how to cache the result.

Stefan
  • 27,908
  • 4
  • 53
  • 82