#+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.
~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
(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"
(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 ]
(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.
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
(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))
(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