From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: "J.P." Newsgroups: gmane.emacs.bugs Subject: bug#73798: 31.0.50; ERC 5.7: New extensibility focused match API Date: Thu, 31 Oct 2024 22:22:41 -0700 Message-ID: <87ldy3v87y.fsf__38041.5920096979$1730438608$gmane$org@neverwas.me> References: <87y12rifv2.fsf@neverwas.me> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="10944"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: emacs-erc@gnu.org To: 73798@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Fri Nov 01 06:23:21 2024 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1t6k7z-0002gf-T2 for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 01 Nov 2024 06:23:20 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1t6k7k-00069M-Ni; Fri, 01 Nov 2024 01:23:04 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t6k7i-00068T-To for bug-gnu-emacs@gnu.org; Fri, 01 Nov 2024 01:23:03 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1t6k7i-0005iQ-LR for bug-gnu-emacs@gnu.org; Fri, 01 Nov 2024 01:23:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:Date:References:In-Reply-To:From:To:Subject; bh=ZHibBrut/f0BrqauRSy3dnH1kswhB6+gYebo/eEykHA=; b=mHq7gbuCyqj3uXwnT5qXELTu5NzVKZvmHyNWlG+j8XSTZ2Pa0ZkKGGdlmySlfaz8C4lGNTlVaxBC6q6r8j1QjrAei0Wszfsd9jDVt4kD9J1NtqCkvMsOQgYYwj0Am7eCFyxJK7pePYoX/H9zmx285cb91OI7MGXjR4pzGiY9636WvZBW1IHwcYxzY0gx8RlfZmZifbWtyk7JisSWcA+H1MaR67yNT4vkv1+S3Tdz5cJBjtiB2xvUGVmzLW82Y99MqBOwhjXF7UwIVu0e0TTC1HPynoqyMBkWyNrH0eKo+cbs513aQOQ14hCqgcf/cyCG7PUiwGJrXIHGxo2aQYIQKQ==; Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1t6k7i-0001Ru-9Y for bug-gnu-emacs@gnu.org; Fri, 01 Nov 2024 01:23:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: "J.P." Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 01 Nov 2024 05:23:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 73798 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 73798-submit@debbugs.gnu.org id=B73798.17304385745552 (code B ref 73798); Fri, 01 Nov 2024 05:23:02 +0000 Original-Received: (at 73798) by debbugs.gnu.org; 1 Nov 2024 05:22:54 +0000 Original-Received: from localhost ([127.0.0.1]:46788 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1t6k7Z-0001RU-Mj for submit@debbugs.gnu.org; Fri, 01 Nov 2024 01:22:54 -0400 Original-Received: from mail-108-mta127.mxroute.com ([136.175.108.127]:40103) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1t6k7V-0001RO-NI for 73798@debbugs.gnu.org; Fri, 01 Nov 2024 01:22:51 -0400 Original-Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta127.mxroute.com (ZoneMTA) with ESMTPSA id 192e62d091b0003e01.001 for <73798@debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Fri, 01 Nov 2024 05:22:44 +0000 X-Zone-Loop: 7eaf0022c2da40c3fb9618f23fd63c1fe3ba2758df51 X-Originating-IP: [136.175.111.3] DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=neverwas.me ; s=x; h=Content-Transfer-Encoding:Content-Type:MIME-Version:Message-ID:Date: References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=ZHibBrut/f0BrqauRSy3dnH1kswhB6+gYebo/eEykHA=; b=GOT66+JjcHICmbQm88Cy8XTTlj 1MSQt4y2lOwWIk5cSCrhxxuFuR2PAYito8rpy/wNdMFCRK2UX8aTCNcZNKQdOGMlauwLCe5U1D27I JDBvIn6gafIl7bE5F2cCMDqamcQUNFOBYZwMxK7SJtNb1M/BEYzpCTjZ9cp2wMQxaQFJUnuKhvZAb Utm0cuCy/fIW7EDuzKxyUaGgwZMVO3UDQjVGEXr7Gfn8r4tBcOSWoyOZJqCnWI5BBEazbOIgGEH0K ollOOyZbcFaWKeuRL/aUgJPyPCE1ed9kKEvjdEyQuZbEILdmQnIG7O4WovdhfAX3KuXKyjqTlhzF6 /CGIGhYw==; In-Reply-To: <87y12rifv2.fsf@neverwas.me> (J. P.'s message of "Sun, 13 Oct 2024 19:21:37 -0700") X-Authenticated-Id: masked@neverwas.me X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:294653 Archived-At: "J.P." writes: > For a detailed example showing how to use this API for more involved > matching that doesn't involve highlighting, see the =E2=80=98notificati= ons=E2=80=99 > module, which lives in =E2=80=98erc-desktop-notifications.el=E2=80=99. = Ignore the parts > that involve adapting the global setup (and teardown) business to a > buffer-local context. Since your module is declared =E2=80=98local=E2= =80=99, as per the > modern convention, you won't be needing such code, so feel free to use > utility functions like =E2=80=98erc-match-add-local-type=E2=80=99 direc= tly in your > module's definition. Actually, I'm not so sure it's wise to hold up the `notifications' module as a shining example of how to use this API. That's because it currently suffers from some potentially confusing quirks, some of which I'd like to address using internal functions that aren't really meant for third parties. > Here, the user leverages a handy subtype of =E2=80=98erc-match=E2=80=99= , called > =E2=80=98erc-match-opt-keyword=E2=80=99, which actually descends direct= ly from another, > intermediate =E2=80=98erc-match=E2=80=99 type: > > -- Struct: erc-match-traditional category face data part > > Use this type or one of its descendants (see below) if you want > =E2=80=98erc-text-matched-hook=E2=80=99 to run alongside (after) t= he =E2=80=98handler=E2=80=99 > slot's default highlighter, =E2=80=98erc-match-highlight=E2=80=99,= on every match > for which the =E2=80=98category=E2=80=99 slot's value is non-=E2= =80=98nil=E2=80=99 (it becomes the > argument provided for the hook's MATCH-TYPE parameter). > > Much more important, however, is =E2=80=98part=E2=80=99. This slo= t determines what > portion of the message is being highlighted or otherwise operated > on. It can be any symbol, but the ones with predefined methods are > =E2=80=98nick=E2=80=99, =E2=80=98message=E2=80=99, =E2=80=98all=E2= =80=99, =E2=80=98keyword=E2=80=99, =E2=80=98nick-or-keyword=E2=80=99, and > =E2=80=98nick-or-mention=E2=80=99. This should probably also mention what the `data' slot does because it features in both examples. > And, finally, here's a more elaborate, module-like example demoing > highlighting based on the =E2=80=98erc-match-traditional=E2=80=99 type: > > ;; -*- lexical-binding: t; -*- > > (require 'erc-match) > (require 'erc-button) > > (defvar my-keywords > `((foonet ("#chan" ,(rx bow (or "foo" "bar" "baz") eow))))) > > (defface my-keyword '((t (:underline (:color "tomato" :style wave)= ))) > "My face.") > > (defun my-get-keyword () > (and-let* ((chans (alist-get (erc-network) my-keywords)) > ((cdr (assoc (erc-target) chans)))))) > > (cl-defstruct (my-match (:include erc-match-opt-keyword > (part 'keyword) There's no need to override `part' here because `keyword' is already the default. > (data (my-get-keyword)) > (face 'my-keyword)) > (:constructor my-match))) > > (setopt erc-match-types (add-to-list 'erc-match-types #'my-match)) > > (cl-defmethod erc-match-highlight-by-part ((instance my-match) > (_ (eql keyword))) > "Highlight keywords by merging instead of clobbering." > (dolist (pat (my-match-data instance)) > (goto-char (my-match-body-beg instance)) > (while (re-search-forward pat nil t) > (erc-button-add-face (match-beginning 0) (match-end 0) > (my-match-face instance))))) > One thing that's possibly unclear about this example is why the `my-match' definition overrides `face' and `data' only to use their accessors in the body of the method. IOW, readers may wonder why it doesn't just use these init forms directly inline. Moreover, while `data' holds an opaque object that users are technically invited to repurpose as needed, doing so only really makes sense if they're subclassing a traditional options-based type. Indeed, for novel purposes, it's much saner for users to just define their own slot and use it for the usual reasons, e.g., to share processed data in various stages of refinement. This example would do well to incorporate such usage. In any case, it's become clear to me that a practical demonstration of this API might be necessary to fully grasp its facets and trade offs. To that end, I offer the following full-featured demo module: https://emacs-erc.gitlab.io/bugs/archive/jabbycat.html To try it out, you can start Emacs like $ HOME=3D$(mktemp -d) ./src/emacs and then eval (require 'package) (push '("erc-bugs" . "https://emacs-erc.gitlab.io/bugs/archive/") package-archives) (package-install 'erc-73798) (sit-for 1) ;; see [1] below (package-install 'jabbycat) (setopt jabbycat-server "xmpp.myvps.example.org:5222" jabbycat-recipient "me@xmpp.myvps.example.org" jabbycat-username "jabbycat@xmpp.myvps.example.org" jabbycat-password "changeme" erc-jabbycat-match-patterns '((Libera.Chat ("#test" . "."))) erc-modules (add-to-list 'erc-modules 'jabbycat)) (erc-tls) If not already obvious, you either need to apply the latest patch set from this bug or (as shown above) run the bug-specific version of ERC with those changes pre-applied. The source code is currently hosted at https://gitlab.com/emacs-erc/jabbycat (though a possibly less objectionable mirror may be provided eventually). Thanks. [1] For some reason, without the pause, `url-insert-file-contents' gives signal(file-error ("https://fake.example.org/foo.tar" "No Data")) package--with-response-buffer-1("https://fake.example.org/" #f(compiled-function () ...>) :file "foo.tar" :async nil :error-function # :noerror ni= l) package-install-from-archive(#s(package-desc :name foo ... :signed nil)) package-download-transaction((#s(package-desc ... :signed nil))) package-install(foo)