2

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-abbrev such 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)
  • 2
    You could use an around advice, instead of a before. And then manually check if an expansion occurred. – Malabarba Oct 16 '14 at 14:12
2

I'm not sure if this is what you are looking for, but the package you linked to can be extended to capture abbrev expansion like so:

(require 'volatile-highlights)
(volatile-highlights-mode t)
(vhl/define-extension 'abbrev 'expand-abbrev)
(vhl/install-extension 'abbrev)
  • That is interesting... had not thought of using it like that :-D My testing has shown that this will highlight from the beginning of the expanded text up to the end of line. My approach highlights only the expanded text. – elemakil Oct 16 '14 at 14:40

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.