* 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)
@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)
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
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."
;; 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."
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)
"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)
(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
"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))
(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
(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)
(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)
(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
(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))))))
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)))
(funcall expect 10 "<alice> 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 "<bob> 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 "<alice> bob: Spotted, detested")
+ (erc-scenarios-common-say "/say /me sad")
+ (funcall expect -0.1 "ERC> /say /me sad")
+ (funcall expect 10 "<tester> /me sad"))
+
+ (ert-info ("Prompt absent for /SV")
+ (funcall expect 10 "<bob> Marcus, my brother!")
+ (erc-scenarios-common-say "/sv")
+ (funcall expect -0.1 "ERC> /sv")
+ (funcall expect 10 "<tester> I'm using ERC"))
+
+ (ert-info ("Prompt absent module list via /SM")
+ (funcall expect 10 "<bob> alice: You still wrangle")
+ (erc-scenarios-common-say "/sm")
+ (funcall expect -0.1 "ERC> /sm")
+ (funcall expect 10 "<tester> I'm using the following modules: ")
+ (funcall expect 10 "<alice> 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
(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