]> git.eshelyaron.com Git - sweep.git/commitdiff
ADDED: new command for updating use_module/autoload directives
authorEshel Yaron <me@eshelyaron.com>
Sat, 26 Nov 2022 13:29:48 +0000 (15:29 +0200)
committerEshel Yaron <me@eshelyaron.com>
Sat, 26 Nov 2022 13:36:00 +0000 (15:36 +0200)
* sweep.pl (sweep_file_path_in_library/2): new predicate.
(sweep_color_normalized/3): normalize autoload source paths.
* sweeprolog.el (sweeprolog-analyze-buffer-with): new helper function.
(sweeprolog-update-dependencies): new command.

sweep.pl
sweeprolog-tests.el
sweeprolog.el

index ca352010f682bfc36bd4ad4d633dd36b94ee2d7d..2eeb37d1621d611232aff003abbf2db6071c25b2 100644 (file)
--- a/sweep.pl
+++ b/sweep.pl
@@ -68,7 +68,8 @@
             sweep_predicate_completion_candidates/2,
             sweep_exportable_predicates/2,
             sweep_interrupt/0,
-            sweep_string_to_atom/2
+            sweep_string_to_atom/2,
+            sweep_file_path_in_library/2
           ]).
 
 :- use_module(library(pldoc)).
@@ -84,6 +85,7 @@
 :- use_module(library(lynx/html_text)).
 :- use_module(library(http/html_write)).
 :- use_module(library(prolog_pack)).
+:- use_module(library(prolog_deps)).
 
 :- if(exists_source(library(help))).
 :- use_module(library(help)).
@@ -466,7 +468,7 @@ sweep_color_normalized_(_, Goal0, [Kind0,Head|_], [Goal,Kind,F,N]) :-
     sweep_color_goal(Goal0),
     !,
     atom_string(Goal0, Goal),
-    term_string(Kind0, Kind),
+    sweeprolog_goal_kind_normalized(Kind0, Kind),
     (   (   var(Head)
         ->  true
         ;   Head == []
@@ -504,6 +506,13 @@ sweep_color_normalized_(_, file_no_depend, [File0|_], ["file_no_depend"|File]) :
 sweep_color_normalized_(_, Nom0, _, Nom) :-
     atom_string(Nom0, Nom).
 
+sweeprolog_goal_kind_normalized(autoload(Path0), ["autoload"|Path]) :-
+    !,
+    absolute_file_name(Path0, Path1, [extensions([pl])]),
+    atom_string(Path1, Path).
+sweeprolog_goal_kind_normalized(Kind0, Kind) :-
+    term_string(Kind0, Kind).
+
 sweep_color_goal(goal).
 sweep_color_goal(goal_term).
 sweep_color_goal(head).
@@ -868,3 +877,8 @@ sweep_string_to_atom(String, AtomString) :-
     format(string(AtomString),
            "~W",
            [Atom, [quoted(true), character_escapes(true)]]).
+
+sweep_file_path_in_library(Path, Spec) :-
+    file_name_on_path(Path, Spec0),
+    prolog_deps:segments(Spec0, Spec1),
+    term_string(Spec1, Spec).
index fb32a9a0d25b0c7b8f43e2da8febf259959fd54c..183068134ca3d83a21e1a94a5be01087bd17d347 100644 (file)
@@ -659,8 +659,98 @@ foo :- bar.
 foo :- Body.
 "))))
 
-(ert-deftest dwim-define-nested-phrase- ()
-  "Tests complex undefined predicate scenario"
+(ert-deftest append-dependencies ()
+  "Tests making implicit autoloads explicit with existing directive."
+  (let ((temp (make-temp-file "sweeprolog-test"
+                              nil
+                              "pl"
+                              "
+:- module(foo, [bar/1]).
+
+/** <module> Foo
+
+*/
+
+:- use_module(library(lists), [ member/2
+                              ]).
+
+bar(X) :- member(X, [1,2,3]).
+bar(X) :- permutation(X, [1,2,3]).
+"
+                              )))
+    (find-file-literally temp)
+    (sweeprolog-mode)
+    (call-interactively #'sweeprolog-update-dependencies)
+    (should (string= (buffer-string)
+                     "
+:- module(foo, [bar/1]).
+
+/** <module> Foo
+
+*/
+
+:- use_module(library(lists), [ member/2,
+                                permutation/2
+                              ]).
+
+bar(X) :- member(X, [1,2,3]).
+bar(X) :- permutation(X, [1,2,3]).
+"
+                     ))))
+
+(ert-deftest update-dependencies ()
+  "Tests making implicit autoloads explicit."
+  (let ((temp (make-temp-file "sweeprolog-test"
+                              nil
+                              "pl"
+                              "
+:- module(foo, [bar/1]).
+
+/** <module> Foo
+
+*/
+
+bar(X) :- member(X, [1,2,3]).
+"
+                              )))
+    (find-file-literally temp)
+    (sweeprolog-mode)
+    (call-interactively #'sweeprolog-update-dependencies)
+    (should (string= (buffer-string)
+                     "
+:- module(foo, [bar/1]).
+
+/** <module> Foo
+
+*/
+
+:- autoload(library(lists), [ member/2
+                            ]).
+
+bar(X) :- member(X, [1,2,3]).
+"
+
+                     ))
+    (goto-char (point-max))
+    (insert "bar(X) :- permutation(X, [1,2,3]).")
+    (call-interactively #'sweeprolog-update-dependencies)
+    (should (string= (buffer-string)
+                     "
+:- module(foo, [bar/1]).
+
+/** <module> Foo
+
+*/
+
+:- autoload(library(lists), [ member/2,
+                              permutation/2
+                            ]).
+
+bar(X) :- member(X, [1,2,3]).
+bar(X) :- permutation(X, [1,2,3])."))))
+
+(ert-deftest dwim-define-nested-phrase ()
+  "Tests complex undefined predicate scenario."
   (let ((temp (make-temp-file "sweeprolog-test"
                               nil
                               "pl"
index f0eccbf827af99ea35161488621cc19c9152298e..4476f0feabeeb3f4b9d42b4788c4da3f3500f6a2 100644 (file)
@@ -356,6 +356,7 @@ non-terminals)."
     (define-key map (kbd "C-c C-d") #'sweeprolog-document-predicate-at-point)
     (define-key map (kbd "C-c C-e") #'sweeprolog-export-predicate)
     (define-key map (kbd "C-c C-i") #'sweeprolog-forward-hole)
+    (define-key map (kbd "C-c C-u") #'sweeprolog-update-dependencies)
     (define-key map (kbd "C-c C-`")
                 (if (fboundp 'flymake-show-buffer-diagnostics)  ;; Flymake 1.2.1+
                     #'sweeprolog-show-diagnostics
@@ -439,6 +440,7 @@ non-terminals)."
       sweeprolog-document-predicate-at-point
       (and (eq major-mode 'sweeprolog-mode)
            (sweeprolog-definition-at-point)) ]
+    [ "Update autoload directives" sweeprolog-update-dependencies t ]
     "--"
     [ "Open top-level"         sweeprolog-top-level       t ]
     [ "Signal top-level"
@@ -1834,6 +1836,8 @@ resulting list even when found in the current clause."
      (list (list beg end (sweeprolog-head-hook-face))))
     (`("head" "built_in" . ,_)
      (list (list beg end (sweeprolog-head-built-in-face))))
+    (`("goal" ("autoload" . ,_) . ,_)
+     (list (list beg end (sweeprolog-autoload-face))))
     (`("head" ,(rx "imported(") . ,_)
      (list (list beg end (sweeprolog-head-imported-face))))
     (`("head" ,(rx "extern(") . ,_)
@@ -1867,8 +1871,6 @@ resulting list even when found in the current clause."
      (list (list beg end (sweeprolog-thread-local-face))))
     (`("goal" ,(rx "extern(") . ,_)
      (list (list beg end (sweeprolog-extern-face))))
-    (`("goal" ,(rx "autoload(") . ,_)
-     (list (list beg end (sweeprolog-autoload-face))))
     (`("goal" ,(rx "imported(") . ,_)
      (list (list beg end (sweeprolog-imported-face))))
     (`("goal" ,(rx "global(") . ,_)
@@ -2756,6 +2758,11 @@ of them signal success by returning non-nil."
        (not (nth 8 (syntax-ppss)))
        (not (looking-at-p (rx bol (or "%" "/*"))))))
 
+(defun sweeprolog-analyze-buffer-with (cb)
+  (add-hook 'sweeprolog-analyze-region-fragment-hook cb nil t)
+  (sweeprolog-analyze-buffer t)
+  (remove-hook 'sweeprolog-analyze-region-fragment-hook cb t))
+
 (defun sweeprolog-analyze-term-at-point (cb)
   (let ((sweeprolog--analyze-point (point)))
     (add-hook 'sweeprolog-analyze-region-fragment-hook cb nil t)
@@ -4028,6 +4035,93 @@ valid Prolog atom."
                    'sweeprolog--find-predicate-from-symbol))
 
 
+;;;; Dependency Managagement
+
+(defun sweeprolog-update-dependencies ()
+  "Add explicit dependencies for implicitly autoaloaded predicates."
+  (interactive "" sweeprolog-mode)
+  (let ((existing nil)
+        (missing nil)
+        (current-directive-beg nil)
+        (current-directive-end nil)
+        (current-directive-file nil))
+    (sweeprolog-analyze-buffer-with
+     (lambda (beg end arg)
+       (pcase arg
+         (`("goal_term" "built_in" "autoload" 2)
+          (setq current-directive-beg beg
+                current-directive-end end))
+         (`("goal_term" "built_in" "use_module" 2)
+          (setq current-directive-beg beg
+                current-directive-end end))
+         ((or `("file"           . ,file)
+              `("file_no_depend" . ,file))
+          (when (and current-directive-beg
+                     (<= current-directive-beg
+                         beg end
+                         current-directive-end))
+            (setq current-directive-file file)))
+         ((or "list" "empty_list")
+          (when (and current-directive-beg
+                     (<= current-directive-beg
+                         beg end
+                         current-directive-end))
+            (push
+             (cons current-directive-file (copy-marker (1- end) t))
+             existing)))
+         (`("goal" ("autoload" . ,file) ,functor ,arity)
+          (let ((autoloaded (list file functor arity)))
+            (unless (member autoloaded missing)
+              (push autoloaded missing)))))))
+    (if missing
+        (progn
+          (dolist (autoloaded missing)
+            (let* ((file    (nth 0 autoloaded))
+                   (functor (nth 1 autoloaded))
+                   (arity   (nth 2 autoloaded))
+                   (pred    (concat (sweeprolog-format-string-as-atom functor)
+                                    "/" (number-to-string arity))))
+              (message "Adding explicit dependency on %s from %s."
+                       pred file)
+              (if-let ((marker (cdr (assoc-string file existing))))
+                  (save-mark-and-excursion
+                    (goto-char marker)
+                    (pcase (sweeprolog-last-token-boundaries)
+                      (`(open ,_ ,oend)
+                       (goto-char oend)
+                       (insert " " pred "\n"))
+                      (`(symbol ,_ ,oend)
+                       (let ((point (point)))
+                         (goto-char oend)
+                         (insert ",")
+                         (goto-char (1+ point))
+                         (insert pred "\n")))
+                      (tok
+                       (user-error "Unexpected token %s while looking for import list"
+                                   tok)))
+                    (indent-region-line-by-line  (save-excursion
+                                                   (sweeprolog-beginning-of-top-term)
+                                                   (point))
+                                                 (save-excursion
+                                                   (sweeprolog-end-of-top-term)
+                                                   (point))))
+                (save-mark-and-excursion
+                  (goto-char (point-min))
+                  (sweeprolog-end-of-top-term)
+                  (while (forward-comment 1))
+                  (insert ":- autoload("
+                          (sweeprolog--query-once "sweep"
+                                                  "sweep_file_path_in_library"
+                                                  file)
+                          ", [ " pred "\n]).\n\n")
+                  (indent-region-line-by-line (save-excursion
+                                                (sweeprolog-beginning-of-top-term)
+                                                (point))
+                                              (point))
+                  (push (cons file (copy-marker (- (point) 5) t)) existing)))))
+          (sweeprolog-analyze-buffer t))
+      (message "No implicit autoloads found."))))
+
 ;;;; Footer
 
 (provide 'sweeprolog)