1

ISSUE:  An overlay after-string at the end of a wrapped line is preventing the function previous-line from moving the cursor directly upwards in a vertical line.

QUESTION:  How to modify the following code snippet so that it essentially excludes the overlay after-string, when point is at the end of the line?

(cons (/ (float (car (posn-x-y (posn-at-point)))) (frame-char-width)) (window-hscroll))

DETAILS:  I have a custom minor-mode that places an overlay after-string at the end of the line, which generates a horizontal overlay stretching from the end of the line to the right edge of the window. That overlay after-string is causing a conflict with line-move-visual, which is used by previous-line. When the cursor / point is at the end of the line, the function previous-line should move the cursor directly upwards in a vertical motion when multiple wrapped lines exist. When the cursor is at the end of the line, it looks like it is a substantial horizontal distance from the right window edge -- however, the overlay after-string causes the above-mentioned code to return a value for the cursor position at the far right window edge. Consequently, the cursor moves to the visual-end of the preceding wrapped line -- instead of moving directly upwards in a vertical motion aligned with the end of the line.

STEP ONE -- Beginning Position at End of Line:

Example

STEP TWO -- UN-desired Effect:

Example

Desire Effect -- After Step One

Example


In the event that anyone would like to duplicate the overlay after-string at the end of the line, here is a scaled down example of what is depicted in the screen-shots above. The code works just by pasting it into the *scratch* buffer and typing M-x eval-buffer RET

(defvar my-eol-ruler nil
"A horizontal ruler stretching from eol (end of line) to the window edge.")
(make-variable-buffer-local 'my-eol-ruler)

(defvar my-eol-pilcrow nil
"A pilcrow symbol placed at the end of every line except the current line.")
(make-variable-buffer-local 'my-eol-pilcrow)

(defsubst col-at-eovl ()
  (save-excursion
    (let ((movement-indicator (vertical-motion 1)))
      (when (= movement-indicator 1)
        (backward-char 1)))
    (- (current-column) (progn (vertical-motion 0) (current-column)))))

(defun my-eol-ruler-function ()
  (let* (
    (opoint (point))
    (window-width (window-width))
    (window-start (window-start))
    (window-end (window-end nil t))
    (col-eovl (col-at-eovl))
    (my-current-line-length (- (- window-width col-eovl) 3))
    (pilcrow
      (propertize (char-to-string ?\u00B6)
        'face '(:foreground "red")
        'cursor t))
    (pilcrow-underlined
      (propertize (char-to-string ?\u00B6)
        'face '(:foreground "white" :underline "blue")
        'cursor t))
    (underline (propertize (char-to-string ?\u2009)
          'display `(space :width ,my-current-line-length)
          'face '(:underline "blue")
          'cursor t)))
  (when (or my-eol-ruler my-eol-pilcrow)
    (dolist (description `(
        ,my-eol-ruler
        ,my-eol-pilcrow ))
      (remove-overlays (point-min) (point-max) 'after-string description)) )
  (setq my-eol-ruler (concat pilcrow-underlined underline))
  (setq my-eol-pilcrow pilcrow)
  (save-excursion
    (end-of-line)
    (overlay-put (make-overlay (point) (point)) 'after-string my-eol-ruler ))
  (save-excursion
    (goto-char window-end)
    (while (re-search-backward "\n" window-start t)
      (let* (
          (pbol (point-at-bol))
          (peol (point))
          (col-eovl (col-at-eovl)) )
        (when
          (or
            (< opoint pbol)
            (> opoint peol))
        (overlay-put (make-overlay peol peol) 'after-string my-eol-pilcrow))))) ))

(add-hook 'post-command-hook 'my-eol-ruler-function)
2
  • IIUC, This looks like a bug. You may be able to hack your way around it, but I would submit it as well.
    – Malabarba
    Mar 7, 2015 at 7:49
  • You could try temporarily changing the that after-string property on the overlay. Yes, that's dirty, but there's probably no cleaner solution.
    – Dmitry
    Apr 26, 2015 at 20:48

1 Answer 1

0

The function posn-at-point is incompatible when certain types of overlays are present. Even removing the overlays prior to redisplay is insufficient to work around this issue, because Emacs uses what was on screen before entering the command loop. As suggested by @Malabarba in a comment above, it would be appropriate to submit a bug report and/or feature request to the Emacs team in relation to this issue.

The following solution uses vertical-motion, which is not dependent upon point being visible.

(defsubst vcol ()
  (- (current-column) (save-excursion (vertical-motion 0) (current-column))))

(setq temporary-goal-column (cons (vcol) (window-hscroll)))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.