From 747e1a91c251341b4fd0610bbd3d8f39c1fd0e17 Mon Sep 17 00:00:00 2001 From: Boris Buliga Date: Sat, 15 Feb 2020 15:37:33 +0200 Subject: [PATCH] stop action for leaving the point at misspelled word Required for #58 and #69 --- CHANGELOG.org | 1 + flyspell-correct-avy-menu.el | 3 +- flyspell-correct-helm.el | 4 +- flyspell-correct-ivy.el | 4 +- flyspell-correct.el | 29 ++++++++---- test/test-flyspell-correct.el | 84 +++++++++++++++++++++++++++++++++-- 6 files changed, 110 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.org b/CHANGELOG.org index ce33445..88a6f2a 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -16,6 +16,7 @@ when any of these functions is called with point at misspelled word. - Rewrite all tests using [[https://github.com/jorgenschaefer/emacs-buttercup][buttercup]] library. - Allow to correct and save the word in one pass (see #66). +- New action - =stop= allowing to leave the point at the misspelled word. * v0.6.1 diff --git a/flyspell-correct-avy-menu.el b/flyspell-correct-avy-menu.el index 0944687..d477c25 100644 --- a/flyspell-correct-avy-menu.el +++ b/flyspell-correct-avy-menu.el @@ -59,7 +59,8 @@ of (command, word) to be used by `flyspell-do-correct'." (base-menu (let ((save `(("Save word" (save . ,word)) ("Accept (session)" (session . ,word)) ("Accept (buffer)" (buffer . ,word)) - ("Skip" (skip . ,word))))) + ("Skip" (skip . ,word)) + ("Stop" (stop . ,word))))) (if (consp cor-menu) (append cor-menu (cons "" save)) save))) diff --git a/flyspell-correct-helm.el b/flyspell-correct-helm.el index 0eeba20..58d519a 100644 --- a/flyspell-correct-helm.el +++ b/flyspell-correct-helm.el @@ -52,7 +52,9 @@ (cons (format "Accept (buffer) \"%s\"" word) (cons 'buffer word)) (cons (format "Skip \"%s\"" word) - (cons 'skip word))))) + (cons 'skip word)) + (cons (format "Stop at \"%s\"" word) + (cons 'stop word))))) (unless (string= helm-pattern "") (setq opts (append opts diff --git a/flyspell-correct-ivy.el b/flyspell-correct-ivy.el index 6c3686e..3a46163 100644 --- a/flyspell-correct-ivy.el +++ b/flyspell-correct-ivy.el @@ -53,12 +53,14 @@ of (command, word) to be used by `flyspell-do-correct'." (action-accept-session (lambda (_) (setq result (cons 'session word)))) (action-accept-buffer (lambda (_) (setq result (cons 'buffer word)))) (action-skip-word (lambda (_) (setq result (cons 'skip word)))) + (action-stop (lambda (_) (setq result (cons 'stop word)))) (action `(1 ("o" ,action-default "correct") ("s" ,action-save-word "Save") ("S" ,action-accept-session "Accept (session)") ("b" ,action-accept-buffer "Accept (buffer)") - ("k" ,action-skip-word "Skip")))) + ("k" ,action-skip-word "Skip") + ("p" ,action-stop "Stop")))) (ivy-read (format "Suggestions for \"%s\" in dictionary \"%s\": " word (or ispell-local-dictionary ispell-dictionary diff --git a/flyspell-correct.el b/flyspell-correct.el index 14c8e9e..022e0e8 100644 --- a/flyspell-correct.el +++ b/flyspell-correct.el @@ -177,7 +177,8 @@ Adapted from `flyspell-correct-word-before-point'." (let ((cmd (car res)) (wrd (cdr res))) (unless (or (eq cmd 'skip) - (eq cmd 'break)) + (eq cmd 'break) + (eq cmd 'stop)) (flyspell-do-correct cmd poss wrd cursor-location start end opoint) (unless (string-equal wrd word) @@ -260,7 +261,8 @@ until all errors in buffer have been addressed." ;; `flyspell-correct-word-before-point'. (interactive "d") (let ((original-pos (point)) - (hard-reset-pos)) + (target-pos (point)) + (hard-move-point)) (save-excursion (let ((incorrect-word-pos)) @@ -296,26 +298,35 @@ until all errors in buffer have been addressed." ;; But with rapid mode, `hard-reset-pos' will be set to nil ;; eventually. Which gives more predictable point location in ;; general. - (setq hard-reset-pos + (setq hard-move-point (and (>= original-pos (overlay-start overlay)) (<= original-pos (overlay-end overlay)))) ;; Correct a word using `flyspell-correct-at-point'. (let ((res (flyspell-correct-at-point))) (when res + ;; stop at misspelled word + (when (eq (car-safe res) 'stop) + (setq target-pos incorrect-word-pos + hard-move-point t)) + + ;; break from rapid mode + (when (or (not rapid) + (eq (car-safe res) 'break) + (eq (car-safe res) 'stop)) + (setq overlay nil)) + + ;; push mark (when (or (not (mark t)) (/= (mark t) (point))) - (push-mark (point) t)) - (when (or (not rapid) - (eq (car-safe res) 'break)) - (setq overlay nil))))))) + (push-mark (point) t))))))) (when incorrect-word-pos (goto-char incorrect-word-pos) (forward-word) (when (= (mark t) (point)) (pop-mark))))) - (when hard-reset-pos - (goto-char original-pos)))) + (when hard-move-point + (goto-char target-pos)))) ;;; Overlays diff --git a/test/test-flyspell-correct.el b/test/test-flyspell-correct.el index 62c23e0..c401a1a 100644 --- a/test/test-flyspell-correct.el +++ b/test/test-flyspell-correct.el @@ -99,6 +99,21 @@ License for most of our software; it applies also to any other werk released this way by its authors. You can apply it to your programs, too." ,@body)) +(defmacro with-mistakes|stop|cursor-before (&rest body) + "Execute BODY in temporary buffer that has a mistake. + +Cursor is placed somewhere before the misspelled word." + `(with-flyspell-buffer + "The licenses for most software and other practical works are +designed to take away your freedom to share and change the works. +By contrast, the GNU Generel Public License |is intended to +guarantee your freedom to share and change all †versiuns of a +program--to make sure it remains free software for all its users. +We, the Free Software Foundation, use the GNU General Public +License for most of our software; it applies also to any other +werk released this way by its authors. You can apply it to your +programs, too." ,@body)) + (defmacro with-mistakes|cursor-inside (&rest body) "Execute BODY in temporary buffer that has a mistake. @@ -144,6 +159,21 @@ Public License for most of our software; it applies also to any other werk released this way by its authors. You can apply it to your programs, too." ,@body)) +(defmacro with-mistakes|stop|cursor-after (&rest body) + "Execute BODY in temporary buffer that has a mistake. + +Cursor is placed somewhere after the misspelled word." + `(with-flyspell-buffer + "The licenses for most software and other practical works are +designed to take away your freedom to share and change the works. +By contrast, the GNU Generel Public License is intended to +guarantee your freedom to share and change all †versiuns of a +program--to make sure it remains free software for all| its +users. We, the Free Software Foundation, use the GNU General +Public License for most of our software; it applies also to any +other werk released this way by its authors. You can apply it to +your programs, too." ,@body)) + (defmacro with-mistakes|cursor-after-all (&rest body) "Execute BODY in temporary buffer that has a mistake. @@ -366,6 +396,19 @@ Simply passed WORD to `correct-word' mock." (expect-no-correction "versiuns")))) + (describe "action - stop" + + (before-each + (spy-on 'flyspell-do-correct) + (spy-on 'correct-interface :and-call-through) + (spy-on 'correct-word :and-call-fake (lambda (word) (cons 'stop word)))) + + (it "stop at the beginning of misspelled word" + (with-mistakes|stop|cursor-before + (flyspell-correct-next (point)) + + (expect-no-correction "versiuns")))) + (describe "action - fix" (before-each @@ -445,6 +488,19 @@ Simply passed WORD to `correct-word' mock." (expect-no-correction "versiuns")))) + (describe "action - stop" + + (before-each + (spy-on 'flyspell-do-correct) + (spy-on 'correct-interface :and-call-through) + (spy-on 'correct-word :and-call-fake (lambda (word) (cons 'stop word)))) + + (it "stop at the beginning of misspelled word" + (with-mistakes|stop|cursor-after + (flyspell-correct-previous (point)) + + (expect-no-correction "versiuns")))) + (describe "action - fix" (before-each @@ -528,9 +584,9 @@ Simply passed WORD to `correct-word' mock." (describe "break" (before-each - (spy-on 'correct-interface :and-call-through) - ;; imitate C-g - (spy-on 'correct-word :and-return-value nil)) + (spy-on 'correct-interface :and-call-through) + ;; imitate C-g + (spy-on 'correct-word :and-return-value nil)) (it "call correct interface only once with backward direction" (with-mistakes|cursor-after @@ -542,6 +598,28 @@ Simply passed WORD to `correct-word' mock." (it "call correct interface only once with forward direction" (with-mistakes|cursor-before + (let ((current-prefix-arg '(64))) + (flyspell-correct-wrapper) + + (expect 'correct-interface :to-have-been-called-times 1) + (expect 'correct-word :to-have-been-called-with "versiuns"))))) + + (describe "stop" + + (before-each + (spy-on 'correct-interface :and-call-through) + (spy-on 'correct-word :and-call-fake (lambda (word) (cons 'stop word)))) + + (it "stop at the first misspelled word with backward direction" + (with-mistakes|stop|cursor-after + (let ((current-prefix-arg '(4))) + (flyspell-correct-wrapper) + + (expect 'correct-interface :to-have-been-called-times 1) + (expect 'correct-word :to-have-been-called-with "versiuns")))) + + (it "stop at the first misspelled word with forward direction" + (with-mistakes|stop|cursor-before (let ((current-prefix-arg '(64))) (flyspell-correct-wrapper)