I don't really like the feeling of not being in control when using
emacs' abbreviations feature. On the one hand, I don't want to be asked all the time but on the other hand I'd like to know when an abbreviation is expanded.
Hence, I fired up
emacs (just kidding, it was already running) and did some
elisp coding. Using some inspiration I got a working prototype, that is a
minor-mode which highlights the expansion inserted by
abbrev-mode for some time (default is 0.5s). You can find the code below.
However, after using this code for some time, I noticed that from time to time, the seemingly random parts of the buffer are highlighted. It appears my "hooking" into
expand-abbrev is not working. So here comes the actual question:
How do you advice
expand-abbrevsuch that the advised code gets only executed when there really was an expansion?
I did some digging in the
abbrev code, added some debug statements, etc. but could not get it to work.
Furthermore, although it has been fun fiddling around with
elisp, I don't think my code is idiomatic and I would not be surprised if there were a better way to approach the problem, thus any comments on the code and how it can be improved are appreciated.
Here comes the code:
(defadvice expand-abbrev (after expand-abbrev-after-expansion-flash) (ahl/add-range last-abbrev-location (+ last-abbrev-location (length (symbol-value last-abbrev))))) (defface ahl/default-face '((((class color) (background light)) (:background "yellow1")) (((class color) (background dark)) (:background "SkyBlue4")) (t :inverse-video t)) "Face used for abbrev highlights.") (defvar ahl/default-time 0.5 "Time the abbrev high light should last.") (defun ahl/add-range (beg end &optional buf face time) "Add a highlight for `TIME' second to the buffer `BUF' at the position specified by `BEG' and `END' using the face `FACE'. When the buffer `BUF' is not specified or its value is `nil', highlight will be added to current buffer. When the face `FACE' is not specified or its value is `nil', the default face `ahl/default-face' will be used as the value. When the time `TIME' is not specified or its value is `nil', the default value `ahl/default-time' will be used as the value." (let* ((face (or face 'ahl/default-face)) (hl (ahl/--make-hl beg end buf face)) (time (or time ahl/default-time))) (run-with-idle-timer time nil (lambda (hl) (ahl/--remove-hl hl)) hl))) (defun ahl/--make-hl (beg end buf face) "Make a highlight at the position specified by `BEG' and `END'." (let (hl) ;; GNU Emacs (setq hl (make-overlay beg end buf)) (overlay-put hl 'face face) (overlay-put hl 'priority 1) (overlay-put hl 'abbrev-high-light t) hl)) (defun ahl/--remove-hl (hl) "Clear highlight." (and (overlayp hl) (delete-overlay hl))) (define-minor-mode abbrev-high-light-mode "Highlight abbreviations upon expansion." nil :lighter "" (if abbrev-high-light-mode (progn (ad-enable-advice 'expand-abbrev 'after 'expand-abbrev-after-expansion-flash) (ad-activate 'expand-abbrev)) (ad-disable-advice 'expand-abbrev 'after 'expand-abbrev-after-expansion-flash) (ad-activate 'expand-abbrev))) (provide 'abbrev-high-light)