1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-15 10:30:25 -08:00

Improve ERC's internal invisibility API

* etc/ERC-NEWS: Mention that line endings have moved from the end to
the beginning of hidden messages.
* lisp/erc/erc-fill.el (erc-fill--wrap-ensure-dependencies): Warn when
users have `erc-legacy-invisible-bounds-p' enabled, and force it to
its default value of nil in the current buffer.
(erc-fill-wrap-mode, erc-fill-wrap-enable): Move business involving
compat variable for enabling legacy hidden-message behavior to helper.
* lisp/erc/erc-match.el (erc-match--hide-fools-offset-bounds): Move
internal variable from to main library file and rename to
`erc-legacy-invisible-bounds-p'.  Also make obsolete and flip
semantics so a non-nil value enables the traditional behavior.
(erc-match--hide-message): Move to main library file and rename to
`erc--hide-message'.  Add a property-value parameter instead of
hard-coding to `erc-match'.  Also, condition behavior on renamed
compatibility flag `erc-legacy-invisible-bounds-p'.
(erc-hide-fools): Call `erc--hide-message' with own value for
`invisible' property specifically for fools.  That is, use
`match-fools' rather than `erc-match' or `erc-match-fools' to save
room when visually inspecting.  This retains the module name as a
prefix to hopefully minimize collisions with invisibility spec members
owned by non-ERC minor modes.  The `timestamp' spec member owned by
erc-stamp likewise lacks a namespace prefix, but its feature/group
affiliation is self-evident.
(erc-match--modify-invisibility-spec): Use toggle command
non-interactively for adding and removing invisibility spec member.
(erc-match-toggle-hidden-fools): Add explicit override argument and
defer to general helper for actually modifying spec.
(erc-match--toggle-hidden): New helper for toggling invisibility
spec.
* lisp/erc/erc.el (erc--merge-prop): If new value is a list, prepend
onto existing.  Add note about possible space optimization.
(erc-legacy-invisible-bounds-p): New obsolete compat variable to
enable traditional pre-5.6 invisibility interval on hidden messages.
Replaces `erc-match--hide-fools-offset-bounds-p' but has an inverted
meaning.  The new default value of nil means invisibility covers a
shifted interval consisting of the message body plus the line ending
immediately preceding it.
(erc--hide-message): New function, formerly `erc-match--hide-message'
from erc-match.el introduced in ERC 5.6.
* test/lisp/erc/erc-scenarios-match.el:
(erc-scenarios-match--invisible-stamp): Fix comment and use API
function in interactive convenience setup.
(erc-scenarios-match--find-bol): New test helper.
(erc-scenarios-match--find-eol): Fix bug affecting interactive use.
(erc-scenarios-match--stamp-left-fools-invisible,
erc-scenarios-match--stamp-right-fools-invisible,
erc-scenarios-match--stamp-right-invisible-fill-wrap,
erc-scenarios-match--stamp-both-invisible-fill-static): Update
`invisible' property from `erc-match' to `match-fools'.
(erc-scenarios-match--stamp-right-fools-invisible,
erc-scenarios-match--stamp-both-invisible-fill-static): Move test
body to function of same name for use in multiple cases.
(erc-scenarios-match--stamp-right-fools-invisible--nooffset,
erc-scenarios-match--stamp-both-invisible-fill-static--nooffset): New
test variants asserting proper hiding with old pre-5.6 invisibility
interval.
* test/lisp/erc/erc-tests.el (erc-tests--equal-including-properties):
Relocate macro higher in same file.
(erc--merge-prop): New test.  (Bug#64301)
This commit is contained in:
F. Jason Park 2023-07-14 21:08:31 -07:00
parent 63d8b2a59a
commit af547c4bbe
6 changed files with 184 additions and 64 deletions

View file

@ -324,11 +324,17 @@ is 0, reset to value of `erc-fill-wrap-visual-keys'."
;; Not sure if this is problematic because `erc-bol' takes no args.
"<remap> <erc-bol>" #'erc-fill--wrap-beginning-of-line)
(defvar erc-match-mode)
(defvar erc-button-mode)
(defvar erc-match--hide-fools-offset-bounds)
(defvar erc-legacy-invisible-bounds-p)
(defun erc-fill--wrap-ensure-dependencies ()
(with-suppressed-warnings ((obsolete erc-legacy-invisible-bounds-p))
(when erc-legacy-invisible-bounds-p
(erc--warn-once-before-connect 'erc-fill-wrap-mode
"Module `fill-wrap' is incompatible with the obsolete compatibility"
" flag `erc-legacy-invisible-bounds-p'. Disabling locally in %s."
(current-buffer))
(setq-local erc-legacy-invisible-bounds-p nil)))
(let (missing-deps)
(unless erc-fill-mode
(push 'fill missing-deps)
@ -389,9 +395,6 @@ them to every line."
(setq erc-fill--function #'erc-fill-wrap)
(add-function :after (local 'erc-stamp--insert-date-function)
#'erc-fill--wrap-stamp-insert-prefixed-date)
(when (or (bound-and-true-p erc-match-mode) (memq 'match erc-modules))
(require 'erc-match)
(setq erc-match--hide-fools-offset-bounds t))
(when erc-fill-wrap-merge
(add-hook 'erc-button--prev-next-predicate-functions
#'erc-fill--wrap-merged-button-p nil t))

View file

@ -655,24 +655,10 @@ See `erc-log-match-format'."
(get-buffer (car buffer-cons))))))
(switch-to-buffer buffer-name)))
(defvar-local erc-match--hide-fools-offset-bounds nil)
(defun erc-hide-fools (match-type _nickuserhost _message)
"Hide comments from designated fools."
(when (eq match-type 'fool)
(erc-match--hide-message)))
(defun erc-match--hide-message ()
(progn ; FIXME raise sexp
(if erc-match--hide-fools-offset-bounds
(let ((beg (point-min))
(end (point-max)))
(save-restriction
(widen)
(erc--merge-prop (1- beg) (1- end) 'invisible 'erc-match)))
;; Before ERC 5.6, this also used to add an `intangible'
;; property, but the docs say it's now obsolete.
(erc--merge-prop (point-min) (point-max) 'invisible 'erc-match))))
(erc--hide-message 'match-fools)))
(defun erc-beep-on-match (match-type _nickuserhost _message)
"Beep when text matches.
@ -682,19 +668,31 @@ This function is meant to be called from `erc-text-matched-hook'."
(defun erc-match--modify-invisibility-spec ()
"Add an `erc-match' property to the local spec."
;; Hopefully, this will be extended to do the same for other
;; invisible properties managed by this module.
(if erc-match-mode
(add-to-invisibility-spec 'erc-match)
(erc-match-toggle-hidden-fools +1)
(erc-with-all-buffers-of-server nil nil
(remove-from-invisibility-spec 'erc-match))))
(erc-match-toggle-hidden-fools -1))))
(defun erc-match-toggle-hidden-fools ()
(defun erc-match-toggle-hidden-fools (arg)
"Toggle fool visibility.
Expect `erc-hide-fools' or a function that does something similar
to be in `erc-text-matched-hook'."
(interactive)
(if (memq 'erc-match (ensure-list buffer-invisibility-spec))
(remove-from-invisibility-spec 'erc-match)
(add-to-invisibility-spec 'erc-match)))
Expect the function `erc-hide-fools' or similar to be present in
`erc-text-matched-hook'."
(interactive "P")
(erc-match--toggle-hidden 'match-fools arg))
(defun erc-match--toggle-hidden (prop arg)
"Toggle invisibility for spec member PROP.
Treat ARG in a manner similar to mode toggles defined by
`define-minor-mode'."
(when arg
(setq arg (prefix-numeric-value arg)))
(if (memq prop (ensure-list buffer-invisibility-spec))
(unless (natnump arg)
(remove-from-invisibility-spec prop))
(when (or (not arg) (natnump arg))
(add-to-invisibility-spec prop))))
(provide 'erc-match)

View file

@ -3011,22 +3011,51 @@ If STRING is nil, the function does nothing."
(defvar erc--compose-text-properties nil
"Non-nil when `erc-put-text-property' defers to `erc--merge-prop'.")
;; To save space, we could maintain a map of all readable property
;; values and optionally dispense archetypal constants in their place
;; in order to ensure all occurrences of some list (a b) across all
;; text-properties in all ERC buffers are actually the same object.
(defun erc--merge-prop (from to prop val &optional object)
"Compose existing PROP values with VAL between FROM and TO in OBJECT.
"Combine existing PROP values with VAL between FROM and TO in OBJECT.
For spans where PROP is non-nil, cons VAL onto the existing
value, ensuring a proper list. Otherwise, just set PROP to VAL.
See also `erc-button-add-face'."
When VAL is itself a list, prepend its members onto an existing
value. See also `erc-button-add-face'."
(let ((old (get-text-property from prop object))
(pos from)
(end (next-single-property-change from prop object to))
new)
(while (< pos to)
(setq new (if old (cons val (ensure-list old)) val))
(setq new (if old
(if (listp val)
(append val (ensure-list old))
(cons val (ensure-list old)))
val))
(put-text-property pos end prop new object)
(setq pos end
old (get-text-property pos prop object)
end (next-single-property-change pos prop object to)))))
(defvar erc-legacy-invisible-bounds-p nil
"Whether to hide trailing rather than preceding newlines.
Beginning in ERC 5.6, invisibility extends from a message's
preceding newline to its last non-newline character.")
(make-obsolete-variable 'erc-legacy-invisible-bounds-p
"decremented interval now permanent" "30.1")
(defun erc--hide-message (value)
"Apply `invisible' text-property with VALUE to current message.
Expect to run in a narrowed buffer during message insertion."
(if erc-legacy-invisible-bounds-p
;; Before ERC 5.6, this also used to add an `intangible'
;; property, but the docs say it's now obsolete.
(erc--merge-prop (point-min) (point-max) 'invisible value)
(let ((beg (point-min))
(end (point-max)))
(save-restriction
(widen)
(erc--merge-prop (1- beg) (1- end) 'invisible value)))))
(defun erc-display-message-highlight (type string)
"Highlight STRING according to TYPE, where erc-TYPE-face is an ERC face.