Skip to content

Commit 006f71e

Browse files
committed
Improve naming, docs and small refactoring
1 parent 188530b commit 006f71e

2 files changed

Lines changed: 74 additions & 69 deletions

File tree

speed-type.el

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,31 @@
4444
(require 'thingatpt)
4545
(require 'dom)
4646

47+
(when (version< emacs-version "29.1")
48+
(eval-and-compile
49+
(defmacro with-undo-amalgamate (&rest body)
50+
"Like `progn' but perform BODY with amalgamated undo barriers.
51+
52+
This allows multiple operations to be undone in a single step.
53+
When undo is disabled this behaves like `progn'."
54+
(declare (indent 0) (debug t))
55+
(let ((handle (make-symbol "--change-group-handle--")))
56+
`(let ((,handle (prepare-change-group))
57+
;; Don't truncate any undo data in the middle of this,
58+
;; otherwise Emacs might truncate part of the resulting
59+
;; undo step: we want to mimic the behavior we'd get if the
60+
;; undo-boundaries were never added in the first place.
61+
(undo-outer-limit nil)
62+
(undo-limit most-positive-fixnum)
63+
(undo-strong-limit most-positive-fixnum))
64+
(unwind-protect
65+
(progn
66+
(activate-change-group ,handle)
67+
,@body)
68+
(progn
69+
(accept-change-group ,handle)
70+
(undo-amalgamate-change-group ,handle))))))))
71+
4772
(defgroup speed-type nil
4873
"Practice touch-typing in Emacs."
4974
:group 'games)
@@ -320,7 +345,6 @@ If nil, the completion is only triggered if all characters are typed."
320345
"Face for point-movement in preview buffer.")
321346

322347
;; internal variables
323-
324348
(defvar speed-type--gb-url-format "https://www.gutenberg.org/cache/epub/%d/pg%d.txt")
325349

326350
(defvar speed-type-explaining-message "
@@ -397,7 +421,6 @@ It's the point within speed-type-buffer.")
397421
"Used to calculate duration of a speed-type session.")
398422
(defvar-local speed-type--last-modified-tick nil
399423
"Used to determine if there was only a property change between before- and after-functions.")
400-
401424
(defvar-local speed-type--last-changed-text nil
402425
"Used to store characters which are going be compared against.
403426
@@ -1083,7 +1106,6 @@ Whitespace is determined using `char-syntax'."
10831106
(setq i (1+ i)))
10841107
still-correct))
10851108

1086-
10871109
(defun speed-type--check-same (pos a b)
10881110
"Return non-nil if A[POS] and B[POS] are identical or both whitespace.
10891111
@@ -1304,7 +1326,6 @@ value return nil."
13041326
(setq-local speed-type--last-position new-last-pos))
13051327
(read-only-mode)))))
13061328

1307-
13081329
(defvar current-correct-streak 0 "Tracks the correct streak since last error or beginning.")
13091330
(defun speed-type--diff (orig new start end)
13101331
"Synchronise local buffer state with buffer-content by comparing ORIG and NEW.
@@ -1355,11 +1376,18 @@ END is a point where the check stops to scan for diff."
13551376
(message "Wrong key"))
13561377
(not any-error)))
13571378

1358-
(defun speed-type--update-overlay (start end)
1359-
"Undo does not track overlay changes but it does update text-properties.
1360-
Undo has finished it's job and we now update the overlay to the new
1361-
text-property value."
1362-
(when-let ((orig-end (cdr (get-text-property (1- (point-max)) 'speed-type-orig-pos))))
1379+
(defun speed-type--sync-after-undo (start end)
1380+
"Sync overlay between START and END with whatever text-properties appear there.
1381+
1382+
Undo does not track overlay changes but it does update text-properties.
1383+
1384+
This function should be called after undo has finished it's job and the
1385+
region got new text-property values.
1386+
1387+
`buffer-undo-list' is per buffer which is why point is synced in
1388+
content-buffer manually if there is a add-extra-word-function."
1389+
(when-let ((add-word-fn speed-type--add-extra-word-content-fn)
1390+
(orig-end (cdr (get-text-property (1- (point-max)) 'speed-type-orig-pos))))
13631391
(with-current-buffer speed-type--content-buffer (goto-char orig-end)))
13641392
(remove-overlays start end 'face 'speed-type-correct-face)
13651393
(remove-overlays start end 'face 'speed-type-error-face)
@@ -1384,12 +1412,12 @@ text-property value."
13841412
LENGTH is ignored. Used for hook AFTER-CHANGE-FUNCTIONS.
13851413
Make sure that the contents don't actually change, but rather the contents
13861414
are color coded and stats are gathered about the typing performance."
1387-
(cond (undo-in-progress (speed-type--update-overlay start end))
1415+
(cond (undo-in-progress (speed-type--sync-after-undo start end))
13881416
((or (member this-command '(fill-paragraph))
13891417
(= speed-type--last-modified-tick (buffer-chars-modified-tick)))
13901418
nil)
13911419
(t (progn
1392-
(unless speed-type--idle-pause-timer (speed-type--resume))
1420+
(speed-type--resume)
13931421
(let ((new-text (buffer-substring start end))
13941422
(old-text speed-type--last-changed-text))
13951423
(speed-type--handle-del start end)
@@ -1542,30 +1570,20 @@ CALLBACK is called when the setup process has been completed."
15421570
(when (null (boundp 'speed-type--extra-word-quote))
15431571
(setq-local speed-type--extra-word-quote nil)))
15441572
(when speed-type-provide-preview-option (speed-type--connect-preview-buffer buf content-buffer))
1545-
(let ((b-inhibit-read-only inhibit-read-only)
1546-
(b-buffer-undo-list buffer-undo-list)
1547-
(b-inhibit-modification-hooks inhibit-modification-hooks)
1548-
(b-inhibit-field-text-motion inhibit-field-text-motion))
1549-
(unwind-protect
1550-
(progn
1551-
(setq-local inhibit-read-only t
1552-
buffer-undo-list t
1553-
inhibit-modification-hooks t
1554-
inhibit-field-text-motion t)
1555-
(insert (if (speed-type--code-buffer-p speed-type--content-buffer) (speed-type--trim text) (string-trim text)))
1556-
(speed-type--replace-map-adjust-properties speed-type-replace-strings 'speed-type-orig-pos)
1557-
(when speed-type-downcase (downcase-region (point-min) (point-max)))
1558-
(unless (speed-type--code-buffer-p speed-type--content-buffer)
1559-
(fill-region (point-min) (point-max) 'none t))
1560-
(when speed-type-ignore-whitespace-for-complete
1561-
(save-excursion
1562-
(goto-char (point-min))
1563-
(while (search-forward-regexp "[[:blank:]\n]+" nil t 1)
1564-
(add-text-properties (match-beginning 0) (match-end 0) '(speed-type-char-status ignore))))))
1565-
(setq-local inhibit-read-only b-inhibit-read-only
1566-
buffer-undo-list b-buffer-undo-list
1567-
inhibit-modification-hooks b-inhibit-modification-hooks
1568-
inhibit-field-text-motion b-inhibit-field-text-motion)))
1573+
(let ((inhibit-read-only t)
1574+
(buffer-undo-list t)
1575+
(inhibit-modification-hooks t)
1576+
(inhibit-field-text-motion t))
1577+
(insert (if (speed-type--code-buffer-p speed-type--content-buffer) (speed-type--trim text) (string-trim text)))
1578+
(speed-type--replace-map-adjust-properties speed-type-replace-strings 'speed-type-orig-pos)
1579+
(when speed-type-downcase (downcase-region (point-min) (point-max)))
1580+
(unless (speed-type--code-buffer-p speed-type--content-buffer)
1581+
(fill-region (point-min) (point-max) 'none t))
1582+
(when speed-type-ignore-whitespace-for-complete
1583+
(save-excursion
1584+
(goto-char (point-min))
1585+
(while (search-forward-regexp "[[:blank:]\n]+" nil t 1)
1586+
(add-text-properties (match-beginning 0) (match-end 0) '(speed-type-char-status ignore))))))
15691587
(set-buffer-modified-p nil)
15701588
(switch-to-buffer buf)
15711589
(when (eq speed-type-provide-preview-option t)
@@ -1661,7 +1679,7 @@ If IGNORE is non-nil, will ignore whitespace which will not account to
16611679
the approximated length.
16621680
16631681
If START and END are the same and TOLERANCE is zero will just return
1664-
'(START END).
1682+
\(START END).
16651683
16661684
Use `save-excursion' to prevent point-movement."
16671685
(dolist (arg `((START . ,start) (END . ,end) (MIN . ,min) (MAX . ,max) (TOLERANCE . ,tolerance)))

test/speed-type-test.el

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -125,21 +125,16 @@
125125
126126
TEST-IN-BUF is a lambda which is executed within the speed-type-buffer."
127127
(let ((content text)
128-
(speed-type-save-statistic-option-b speed-type-save-statistic-option)
128+
(speed-type-save-statistic-option 'never)
129129
(speed-type-statistic-filename (concat (temporary-file-directory) "speed-type-statistic.el"))
130-
(speed-type-randomize-b speed-type-randomize))
130+
(speed-type-randomize-b t))
131131
(with-temp-buffer
132132
(insert content)
133133
(funcall 'fundamental-mode)
134-
(setq speed-type-save-statistic-option 'never
135-
speed-type-randomize t)
136134
(let ((buf (speed-type-buffer nil)))
137-
(unwind-protect
138-
(with-current-buffer buf
139-
(funcall test-in-buf))
140-
(setq speed-type-save-statistic-option speed-type-save-statistic-option-b
141-
speed-type-randomize speed-type-randomize-b)
142-
(kill-buffer buf))))))
135+
(with-current-buffer buf
136+
(funcall test-in-buf))
137+
(kill-buffer buf)))))
143138

144139
(defun speed-type-test-region (test-in-buf)
145140
"Setup a speed-type-region for testing.
@@ -153,10 +148,9 @@ TEST-IN-BUF is a lambda which is executed within the speed-type-buffer."
153148
(insert content)
154149
(funcall mode)
155150
(let ((buf (speed-type-region (point-min) (point-max))))
156-
(unwind-protect
157-
(with-current-buffer buf
158-
(funcall test-in-buf))
159-
(kill-buffer buf))))))
151+
(with-current-buffer buf
152+
(funcall test-in-buf))
153+
(kill-buffer buf)))))
160154

161155
(ert-deftest speed-type-test/times-is-empty-when-no-input ()
162156
"Test the time-register-variable is empty for flow: session-start -> complete."
@@ -271,25 +265,18 @@ TEST-IN-BUF is a lambda which is executed within the speed-type-buffer."
271265
"Test if text is downcased when speed-type-downcase is t.
272266
273267
Also assure when that added words are downcased too."
274-
(let ((b-speed-type-downcase speed-type-downcase)
275-
(b-speed-type-add-extra-words-on-error speed-type-add-extra-words-on-error)
276-
(b-speed-type-add-extra-words-on-non-consecutive-errors speed-type-add-extra-words-on-non-consecutive-errors))
277-
(setq speed-type-downcase t
278-
speed-type-add-extra-words-on-error 1
279-
speed-type-add-extra-words-on-non-consecutive-errors 0)
280-
(unwind-protect
281-
(speed-type-test-buffer
282-
"ASDF"
283-
(lambda ()
284-
(should (string= "asdf" (buffer-string)))
285-
(insert "b")
286-
(sleep-for 0.1)
287-
(should (string= "asdf asdf" (buffer-string)))
288-
(with-current-buffer speed-type--content-buffer
289-
(should (string= "ASDF" (buffer-string))))))
290-
(setq speed-type-downcase b-speed-type-downcase
291-
speed-type-add-extra-words-on-error b-speed-type-add-extra-words-on-error
292-
speed-type-add-extra-words-on-non-consecutive-errors b-speed-type-add-extra-words-on-non-consecutive-errors))))
268+
(let ((speed-type-downcase t)
269+
(speed-type-add-extra-words-on-error 1)
270+
(speed-type-add-extra-words-on-non-consecutive-errors 0))
271+
(speed-type-test-buffer
272+
"ASDF"
273+
(lambda ()
274+
(should (string= "asdf" (buffer-string)))
275+
(insert "b")
276+
(sleep-for 0.3)
277+
(should (string= "asdf asdf" (buffer-string)))
278+
(with-current-buffer speed-type--content-buffer
279+
(should (string= "ASDF" (buffer-string))))))))
293280

294281
; assure preview buffer in general region
295282
; test continue feature

0 commit comments

Comments
 (0)