From 9bc4ba18b7e6da524a63917fba55e5e55291fb49 Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Thu, 26 Jan 2023 17:21:09 +0200 Subject: [PATCH] ADDED: numeric argument for sweeprolog-forward/backward-hole * sweeprolog.el (sweeprolog-count-holes): new command, counts holes in the current buffer. (sweeprolog-forward-hole, sweeprolog-backward-hole): new numeric argument, corresponding to the prefix argument when called interactively. With positive/negative numeric argument, move over that many holes. With zero numeric argument, call sweeprolog-count-holes instead. --- README.org | 20 ++++++++-- sweeprolog-tests.el | 23 ++++++++++++ sweeprolog.el | 90 ++++++++++++++++++++++++++------------------- 3 files changed, 93 insertions(+), 40 deletions(-) diff --git a/README.org b/README.org index d306ddb..67d436c 100644 --- a/README.org +++ b/README.org @@ -998,10 +998,15 @@ Use these commands to move between holes in the current Prolog buffer: #+KINDEX: C-c C-i - Key: C-c TAB (sweeprolog-forward-hole) :: Move point to the next - hole in the buffer. + hole in the buffer and select it as the region. With numeric prefix + argument /n/, move forward over /n/ - 1 holes and select the next one. #+KINDEX: C-c C-S-i - Key: C-c S-TAB (sweeprolog-backward-hole) :: Move point to the - previous hole in the buffer. + previous hole in the buffer and select it as the region. With + numeric prefix argument /n/, move backward over /n/ - 1 holes and select + the next one. +- Key: C-0 C-c TAB (sweeprolog-count-holes) :: Display the number of + holes that are present in the buffer. - Command: sweeprolog-forward-hole-on-tab-mode :: Toggle moving to the next hole in the buffer with ~TAB~ if the current line is already properly indented. @@ -1010,9 +1015,18 @@ To jump to the next hole in a ~sweeprolog-mode~ buffer, use the command ~M-x sweeprolog-forward-hole~, bound by default to ~C-c TAB~ (or ~C-c C-i~). This command sets up the region to cover the next hole after point leaving the cursor at right after the hole. To jump to the previous -hole instead, use ~sweeprolog-backward-hole~ or call +hole use ~C-c S-TAB~ (~sweeprolog-backward-hole~), or call ~sweeprolog-forward-hole~ with a negative prefix argument (~C-- C-c TAB~). +You can also call ~sweeprolog-forward-hole~ and ~sweeprolog-backward-hole~ +with a numeric prefix argument to jump over the specified number of +holes. For example, typing ~C-3 C-c TAB~ skips the next two holes in +the buffer and selects the third as the region. As a special case, if +you call these commands with a zero prefix argument (~C-0 C-c TAB~), +they invoke the command ~sweeprolog-count-holes~ instead of jumping. +This command counts how many holes are left in the current buffer and +reports its finding via a message in the echo area. + When the minor mode ~sweeprolog-forward-hole-on-tab-mode~ is enabled, the ~TAB~ key is bound to a command moves to the next hole when called in a properly indented line (otherwise it indents the line). This diff --git a/sweeprolog-tests.el b/sweeprolog-tests.el index e44ccca..c4e3b1f 100644 --- a/sweeprolog-tests.el +++ b/sweeprolog-tests.el @@ -287,6 +287,29 @@ foo(Foo) :- bar. (should (string= (buffer-string) "foo(bar, (_->_;_), _):-_.")))) +(ert-deftest forward-many-holes () + "Tests jumping over holes with `sweeprolog-forward-hole'." + (let ((temp (make-temp-file "sweeprolog-test" + nil + ".pl" + "\n" + ))) + (find-file-literally temp) + (sweeprolog-mode) + (goto-char (point-min)) + (sweeprolog-insert-term-with-holes ":-" 2) + (deactivate-mark) + (goto-char (point-max)) + (sweeprolog-insert-term-with-holes ":-" 2) + (goto-char (point-min)) + (should (= (sweeprolog-count-holes) 4)) + (sweeprolog-forward-hole 2) + (should (= (point) 5)) + (sweeprolog-forward-hole -1) + (should (= (point) 2)) + (sweeprolog-forward-hole -2) + (should (= (point) 8)))) + (ert-deftest plunit-testset-skeleton () "Tests inserting PlUnit test-set blocks." (let ((temp (make-temp-file "sweeprolog-test" diff --git a/sweeprolog.el b/sweeprolog.el index 893a77b..0cec3c6 100644 --- a/sweeprolog.el +++ b/sweeprolog.el @@ -506,6 +506,8 @@ token via its `help-echo' text property." (eq major-mode 'sweeprolog-mode) ] [ "Search Term" sweeprolog-term-search (derived-mode-p 'sweeprolog-mode)] + [ "Count Holes" sweeprolog-count-holes + (derived-mode-p 'sweeprolog-mode)] "--" [ "Set Prolog Flag" sweeprolog-set-prolog-flag t ] [ "Install Prolog Package" sweeprolog-pack-install t ] @@ -3094,6 +3096,25 @@ is the prefix argument." (setq end (1+ end))) (1+ end)))) + +(defun sweeprolog-count-holes (&optional interactive) + "Count holes in the current buffer and return the total number. +If INTERACTIVE is non-nil, as it is when called interactively, +also print a message with the result." + (interactive (list t) sweeprolog-mode) + (save-excursion + (goto-char (point-min)) + (let ((hole nil) (count 0)) + (while (setq hole (sweeprolog--next-hole)) + (goto-char (cdr hole)) + (setq count (1+ count))) + (when interactive + (message "%s %s left in buffer %s." + (if (zerop count) "No" count) + (ngettext "hole" "holes" count) + (buffer-name))) + count))) + (defun sweeprolog--next-hole (&optional wrap) "Return the bounds of the next hole in the current buffer. @@ -3127,10 +3148,12 @@ point and the end of the buffer." When WRAP in non-nil, wrap around if no holes are found between point and the beginning of the buffer." + (when (and (< (point-min) (point)) + (sweeprolog-at-hole-p (1- (point)))) + (forward-char -1) + (while (and (sweeprolog-at-hole-p) (not (bobp))) + (forward-char -1))) (let ((start (point))) - (when (use-region-p) - (goto-char (region-beginning)) - (deactivate-mark)) (when (sweeprolog--backward-wrap wrap) (if-let ((current-hole-beg (sweeprolog-beginning-of-hole))) (cons current-hole-beg @@ -3138,7 +3161,7 @@ point and the beginning of the buffer." (let ((point (point))) (while (not (or (sweeprolog-at-hole-p) (bobp))) (forward-char -1)) - (if (bobp) + (if (and (bobp) (not (sweeprolog-at-hole-p))) (or (and wrap (save-restriction (goto-char (point-max)) @@ -3148,44 +3171,37 @@ point and the beginning of the buffer." (cons (sweeprolog-beginning-of-hole) (sweeprolog-end-of-hole)))))))) -(defun sweeprolog--forward-hole (&optional wrap) - (if-let ((hole (sweeprolog--next-hole wrap)) - (beg (car hole)) - (end (cdr hole))) - (progn - (goto-char end) - (push-mark beg t t)) - (user-error "No holes following point"))) - -(defun sweeprolog--backward-hole (&optional wrap) - (if-let ((hole (sweeprolog--previous-hole wrap)) - (beg (car hole)) - (end (cdr hole))) - (progn - (goto-char end) - (push-mark beg t t)) - (user-error "No holes before point"))) +(defun sweeprolog-backward-hole (&optional n) + "Move point to the previous Nth hole in the current buffer. +If N is 0, display the number of holes in the current buffer by +calling `sweeprolog-count-holes' instead. -(defun sweeprolog-backward-hole (&optional arg) - "Move point to the previous hole in a `sweeprolog-mode' buffer. - -With negative prefix argument ARG, move to the next hole -instead." +See also `sweeprolog-forward-hole'." (interactive "p" sweeprolog-mode) - (setq arg (or arg 1)) - (sweeprolog-forward-hole (- arg))) + (sweeprolog-forward-hole (- (or n 1)))) -(defun sweeprolog-forward-hole (&optional arg) - "Move point to the next hole in a `sweeprolog-mode' buffer. +(defun sweeprolog-forward-hole (&optional n) + "Move point to the next Nth hole in the current buffer. +If N is 0, display the number of holes in the current buffer by +calling `sweeprolog-count-holes' instead. -With negative prefix argument ARG, move to the previous hole -instead." +See also `sweeprolog-backward-hole'." (interactive "p" sweeprolog-mode) - (setq arg (or arg 1) - deactivate-mark nil) - (if (> 0 arg) - (sweeprolog--backward-hole t) - (sweeprolog--forward-hole t))) + (setq n (or n 1)) + (if (zerop n) + (sweeprolog-count-holes t) + (let* ((func (if (< 0 n) + #'sweeprolog--next-hole + #'sweeprolog--previous-hole)) + (hole (funcall func t))) + (unless hole + (user-error "No holes in buffer %s" (buffer-name))) + (goto-char (cdr hole)) + (dotimes (_ (1- (abs n))) + (setq hole (funcall func t)) + (goto-char (cdr hole))) + (setq deactivate-mark nil) + (push-mark (car hole) t t)))) (put 'sweeprolog-backward-hole 'repeat-map -- 2.39.2