before showing hook members the result. For compatibility,
third-party code can request that the final input be adjusted again
prior to being sent. To facilitate this, the 'erc-input' object
-shared among hook members has gained a "phony" 'refoldp' slot that's
-only accessible from 'erc-pre-send-functions'. See doc string for
-details.
+shared among hook members has gained a 'refoldp' slot. See doc string
+for details.
+
+*** More flexibility in sending and displaying prompt input.
+The abnormal hook 'erc-pre-send-functions' previously married outgoing
+message text to its inserted representation in an ERC target buffer.
+Going forward, users can populate the new slot 'substxt' with
+alternate text to insert in place of the 'string' slot's contents,
+which ERC still sends to the server. This dichotomy lets users
+completely avoid the often fiddly 'erc-send-modify-hook' and friends
+for use cases like language translation and subprotocol encoding.
*** ERC's prompt survives the insertion of user input and messages.
Previously, ERC's prompt and its input marker disappeared while
(declare-function widget-type "wid-edit" (widget))
(cl-defstruct erc-input
- string insertp sendp)
+ "Object shared among members of `erc-pre-send-functions'.
+Any use outside of the hook is not supported."
+ ( string "" :type string
+ :documentation "String to send and, without `substxt', insert.
+ERC treats separate lines as separate messages.")
+ ( insertp nil :type boolean
+ :documentation "Whether to insert outgoing message.
+When nil, ERC still sends `string'.")
+ ( sendp nil :type boolean
+ :documentation "Whether to send and (for compat reasons) insert.
+To insert without sending, define a (slash) command.")
+ ( substxt nil :type (or function string null)
+ :documentation "Alternate string to insert without splitting.
+The function form is for internal use.")
+ ( refoldp nil :type boolean
+ :documentation "Whether to resplit a possibly overlong `string'.
+ERC only refolds `string', never `substxt'."))
(cl-defstruct (erc--input-split (:include erc-input
(string "" :read-only t)
(sendp (with-suppressed-warnings
((obsolete erc-send-this))
erc-send-this))))
- (refoldp nil :type boolean)
(lines nil :type (list-of string))
(abortp nil :type (list-of symbol))
(cmdp nil :type boolean))
(make-obsolete-variable 'erc-send-pre-hook 'erc-pre-send-functions "27.1")
(defcustom erc-pre-send-functions nil
- "Special hook run to possibly alter the string that is sent.
-The functions are called with one argument, an `erc-input' struct,
-and should alter that struct.
+ "Special hook to possibly alter the string to send and insert.
+ERC calls the member functions with one argument, an `erc-input'
+struct instance to modify as needed.
-The struct has three slots:
-
- `string': The current input string.
- `insertp': Whether the string should be inserted into the erc buffer.
- `sendp': Whether the string should be sent to the irc server.
-
-And one \"phony\" slot only accessible by hook members at runtime:
+The struct has five slots:
- `refoldp': Whether the string should be re-split per protocol limits.
+ `string': String to send, originally from prompt input.
+ `insertp': Whether a string should be inserted in the buffer.
+ `sendp': Whether `string' should be sent to the IRC server.
+ `substxt': String to display (but not send) instead of `string'.
+ `refoldp': Whether to re-split `string' per protocol limits.
This hook runs after protocol line splitting has taken place, so
-the value of `string' is originally \"pre-filled\". If you need
-ERC to refill the entire payload before sending it, set the phony
-`refoldp' slot to a non-nil value. Note that this refilling is
-only a convenience, and modules with special needs, such as
-preserving \"preformatted\" text or encoding for subprotocol
-\"tunneling\", should handle splitting manually."
- :group 'erc
- :type 'hook
- :version "27.1")
+the value of `string' comes \"pre-split\" according to the option
+`erc-split-line-length'. If you need ERC to refill the entire
+payload before sending it, set the `refoldp' slot to a non-nil
+value. Note that this refilling is only a convenience, and
+modules with special needs, such as preserving \"preformatted\"
+text or encoding for subprotocol \"tunneling\", should handle
+splitting manually and possibly also specify replacement text to
+display via the `substxt' slot."
+ :package-version '(ERC . "5.3")
+ :group 'erc-hooks
+ :type 'hook)
(define-obsolete-variable-alias 'erc--pre-send-split-functions
'erc--input-review-functions "30.1")
(setf (erc--input-split-lines state)
(mapcan #'erc--split-line (erc--input-split-lines state)))))
-(defun erc--input-ensure-hook-context ()
- (unless (erc--input-split-p erc--current-line-input-split)
- (error "Invoked outside of `erc-pre-send-functions'")))
-
-(defun erc-input-refoldp (_)
- "Impersonate accessor for phony `erc-input' `refoldp' slot.
-This function only works inside `erc-pre-send-functions' members."
- (declare (gv-setter (lambda (v)
- `(progn
- (erc--input-ensure-hook-context)
- (setf (erc--input-split-refoldp
- erc--current-line-input-split)
- ,v)))))
- (erc--input-ensure-hook-context)
- (erc--input-split-refoldp erc--current-line-input-split))
-
(defun erc--run-send-hooks (lines-obj)
"Run send-related hooks that operate on the entire prompt input.
Sequester some of the back and forth involved in honoring old
(state (progn
;; This may change `str' and `erc-*-this'.
(run-hook-with-args 'erc-send-pre-hook str)
- (make-erc-input :string str
- :insertp erc-insert-this
- :sendp erc-send-this))))
+ (make-erc-input
+ :string str
+ :insertp erc-insert-this
+ :sendp erc-send-this
+ :substxt (erc--input-split-substxt lines-obj)
+ :refoldp (erc--input-split-refoldp lines-obj)))))
(run-hook-with-args 'erc-pre-send-functions state)
(setf (erc--input-split-sendp lines-obj) (erc-input-sendp state)
(erc--input-split-insertp lines-obj) (erc-input-insertp state)
+ (erc--input-split-substxt lines-obj) (erc-input-substxt state)
+ (erc--input-split-refoldp lines-obj) (erc-input-refoldp state)
;; See note in test of same name re trailing newlines.
(erc--input-split-lines lines-obj)
(let ((lines (split-string (erc-input-string state)
(defun erc--send-input-lines (lines-obj)
"Send lines in `erc--input-split-lines' object LINES-OBJ."
(when (erc--input-split-sendp lines-obj)
- (dolist (line (erc--input-split-lines lines-obj))
- (when (erc--input-split-insertp lines-obj)
- (if (eq (erc--input-split-insertp lines-obj)
- 'erc--command-indicator-display)
- (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))))))
+ (let ((insertp (erc--input-split-insertp lines-obj))
+ (substxt (erc--input-split-substxt lines-obj)))
+ (when (and insertp substxt)
+ (setq insertp nil)
+ (if (functionp substxt)
+ (apply substxt (erc--input-split-lines lines-obj))
+ (erc-display-msg substxt)))
+ (dolist (line (erc--input-split-lines lines-obj))
+ (when insertp
+ (erc-display-msg line))
+ (erc-process-input-line (concat line "\n")
+ (null erc-flood-protect)
+ (not (erc--input-split-cmdp lines-obj)))))))
(defun erc-send-input (input &optional skip-ws-chk)
"Treat INPUT as typed in by the user.