2

I have added the following definitions to my initialization file in order to make the mark show up as a red highlight:

(defface mmv-face
  '((t :inherit default :background "red"))
  "Face used for showing the mark's position.")

(defvar mmv-mark-overlay nil "Overlay for showing the mark's position.")
(make-variable-buffer-local 'mmv-mark-overlay)

;; The three optional arguments are needed to cover the optional arguments of
;; those functions that this function will modify through `advice-add'.
(defun mmv-show-mark (&optional ARG1 ARG2 ARG3)
  "Make the mark's position stand out by means of a one-character-long overlay."
  (unless mmv-mark-overlay
    (setq mmv-mark-overlay (make-overlay 0 0 nil t))
    (overlay-put mmv-mark-overlay 'face 'mmv-face))
  (let ((mark-position (mark t)))
    (when mark-position
      ; Function `mark' returns non-nil only if the buffer's mark is set, so
      ; doing the following is pointless if `mark-position' is nil.
      (move-overlay mmv-mark-overlay mark-position (1+ mark-position)))))

(advice-add 'set-mark :after #'mmv-show-mark)
(advice-add 'pop-mark :after #'mmv-show-mark)
(advice-add 'push-mark :after #'mmv-show-mark)

It works well otherwise, except that if the mark is at the end of a line, everything to the right of the mark is also highlighted; see the screenshot below. Why would this be, and how can it be fixed?

Screenshot of a mark at end-of-line generating excessive highlighting

4
  • How about testing for a line end \n / 10 and if so, then don't place an overlay spanning that line-end? Alternatively, for line ends you could use a floating overlay with the after-string property -- in which case the overlay would not span a full point, but rather the BEG/END would be the same point. You can set the width of a floating overlay after-string too.
    – lawlist
    Sep 10 '18 at 13:59
  • Why :inherit default ?
    – Stefan
    Sep 10 '18 at 14:03
  • @lawlist Thanks for the suggestion. Stefan's answer uses the after-string property. Sep 10 '18 at 14:47
  • @Stefan That was part of code I copied (from emacswiki.org/emacs/MakingMarkVisible) and then edited to arrive at the present code. It seems it's not necessary. Sep 10 '18 at 14:49
1

When a face is placed on a newline (aka "LF") character, Emacs highlights the whole "rest of the line". That's why (in your case when the mark is at EOL, mark-position is just before LF and (1+ mark-position) is just after).

As for how to fix it, I think you'll want to do something like:

(defface mmv-face
  '((t :background "red"))
  "Face used for showing the mark's position.")

(defvar-local mmv-mark-overlay nil "Overlay for showing the mark's position.")

(defun mmv-show-mark (&rest _)
  "Make the mark's position stand out by means of a one-character-long overlay."
  (unless mmv-mark-overlay
    (setq mmv-mark-overlay (make-overlay 0 0 nil t))
    (overlay-put mmv-mark-overlay 'face 'mmv-face))
  (let ((mark-position (mark t)))
    (cond
     ((null mark-position) (delete-overlay mmv-mark-overlay))
     ((and (< mark-position (point-max))
           (not (eq ?\n (char-after mark-position))))
      (overlay-put mmv-mark-overlay 'after-string nil)
      (move-overlay mmv-mark-overlay
                    mark-position (1+ mark-position)))
     (t
      ;; This branch is called when the mark is at the end of a line or at the
      ;; end of the buffer. We use a bit of trickery to avoid the higlight
      ;; extending from the mark all the way to the right end of the frame.
      (overlay-put mmv-mark-overlay 'after-string
                   (propertize " " 'face (overlay-get mmv-mark-overlay 'face)))
      (move-overlay mmv-mark-overlay
                    mark-position mark-position)))))

(add-hook 'pre-redisplay-functions #'mmv-show-mark)

Note that this also takes care of removing the overlay when/if the mark is removed (this normally never happens, but we may as well), as well as handle the EOB case.

Two more things:

  1. You can use defvar-local.
  2. Rather than &optional ARG1 ARG2 ARG3 you're better doing &rest _ to simply accept any number of arguments and say that you'll ignore them.
  3. Rather than advise an ever growing number of commands that can move/activate the mark, you should likely use

    (add-hook 'pre-redisplay-functions #'mmv-show-mark)
    

    this is the same hook normally used to highlight the region.

2
  • In most of your code that I have seen over the years, you do not use point and point+1 for an after-string; but rather you have used point/point. Perhaps that is the issue?
    – lawlist
    Sep 10 '18 at 15:07
  • @lawlist: the after-string is displayed at the overlay-end position and is unaffected by the overlay-start position (unless you set evaporate on the overlay, in which case start==end will delete the overlay).
    – Stefan
    Sep 11 '18 at 12:05

This site is temporarily in read only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .