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

  • 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. – Teemu Leisti 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. – Teemu Leisti 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.

  • 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

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.