0

How do I get continuation indicators (a character indicator at the far right edge, normally \) in visual-line mode when I'm working in a terminal emacs. FYI, the continuation markers on visual-line-fringe-indicators, do NOT work in terminal emacs.

I would like to differentiate between hard and soft newlines, and I would prefer indicators that are easy on the eyes.

Right now I'm using whitespace-mode to highlight the HARD newlines. So, if I look at a line and it DOESN'T have that highlight, then it must be a soft newline.

2 Answers 2

1

To get this

Display HARD NEWLINES as RED UNDERSCOREs

enter image description here

do this

  1. emacs -Q -nw
  2. Copy the below snippet to *scratch* buffer, and do M-x eval-buffer
(when (display-graphic-p)
  (fringe-mode (cdr (assoc "no-fringes" fringe-styles))))

(custom-set-variables
 '(whitespace-display-mappings
   '((space-mark 32
                 [183]
                 [46])
     (space-mark 160
                 [164]
                 [95])
     (newline-mark 10
                   [95 10])
     (tab-mark 9
               [187 9]
               [92 9])))
 '(whitespace-style '(face newline newline-mark))
 '(global-whitespace-mode 1))

(custom-set-faces
 '(whitespace-newline
   ((t
     (:foreground "red" :weight bold)))))


1
  • Thanks for the formatting edits to my question, and for the hard-newline highlighting code. Unfortunately, that's what I'm currently doing, and not what I was asking about. I'm looking for a way to highlight SOFT newlines. Upon re-reading, I see that my postscript about customizing was unclear. I was applying that to the soft newlines as well. I'm currently customizing the hard newline indicator. Still, I think your code is useful for posterity. I should have done that my myself. Commented Oct 3, 2022 at 12:33
1

BUYER BEWARE: This is a prototype code, and during the development of this snippet, I had to re-start my emacs multiple times.

If the custom fontifier doesn't move the point (or doesn't behave like a good citizen, in the sense that font-lock machinery expects it to) then emacs locks up the cpu, and becomes usable. So, use this snippet only after good amount of testing.

So, don't this snippet on a buffer which has your dissertation thesis, or some such important thing.


  1. emacs -Q -nw
  2. Copy the snippet to *scratch* buffer, and do M-x eval-buffer. The snippet adds soft wrap indicators to visual-line-mode buffer, just the way you want it---that is, right within the buffer, and immediately at the end of the soft wrap-ped line The snippet binds C-c C-c global-ly to visual-line-mode for quick testing.
;; testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode

;; testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode testing soft-wrap mode 

(global-set-key (kbd "C-c C-c") 'visual-line-mode)

(defface soft-wrap-face
  '((t :foreground "red"))
  "Face for hi-lock mode."
  :group 'hi-lock-faces)

(defvar soft-wrap)

(put 'soft-wrap 'display "\N{DOWN ARROW WITH TIP LEFT}")

(put 'soft-wrap 'soft-wrap t)
(put 'soft-wrap 'face 'soft-wrap-face)
;; (put 'soft-wrap 'face nil)

(defun make-soft-wrap-overlay (&optional p)
  (let* ((p (or p (point)))
         (ov (make-overlay p (1+ p))))
    (overlay-put ov 'category 'soft-wrap)))

(defun remove-soft-wrap-overlays (&optional beg end)
  (let* ((beg (or beg (point-min)))
         (end (or end (point-max))))
    (remove-overlays beg end 'soft-wrap t)))

(defun my-font-lock-matcher (limit)
  (let* ((points '()))
    (end-of-visual-line)
    (while (< (point) limit)
      (cond
       ((looking-back "\n" (1- (point)))
        (forward-char 2)
        (end-of-visual-line))
       ((looking-at "\n")
        (skip-chars-forward "\n"))
       (t
        (push (point) points)
        (forward-char 2)
        (end-of-visual-line))))
    (while points
      (let ((p (pop points)))
        (make-soft-wrap-overlay p)))
    (goto-char limit)
    t))

(defun my-extend-region-function (beg end old-len)
  (let* ((end (progn (goto-char end)
                     (re-search-forward "\n" nil 'move)
                     (point)))
         (cursor beg))
    (remove-soft-wrap-overlays beg end)
    (cons beg end)))

(defun turn-on-soft-wrap ()
  (font-lock-add-keywords
   nil (list '(my-font-lock-matcher)))
  (setq-local font-lock-extend-after-change-region-function
              #'my-extend-region-function)
  (font-lock-flush))

(defun turn-off-soft-wrap ()
  (remove-soft-wrap-overlays)
  (font-lock-remove-keywords
   nil (list '(my-font-lock-matcher))))

(add-hook 'visual-line-mode-hook
          (defun my-visual-line-mode-hook-1 ()
            (cond
             (visual-line-mode
              (auto-fill-mode -1)
              (turn-on-soft-wrap))
             (t (turn-off-soft-wrap)))))

(add-hook 'visual-line-mode-hook
       (defun my-visual-line-mode-hook ()
         (unless (display-graphic-p)
           ;; UTF-8 support
           ;; (prefer-coding-system 'utf-8)
           ;; (set-default-coding-systems 'utf-8)
           (set-terminal-coding-system 'utf-8)
           ;; (set-keyboard-coding-system 'utf-8)
           ;; (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))

           ;; (info "(elisp) Truncation")
           ;; [Truncation (GNU Emacs Lisp Reference Manual)](https://www.gnu.org/software/emacs/manual/html_node/elisp/Truncation.html#index-line_002dprefix)
           (setq line-prefix
                 (propertize "\N{SPACE}" 'face 'highlight))
           (setq wrap-prefix
                 (propertize "\N{DOWN ARROW WITH TIP RIGHT}" 'face 'highlight))

           ;; This is for wrap at the window edge
           ;; (info "(elisp) Display Tables")
           ;; [Display Tables (GNU Emacs Lisp Reference Manual)](https://www.gnu.org/software/emacs/manual/html_node/elisp/Display-Tables.html#index-display_002dtable_002dslot)
           (set-display-table-slot standard-display-table
                                   'wrap (make-glyph-code ?\N{DOWN ARROW WITH TIP LEFT} 'highlight)))))
;; Local Variables:
;; byte-compile-warnings: all
;; End:


  1. Do M-x visual-line-mode, and this is what you will see.

Custom soft-wrap indicators in visual-line-mode; also shows wrap indicators--seen at the beginning of line--which comes by default with emacs Custom soft-wrap indicators in visual-line-mode

  1. Edit the long lines; Monkey around by deleting large chunk of test, or inserting large chuck of text, or by breaking a long line by inserting newlines. Satisfies yourself that the soft-wrap markers at the right side of text, are redrawn, along the expected lines (with old soft-wrap markers vanishing in to thin air)

  2. FWIW, this is how the buffer looks in NON visual-line-mode

Buffer with long lines; and visual-line-mode is OFF

Buffer with long lines in NON visual-line-mode


Apropos (forward-char 2)---the code that moves the point to the next visual line: Intuitively movement by 1 char is sufficient to get past the end of visual line space or tab character (displayed as soft wrap). But once these space characters have a display property, then the point moves in a counter-intuitive way. (Difficult to explain by words, and interested parties can experiment on their own, make sense of what I say here)

There are plenty of reports on official emacs channel and in stackexchange, about display property on soft wrap spaces influencing the vertical-motion in a counter-intuitive way.

Initially, I went with 1 and the point was not moving in the MATCHER routine. So, emacs was locking up. (Lockups are a nightmare, and difficult to debug.)

Let me repeat, consider this code as a prototype; I recommend that you don't use it on very important buffers.


REFERENCES

Instead of continuation indicator---indicator that appears on the right window edge, right next to the point where the line wraps---what you instead get is prefix indicators---line-prefix and wrap-prefix. That is the prefix indicators appear AFTER the line has wrapped, and appears on the left window edge. (They are are NOT "user-friendly", and forces you to "wrap" your brains).


(info "(elisp) Truncation")

(info "(elisp) Display Tables")
1
  • OMG. Who ARE you? This might be the most hard-core response I have ever seen on stack. I won't be able to dig in and play with it for a few days, but I wanted to let you know ASAP that I am in appreciative awe. Also, warning acknowledged. I'll test it on an air-gapped laptop down in my bunker while the wife is out of town. I turned my dissertation in about 20 years ago, so unless your code's destructive power includes time travel, I'm probably safe. Commented Oct 6, 2022 at 22:07

Your Answer

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

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