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)
This commit is contained in:
parent
c266c22b41
commit
f9ecde75bb
4 changed files with 163 additions and 2 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
100
test/lisp/erc/erc-scenarios-spelling.el
Normal file
100
test/lisp/erc/erc-scenarios-spelling.el
Normal file
|
@ -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
|
35
test/lisp/erc/resources/spelling/auto-correct.eld
Normal file
35
test/lisp/erc/resources/spelling/auto-correct.eld
Normal file
|
@ -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."))
|
Loading…
Add table
Reference in a new issue