diff options
| author | Po Lu | 2024-01-27 09:30:16 +0800 |
|---|---|---|
| committer | Po Lu | 2024-01-27 09:30:16 +0800 |
| commit | 6667d6c19c3934871ed54d89dc153efc72f947de (patch) | |
| tree | 1549ab585a34d37f753d7359fb5bad2d1805f990 | |
| parent | 972466dce268c5697f47a7f342b13dbf01f23a39 (diff) | |
| download | emacs-6667d6c19c3934871ed54d89dc153efc72f947de.tar.gz emacs-6667d6c19c3934871ed54d89dc153efc72f947de.zip | |
Import ELPA package adaptive-wrap as visual-wrap
* doc/emacs/basic.texi (Continuation Lines): Document
visual-wrap and its applications.
* etc/NEWS (Editing Changes in Emacs 30.1): Ditto.
* lisp/visual-wrap.el (visual-wrap-extra-indent)
(visual-wrap--face-extend-p, visual-wrap--prefix-face)
(visual-wrap--prefix, visual-wrap-fill-context-prefix)
(visual-wrap-prefix-function, visual-wrap-prefix-mode, lookup-key)
(visual-wrap): New file. Update copyright years and rename to
`visual-wrap'.
| -rw-r--r-- | doc/emacs/basic.texi | 11 | ||||
| -rw-r--r-- | etc/NEWS | 12 | ||||
| -rw-r--r-- | lisp/visual-wrap.el | 203 |
3 files changed, 226 insertions, 0 deletions
diff --git a/doc/emacs/basic.texi b/doc/emacs/basic.texi index f64b3995d25..a6b71db4bea 100644 --- a/doc/emacs/basic.texi +++ b/doc/emacs/basic.texi | |||
| @@ -630,6 +630,17 @@ before they get too long, by inserting newlines. If you prefer, you | |||
| 630 | can make Emacs insert a newline automatically when a line gets too | 630 | can make Emacs insert a newline automatically when a line gets too |
| 631 | long, by using Auto Fill mode. @xref{Filling}. | 631 | long, by using Auto Fill mode. @xref{Filling}. |
| 632 | 632 | ||
| 633 | @cindex continuation lines, wrapping with prefix | ||
| 634 | @findex visual-wrap-prefix-mode | ||
| 635 | Normally, the first character of each continuation line is | ||
| 636 | positioned at the beginning of the screen line where it is displayed. | ||
| 637 | The minor mode @code{visual-wrap-prefix-mode} arranges that | ||
| 638 | continuation lines be prefixed by slightly adjusted versions of the | ||
| 639 | fill prefixes (@pxref{Fill Prefix}) of their respective logical lines, | ||
| 640 | so that indentation characters or the prefixes of source code comments | ||
| 641 | are replicated across every continuation line, and the appearance of | ||
| 642 | such comments or indentation is not broken. | ||
| 643 | |||
| 633 | Sometimes, you may need to edit files containing many long logical | 644 | Sometimes, you may need to edit files containing many long logical |
| 634 | lines, and it may not be practical to break them all up by adding | 645 | lines, and it may not be practical to break them all up by adding |
| 635 | newlines. In that case, you can use Visual Line mode, which enables | 646 | newlines. In that case, you can use Visual Line mode, which enables |
| @@ -318,6 +318,18 @@ name detection. | |||
| 318 | * Editing Changes in Emacs 30.1 | 318 | * Editing Changes in Emacs 30.1 |
| 319 | 319 | ||
| 320 | +++ | 320 | +++ |
| 321 | ** New minor mode 'visual-wrap-prefix-mode'. | ||
| 322 | |||
| 323 | When enabled, continuation lines displayed for a folded long line will | ||
| 324 | receive a 'wrap-prefix' automatically computed from the line's | ||
| 325 | surrounding context by the function 'fill-context-prefix', which | ||
| 326 | generally indents continuation lines as if the line were filled with | ||
| 327 | 'M-q', or similar. | ||
| 328 | |||
| 329 | This minor mode is the 'adaptive-wrap' ELPA package renamed and | ||
| 330 | lightly edited for inclusion in Emacs. | ||
| 331 | |||
| 332 | +++ | ||
| 321 | ** New user option 'gud-highlight-current-line'. | 333 | ** New user option 'gud-highlight-current-line'. |
| 322 | When enabled, Gud will visually emphasize the line being executed upon | 334 | When enabled, Gud will visually emphasize the line being executed upon |
| 323 | pauses in the debugee's execution, such as those occasioned by | 335 | pauses in the debugee's execution, such as those occasioned by |
diff --git a/lisp/visual-wrap.el b/lisp/visual-wrap.el new file mode 100644 index 00000000000..9f52a1868c1 --- /dev/null +++ b/lisp/visual-wrap.el | |||
| @@ -0,0 +1,203 @@ | |||
| 1 | ;;; visual-wrap.el --- Smart line-wrapping with wrap-prefix | ||
| 2 | |||
| 3 | ;; Copyright (C) 2011-2021, 2024 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Stephen Berman <stephen.berman@gmx.net> | ||
| 6 | ;; Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 7 | ;; Maintainer: emacs-devel@gnu.org | ||
| 8 | ;; Keywords: convenience | ||
| 9 | ;; Package: emacs | ||
| 10 | |||
| 11 | ;; This file is part of GNU Emacs. | ||
| 12 | |||
| 13 | ;; This program is free software; you can redistribute it and/or modify | ||
| 14 | ;; it under the terms of the GNU General Public License as published by | ||
| 15 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 16 | ;; (at your option) any later version. | ||
| 17 | |||
| 18 | ;; This program is distributed in the hope that it will be useful, | ||
| 19 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | ;; GNU General Public License for more details. | ||
| 22 | |||
| 23 | ;; You should have received a copy of the GNU General Public License | ||
| 24 | ;; along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 25 | |||
| 26 | ;;; Commentary: | ||
| 27 | |||
| 28 | ;; This package provides the `visual-wrap-prefix-mode' minor mode | ||
| 29 | ;; which sets the wrap-prefix property on the fly so that | ||
| 30 | ;; single-long-line paragraphs get word-wrapped in a way similar to | ||
| 31 | ;; what you'd get with M-q using visual-fill-mode, but without | ||
| 32 | ;; actually changing the buffer's text. | ||
| 33 | |||
| 34 | ;;; Code: | ||
| 35 | |||
| 36 | (defcustom visual-wrap-extra-indent 0 | ||
| 37 | "Number of extra spaces to indent in `visual-wrap-prefix-mode'. | ||
| 38 | |||
| 39 | `visual-wrap-prefix-mode' indents the visual lines to the level | ||
| 40 | of the actual line plus `visual-wrap-extra-indent'. A negative | ||
| 41 | value will do a relative de-indent. | ||
| 42 | |||
| 43 | Examples: | ||
| 44 | |||
| 45 | actual indent = 2 | ||
| 46 | extra indent = -1 | ||
| 47 | |||
| 48 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed | ||
| 49 | do eiusmod tempor incididunt ut labore et dolore magna | ||
| 50 | aliqua. Ut enim ad minim veniam, quis nostrud exercitation | ||
| 51 | ullamco laboris nisi ut aliquip ex ea commodo consequat. | ||
| 52 | |||
| 53 | actual indent = 2 | ||
| 54 | extra indent = 2 | ||
| 55 | |||
| 56 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed | ||
| 57 | do eiusmod tempor incididunt ut labore et dolore magna | ||
| 58 | aliqua. Ut enim ad minim veniam, quis nostrud exercitation | ||
| 59 | ullamco laboris nisi ut aliquip ex ea commodo consequat." | ||
| 60 | :type 'integer | ||
| 61 | :safe 'integerp | ||
| 62 | :group 'visual-line) | ||
| 63 | |||
| 64 | (defun visual-wrap--face-extend-p (face) | ||
| 65 | ;; Before Emacs 27, faces always extended beyond EOL, so we check | ||
| 66 | ;; for a non-default background instead. | ||
| 67 | (cond | ||
| 68 | ((listp face) | ||
| 69 | (plist-get face (if (fboundp 'face-extend-p) :extend :background))) | ||
| 70 | ((symbolp face) | ||
| 71 | (if (fboundp 'face-extend-p) | ||
| 72 | (face-extend-p face nil t) | ||
| 73 | (face-background face nil t))))) | ||
| 74 | |||
| 75 | (defun visual-wrap--prefix-face (fcp _beg end) | ||
| 76 | ;; If the fill-context-prefix already specifies a face, just use that. | ||
| 77 | (cond ((get-text-property 0 'face fcp)) | ||
| 78 | ;; Else, if the last character is a newline and has a face | ||
| 79 | ;; that extends beyond EOL, assume that this face spans the | ||
| 80 | ;; whole line and apply it to the prefix to preserve the | ||
| 81 | ;; "block" visual effect. | ||
| 82 | ;; | ||
| 83 | ;; NB: the face might not actually span the whole line: see | ||
| 84 | ;; for example removed lines in diff-mode, where the first | ||
| 85 | ;; character has the diff-indicator-removed face, while the | ||
| 86 | ;; rest of the line has the diff-removed face. | ||
| 87 | ((= (char-before end) ?\n) | ||
| 88 | (let ((eol-face (get-text-property (1- end) 'face))) | ||
| 89 | ;; `eol-face' can be a face, a "face value" | ||
| 90 | ;; (plist of face properties) or a list of one of those. | ||
| 91 | (if (or (not (consp eol-face)) (keywordp (car eol-face))) | ||
| 92 | ;; A single face. | ||
| 93 | (if (visual-wrap--face-extend-p eol-face) eol-face) | ||
| 94 | ;; A list of faces. Keep the ones that extend beyond EOL. | ||
| 95 | (delq nil (mapcar (lambda (f) | ||
| 96 | (if (visual-wrap--face-extend-p f) f)) | ||
| 97 | eol-face))))))) | ||
| 98 | |||
| 99 | (defun visual-wrap--prefix (fcp) | ||
| 100 | (let ((fcp-len (string-width fcp))) | ||
| 101 | (cond | ||
| 102 | ((= 0 visual-wrap-extra-indent) | ||
| 103 | fcp) | ||
| 104 | ((< 0 visual-wrap-extra-indent) | ||
| 105 | (concat fcp (make-string visual-wrap-extra-indent ?\s))) | ||
| 106 | ((< 0 (+ visual-wrap-extra-indent fcp-len)) | ||
| 107 | (substring fcp | ||
| 108 | 0 | ||
| 109 | (+ visual-wrap-extra-indent fcp-len))) | ||
| 110 | (t | ||
| 111 | "")))) | ||
| 112 | |||
| 113 | (defun visual-wrap-fill-context-prefix (beg end) | ||
| 114 | "Like `fill-context-prefix', but with length adjusted by | ||
| 115 | `visual-wrap-extra-indent'." | ||
| 116 | (let* ((fcp | ||
| 117 | ;; `fill-context-prefix' ignores prefixes that look like | ||
| 118 | ;; paragraph starts, in order to avoid inadvertently | ||
| 119 | ;; creating a new paragraph while filling, but here we're | ||
| 120 | ;; only dealing with single-line "paragraphs" and we don't | ||
| 121 | ;; actually modify the buffer, so this restriction doesn't | ||
| 122 | ;; make much sense (and is positively harmful in | ||
| 123 | ;; taskpaper-mode where paragraph-start matches everything). | ||
| 124 | (or (let ((paragraph-start "\\`\\'a")) | ||
| 125 | (fill-context-prefix beg end)) | ||
| 126 | ;; Note: fill-context-prefix may return nil; See: | ||
| 127 | ;; http://article.gmane.org/gmane.emacs.devel/156285 | ||
| 128 | "")) | ||
| 129 | (prefix (visual-wrap--prefix fcp)) | ||
| 130 | (face (visual-wrap--prefix-face fcp beg end))) | ||
| 131 | (if face | ||
| 132 | (propertize prefix 'face face) | ||
| 133 | prefix))) | ||
| 134 | |||
| 135 | (defun visual-wrap-prefix-function (beg end) | ||
| 136 | "Indent the region between BEG and END with visual filling." | ||
| 137 | ;; Any change at the beginning of a line might change its wrap | ||
| 138 | ;; prefix, which affects the whole line. So we need to "round-up" | ||
| 139 | ;; `end' to the nearest end of line. We do the same with `beg' | ||
| 140 | ;; although it's probably not needed. | ||
| 141 | (goto-char end) | ||
| 142 | (unless (bolp) (forward-line 1)) | ||
| 143 | (setq end (point)) | ||
| 144 | (goto-char beg) | ||
| 145 | (forward-line 0) | ||
| 146 | (setq beg (point)) | ||
| 147 | (while (< (point) end) | ||
| 148 | (let ((lbp (point))) | ||
| 149 | (put-text-property | ||
| 150 | (point) (progn (search-forward "\n" end 'move) (point)) | ||
| 151 | 'wrap-prefix | ||
| 152 | (let ((pfx (visual-wrap-fill-context-prefix | ||
| 153 | lbp (point)))) | ||
| 154 | ;; Remove any `wrap-prefix' property that might have been | ||
| 155 | ;; added earlier. Otherwise, we end up with a string | ||
| 156 | ;; containing a `wrap-prefix' string containing a | ||
| 157 | ;; `wrap-prefix' string ... | ||
| 158 | (remove-text-properties | ||
| 159 | 0 (length pfx) '(wrap-prefix) pfx) | ||
| 160 | (let ((dp (get-text-property 0 'display pfx))) | ||
| 161 | (when (and dp (eq dp (get-text-property (1- lbp) 'display))) | ||
| 162 | ;; There's a `display' property which covers not just the | ||
| 163 | ;; prefix but also the previous newline. So it's not | ||
| 164 | ;; just making the prefix more pretty and could interfere | ||
| 165 | ;; or even defeat our efforts (e.g. it comes from | ||
| 166 | ;; `visual-fill-mode'). | ||
| 167 | (remove-text-properties | ||
| 168 | 0 (length pfx) '(display) pfx))) | ||
| 169 | pfx)))) | ||
| 170 | `(jit-lock-bounds ,beg . ,end)) | ||
| 171 | |||
| 172 | ;;;###autoload | ||
| 173 | (define-minor-mode visual-wrap-prefix-mode | ||
| 174 | "Wrap the buffer text with visual filling." | ||
| 175 | :lighter "" | ||
| 176 | :group 'visual-line | ||
| 177 | (if visual-wrap-prefix-mode | ||
| 178 | (progn | ||
| 179 | ;; HACK ATTACK! We want to run after font-lock (so our | ||
| 180 | ;; wrap-prefix includes the faces applied by font-lock), but | ||
| 181 | ;; jit-lock-register doesn't accept an `append' argument, so | ||
| 182 | ;; we add ourselves beforehand, to make sure we're at the end | ||
| 183 | ;; of the hook (bug#15155). | ||
| 184 | (add-hook 'jit-lock-functions | ||
| 185 | #'visual-wrap-prefix-function 'append t) | ||
| 186 | (jit-lock-register #'visual-wrap-prefix-function)) | ||
| 187 | (jit-lock-unregister #'visual-wrap-prefix-function) | ||
| 188 | (with-silent-modifications | ||
| 189 | (save-restriction | ||
| 190 | (widen) | ||
| 191 | (remove-text-properties (point-min) (point-max) '(wrap-prefix nil)))))) | ||
| 192 | |||
| 193 | ;;;###autoload | ||
| 194 | (define-key-after (lookup-key menu-bar-options-menu [line-wrapping]) | ||
| 195 | [visual-wrap] | ||
| 196 | '(menu-item "Visual Wrap" visual-wrap-prefix-mode | ||
| 197 | :visible (menu-bar-menu-frame-live-and-visible-p) | ||
| 198 | :help "Display continuation lines with prefix derived from context" | ||
| 199 | :button (:toggle . (bound-and-true-p visual-wrap-prefix-mode))) | ||
| 200 | word-wrap) | ||
| 201 | |||
| 202 | (provide 'visual-wrap) | ||
| 203 | ;;; visual-wrap.el ends here | ||