For further details, please consult the manual:
<https://eshelyaron.com/sweep.html>.
+* Version 0.8.3 on 2022-11-07
+
+** New commands that operate on entire predicate definitions
+
+~sweeprolog-mode~ now includes dedicated function for acting on
+predicate definitions that span multiple clauses. The new commands
+are ~sweeprolog-forward-predicate~ and ~sweeprolog-backward-predicate~
+bound to ~M-n~ and ~M-p~ respectively, and ~sweeprolog-mark-predicate~ bound
+to ~M-h~.
+
* Version 0.8.2 on 2022-11-07
** Renamed ~sweeprolog-colourise-*~ to ~sweeprolog-analyze-*~
(bound by default to =M-g i= in Emacs version 29). For information
about customizing =imenu=, see [[info:emacs#Imenu][Imenu in the Emacs manual]].
+** Predicate definition boundaries
+:PROPERTIES:
+:CUSTOM_ID: predicate-boundaries
+:DESCRIPTION: Commands operating on a Prolog predicate definition as a single unit
+:END:
+
+#+CINDEX: predicate-based motion
+#+FINDEX: sweeprolog-forward-predicate
+#+FINDEX: sweeprolog-backward-predicate
+#+KINDEX: M-n
+#+KINDEX: M-p
+In ~sweeprolog-mode~, the commands ~M-n~ (~sweeprolog-forward-predicate~)
+and ~M-p~ (~sweeprolog-backward-predicate~) are available for quickly
+jumping to the first line of the next or previous predicate
+definition in the current buffer.
+
+#+KINDEX: M-h
+The command ~M-h~ (~sweeprolog-mark-predicate~) marks the entire predicate
+definition at point, along with its =PlDoc= comments if there are any.
+This can be followed, for example, with killing the marked region to
+relocate the defined predicate by typing ~M-h C-w~.
+
** Following file specifications
:PROPERTIES:
:CUSTOM_ID: following-file-specs
definition, ideally with optional =PlDoc= comments (see [[#sweeprolog-pldoc][Documenting
predicates]]).
-- Add commands for narrowing and moving by predicate definitions :: ~sweeprolog-mode~
- should include commands for moving point to the next/previous
- predicate definition. We already have commands for clause-based
- motion (~C-M-a~, ~C-M-e~) but it would be useful to have predicate-based
- variants as well. These commands could then be bound to ~C-c C-n~ for
- moving to the next predicate definition and ~C-c C-p~ for moving to
- the previous.
-
- Improve the information provided for predicate completion candidates :: predicate
completion with ~C-M-i~ should annotate each completion candidate with
the names and modes of its arguments, when available. E.g. say
sweep_predicate_html_documentation/2,
sweep_predicate_properties/2,
sweep_analyze_region/2,
- sweep_xref_source/2
+ sweep_xref_source/2,
+ sweep_beginning_of_next_predicate/2,
+ sweep_beginning_of_last_predicate/2
]).
:- use_module(library(pldoc)).
atom_string(Path, String),
sweep_module_path_(Module, Path).
sweep_current_module(user).
+
+sweep_beginning_of_last_predicate(Start, Next) :-
+ sweep_source_id(Path),
+ xref_source(Path, [comments(store)]),
+ findall(L,
+ ( xref_defined(Path, _, H),
+ xref_definition_line(H, L),
+ L < Start
+ ),
+ Ls),
+ reverse(Ls, [Next|_]).
+
+sweep_beginning_of_next_predicate(Start, Next) :-
+ sweep_source_id(Path),
+ xref_source(Path, [comments(store)]),
+ xref_defined(Path, _, H), xref_definition_line(H, Next),
+ Start < Next.
+
+
+sweep_source_id(Path) :-
+ sweep_main_thread,
+ user:sweep_funcall("buffer-file-name", Path),
+ string(Path).
'(sweeprolog-undefined-default-face
sweeprolog-clause-default-face)))))
+
+(ert-deftest mark-predicate ()
+ "Test marking predicate definition."
+ (let ((temp (make-temp-file "sweeprolog-test"
+ nil
+ ".pl"
+ "
+:- module(baz, []).
+
+
+%! baz(-Baz) is semidet.
+%
+% Foobar.
+
+baz(Baz) :- bar(Baz).
+baz(_) :- false.
+
+%! bar(-Bar) is semidet.
+%
+% Spam.
+
+bar(Bar) :- baz(Bar).
+"
+ )))
+ (find-file-literally temp)
+ (sweeprolog-mode)
+ (call-interactively #'sweeprolog-mark-predicate)
+ (should (= (point) 24))
+ (should (= (mark) 104))))
+
(ert-deftest export-predicate ()
"Test exporting a predicate."
(let ((temp (make-temp-file "sweeprolog-test"
(goto-char (point-max))
(backward-word)
(should (equal (sweeprolog-definition-at-point)
- '(1 "foo" 1)))))
+ '(1 "foo" 1 21)))))
(ert-deftest file-at-point ()
"Test recognizing file specifications."
;; Maintainer: Eshel Yaron <~eshel/dev@lists.sr.ht>
;; Keywords: prolog languages extensions
;; URL: https://git.sr.ht/~eshel/sweep
-;; Package-Version: 0.8.2
+;; Package-Version: 0.8.3
;; Package-Requires: ((emacs "28.1"))
;; This file is NOT part of GNU Emacs.
#'flymake-show-diagnostics-buffer))
(define-key map (kbd "C-M-^") #'kill-backward-up-list)
(define-key map (kbd "C-M-m") #'sweeprolog-insert-term-dwim)
+ (define-key map (kbd "M-p") #'sweeprolog-backward-predicate)
+ (define-key map (kbd "M-n") #'sweeprolog-forward-predicate)
+ (define-key map (kbd "M-h") #'sweeprolog-mark-predicate)
map)
"Keymap for `sweeprolog-mode'.")
(not (= p (point))))
(sweeprolog-beginning-of-next-top-term (- times)))))
-(defun sweeprolog-beginning-of-next-top-term (times)
+(defun sweeprolog-beginning-of-next-top-term (&optional times)
+ (setq times (or times 1))
(let ((p (point)))
+ (when (sweeprolog-at-beginning-of-top-term-p)
+ (forward-char)
+ (re-search-forward (rx bol graph) nil t)
+ (while (and (or (nth 8 (syntax-ppss))
+ (nth 8 (syntax-ppss (1+ (point)))))
+ (not (eobp)))
+ (re-search-forward (rx bol graph) nil t))
+ (setq times (1- times)))
(while (and (< 0 times) (not (eobp)))
(setq times (1- times))
- (unless (eobp)
- (forward-char)
- (re-search-forward (rx bol graph) nil t))
- (while (and (nth 8 (syntax-ppss)) (not (eobp)))
- (forward-char)
+ (re-search-forward (rx bol graph) nil t)
+ (while (and (or (nth 8 (syntax-ppss))
+ (nth 8 (syntax-ppss (1+ (point)))))
+ (not (eobp)))
(re-search-forward (rx bol graph) nil t)))
+ (beginning-of-line)
(not (= p (point)))))
(defun sweeprolog-end-of-top-term ()
(when-let ((pred (sweeprolog-identifier-at-point point)))
(unless (sweeprolog-predicate-properties pred)
(push-mark)
- (sweeprolog-end-of-predicate-definition)
+ (sweeprolog-end-of-predicate-at-point)
(let ((functor-arity (sweeprolog--mfn-to-functor-arity pred)))
(sweeprolog-insert-clause (car functor-arity)
(cdr functor-arity)))
(pcase arg
(`("head_term" ,_ ,f ,a)
(setq def-at-point
- (list beg f a))))))
+ (list beg f a)))
+ ("fullstop"
+ (when def-at-point
+ (setq def-at-point
+ (append def-at-point
+ (list beg))))))))
def-at-point)))
(defun sweeprolog-insert-pldoc-for-predicate (functor arguments det summary)
summary))
(fill-paragraph))
-(defun sweeprolog-end-of-predicate-definition ()
+(defun sweeprolog-end-of-predicate-at-point ()
"Move to the end of the predicate definition at point."
(when-let* ((def (sweeprolog-definition-at-point)))
(let ((point (point))
(goto-char point)
(setq point nil))))))
+(defun sweeprolog-forward-predicate (&optional arg)
+ "Move forward over the ARGth next predicate defintion from point."
+ (interactive "p" sweeprolog-mode)
+ (setq arg (or arg 1))
+ (while (< 0 arg)
+ (setq arg (1- arg))
+ (if-let ((line
+ (sweeprolog--query-once "sweep" "sweep_beginning_of_next_predicate"
+ (line-number-at-pos))))
+ (progn
+ (goto-char (point-min))
+ (forward-line (1- line)))
+ (setq arg 0)
+ (user-error "No next predicate"))))
+
+(defun sweeprolog-backward-predicate (&optional arg)
+ "Move backward over the ARGth next predicate defintion from point."
+ (interactive "p" sweeprolog-mode)
+ (setq arg (or arg 1))
+ (while (< 0 arg)
+ (setq arg (1- arg))
+ (if-let ((line
+ (sweeprolog--query-once "sweep" "sweep_beginning_of_last_predicate"
+ (line-number-at-pos))))
+ (progn
+ (goto-char (point-min))
+ (forward-line (1- line)))
+ (setq arg 0)
+ (user-error "No previous predicate"))))
+
+(defun sweeprolog-end-of-next-predicate ()
+ (let ((def-at-point (sweeprolog-definition-at-point)))
+ (when (or (and def-at-point (<= (point) (nth 3 def-at-point)))
+ (condition-case _
+ (progn (sweeprolog-forward-predicate)
+ t)))
+ (sweeprolog-end-of-predicate-at-point)
+ (point))))
+
+(defun sweeprolog-mark-predicate (&optional allow-extend)
+ "Put point at beginning of this predicate, mark at end.
+
+Interactively (or if ALLOW-EXTEND is non-nil), if this command is
+repeated or (in Transient Mark mode) if the mark is active, it
+marks the next predicate after the ones already marked."
+ (interactive "p" sweeprolog-mode)
+ (if (and allow-extend
+ (or (and (eq last-command this-command) (mark t))
+ (and transient-mark-mode mark-active)))
+ (set-mark
+ (save-excursion
+ (goto-char (mark))
+ (sweeprolog-end-of-next-predicate)))
+ (when (sweeprolog-end-of-next-predicate)
+ (push-mark nil t t)
+ (sweeprolog-backward-predicate)
+ (let ((last (or (caddr (sweeprolog-last-token-boundaries))
+ (point-min))))
+ (while (re-search-backward (rx bol "%" (or "%" "!")) last t))))))
+
(defun sweeprolog-beginning-of-predicate-at-point (&optional point)
"Find the beginning of the predicate definition at or above POINT.
(while (and (not (bobp)) go)
(skip-chars-backward " \t\n")
(unless (bobp)
- (forward-char -1)
+ (unless (nth 4 (syntax-ppss))
+ (forward-char -1))
(if (nth 4 (syntax-ppss))
(goto-char (nth 8 (syntax-ppss)))
(setq go nil))))