]> git.eshelyaron.com Git - sweep.git/commitdiff
ENHANCED: use terms at point as "future history" for term-search
authorEshel Yaron <me@eshelyaron.com>
Sat, 7 Jan 2023 06:20:01 +0000 (08:20 +0200)
committerEshel Yaron <me@eshelyaron.com>
Sat, 7 Jan 2023 06:20:01 +0000 (08:20 +0200)
* sweep.pl (sweep_terms_at_point/2): new predicate.
* sweeprolog.el (sweeprolog-terms-at-point): new function.
(sweeprolog-read-term): use it for setting the future history.
(sweeprolog-read-goal): new function.
(sweeprolog-term-search): use it for reading a goal when called with
prefix argument.

README.org
sweep.pl
sweeprolog-tests.el
sweeprolog.el

index 713a150154054ce0dfcaefea4fe6c6dd4c0fdbb9..ccbb0ee09aaf954f4c551b6313a72662debb6624 100644 (file)
@@ -1340,10 +1340,22 @@ search for and finds terms in the current buffer that the search term
 subsumes.  It highlights all matching terms in the buffer and moves
 the cursor to the beginning of the next match after point.  For
 example, to find if-then-else constructs in the current buffer do ~C-c
-C-s _ -> _ ; _ RET~.  You can further refine the search with an
-arbitrary Prolog goal that variables in the search term should satisfy
-by invoking ~sweeprolog-term-search~ with a prefix argument (i.e. typing
-~C-u C-c C-c~).
+C-s _ -> _ ; _ RET~.
+
+While prompting for a search term in the minibuffer, this command
+populates the "future history" with the Prolog terms at point, with
+the most nested term at point on top.  Typing ~M-n~ once in the
+minibuffer fills it the innermost term at point, typing ~M-n~ again
+cycles up the syntax tree at point filling the minibuffer with larger
+terms, up until the top-term at point.  For more information about
+minibuffer history commands, see [[info:emacs#Minibuffer History][Minibuffer History]] in the Emacs
+manual.
+
+If you invoke ~sweeprolog-term-search~ with a prefix argument, e.g. by
+typing ~C-u C-c C-c~, you can further refine the search with an
+arbitrary Prolog goal for filtering out search results that fail it.
+The given goal runs for each matching term, it may use variables from
+the search term to refer to subterms of the matching term.
 
 #+FINDEX: sweeprolog-term-search-repeat-forward
 #+FINDEX: sweeprolog-term-search-repeat-backward
@@ -1853,11 +1865,6 @@ there some further improvements that we want to pursue:
   ~help-echo~ property that says what kind of token this is, to expose
   the precise semantics of each token to the user.
 
-- Add a command for interactively inserting a new predicate :: ~sweeprolog-mode~
-  should provide a command for interactively inserting a new predicate
-  definition, ideally with optional =PlDoc= comments (see [[#sweeprolog-pldoc][Documenting
-  predicates]]).
-
 - Make predicate completion aware of module-qualification :: predicate
   completion should detect when the prefix it's trying to complete
   starts with a module-qualification ~foo:ba<|>~ and restrict completion
index 9e80898476238b932af17408ac969aefb89302a9..898df6643bbe45d1fc5b5d25a8c21e91d8a96dda 100644 (file)
--- a/sweep.pl
+++ b/sweep.pl
@@ -74,7 +74,8 @@
             sweep_format_head/2,
             sweep_format_term/2,
             sweep_current_functors/2,
-            sweep_term_search/2
+            sweep_term_search/2,
+            sweep_terms_at_point/2
           ]).
 
 :- use_module(library(pldoc)).
@@ -1036,3 +1037,54 @@ sweep_match_term(quasi_quotation_position(_, _, SyntaxTerm, SyntaxPos, _), _, Te
 
 list_tail([_|T0], T) :- nonvar(T0), T0 = [_|_], !, list_tail(T0, T).
 list_tail([_|T], T).
+
+sweep_terms_at_point([String, Start, Point], Res) :-
+    (   sweep_source_id(Path0),
+        atom_string(Path, Path0),
+        findall(Op, xref_op(Path, Op), Ops),
+        (   xref_module(Path, Module)
+        ->  true
+        ;   Module = user
+        )
+    ->  true
+    ;   Module = user, Ops = []
+    ),
+    with_buffer_stream(
+        Stream,
+        String,
+        (   ignore((   nonvar(Path),
+                       set_stream(Stream, file_name(Path))
+                   )),
+            read_source_term_at_location(Stream, _,
+                                         [module(Module),
+                                          operators(Ops),
+                                          subterm_positions(SubPos)]),
+            findall([Beg|End],
+                    sweep_terms_at_point_(SubPos, Start, Point, Beg, End),
+                    Res)
+        )).
+
+sweep_terms_at_point_(SubPos, Start, Point, Beg, End) :-
+    SubPos \= parentheses_term_position(_, _, _),
+    arg(1, SubPos, Beg0),
+    arg(2, SubPos, End0),
+    Beg0 =< Point,
+    Point =< End0,
+    Beg is Beg0 + Start,
+    End is End0 + Start.
+sweep_terms_at_point_(list_position(_, _, Elms, _), Start, Point, Beg, End) :-
+    member(SubPos, Elms),
+    sweep_terms_at_point_(SubPos, Start, Point, Beg, End).
+sweep_terms_at_point_(list_position(_, _, _, SubPos), Start, Point, Beg, End) :-
+    SubPos \== none,
+    sweep_terms_at_point_(SubPos, Start, Point, Beg, End).
+sweep_terms_at_point_(term_position(_, _, _, _, Args), Start, Point, Beg, End) :-
+    member(SubPos, Args),
+    sweep_terms_at_point_(SubPos, Start, Point, Beg, End).
+sweep_terms_at_point_(dict_position(_, _, _, _, KeyValuePosList), Start, Point, Beg, End) :-
+    member(key_value_position(_, _, _, _, _, _, SubPos), KeyValuePosList),
+    sweep_terms_at_point_(SubPos, Start, Point, Beg, End).
+sweep_terms_at_point_(parentheses_term_position(_, _, SubPos), Start, Point, Beg, End) :-
+    sweep_terms_at_point_(SubPos, Start, Point, Beg, End).
+sweep_terms_at_point_(quasi_quotation_position(_, _, _, SubPos, _), Start, Point, Beg, End) :-
+    sweep_terms_at_point_(SubPos, Start, Point, Beg, End).
index 5fa1cf8df97ac850d662216a43c4d8b207683c9f..a60d98d5ee40e97c1b1b98215f33621365dd32de 100644 (file)
@@ -78,7 +78,37 @@ foo(Baz) :- baz.
     (should (not (sweeprolog-beginning-of-next-top-term)))
     (should (= (point) 19))))
 
-(ert-deftest beginning-of-next-top-term ()
+(ert-deftest terms-at-point ()
+  "Test `sweeprolog-term-search'."
+  (let ((temp (make-temp-file "sweeprolog-terms-at-point-test"
+                              nil
+                              "pl"
+                              "
+recursive(Var) :-
+    (   true
+    ->  recursive(Bar)
+    ;   var(Baz)
+    *-> Bar is foo
+    ).
+")))
+    (find-file-literally temp)
+    (sweeprolog-mode)
+    (should (equal (sweeprolog-terms-at-point 81)
+                '("Bar"
+                  "Bar is foo"
+                  "var(Baz)
+    *-> Bar is foo" "true
+    ->  recursive(Bar)
+    ;   var(Baz)
+    *-> Bar is foo"
+    "recursive(Var) :-
+    (   true
+    ->  recursive(Bar)
+    ;   var(Baz)
+    *-> Bar is foo
+    )")))))
+
+(ert-deftest term-search ()
   "Test `sweeprolog-term-search'."
   (let ((temp (make-temp-file "sweeprolog-test"
                               nil
index 5b4784bf12da2845a7e7c27fac48c056d384e306..d396dccbc67765fda7e7a44ae4879ccdfe6059f5 100644 (file)
@@ -2524,7 +2524,7 @@ GOAL.  Otherwise, GOAL is set to a default value specified by
 `sweeprolog-top-level-signal-default-goal'."
   (interactive (list (if current-prefix-arg
                          (read-string "Signal goal: ?- " nil
-                                      sweeprolog-top-level-signal-goal-history)
+                                      'sweeprolog-top-level-signal-goal-history)
                        sweeprolog-top-level-signal-default-goal)))
   (sweeprolog-signal-thread sweeprolog-top-level-thread-id goal))
 
@@ -4263,6 +4263,7 @@ accordingly."
 
 ;;;; Help
 
+;;;###autoload
 (defun sweeprolog-info-manual ()
   "Display the Sweep manual in Info mode."
   (interactive)
@@ -4736,15 +4737,49 @@ moving point."
     map)
   "Keymap used by `sweeprolog-read-term'.")
 
+(defun sweeprolog-terms-at-point (&optional point)
+  "Return boundarines of Prolog terms at POINT, innermost first."
+  (setq point (or point (point)))
+  (save-excursion
+    (goto-char point)
+    (unless (sweeprolog-at-beginning-of-top-term-p)
+      (sweeprolog-beginning-of-top-term))
+    (unless (bobp)
+      (forward-char -1))
+    (let ((start (point)))
+      (sweeprolog-end-of-top-term)
+      (mapcar (lambda (beg-end)
+                (buffer-substring-no-properties (car beg-end)
+                                                (cdr beg-end)))
+              (reverse
+               (sweeprolog--query-once "sweep" "sweep_terms_at_point"
+                                       (list
+                                        (buffer-substring-no-properties
+                                         start (point))
+                                        start
+                                        (- point start))))))))
+
 (defvar sweeprolog-read-term-history nil
   "History list for `sweeprolog-read-term'.")
 
+(defvar sweeprolog-read-goal-history nil
+  "History list for `sweeprolog-read-goal'.")
+
 (defun sweeprolog-read-term (&optional prompt)
+  "Read a Prolog term prompting with PROMPT (default \"?- \")."
+  (setq prompt (or prompt "?- "))
+  (read-from-minibuffer prompt nil
+                        sweeprolog-read-term-map nil
+                        'sweeprolog-read-term-history
+                        (when (derived-mode-p 'sweeprolog-mode)
+                          (sweeprolog-terms-at-point))))
+
+(defun sweeprolog-read-goal (&optional prompt)
+  "Read a Prolog goal prompting with PROMPT (default \"?- \")."
   (setq prompt (or prompt "?- "))
-  "Read a Prolog term using the minibuffer."
   (read-from-minibuffer prompt nil
                         sweeprolog-read-term-map nil
-                        sweeprolog-read-term-history))
+                        'sweeprolog-read-goal-history))
 
 (defun sweeprolog-term-search-next (point overlays backward)
   "Return first overlay in OVERLAYS starting after POINT.
@@ -4788,7 +4823,7 @@ When called interactively with a prefix argument, prompt for
 GOAL."
   (interactive (let* ((term (sweeprolog-read-term "[Term-search] ?- "))
                       (goal (if current-prefix-arg
-                                (sweeprolog-read-term
+                                (sweeprolog-read-goal
                                  (concat "[Term-search goal for "
                                          term
                                          "] ?- "))
@@ -4831,6 +4866,7 @@ GOAL."
          "\\[sweeprolog-term-search-repeat-forward] for next match, "
          "\\[sweeprolog-term-search-repeat-backward] for previous match."))))))
 
+
 ;;;; Footer
 
 (provide 'sweeprolog)