From b6685530bd6fc8faba289df0672fe0be942f95bc Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Sun, 6 Aug 2023 22:05:26 -0700 Subject: [PATCH 3/3] [5.6] Add line-wise movement commands for erc-fill-wrap * lisp/erc/erc-fill.el (erc-fill--wrap-escape-hidden-speaker): New helper to move point to beginning of visible text. (erc-fill--wrap-beginning-of-line): Factor out adjustment for hidden speakers. (erc-fill--wrap-previous-line, erc-fill--wrap-next-line): Add commands for moving to previous and next line in a manner consistent with the value of `erc-fill--wrap-visual-keys'. (erc-fill-warp-mode-map): Add bindings for `next-line' and `previous-line'. (erc-fill-wrap-mode): Revise doc string. (erc-fill-wrap-nudge): Fix vertical anchoring so that point's line remains fixed throughout the adjustment. The previous approach crudely approximated the current window line by betting that all messages are roughly the same length. It also wrongly assumed that `point-max' at least equaled `window-end'. That is, it did not account for blank space between EOB and the bottom of the window. (Bug#60936) --- lisp/erc/erc-fill.el | 70 +++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index e2a82582a3f..7eace924da7 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -262,6 +262,14 @@ erc-fill--wrap-kill-line ;; `kill-line' anyway so that users can see the error. (erc-fill--wrap-move #'kill-line #'kill-visual-line arg)) +(defun erc-fill--wrap-escape-hidden-speaker () + "Move to start of message text when left of speaker. +Basically mimic what `move-beginning-of-line' does with invisible text." + (when-let ((erc-fill-wrap-merge) + (prop (get-text-property (point) 'display)) + ((or (equal prop "") (eq 'margin (car-safe (car-safe prop)))))) + (goto-char (text-property-not-all (point) (pos-eol) 'display prop)))) + (defun erc-fill--wrap-beginning-of-line (arg) "Defer to `move-beginning-of-line' or `beginning-of-visual-line'." (interactive "^p") @@ -271,10 +279,22 @@ erc-fill--wrap-beginning-of-line (if (get-text-property (point) 'erc-prompt) (goto-char erc-input-marker) ;; Mimic what `move-beginning-of-line' does with invisible text. - (when-let ((erc-fill-wrap-merge) - (prop (get-text-property (point) 'display)) - ((or (equal prop "") (eq 'margin (car-safe (car-safe prop)))))) - (goto-char (text-property-not-all (point) (pos-eol) 'display prop))))) + (erc-fill--wrap-escape-hidden-speaker))) + +(defun erc-fill--wrap-previous-line (&optional arg try-vscroll) + "Move to ARGth previous screen or logical line." + (interactive "^p\np") + (if erc-fill--wrap-visual-keys + (with-no-warnings (previous-line arg try-vscroll)) + (prog1 (previous-logical-line arg try-vscroll) + (erc-fill--wrap-escape-hidden-speaker)))) + +(defun erc-fill--wrap-next-line (&optional arg try-vscroll) + "Move to ARGth next screen or logical line." + (interactive "^p\np") + (if erc-fill--wrap-visual-keys + (with-no-warnings (next-line arg try-vscroll)) + (next-logical-line arg try-vscroll))) (defun erc-fill--wrap-end-of-line (arg) "Defer to `move-end-of-line' or `end-of-visual-line'." @@ -320,6 +340,8 @@ erc-fill-wrap-mode-map " " #'erc-fill--wrap-end-of-line " " #'erc-fill--wrap-beginning-of-line " " #'erc-fill-wrap-toggle-truncate-lines + " " #'erc-fill--wrap-next-line + " " #'erc-fill--wrap-previous-line "C-c a" #'erc-fill-wrap-cycle-visual-movement ;; Not sure if this is problematic because `erc-bol' takes no args. " " #'erc-fill--wrap-beginning-of-line) @@ -359,28 +381,36 @@ erc-fill--wrap-ensure-dependencies ;;;###autoload(put 'fill-wrap 'erc--feature 'erc-fill) (define-erc-module fill-wrap nil "Fill style leveraging `visual-line-mode'. -This local module displays nicks overhanging leftward to a common -offset, as determined by the option `erc-fill-static-center'. It -depends on the `fill', `stamp', and `button' modules and assumes -users who've defined their own `erc-insert-timestamp-function' -have also customized the option `erc-fill-wrap-margin-side' to an -explicit side. To use this module, either include `fill-wrap' in -`erc-modules' or set `erc-fill-function' to `erc-fill-wrap'. -Manually invoking one of the minor-mode toggles is not -recommended. +This module displays nicks overhanging leftward to a common +offset, as determined by the option `erc-fill-static-center'. To +use it, either include `fill-wrap' in `erc-modules' or set +`erc-fill-function' to `erc-fill-wrap'. Most users will want to +enable the `scrolltobottom' module as well. Once active, use +\\[erc-fill-wrap-nudge] to adjust the width of the indent and the +stamp margin, and use \\[erc-fill-wrap-toggle-truncate-lines] for +cycling between logical- and screen-oriented movement commands. This module imposes various restrictions on the appearance of timestamps. Most notably, it insists on displaying them in the margins. Users preferring left-sided stamps may notice that ERC also displays the prompt in the left margin, possibly truncating -or padding it to constrain it to the margin's width. When stamps +or padding it to constrain it to the margin's width. +Additionally, this module assumes that users providing their own +`erc-insert-timestamp-function' have also customized the option +`erc-fill-wrap-margin-side' to an explicit side. When stamps appear in the right margin, which they do by default, users may find that ERC actually appends them to copy-as-killed messages without an intervening space. This normally poses at most a minor inconvenience, however users of the `log' module may prefer a workaround provided by `erc-stamp-prefix-log-filter', which strips trailing stamps from logged messages and instead prepends -them to every line." +them to every line. + +As a so-called \"local\" module, `fill-wrap' depends on the +global modules `fill', `stamp', and `button'; it activates them +as needed when initializing. Please note that enabling and +disabling this module by invoking one of its minor-mode toggles +is not recommended." ((erc-fill--wrap-ensure-dependencies) (erc--restore-initialize-priors erc-fill-wrap-mode erc-fill--wrap-visual-keys erc-fill-wrap-visual-keys @@ -548,8 +578,8 @@ erc-fill-wrap-nudge (user-error "Command called in an undisplayed buffer")) (let* ((total (erc-fill--wrap-nudge arg)) (leftp erc-stamp--margin-left-p) - (win-ratio (/ (float (- (window-point) (window-start))) - (- (window-end nil t) (window-start))))) + ;; Anchor current line vertically. + (line (count-screen-lines (window-start) (window-point)))) (when (zerop arg) (setq arg 1)) (erc-compat-call @@ -564,7 +594,7 @@ erc-fill-wrap-nudge (lambda () (interactive) (cl-incf total (erc-fill--wrap-nudge a)) - (recenter (round (* win-ratio (window-height)))))))) + (recenter line))))) (dolist (key '(?\) ?_ ?+)) (let ((a (pcase key (?\) 0) @@ -575,7 +605,7 @@ erc-fill-wrap-nudge (interactive) (erc-stamp--adjust-margin (- a) (zerop a)) (when leftp (erc-stamp--refresh-left-margin-prompt)) - (recenter (round (* win-ratio (window-height)))))))) + (recenter line))))) map) t (lambda () @@ -584,7 +614,7 @@ erc-fill-wrap-nudge (if leftp left-margin-width right-margin-width))) "Use %k for further adjustment" 1) - (recenter (round (* win-ratio (window-height)))))) + (recenter line))) (defun erc-fill-regarding-timestamp () "Fills a text such that messages start at column `erc-fill-static-center'." -- 2.41.0