]> git.eshelyaron.com Git - sweep.git/commitdiff
ADDED: sweeprolog-forward/backward/mark-predicate V8.5.20-sweep-0.8.3
authorEshel Yaron <me@eshelyaron.com>
Mon, 7 Nov 2022 10:29:53 +0000 (12:29 +0200)
committerEshel Yaron <me@eshelyaron.com>
Mon, 7 Nov 2022 10:29:53 +0000 (12:29 +0200)
NEWS.org
README.org
sweep.pl
sweeprolog-tests.el
sweeprolog.el

index 1d197a25a75f1b09933c3dbe3d319a946e4ece70..a8cc5079330918431ce8ee07845d717855708347 100644 (file)
--- a/NEWS.org
+++ b/NEWS.org
@@ -11,6 +11,16 @@ SWI-Prolog in Emacs.
 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-*~
index 7868bf1cf1c9c6ff34e6b341f8ec4f7e66156240..7baf76aa8b1e0adb31bee696597053a015380e45 100644 (file)
@@ -680,6 +680,28 @@ buffer.  To jump to a definition in the current buffer, type =M-x imenu=
 (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
@@ -1448,14 +1470,6 @@ there some further improvements that we want to pursue:
   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
index c5dfd37f4e466a03c0e72aee6cb701c1efce06e9..9f42fd05646aea5ab6953ec4384f2df328e353ac 100644 (file)
--- a/sweep.pl
+++ b/sweep.pl
@@ -61,7 +61,9 @@
             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)).
@@ -752,3 +754,26 @@ sweep_current_module(Module) :-
     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).
index 16364e7dad113635aa29e7819c3b167d76efbc58..834c7e644c0431868f6da7e141a8b06b8beb24d0 100644 (file)
@@ -105,6 +105,36 @@ foo(Foo) :- bar.
                    '(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"
@@ -156,7 +186,7 @@ foo(Bar) :- bar(Bar).
     (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."
index 5b936bd65ed4250e7aff1f251a50e39056f31ec4..9009fd3ac3b31535c749c5b7fa1441ad779af2b2 100644 (file)
@@ -6,7 +6,7 @@
 ;; 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.
@@ -326,6 +326,9 @@ clause."
                   #'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'.")
 
@@ -2247,16 +2250,25 @@ Interactively, POINT is set to the current point."
           (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 ()
@@ -2341,7 +2353,7 @@ instead."
   (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)))
@@ -2381,7 +2393,12 @@ of them signal success by returning non-nil."
                                           (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)
@@ -2396,7 +2413,7 @@ of them signal success by returning non-nil."
                   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))
@@ -2413,6 +2430,66 @@ of them signal success by returning non-nil."
           (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.
 
@@ -2535,7 +2612,8 @@ predicate definition at or directly 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))))