emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master f9ecde75bbc 2/3: Improve use of Flyspell's API in erc-spelling


From: F. Jason Park
Subject: master f9ecde75bbc 2/3: Improve use of Flyspell's API in erc-spelling
Date: Tue, 7 Jan 2025 20:39:02 -0500 (EST)

branch: master
commit f9ecde75bbcd315557481585a1146f976f719504
Author: F. Jason Park <jp@neverwas.me>
Commit: F. Jason Park <jp@neverwas.me>

    Improve use of Flyspell's API in erc-spelling
    
    * etc/ERC-NEWS: Announce deprecation of `erc-spelling-flyspell-verify'
    and `erc-spelling-unhighlight-word'.  A slight behavioral change not
    worth mentioning is that, previously, ERC arranged for Flyspell to
    ignore any word immediately following a forward slash anywhere in the
    prompt input, even those for which the slash served as mere
    punctuation (a "stroke"), as in "something/misspelt."  As of this
    change, Flyspell only unconditionally exempts an initial slash-prepended
    word, like "tableflip" in "ERC> /tableflip", and checks all others that
    follow against known slash commands.
    * lisp/erc/erc-spelling.el: Change top-level assignment of `erc-mode'
    symbol-property `flyspell-mode-predicate' from
    `erc-spelling-flyspell-verify' to `erc-spelling--flyspell-input-p'.
    (erc-spelling-mode, erc-spelling-disable): Remove local member from
    `flyspell-incorrect-hook'.
    (erc-spelling-init): Add `erc-spelling--flyspell-check' to
    `flyspell-incorrect-hook' locally.  Don't bother explicitly setting
    `flyspell-generic-check-word-predicate' because Flyspell already does
    that for clients using the `flyspell-mode-predicte' interface.
    (erc-spelling-flyspell-verify, erc-spelling-unhighlight-word): Mark
    obsolete.
    (erc-spelling--flyspell-check, erc-spelling--flyspell-input-p): New
    functions, essentially the two halves of a reworked and bifurcated
    `erc-spelling-flyspell-verify'.  Though used as a predicate, the first
    is not named as such because it performs side effects.
    * test/lisp/erc/erc-scenarios-spelling.el: New file.
    * test/lisp/erc/resources/spelling/auto-correct.eld: New file.
    (Bug#75327)
---
 etc/ERC-NEWS                                      |   5 ++
 lisp/erc/erc-spelling.el                          |  25 +++++-
 test/lisp/erc/erc-scenarios-spelling.el           | 100 ++++++++++++++++++++++
 test/lisp/erc/resources/spelling/auto-correct.eld |  35 ++++++++
 4 files changed, 163 insertions(+), 2 deletions(-)

diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index f79d45b94b6..d491c3e5132 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -96,6 +96,11 @@ Although this has always been the case, string values are 
now more
 likely to be seen because ERC no longer coerces service names to port
 numbers.
 
+*** The 'spelling' module makes better use of Flyspell's API.
+As a consequence, the library functions 'erc-spelling-flyspell-verify'
+and 'erc-spelling-unhighlight-word' are now unused and have been marked
+obsolete.
+
 
 * Changes in ERC 5.6
 
diff --git a/lisp/erc/erc-spelling.el b/lisp/erc/erc-spelling.el
index 01e587af368..b354349bcec 100644
--- a/lisp/erc/erc-spelling.el
+++ b/lisp/erc/erc-spelling.el
@@ -48,6 +48,7 @@
        (erc-spelling-init (current-buffer)))))
   ((remove-hook 'erc-connect-pre-hook #'erc-spelling-init)
    (dolist (buffer (erc-buffer-list))
+     (remove-hook 'flyspell-incorrect-hook #'erc-spelling--flyspell-check t)
      (with-current-buffer buffer (flyspell-mode 0)))))
 
 (defcustom erc-spelling-dictionaries nil
@@ -78,7 +79,7 @@ The current buffer is given by BUFFER."
               (if dicts
                   (cadr (car dicts))
                 (erc-with-server-buffer ispell-local-dictionary)))))
-    (setq flyspell-generic-check-word-predicate #'erc-spelling-flyspell-verify)
+    (add-hook 'flyspell-incorrect-hook #'erc-spelling--flyspell-check 20 t)
     (flyspell-mode 1)))
 
 (defun erc-spelling-unhighlight-word (word)
@@ -92,6 +93,7 @@ The cadr is the beginning and the caddr is the end."
 
 (defun erc-spelling-flyspell-verify ()
   "Flyspell only the input line, nothing else."
+  (declare (obsolete erc-spelling--flyspell-input-p "31.1"))
   ;; FIXME: Don't use `flyspell-word'!
   (let ((word-data (and (boundp 'flyspell-word)
                         flyspell-word)))
@@ -109,9 +111,28 @@ The cadr is the beginning and the caddr is the end."
              nil)
             (t t)))))
 
+;; Do this down here to avoid having to wrap the call sites above in
+;; `with-suppressed-warnings'.
+(make-obsolete 'erc-spelling-unhighlight-word
+               "value from `flyspell-get-word' now unused" "31.1")
+
+(defun erc-spelling--flyspell-check (beg end _)
+  "Return non-nil and remove overlay if text between BEG and END is correct."
+  (or (and erc-channel-users
+           (erc-get-channel-user (buffer-substring-no-properties beg end))
+           (always (flyspell-unhighlight-at beg)))
+      (and erc-input-marker (> beg erc-input-marker) (eq (char-before beg) ?/)
+           (or (= beg (1+ erc-input-marker)) ; allow /misspelled at prompt
+               (erc-command-symbol (buffer-substring-no-properties beg end)))
+           (always (flyspell-unhighlight-at beg)))))
+
+(defun erc-spelling--flyspell-input-p ()
+  "Return non-nil if Flyspell should check the prompt input at point."
+  (>= (point) erc-input-marker))
+
 (put 'erc-mode
      'flyspell-mode-predicate
-     #'erc-spelling-flyspell-verify)
+     #'erc-spelling--flyspell-input-p)
 
 (provide 'erc-spelling)
 
diff --git a/test/lisp/erc/erc-scenarios-spelling.el 
b/test/lisp/erc/erc-scenarios-spelling.el
new file mode 100644
index 00000000000..a6660267fe8
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-spelling.el
@@ -0,0 +1,100 @@
+;;; erc-scenarios-spelling.el --- Basic spelling scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2025 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(require 'erc-spelling)
+
+(ert-deftest erc-scenarios-spelling--auto-correct ()
+  :tags `(:expensive-test
+          :unstable
+          ,@(and (getenv "ERC_TESTS_GRAPHICAL") '(:erc--graphical)))
+
+  ;; Allow running locally with SELECTOR=t if user has ispell configured.
+  (unless (ignore-errors
+            (and (executable-find ispell-program-name)
+                 (progn (ispell-check-version) t)
+                 (member "american" (ispell-valid-dictionary-list))))
+    (ert-skip "Missing ispell program"))
+
+  (ert-with-temp-directory erc-scenarios-spelling
+
+    (erc-scenarios-common-with-noninteractive-in-term
+        ((erc-scenarios-common-dialog "spelling")
+         (process-environment (cons
+                               (format "HOME=%s" erc-scenarios-spelling)
+                               process-environment))
+         (dumb-server (erc-d-run "localhost" t 'auto-correct))
+         (port (process-contact dumb-server :service))
+         (expect (erc-d-t-make-expecter))
+         (erc-autojoin-channels-alist '((foonet "#chan")))
+         (erc-modules (cons 'spelling erc-modules))
+         (erc-server-flood-penalty 0.1))
+
+      (ert-info ("Connect to foonet")
+        (with-current-buffer (erc :server "127.0.0.1"
+                                  :port port
+                                  :nick "tester"
+                                  :full-name "tester")
+          (funcall expect 10 "no longer marked as being")
+          (should erc-spelling-mode)
+          (should flyspell-mode)))
+
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+        (should erc-spelling-mode)
+        (should flyspell-mode)
+        (funcall expect 10 "<alice> tester, welcome!")
+
+        ;; Insert a command with one misspelled word.
+        (set-window-buffer nil (current-buffer))
+        (execute-kbd-macro "\M->/AMSG an/dor /gmsg one fsbot two frob my shoe")
+        (funcall expect 10 "shoe")
+
+        (let* ((ovs (overlays-in erc-input-marker (point)))
+               (ov1 (pop ovs))
+               (ov2 (pop ovs)))
+          ;; At this point, flyspell should have done its thing.  There
+          ;; should be two overlays: one on "dor" and the other on
+          ;; "frob".  The spelling module's modifications should have
+          ;; prevented the two valid slash commands as well as "fsbot"
+          ;; from being highlighted.
+          (should-not ovs)
+          (should (flyspell-overlay-p ov1))
+          (should (equal "dor" (buffer-substring (overlay-start ov1)
+                                                 (overlay-end ov1))))
+          (should (flyspell-overlay-p ov2))
+          (should (equal "frob" (buffer-substring (overlay-start ov2)
+                                                  (overlay-end ov2))))
+          (goto-char (overlay-start ov2))
+
+          ;; Depending on the machine, this should become something
+          ;; like: "/AMSG an/dor /gmsg one fsbot two Rob my shoe".
+          (execute-kbd-macro (key-parse "M-TAB"))
+          (should (equal (overlays-in erc-input-marker (point-max))
+                         (list ov1)))))
+
+      (when noninteractive
+        (erc-spelling-mode -1)))))
+
+;;; erc-scenarios-spelling.el ends here
diff --git a/test/lisp/erc/resources/spelling/auto-correct.eld 
b/test/lisp/erc/resources/spelling/auto-correct.eld
new file mode 100644
index 00000000000..0f00ee4825c
--- /dev/null
+++ b/test/lisp/erc/resources/spelling/auto-correct.eld
@@ -0,0 +1,35 @@
+;; -*- mode: lisp-data; -*-
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Wed, 05 May 2021 
09:05:34 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect.")
+ (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
+
+((join 10 "JOIN #chan")
+ (0 ":tester!~u@247eaxkrufj44.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice fsbot @bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of /NAMES list."))
+
+((mode-chan 10 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620205534")
+ (0 ":alice!~u@yppdd5tt4admc.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":bob!~u@yppdd5tt4admc.irc PRIVMSG #chan :alice: Nor I no strength to 
climb without thy help.")
+ (0 ":alice!~u@yppdd5tt4admc.irc PRIVMSG #chan :bob: Nothing, but let him have 
thanks."))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]