From: F. Jason Park Date: Fri, 10 Nov 2023 21:34:31 +0000 (-0800) Subject: Revive erc-command-indicator as new module X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=1d2aa130caeb6494e647db02237cfd414249a3db;p=emacs.git Revive erc-command-indicator as new module * doc/misc/erc.texi: Add entry for `command-indicator' to Modules chapter. * etc/ERC-NEWS: Mention new module `command-indicator'. * lisp/erc/erc-goodies.el (erc-noncommands-list): Replace the nonexistent `erc-cmd-SMV' with function `erc-cmd-SAY'. (erc-noncommands-mode, erc-noncommands-enable, erc-noncommands-disable): Deprecate this module because it's a no-op. (erc-command-indicator-face, erc-command-indicator): Migrate from main library. (erc-command-indicator-mode, erc-command-indicator-enable, erc-command-indicator-disable): New module to take the spiritual place of `noncommands'. (erc-command-indicator): Move function here from main library, along with option namesake mentioned above. (erc-command-indicator-toggle-hidden): New command to toggle echoed command-line visibility. (erc--command-indicator-permit-insertion): New function. (erc--command-indicator-display): New function, a slightly revised version of the old `erc-display-command' from the main library. Its only call site was removed back in d1036d288de "backport: erc bugfixes". However, references were left behind to associated assets, like `erc-command-indicator', etc. The function was later commented out in 0c599ee2e2c "* lisp/erc/erc.el: Use `run-hook-with-args` for `erc-pre-send-functions`", and then removed by a63ed6f78a6 "Remove duplicate ERC prompt on reconnect". * lisp/erc/erc-match.el (erc-match-toggle-hidden-fools): Use new non-module-specific name for `erc-match--toggle-hidden'. (erc-match--toggle-hidden): Move to main library for shared use by other modules. * lisp/erc/erc.el (erc-hide-prompt): Leave note explaining updated role. (erc-command-indicator): Move option and function of same name to erc-goodies. (erc-command-indicator-face): Move to erc-goodies. (erc-modules): Remove module `noncommands' from standard value and Custom set. Add `command-indicator' to set. (erc--toggle-hidden): "New" function, a rebranded version of the utility `erc-match--toggle-hidden' from erc-match. (erc--send-input-lines): Accommodate modules wanting alternate insertion functions. (erc-load-irc-script-lines): Account for `erc-command-indicator' no longer being defined in this library. * test/lisp/erc/erc-scenarios-base-send-message.el (erc-scenarios-base-send-message--command-indicator): New test. * test/lisp/erc/erc-tests.el (erc-tests--modules): Remove deprecated module `noncommands' from manifest. (Bug#67031) --- diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index 10902eac33f..44e82084b90 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -450,6 +450,11 @@ Buttonize URLs, nicknames, and other text @item capab-identify Mark unidentified users on freenode and other servers supporting CAPAB. +@cindex modules, command-indicator +@item command-indicator +Echo command lines for ``slash commands'', like @kbd{/JOIN #erc} and +@kbd{/HELP join} + @cindex modules, completion @cindex modules, pcomplete @item completion (aka pcomplete) diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index f59023eae62..cd4a283ef1c 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -157,6 +157,19 @@ asking users who've customized this option to switch to that some other solution, like automatic migration, is justified, please make that known on the bug list. +** Module 'noncommands' deprecated, replaced by 'command-indicator'. +Command-line echoing has returned to ERC after a near decade-long +hiatus. This means you can elect to have ERC leave a trail of (most) +slash-command input submitted at the prompt, in a manner resembling +that of a shell or a REPL. The particulars are likely of little +interest to most users, but the gist is that this functionality was +removed in 5.3.x (Emacs 24.5) without mention in this document or a +change log. Everything's mostly been restored, except that the +feature is now opt-in. The only real gotcha is that related faces and +options, like 'erc-command-indicator', have moved to the 'erc-goodies' +library, although their Custom groups remain the same. Add +'command-indicator' to 'erc-modules' to get started. + ** 'erc-button-alist' and 'erc-nick-popup-alist' have evolved slightly. It's no secret that the 'buttons' module treats potential nicknames specially. This is perhaps most evident in its treatment of the diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el index 4cc81dd9378..1482c21e931 100644 --- a/lisp/erc/erc-goodies.el +++ b/lisp/erc/erc-goodies.el @@ -471,21 +471,26 @@ For use with `keep-place-indicator' module." erc-cmd-COUNTRY erc-cmd-SV erc-cmd-SM - erc-cmd-SMV + erc-cmd-SAY erc-cmd-LASTLOG) - "List of commands that are aliases for CTCP ACTION or for ERC messages. - -If a command's function symbol is in this list, the typed command -does not appear in the ERC buffer after the user presses ENTER.") + "List of client \"slash commands\" that perform their own buffer I/O. +The `command-indicator' module forgoes echoing these commands, +most of which aren't actual interactive lisp commands.") ;;;###autoload(autoload 'erc-noncommands-mode "erc-goodies" nil t) (define-erc-module noncommands nil - "This mode distinguishes non-commands. -Commands listed in `erc-insert-this' know how to display -themselves." + "Treat commands that display themselves specially. +This module has been a no-op since ERC 5.3 and has likely only +ever made sense in the context of `erc-command-indicator'. It +was deprecated in ERC 5.6." ((add-hook 'erc--input-review-functions #'erc-send-distinguish-noncommands)) ((remove-hook 'erc--input-review-functions #'erc-send-distinguish-noncommands))) +(make-obsolete-variable 'erc-noncommand-mode + 'erc-command-indicator-mode "30.1") +(make-obsolete 'erc-noncommand-mode 'erc-command-indicator-mode "30.1") +(make-obsolete 'erc-noncommand-enable 'erc-command-indicator-enable "30.1") +(make-obsolete 'erc-noncommand-disable 'erc-command-indicator-disable "30.1") (defun erc-send-distinguish-noncommands (state) "If STR is an ERC non-command, set `insertp' in STATE to nil." @@ -499,6 +504,106 @@ themselves." ;; Inhibit sending this string. (setf (erc-input-insertp state) nil)))) + +;;; Command-indicator + +(defface erc-command-indicator-face + '((t :inherit (erc-input-face fixed-pitch-serif))) + "Face for echoed command lines, including the prompt. +See option `erc-command-indicator'." + :package-version '(ERC . "5.6") ; standard value, from bold + :group 'erc-faces) + +(defcustom erc-command-indicator 'erc-prompt + "Pseudo prompt for echoed command lines. +An analog of the option `erc-prompt' that replaces the \"speaker +label\" for echoed \"slash\" commands submitted at the prompt. A +value of nil means ERC only inserts the command-line portion +alone, without the prompt, which may trick certain modules, like +`fill', into treating the leading slash command itself as the +message's speaker." + :package-version '(ERC . "5.6") + :group 'erc-display + :type '(choice (const :tag "Defer to `erc-prompt'" erc-prompt) + (const :tag "Print command lines without a prompt" nil) + (string :tag "User-provided string") + (function :tag "User-provided function"))) + +;;;###autoload(autoload 'erc-command-indicator-mode "erc-goodies" nil t) +(define-erc-module command-indicator nil + "Echo command lines for \"slash commands,\" like /JOIN, /HELP, etc. +Skip those appearing in `erc-noncommands-list'. + +Users can run \\[erc-command-indicator-toggle-hidden] to hide and +reveal echoed command lines after they've been inserted." + ((add-hook 'erc--input-review-functions + #'erc--command-indicator-permit-insertion 80 t) + (erc-command-indicator-toggle-hidden -1)) + ((remove-hook 'erc--input-review-functions + #'erc--command-indicator-permit-insertion t) + (erc-command-indicator-toggle-hidden +1)) + 'local) + +(defun erc-command-indicator () + "Return the command-indicator prompt as a string. +Do nothing if the variable `erc-command-indicator' is nil." + (and erc-command-indicator + (let ((prompt (if (functionp erc-command-indicator) + (funcall erc-command-indicator) + erc-command-indicator))) + (concat prompt (and (not (string-empty-p prompt)) + (not (string-suffix-p " " prompt)) + " "))))) + +(defun erc-command-indicator-toggle-hidden (arg) + "Toggle whether echoed \"slash commands\" are visible." + (interactive "P") + (erc--toggle-hidden 'command-indicator arg)) + +(defun erc--command-indicator-permit-insertion (state) + "Insert `erc-input' STATE's message if it's an echoed command." + (cl-assert erc-command-indicator-mode) + (when (erc--input-split-cmdp state) + (setf (erc--input-split-insertp state) #'erc--command-indicator-display) + (erc-send-distinguish-noncommands state))) + +;; This function used to be called `erc-display-command'. It was +;; neutered in ERC 5.3.x (Emacs 24.5), commented out in 5.4, removed +;; in 5.5, and restored in 5.6. +(defun erc--command-indicator-display (line) + "Insert command LINE as echoed input resembling that of REPLs and shells." + (when erc-insert-this + (save-excursion + (erc--assert-input-bounds) + (let ((insert-position (marker-position (goto-char erc-insert-marker))) + (erc--msg-props (or erc--msg-props + (let ((ovs erc--msg-prop-overrides)) + (map-into `((erc-msg . slash-cmd) + ,@(reverse ovs)) + 'hash-table))))) + (when-let ((string (erc-command-indicator)) + (erc-input-marker (copy-marker erc-input-marker))) + (erc-display-prompt nil nil string 'erc-command-indicator-face) + (remove-text-properties insert-position (point) + '(field nil erc-prompt nil)) + (set-marker erc-input-marker nil)) + (let ((beg (point))) + (insert line) + (erc-put-text-property beg (point) + 'font-lock-face 'erc-command-indicator-face) + (insert "\n")) + (save-restriction + (narrow-to-region insert-position (point)) + (run-hooks 'erc-send-modify-hook) + (run-hooks 'erc-send-post-hook) + (cl-assert (> (- (point-max) (point-min)) 1)) + (erc--hide-message 'command-indicator) + (add-text-properties (point-min) (1+ (point-min)) + (erc--order-text-properties-from-hash + erc--msg-props)))) + (erc--refresh-prompt)))) + + ;;; IRC control character processing. (defgroup erc-control-characters nil "Dealing with control characters." diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 8644e61106f..6fff54d3cf4 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -695,19 +695,7 @@ This function is meant to be called from `erc-text-matched-hook'." 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)))) + (erc--toggle-hidden 'match-fools arg)) (provide 'erc-match) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 6a110f7ca77..cd1c925a757 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -346,8 +346,13 @@ with a value of 2 and means disallow more than 1 line of input." "If non-nil, hide input prompt upon disconnecting. To unhide, type something in the input area. Once revealed, a prompt remains unhidden until the next disconnection. Channel -prompts are unhidden upon rejoining. See -`erc-unhide-query-prompt' for behavior concerning query prompts." +prompts are unhidden upon rejoining. For behavior concerning +query prompts, see `erc-unhide-query-prompt'. Longtime ERC users +should note that this option was repurposed in ERC 5.5 because it +had lain dormant for years after being sidelined in 5.3 when its +only use in the interactive client was removed. Before then, its +role was controlling whether `erc-command-indicator' would appear +alongside echoed slash-command lines." :package-version '(ERC . "5.5") :group 'erc-display :type '(choice (const :tag "Always hide prompt" t) @@ -759,28 +764,6 @@ See also the variable `erc-prompt'." (concat prompt " ") prompt))) -(defcustom erc-command-indicator nil - "Indicator used by ERC for showing commands. - -If non-nil, this will be used in the ERC buffer to indicate -commands (i.e., input starting with a `/'). - -If nil, the prompt will be constructed from the variable `erc-prompt'." - :group 'erc-display - :type '(choice (const nil) string function)) - -(defun erc-command-indicator () - "Return the command indicator prompt as a string. - -This only has any meaning if the variable `erc-command-indicator' is non-nil." - (and erc-command-indicator - (let ((prompt (if (functionp erc-command-indicator) - (funcall erc-command-indicator) - erc-command-indicator))) - (if (> (length prompt) 0) - (concat prompt " ") - prompt)))) - (defcustom erc-notice-prefix "*** " "Prefix for all notices." :group 'erc-display @@ -1364,12 +1347,6 @@ This will only be used if `erc-header-line-face-method' is non-nil." "ERC face for the prompt." :group 'erc-faces) -(defface erc-command-indicator-face - '((t :weight bold)) - "ERC face for the command indicator. -See the variable `erc-command-indicator'." - :group 'erc-faces) - (defface erc-notice-face '((default :weight bold) (((class color) (min-colors 88) (supports :weight semi-bold)) @@ -2077,7 +2054,7 @@ buffer rather than a server buffer.") (defcustom erc-modules '( autojoin button completion fill imenu irccontrols list match menu move-to-prompt netsplit - networks noncommands readonly ring stamp track) + networks readonly ring stamp track) "A list of modules which ERC should enable. If you set the value of this without using `customize' remember to call \(erc-update-modules) after you change it. When using `customize', modules @@ -2127,6 +2104,7 @@ removed from the list will be disabled." (const :tag "button: Buttonize URLs, nicknames, and other text" button) (const :tag "capab: Mark unidentified users on servers supporting CAPAB" capab-identify) + (const :tag "command-indicator: Echo command lines." command-indicator) (const :tag "completion: Complete nicknames and commands (programmable)" completion) (const :tag "dcc: Provide Direct Client-to-Client support" dcc) @@ -2146,7 +2124,7 @@ removed from the list will be disabled." (const :tag "networks: Provide data about IRC networks" networks) (const :tag "nickbar: Show nicknames in a dyamic side window" nickbar) (const :tag "nicks: Uniquely colorize nicknames in target buffers" nicks) - (const :tag "noncommands: Don't display non-IRC commands after evaluation" + (const :tag "noncommands: Deprecated. See module `command-indicator'." noncommands) (const :tag "notifications: Desktop alerts on PRIVMSG or mentions" notifications) @@ -3328,6 +3306,18 @@ don't bother including the preceding newline." (cl-incf beg)) (erc--merge-prop (1- beg) (1- end) 'invisible value))))) +(defun erc--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)))) + (defun erc--delete-inserted-message (beg-or-point &optional end) "Remove message between BEG and END. Expect BEG and END to match bounds as returned by the macro @@ -7051,7 +7041,9 @@ queue. Expect LINES-OBJ to be an `erc--input-split' object." (when (erc--input-split-sendp lines-obj) (dolist (line (erc--input-split-lines lines-obj)) (when (erc--input-split-insertp lines-obj) - (erc-display-msg line)) + (if (functionp (erc--input-split-insertp lines-obj)) + (funcall (erc--input-split-insertp lines-obj) line) + (erc-display-msg line))) (erc-process-input-line (concat line "\n") (null erc-flood-protect) (not (erc--input-split-cmdp lines-obj)))))) @@ -7557,7 +7549,10 @@ sequences, process the lines verbatim. Use this for multiline user input." (let* ((cb (current-buffer)) (s "") - (sp (or (erc-command-indicator) (erc-prompt))) + (sp (or (and (bound-and-true-p erc-command-indicator-mode) + (fboundp 'erc-command-indicator) + (erc-command-indicator)) + (erc-prompt))) (args (and (boundp 'erc-script-args) erc-script-args))) (if (and args (string-match "^ " args)) (setq args (substring args 1))) diff --git a/test/lisp/erc/erc-scenarios-base-send-message.el b/test/lisp/erc/erc-scenarios-base-send-message.el index 904381abe6a..bf9e0f5ae3a 100644 --- a/test/lisp/erc/erc-scenarios-base-send-message.el +++ b/test/lisp/erc/erc-scenarios-base-send-message.el @@ -69,4 +69,58 @@ (funcall expect 10 " No, not till Thursday;")))))) +;; This asserts that the `command-indicator' module only inserts +;; prompt-like prefixes for normal slash commands, like /JOIN. + +(ert-deftest erc-scenarios-base-send-message--command-indicator () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/send-message") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'noncommands)) + (erc-modules `(command-indicator fill-wrap ,@erc-modules)) + (expect (erc-d-t-make-expecter))) + + (ert-info ("Connect to foonet") + (with-current-buffer (erc :server "127.0.0.1" + :port (process-contact dumb-server :service) + :nick "tester" + :full-name "tester") + (funcall expect 5 "debug mode") + (erc-scenarios-common-say "/join #chan") + (funcall expect 10 "ERC> /join #chan"))) + + (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan")) + (ert-info ("Prompt absent for CTCP ACTION") + (funcall expect 10 " alice: For hands, to do Rome") + (erc-scenarios-common-say "/me sad") + (funcall expect -0.1 "ERC> /me sad") + (funcall expect 10 "* tester sad")) + + (ert-info ("Prompt absent for literal command") + (funcall expect 10 " bob: Spotted, detested") + (erc-scenarios-common-say "/say /me sad") + (funcall expect -0.1 "ERC> /say /me sad") + (funcall expect 10 " /me sad")) + + (ert-info ("Prompt absent for /SV") + (funcall expect 10 " Marcus, my brother!") + (erc-scenarios-common-say "/sv") + (funcall expect -0.1 "ERC> /sv") + (funcall expect 10 " I'm using ERC")) + + (ert-info ("Prompt absent module list via /SM") + (funcall expect 10 " alice: You still wrangle") + (erc-scenarios-common-say "/sm") + (funcall expect -0.1 "ERC> /sm") + (funcall expect 10 " I'm using the following modules: ") + (funcall expect 10 " No, not till Thursday;")) + + (ert-info ("Prompt present for /QUIT in issuing buffer") + (erc-scenarios-common-say "/quit") + (funcall expect 10 "ERC> /quit")) + + (with-current-buffer "foonet" + (funcall expect 10 "ERC finished"))))) + ;;; erc-scenarios-base-send-message.el ends here diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 2898ca7be75..e7422d330c0 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -2543,7 +2543,8 @@ (kill-buffer "#chan"))) (defconst erc-tests--modules - '( autoaway autojoin bufbar button capab-identify completion dcc fill identd + '( autoaway autojoin bufbar button capab-identify + command-indicator completion dcc fill identd imenu irccontrols keep-place list log match menu move-to-prompt netsplit networks nickbar nicks noncommands notifications notify page readonly replace ring sasl scrolltobottom services smiley sound