>From 44cb69befc28ae4e14499521fb2f8a09d7acaf5c Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Mon, 24 Oct 2022 22:58:13 -0700 Subject: [PATCH] Warn of future breaking change to erc-response.tags * lisp/erc/erc-backend.el (erc-parse-tags-format): New option to determine type of the `erc-response' "tags" field. (erc-parse-tags): Defer to internal generic function. (erc--parse-tags): New function to hold original `erc-parse-tags' implementation. (erc--parse-message-tags): New generic function that conditionally calls `erc--parse-tags', perhaps emitting a warning beforehand. (erc-parse-server-response): Call `erc--parse-message-tags'. --- lisp/erc/erc-backend.el | 59 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index df9efe4b0c..9854e863c3 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -992,8 +992,39 @@ erc-send-ctcp-notice ;;;; Handling responses +(defcustom erc-tags-format 'overridable + "Shape of the `tags' alist in `erc-response' objects. +When set to `legacy', pre-5.5 parsing behavior takes effect for +the tags portion of every message. The resulting alist contains +conses of the form (STRING . LIST), in which LIST is comprised of +at most one (possibly empty) string. + +When nil, ERC only parses tags if an active module defines an +implementation. It otherwise ignores them. In such cases, each +alist element is a cons of a symbol and an optional, non-empty +string. + +With the default value of `overridable', ERC behaves as it does +with `legacy' except that it emits a warning whenever first +encountering a message containing tags in a given Emacs session. +But it only does so when a module implementing overriding, +non-legacy behavior isn't already active in the current network +context. + +Note that future bundled modules providing IRCv3 functionality +may not be compatible with the legacy format. User code should +eventually transition to expecting this \"5.5+ variant\" and set +this option to nil." + :package-version '(ERC . "5.4.1") ; FIXME increment on next release + :type '(choice (const nil) + (const legacy) + (const overridable))) + (defun erc-parse-tags (string) "Parse IRCv3 tags list in STRING to a (tag . value) alist." + (erc--parse-message-tags string)) + +(defun erc--parse-tags (string) (let ((tags) (tag-strings (split-string string ";"))) (dolist (tag-string tag-strings tags) @@ -1003,6 +1034,28 @@ erc-parse-tags `(,pair)) tags))))) +;; One benefit of this function being internal is to avoid having to +;; define a separate method just to ensure an `erc-tags-format' value +;; of `legacy' always wins. The downside is that module code must +;; take care to preserve that promise manually. + +(cl-defgeneric erc--parse-message-tags (string) + "Parse STRING into an alist of (TAG . VALUE) conses. +TAG is a symbol. VALUE is nil or a non-empty string. Composite +raw input values containing commas are never split but always +left as a single string." + (when erc-tags-format + (unless (or (eq erc-tags-format 'legacy) + (get 'erc-parse-tags 'erc-v3-warned-p)) + (put 'erc-parse-tags 'erc-v3-warned-p t) + (display-warning + 'ERC + (concat + "Legacy ERC tags behavior is currently in effect, but other modules," + " including those bundled with ERC, may override this in future" + " releases. See `erc-tags-format' for more info."))) + (erc--parse-tags string))) + (defun erc-parse-server-response (proc string) "Parse and act upon a complete line from an IRC server. PROC is the process (connection) from which STRING was received. @@ -1012,9 +1065,9 @@ erc-parse-server-response (let* ((tag-list (when (eq (aref string 0) ?@) (substring string 1 (string-search " " string)))) - (msg (make-erc-response :unparsed string :tags (when tag-list - (erc-parse-tags - tag-list)))) + (msg (make-erc-response :unparsed string :tags + (when tag-list + (erc--parse-message-tags tag-list)))) (string (if tag-list (substring string (+ 1 (string-search " " string))) string)) -- 2.37.3