aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorF. Jason Park2023-12-23 12:46:33 -0800
committerF. Jason Park2023-12-27 21:32:25 -0800
commit65735efdca017f2ec0aa1022b7e82f68fbe0084d (patch)
tree9e00293e01aff32fe594e43ba484a702429a0a26
parent8f571769e155a214ae2f9f760dd179b687d9982e (diff)
downloademacs-65735efdca017f2ec0aa1022b7e82f68fbe0084d.tar.gz
emacs-65735efdca017f2ec0aa1022b7e82f68fbe0084d.zip
Improve multi-window erc-keep-place-indicator-mode
* lisp/erc/erc-goodies.el (erc-keep-place-indicator-follow): Describe condition causing an indicator update. (erc--keep-place-indicator-on-window-configuration-change, erc--keep-place-indicator-on-window-buffer-change): Rename former to latter, add required WINDOW parameter, and don't move indicator if buffer appears in multiple windows. Also, don't bother checking whether either buffer is a mini because the manual says window change functions don't run for minibuffer replacements. (erc--keep-place-indicator-setup): Hook on `window-buffer-change-functions' instead of `window-configuration-change-hook'. (erc-keep-place-mode, erc-keep-place-disable): Remove member from `window-buffer-change-functions' instead of `window-configuration-change-hook'. (erc-keep-place): Use `visible' FRAME arg of `get-buffer-window'. Don't twiddle `window-prev-buffers' when `erc-keep-place-indicator-mode' is non-nil. This feature was originally introduced by bug#59943. * test/lisp/erc/erc-goodies-tests.el (erc-goodies-tests--assert-kp-indicator-on, erc-goodies-tests--assert-kp-indicator-off): Update hook name. * test/lisp/erc/erc-scenarios-keep-place-indicator.el: New file. * test/lisp/erc/resources/keep-place/follow.eld: New file.
-rw-r--r--lisp/erc/erc-goodies.el54
-rw-r--r--test/lisp/erc/erc-goodies-tests.el4
-rw-r--r--test/lisp/erc/erc-scenarios-keep-place-indicator.el134
-rw-r--r--test/lisp/erc/resources/keep-place/follow.eld73
4 files changed, 244 insertions, 21 deletions
diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el
index e10f047b187..9d385b628dc 100644
--- a/lisp/erc/erc-goodies.el
+++ b/lisp/erc/erc-goodies.el
@@ -300,7 +300,10 @@ A value of t means \"all\" ERC buffers."
300 300
301(defcustom erc-keep-place-indicator-follow nil 301(defcustom erc-keep-place-indicator-follow nil
302 "Whether to sync visual kept place to window's top when reading. 302 "Whether to sync visual kept place to window's top when reading.
303For use with `erc-keep-place-indicator-mode'." 303For use with `erc-keep-place-indicator-mode'. When enabled, the
304indicator updates when the last window displaying the same buffer
305switches away, but only if the indicator resides earlier in the
306buffer than the window's start."
304 :group 'erc 307 :group 'erc
305 :package-version '(ERC . "5.6") 308 :package-version '(ERC . "5.6")
306 :type 'boolean) 309 :type 'boolean)
@@ -328,17 +331,26 @@ For use with `erc-keep-place-indicator-mode'."
328(defvar-local erc--keep-place-indicator-overlay nil 331(defvar-local erc--keep-place-indicator-overlay nil
329 "Overlay for `erc-keep-place-indicator-mode'.") 332 "Overlay for `erc-keep-place-indicator-mode'.")
330 333
331(defun erc--keep-place-indicator-on-window-configuration-change () 334(defun erc--keep-place-indicator-on-window-buffer-change (window)
332 "Maybe sync `erc--keep-place-indicator-overlay'. 335 "Maybe sync `erc--keep-place-indicator-overlay'.
333Specifically, do so unless switching to or from another window in 336Do so only when switching to a new buffer in the same window if
334the active frame." 337the replaced buffer is no longer visible in another window and
335 (when erc-keep-place-indicator-follow 338its `window-start' at the time of switching is strictly greater
336 (unless (or (minibuffer-window-active-p (minibuffer-window)) 339than the indicator's position."
337 (eq (window-old-buffer) (current-buffer))) 340 (when-let ((erc-keep-place-indicator-follow)
338 (when (< (overlay-end erc--keep-place-indicator-overlay) 341 ((eq window (selected-window)))
339 (window-start) 342 (old-buffer (window-old-buffer window))
340 erc-insert-marker) 343 ((buffer-live-p old-buffer))
341 (erc-keep-place-move (window-start)))))) 344 ((not (eq old-buffer (current-buffer))))
345 (ov (buffer-local-value 'erc--keep-place-indicator-overlay
346 old-buffer))
347 ((not (get-buffer-window old-buffer 'visible)))
348 (prev (assq old-buffer (window-prev-buffers window)))
349 (old-start (nth 1 prev))
350 (old-inmkr (buffer-local-value 'erc-insert-marker old-buffer))
351 ((< (overlay-end ov) old-start old-inmkr)))
352 (with-current-buffer old-buffer
353 (erc-keep-place-move old-start))))
342 354
343(defun erc--keep-place-indicator-setup () 355(defun erc--keep-place-indicator-setup ()
344 "Initialize buffer for maintaining `erc--keep-place-indicator-overlay'." 356 "Initialize buffer for maintaining `erc--keep-place-indicator-overlay'."
@@ -347,8 +359,8 @@ the active frame."
347 erc--keep-place-indicator-overlay (make-overlay 0 0)) 359 erc--keep-place-indicator-overlay (make-overlay 0 0))
348 (add-hook 'erc-keep-place-mode-hook 360 (add-hook 'erc-keep-place-mode-hook
349 #'erc--keep-place-indicator-on-global-module nil t) 361 #'erc--keep-place-indicator-on-global-module nil t)
350 (add-hook 'window-configuration-change-hook 362 (add-hook 'window-buffer-change-functions
351 #'erc--keep-place-indicator-on-window-configuration-change nil t) 363 #'erc--keep-place-indicator-on-window-buffer-change 40 t)
352 (when-let* (((memq erc-keep-place-indicator-style '(t arrow))) 364 (when-let* (((memq erc-keep-place-indicator-style '(t arrow)))
353 (ov-property (if (zerop (fringe-columns 'left)) 365 (ov-property (if (zerop (fringe-columns 'left))
354 'after-string 366 'after-string
@@ -368,7 +380,11 @@ the active frame."
368 "Buffer-local `keep-place' with fringe arrow and/or highlighted face. 380 "Buffer-local `keep-place' with fringe arrow and/or highlighted face.
369Play nice with global module `keep-place' but don't depend on it. 381Play nice with global module `keep-place' but don't depend on it.
370Expect that users may want different combinations of `keep-place' 382Expect that users may want different combinations of `keep-place'
371and `keep-place-indicator' in different buffers." 383and `keep-place-indicator' in different buffers. Unlike global
384`keep-place', when `switch-to-buffer-preserve-window-point' is
385enabled, don't forcibly sync point in all windows where buffer
386has previously been shown because that defeats the purpose of
387having a placeholder."
372 ((cond (erc-keep-place-mode) 388 ((cond (erc-keep-place-mode)
373 ((memq 'keep-place erc-modules) 389 ((memq 'keep-place erc-modules)
374 (erc-keep-place-mode +1)) 390 (erc-keep-place-mode +1))
@@ -382,8 +398,8 @@ and `keep-place-indicator' in different buffers."
382 (erc-keep-place-indicator-mode -1))) 398 (erc-keep-place-indicator-mode -1)))
383 ((when erc--keep-place-indicator-overlay 399 ((when erc--keep-place-indicator-overlay
384 (delete-overlay erc--keep-place-indicator-overlay)) 400 (delete-overlay erc--keep-place-indicator-overlay))
385 (remove-hook 'window-configuration-change-hook 401 (remove-hook 'window-buffer-change-functions
386 #'erc--keep-place-indicator-on-window-configuration-change t) 402 #'erc--keep-place-indicator-on-window-buffer-change t)
387 (remove-hook 'erc-keep-place-mode-hook 403 (remove-hook 'erc-keep-place-mode-hook
388 #'erc--keep-place-indicator-on-global-module t) 404 #'erc--keep-place-indicator-on-global-module t)
389 (remove-hook 'erc-insert-pre-hook #'erc-keep-place t) 405 (remove-hook 'erc-insert-pre-hook #'erc-keep-place t)
@@ -450,13 +466,13 @@ For use with `keep-place-indicator' module."
450 (forward-line -1) 466 (forward-line -1)
451 (when erc-keep-place-indicator-mode 467 (when erc-keep-place-indicator-mode
452 (unless (or (minibuffer-window-active-p (selected-window)) 468 (unless (or (minibuffer-window-active-p (selected-window))
453 (and (frame-visible-p (selected-frame)) 469 (get-buffer-window nil 'visible))
454 (get-buffer-window (current-buffer) (selected-frame))))
455 (erc-keep-place-move nil))) 470 (erc-keep-place-move nil)))
456 ;; if `switch-to-buffer-preserve-window-point' is set, 471 ;; if `switch-to-buffer-preserve-window-point' is set,
457 ;; we cannot rely on point being saved, and must commit 472 ;; we cannot rely on point being saved, and must commit
458 ;; it to window-prev-buffers. 473 ;; it to window-prev-buffers.
459 (when switch-to-buffer-preserve-window-point 474 (when (and switch-to-buffer-preserve-window-point
475 (not erc-keep-place-indicator-mode))
460 (dolist (frame (frame-list)) 476 (dolist (frame (frame-list))
461 (walk-window-tree 477 (walk-window-tree
462 (lambda (window) 478 (lambda (window)
diff --git a/test/lisp/erc/erc-goodies-tests.el b/test/lisp/erc/erc-goodies-tests.el
index cdf861e2018..ca02089eb7c 100644
--- a/test/lisp/erc/erc-goodies-tests.el
+++ b/test/lisp/erc/erc-goodies-tests.el
@@ -247,7 +247,7 @@
247 247
248(defun erc-goodies-tests--assert-kp-indicator-on () 248(defun erc-goodies-tests--assert-kp-indicator-on ()
249 (should erc--keep-place-indicator-overlay) 249 (should erc--keep-place-indicator-overlay)
250 (should (local-variable-p 'window-configuration-change-hook)) 250 (should (local-variable-p 'window-buffer-change-functions))
251 (should window-configuration-change-hook) 251 (should window-configuration-change-hook)
252 (should (memq 'erc-keep-place erc-insert-pre-hook)) 252 (should (memq 'erc-keep-place erc-insert-pre-hook))
253 (should (eq erc-keep-place-mode 253 (should (eq erc-keep-place-mode
@@ -255,7 +255,7 @@
255 255
256(defun erc-goodies-tests--assert-kp-indicator-off () 256(defun erc-goodies-tests--assert-kp-indicator-off ()
257 (should-not (local-variable-p 'erc-insert-pre-hook)) 257 (should-not (local-variable-p 'erc-insert-pre-hook))
258 (should-not (local-variable-p 'window-configuration-change-hook)) 258 (should-not (local-variable-p 'window-buffer-change-functions))
259 (should-not erc--keep-place-indicator-overlay)) 259 (should-not erc--keep-place-indicator-overlay))
260 260
261(defun erc-goodies-tests--kp-indicator-populate () 261(defun erc-goodies-tests--kp-indicator-populate ()
diff --git a/test/lisp/erc/erc-scenarios-keep-place-indicator.el b/test/lisp/erc/erc-scenarios-keep-place-indicator.el
new file mode 100644
index 00000000000..7566288066e
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-keep-place-indicator.el
@@ -0,0 +1,134 @@
1;;; erc-scenarios-keep-place-indicator.el --- erc-keep-place-indicator-mode -*- lexical-binding: t -*-
2
3;; Copyright (C) 2023 Free Software Foundation, Inc.
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software: you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation, either version 3 of the License, or
10;; (at your option) any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
19
20;;; Code:
21
22(require 'ert-x)
23(eval-and-compile
24 (let ((load-path (cons (ert-resource-directory) load-path)))
25 (require 'erc-scenarios-common)))
26
27(require 'erc-goodies)
28
29;; This test shows that the indicator does not update when at least
30;; one window remains. When the last window showing a buffer switches
31;; away, the indicator is updated if it's earlier in the buffer.
32(ert-deftest erc-scenarios-keep-place-indicator--follow ()
33 :tags `(:expensive-test
34 ,@(and (getenv "ERC_TESTS_GRAPHICAL") '(:erc--graphical)))
35 (when (version< emacs-version "29") (ert-skip "Times out"))
36 ;; XXX verify that this continues to be the case ^.
37
38 (should-not erc-scrolltobottom-all)
39 (should-not erc-scrolltobottom-mode)
40 (should-not erc-keep-place-mode)
41
42 (erc-scenarios-common-with-noninteractive-in-term
43 ((erc-scenarios-common-dialog "keep-place")
44 (dumb-server (erc-d-run "localhost" t 'follow))
45 (port (process-contact dumb-server :service))
46 (erc-modules `( keep-place-indicator scrolltobottom fill-wrap
47 ,@erc-modules))
48 (erc-keep-place-indicator-follow t)
49 (erc-scrolltobottom-all t)
50 (erc-server-flood-penalty 0.1)
51 (erc-autojoin-channels-alist '((foonet "#chan" "#spam")))
52 (expect (erc-d-t-make-expecter)))
53
54 (ert-info ("Connect")
55 (with-current-buffer (erc :server "127.0.0.1"
56 :port port
57 :full-name "tester"
58 :nick "tester"
59 :user "tester")
60 (funcall expect 10 "debug mode")))
61
62 (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
63 (set-window-buffer nil (current-buffer))
64 (delete-other-windows)
65 (split-window-below)
66 (funcall expect 10 "<bob> tester, welcome!")
67 (recenter 0)
68 (other-window 1)
69 (funcall expect 10 "<alice> tester, welcome!")
70 (recenter 0)
71 (should (= 2 (length (window-list))))
72
73 (ert-info ("Last window to switch away has point earlier in buffer")
74 ;; Lower window, with point later in buffer, switches away first.
75 (switch-to-buffer (erc-d-t-wait-for 10 (get-buffer "#spam"))) ; lower
76 (other-window 1)
77 (switch-to-buffer "#spam") ; upper
78 (erc-scenarios-common-say "one")
79 (funcall expect 10 "Ay, the heads")
80
81 ;; Overlay has moved to upper window start.
82 (switch-to-buffer "#chan")
83 (redisplay) ; force overlay to update
84 (save-excursion
85 (goto-char (window-point))
86 (should (looking-back (rx "<bob> tester, welcome!")))
87 (should (= (pos-bol) (window-start)))
88 (should (= (overlay-start erc--keep-place-indicator-overlay)
89 (pos-bol))))
90 ;; Lower window is still centered at start.
91 (other-window 1)
92 (switch-to-buffer "#chan")
93 (save-excursion
94 (goto-char (window-point))
95 (should (looking-back (rx "<alice> tester, welcome!")))
96 (should (= (pos-bol) (window-start)))))
97
98 (ert-info ("Last window to switch away has point later in buffer")
99 ;; Lower window advances.
100 (funcall expect 10 "<bob> alice: Since you can cog")
101 (recenter 0)
102 (redisplay) ; force ^ to appear on first line
103
104 (other-window 1) ; upper still at indicator, swtiches first
105 (switch-to-buffer "#spam")
106 (other-window 1)
107 (switch-to-buffer "#spam") ; lower follows, speaks to sync
108 (erc-scenarios-common-say "two")
109 (funcall expect 10 "<bob> Cause they take")
110
111 ;; Upper switches back first, finds indicator gone.
112 (other-window 1)
113 (switch-to-buffer "#chan")
114 (save-excursion
115 (goto-char (window-point))
116 (should (looking-back (rx "<bob> tester, welcome!")))
117 (should (= (pos-bol) (window-start)))
118 (should (> (overlay-start erc--keep-place-indicator-overlay)
119 (pos-eol))))
120
121 ;; Lower window follows, window-start preserved.
122 (other-window 1)
123 (switch-to-buffer "#chan")
124 (save-excursion
125 (goto-char (window-point))
126 (should (looking-back (rx "you can cog")))
127 (should (= (pos-bol) (window-start)))
128 (should (= (overlay-start erc--keep-place-indicator-overlay)
129 (pos-bol))))))
130
131 (erc-keep-place-mode -1)
132 (erc-scrolltobottom-mode -1)))
133
134;;; erc-scenarios-keep-place-indicator.el ends here
diff --git a/test/lisp/erc/resources/keep-place/follow.eld b/test/lisp/erc/resources/keep-place/follow.eld
new file mode 100644
index 00000000000..e857c17175d
--- /dev/null
+++ b/test/lisp/erc/resources/keep-place/follow.eld
@@ -0,0 +1,73 @@
1;; -*- mode: lisp-data; -*-
2((nick 10 "NICK tester"))
3((user 10 "USER tester 0 * :tester")
4 (0.00 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
5 (0.01 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version ergo-v2.11.1")
6 (0.01 ":irc.foonet.org 003 tester :This server was created Tue, 26 Dec 2023 08:36:35 UTC")
7 (0.01 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.11.1 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
8 (0.00 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# CHATHISTORY=1000 ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX :are supported by this server")
9 (0.01 ":irc.foonet.org 005 tester KICKLEN=390 MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN=390 UTF8ONLY WHOX :are supported by this server")
10 (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=1000 :are supported by this server")
11 (0.01 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 server(s)")
12 (0.01 ":irc.foonet.org 252 tester 0 :IRC Operators online")
13 (0.00 ":irc.foonet.org 253 tester 0 :unregistered connections")
14 (0.00 ":irc.foonet.org 254 tester 2 :channels formed")
15 (0.00 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
16 (0.00 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
17 (0.00 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
18 (0.03 ":irc.foonet.org 422 tester :MOTD File is missing")
19 (0.01 ":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."))
20
21((mode 10 "MODE tester +i"))
22
23((join 10 "JOIN #chan")
24 (0.01 ":irc.foonet.org 221 tester +i")
25 (0.01 ":tester!~u@p64eqfwvvbxrk.irc JOIN #chan")
26 (0.03 ":irc.foonet.org 353 tester = #chan :@fsbot bob alice tester")
27 (0.01 ":irc.foonet.org 366 tester #chan :End of NAMES list")
28 (0.00 ":bob!~u@2q6ysndq32az6.irc PRIVMSG #chan :tester, welcome!")
29 (0.01 ":alice!~u@2q6ysndq32az6.irc PRIVMSG #chan :tester, welcome!"))
30
31((join 10 "JOIN #spam")
32 (0.00 ":tester!~u@p64eqfwvvbxrk.irc JOIN #spam")
33 (0.06 ":irc.foonet.org 353 tester = #spam :@fsbot bob alice tester")
34 (0.01 ":irc.foonet.org 366 tester #spam :End of NAMES list")
35 (0.03 ":alice!~u@2q6ysndq32az6.irc PRIVMSG #spam :tester, welcome!")
36 (0.01 ":bob!~u@2q6ysndq32az6.irc PRIVMSG #spam :tester, welcome!"))
37
38((mode 10 "MODE #chan")
39 (0.00 ":irc.foonet.org 324 tester #chan +Cnt")
40 (0.02 ":irc.foonet.org 329 tester #chan 1703579802")
41 (0.02 ":alice!~u@2q6ysndq32az6.irc PRIVMSG #chan :bob: Madam, my lord is gone, for ever gone.")
42 (0.10 ":alice!~u@2q6ysndq32az6.irc PRIVMSG #chan :The kinder we, to give them thanks for nothing."))
43
44((mode 10 "MODE #spam")
45 (0.00 ":irc.foonet.org 324 tester #spam +Cnt")
46 (0.02 ":irc.foonet.org 329 tester #spam 1703579805")
47 (0.02 ":bob!~u@2q6ysndq32az6.irc PRIVMSG #chan :Most manifest, and not denied by himself.")
48 (0.02 ":bob!~u@2q6ysndq32az6.irc PRIVMSG #chan :alice: To bed, to bed: there's knocking at the gate. Come, come, come, come, give me your hand. What's done cannot be undone.")
49 (0.02 ":alice!~u@2q6ysndq32az6.irc PRIVMSG #chan :bob: And what I spake, I spake it to my face.")
50 (0.08 ":bob!~u@2q6ysndq32az6.irc PRIVMSG #chan :alice: Since you can cog, I'll play no more with you.")
51 (0.06 ":alice!~u@2q6ysndq32az6.irc PRIVMSG #chan :bob: The little casket bring me hither.")
52 (0.01 ":bob!~u@2q6ysndq32az6.irc PRIVMSG #chan :alice: Not to-night, good Iago: I have very poor and unhappy brains for drinking: I could well wish courtesy would invent some other custom of entertainment.")
53 (0.02 ":alice!~u@2q6ysndq32az6.irc PRIVMSG #chan :Yes, faith will I, Fridays and Saturdays and all."))
54
55((privmsg 10 "PRIVMSG #spam :one")
56 (0.03 ":alice!~u@2q6ysndq32az6.irc PRIVMSG #chan :bob: This is the first truth that e'er thine own tongue was guilty of.")
57 (0.02 ":bob!~u@2q6ysndq32az6.irc PRIVMSG #chan :alice: Drown the lamenting fool in sea-salt tears.")
58
59 ;; Insert some lines ^ before rendezvous, so #chan can update scrolltobottom.
60 (0.01 ":bob!~u@2q6ysndq32az6.irc PRIVMSG #spam :Ay, the heads of the maids, or their maidenheads; take it in what sense thou wilt.")
61
62 (0.05 ":bob!~u@2q6ysndq32az6.irc PRIVMSG #chan :alice: And work confusion on his enemies.")
63 (0.06 ":alice!~u@2q6ysndq32az6.irc PRIVMSG #chan :bob: Truly, she must be given, or the marriage is not lawful."))
64
65((privmsg 10 "PRIVMSG #spam :two")
66 (0.02 ":bob!~u@2q6ysndq32az6.irc PRIVMSG #chan :To be whipped; and yet a better love than my master.")
67 (0.06 ":alice!~u@2q6ysndq32az6.irc PRIVMSG #chan :And duty in his service perishing.")
68
69 ;; Second check point.
70 (0.01 ":bob!~u@2q6ysndq32az6.irc PRIVMSG #spam :Cause they take vengeance of such kind of men.")
71
72 (0.03 ":bob!~u@2q6ysndq32az6.irc PRIVMSG #chan :alice: No egma, no riddle, no l'envoy; no salve in the mail, sir. O! sir, plantain, a plain plantain: no l'envoy, no l'envoy: no salve, sir, but a plantain.")
73 (0.03 ":alice!~u@2q6ysndq32az6.irc PRIVMSG #chan :Signior Iachimo will not from it. Pray, let us follow 'em."))