]> git.eshelyaron.com Git - sweep.git/commitdiff
MODIFIED: sweeprolog-update-dependencies choice of directives
authorEshel Yaron <me@eshelyaron.com>
Mon, 13 Feb 2023 18:35:10 +0000 (20:35 +0200)
committerEshel Yaron <me@eshelyaron.com>
Mon, 13 Feb 2023 18:35:10 +0000 (20:35 +0200)
* sweeprolog.el (sweeprolog-dependency-directive): New user option.
Determines which directive to use in...
(sweeprolog-update-dependencies): Fix edge cases in finding where to
insert new directives. Optionally infer directive to add based on
current buffer contents.

* README.org (Managing Dependencies): Update section.

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

index ccd5355b71d67b44b8dc57faebaabd65afb4906c..3644f1203940cd635bf5e5a20337a14a9f284674 100644 (file)
@@ -1674,13 +1674,33 @@ sweeprolog-update-dependencies~ bound to ~C-c C-u~.
 - Key: C-c C-u (sweeprolog-update-dependencies) :: Add explicit
   dependencies for implicitly autoloaded predicates in the current
   buffer.
+#+VINDEX: sweeprolog-dependency-directive
+- User Option: sweeprolog-dependency-directive :: Determines which
+  Prolog directive to use in ~sweeprolog-update-dependencies~ when
+  adding new directives.  The value of this user option is one of the
+  symbols ~use-module~, ~autoload~ or ~infer~.  If it is ~use-module~,
+  ~sweeprolog-update-dependencies~ adds ~use_module/2~ directives,
+  ~autoload~ means to add ~autoload/2~ directives, and ~infer~ says to infer
+  which directive to use based on the existing dependency directives
+  in the buffer, if any.  Defaults to ~infer~.
 #+VINDEX: sweeprolog-note-implicit-autoloads
 - User Option: sweeprolog-note-implicit-autoloads :: If non-nil, have
   Flymake complain about implicitly autoloaded predicates in
   ~sweeprolog-mode~ buffers.
 
-This command analyzes the current buffer and adds or updates
-~autoload/2~ and ~use_module/2~ as needed.
+The command ~sweeprolog-update-dependencies~, bound to ~C-c C-u~, analyzes
+the current buffer and adds or updates ~autoload/2~ and ~use_module/2~ as
+needed.
+
+When this command adds a new directive, rather than updating an
+existing one, it can use either ~autoload/2~ or ~use_module/2~ to declare
+the new dependency based on the value of the user option
+~sweeprolog-dependency-directive~.  If you set this option is to
+~use-module~, new dependencies use the ~use_module/2~ directive.  If it's
+~autoload~, new dependencies use ~autoload/2~.  If it's ~infer~, as it is by
+default, new dependencies use ~autoload/2~ unless the buffer already
+contains dependency directives and they are all ~use_module/2~
+directives, in which case they also use ~use_module/2~.
 
 By default, when Flymake integration is enabled (see [[#diagnostics][Examining
 diagnostics]]), calls to implicitly autoloaded predicates are marked
index 48a8c0dc0a23c13aeed2b5551c26da27109ddf56..7f0fb340c109e71b2f40c8af2c04bab2c899d2d3 100644 (file)
--- a/sweep.pl
+++ b/sweep.pl
@@ -192,7 +192,7 @@ sweep_analyze_region_(OneTerm, Offset, Stream, Path, _) :-
 sweep_handle_fragment(Offset, comment(Kind), Beg, Len) :-
     !,
     Start is Beg + Offset,
-    asserta(sweep_current_comment(Kind, Start, Len)).
+    assertz(sweep_current_comment(Kind, Start, Len)).
 sweep_handle_fragment(Offset, Col, Beg, Len) :-
     sweep_handle_fragment_(Offset, Col, Beg, Len).
 
index 6f5f6bf9496a52ab6064a047c32197cd9bf098ac..42ebabaa3fee631eea9d2941737b344feb99f814 100644 (file)
@@ -909,7 +909,7 @@ foo :- Body.
 "))))
 
 (ert-deftest update-dependencies-no-autoload ()
-  "Tests making adding a use_module/1 directive."
+  "Tests adding a use_module/2 directive."
   (let ((temp (make-temp-file "sweeprolog-test"
                               nil
                               "pl"
@@ -929,14 +929,12 @@ bar(X) :- arithmetic_function(X).
     (should (string= (buffer-string)
                               "
 :- module(foo, [bar/1]).
+:- use_module(library(arithmetic), [arithmetic_function/1]).
 
 /** <module> Foo
 
 */
 
-:- use_module(library(arithmetic), [ arithmetic_function/1
-                                   ]).
-
 bar(X) :- arithmetic_function(X).
 "))))
 
@@ -979,6 +977,120 @@ bar(X) :- permutation(X, [1,2,3]).
 "
                      ))))
 
+(ert-deftest update-dependencies-without-inference ()
+  "Tests setting `sweeprolog-dependency-directive' to `autoload'."
+  (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) :- maplist(X, [1,2,3]).
+"
+                              )))
+    (find-file-literally temp)
+    (sweeprolog-mode)
+    (let ((sweeprolog-dependency-directive 'autoload))
+     (call-interactively #'sweeprolog-update-dependencies))
+    (should (string= (buffer-string)
+                     "
+:- module(foo, [bar/1]).
+
+/** <module> Foo
+
+*/
+
+:- use_module(library(lists), [ member/2
+                              ]).
+:- autoload(library(apply), [maplist/2]).
+
+bar(X) :- member(X, [1,2,3]).
+bar(X) :- maplist(X, [1,2,3]).
+"
+                     ))))
+
+(ert-deftest update-dependencies-without-inference-2 ()
+  "Tests setting `sweeprolog-dependency-directive' to `use-module'."
+  (let ((temp (make-temp-file "sweeprolog-test"
+                              nil
+                              "pl"
+                              "
+:- module(foo, [bar/1]).
+
+/** <module> Foo
+
+*/
+
+bar(X) :- member(X, [1,2,3]).
+bar(X) :- maplist(X, [1,2,3]).
+"
+                              )))
+    (find-file-literally temp)
+    (sweeprolog-mode)
+    (let ((sweeprolog-dependency-directive 'use-module))
+     (call-interactively #'sweeprolog-update-dependencies))
+    (should (string= (buffer-string)
+                     "
+:- module(foo, [bar/1]).
+:- use_module(library(apply), [maplist/2]).
+:- use_module(library(lists), [member/2]).
+
+/** <module> Foo
+
+*/
+
+bar(X) :- member(X, [1,2,3]).
+bar(X) :- maplist(X, [1,2,3]).
+"
+                     ))))
+
+(ert-deftest update-dependencies-with-use-module ()
+  "Tests updating dependencies in presence of use_module directives."
+  (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) :- maplist(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
+                              ]).
+:- use_module(library(apply), [maplist/2]).
+
+bar(X) :- member(X, [1,2,3]).
+bar(X) :- maplist(X, [1,2,3]).
+"
+                     ))))
+
 (ert-deftest update-dependencies-autoload-from-package ()
   "Tests making implicit autoloads from a package explicit."
   (let ((temp (make-temp-file "sweeprolog-test"
@@ -1000,14 +1112,12 @@ bar(X) :- http_open(X, X, X).
     (should (string= (buffer-string)
                      "
 :- module(foo, [bar/1]).
+:- autoload(library(http/http_open), [http_open/3]).
 
 /** <module> Foo
 
 */
 
-:- autoload(library(http/http_open), [ http_open/3
-                                     ]).
-
 bar(X) :- http_open(X, X, X).
 "))))
 
@@ -1032,14 +1142,12 @@ bar(X) :- member(X, [1,2,3]).
     (should (string= (buffer-string)
                      "
 :- module(foo, [bar/1]).
+:- autoload(library(lists), [member/2]).
 
 /** <module> Foo
 
 */
 
-:- autoload(library(lists), [ member/2
-                            ]).
-
 bar(X) :- member(X, [1,2,3]).
 "
 
@@ -1050,15 +1158,12 @@ bar(X) :- member(X, [1,2,3]).
     (should (string= (buffer-string)
                      "
 :- module(foo, [bar/1]).
+:- autoload(library(lists), [member/2, permutation/2]).
 
 /** <module> Foo
 
 */
 
-:- autoload(library(lists), [ member/2,
-                              permutation/2
-                            ]).
-
 bar(X) :- member(X, [1,2,3]).
 bar(X) :- permutation(X, [1,2,3])."))))
 
index 990b3e00c9bb4a8ffda013aaca6c6532ae20cc47..4bdbfa1924506e1ef093221a9452080f7003cd1a 100644 (file)
@@ -398,6 +398,26 @@ first."
                  (const :tag "Refuse"  nil))
   :group 'sweeprolog)
 
+(defcustom sweeprolog-dependency-directive 'infer
+  "Prolog directive to use for adding dependencies.
+This determines whether `sweeprolog-update-dependencies' uses
+`autoload/2' or `use_module/2' directives to make implicit
+dependencies into explicit dependencies.
+
+If set to the symbol `use-module', then
+`sweeprolog-update-dependencies' only uses `use_module/2'
+directives.  If set to the symbol `infer', then
+`sweeprolog-update-dependencies' uses `autoload/2' directives
+unless the buffer already contains dependency directives and all
+of them are `use_module/2' directives.  Any other values means to
+use `autoload/2' for all added directives."
+  :package-version '((sweeprolog "0.16.1"))
+  :type '(choice (const :tag "Prefer use_module/2" use-module)
+                 (const :tag "Prefer autoload/2"  autoload)
+                 (const :tag "Infer" infer))
+  :group 'sweeprolog)
+
+
 ;;;; Keymaps
 
 (defvar sweeprolog-mode-map
@@ -4902,19 +4922,60 @@ accordingly."
 (defun sweeprolog-update-dependencies ()
   "Add explicit dependencies for implicitly autoaloaded predicates."
   (interactive "" sweeprolog-mode)
-  (let ((existing nil)
+  (let ((styles   nil)
+        (existing nil)
         (current-directive-beg nil)
         (current-directive-end nil)
-        (current-directive-file nil))
+        (current-directive-file nil)
+        (last-directive-end nil)
+        (in-directive nil)
+        (seen-non-directive nil)
+        (first-structured-comment nil))
     (sweeprolog-analyze-buffer-with
      (lambda (beg end arg)
        (pcase arg
+         ("directive"
+          (setq in-directive t))
+         (`("goal_term" "built_in" "autoload" 1)
+          (when in-directive
+            (add-to-list 'styles 'autoload)
+            (unless seen-non-directive
+              (setq last-directive-end end))))
          (`("goal_term" "built_in" "autoload" 2)
-          (setq current-directive-beg beg
-                current-directive-end end))
+          (when in-directive
+            (setq current-directive-beg beg
+                  current-directive-end end)
+            (unless seen-non-directive
+              (setq last-directive-end end))
+            (add-to-list 'styles 'autoload)))
+         (`("goal_term" "built_in" "use_module" 1)
+          (when in-directive
+            (add-to-list 'styles 'use-module)
+            (unless seen-non-directive
+              (setq last-directive-end end))))
          (`("goal_term" "built_in" "use_module" 2)
-          (setq current-directive-beg beg
-                current-directive-end end))
+          (when in-directive
+            (setq current-directive-beg beg
+                  current-directive-end end)
+            (unless seen-non-directive
+              (setq last-directive-end end))
+            (add-to-list 'styles 'use-module)))
+         (`("goal_term" "built_in" "module" 2)
+          (when in-directive
+            (unless seen-non-directive
+              (setq last-directive-end end))))
+         (`("goal_term" . ,_)
+          (setq in-directive nil))
+         ((or "term"
+              "clause"
+              "grammar_rule"
+              "method")
+          (setq in-directive nil
+                seen-non-directive beg))
+         (`("comment" . "structured")
+          (unless (or first-structured-comment
+                      (< seen-non-directive beg))
+            (setq first-structured-comment beg)))
          ((or `("file"           . ,file)
               `("file_no_depend" . ,file))
           (when (and current-directive-beg
@@ -4930,6 +4991,14 @@ accordingly."
             (push
              (cons current-directive-file (copy-marker (1- end) t))
              existing))))))
+    (setq last-directive-end
+          (copy-marker (or (and last-directive-end
+                                (save-excursion
+                                  (goto-char last-directive-end)
+                                  (sweeprolog-end-of-top-term)
+                                  (point)))
+                           first-structured-comment
+                           (point-min))))
     (if-let ((missing
               (sweeprolog--query-once "sweep" "sweep_file_missing_dependencies"
                                       (buffer-file-name))))
@@ -4937,59 +5006,72 @@ accordingly."
           (dolist (autoloaded missing)
             (let* ((file    (nth 0 autoloaded))
                    (pred    (nth 1 autoloaded))
-                   (kind    (nth 2 autoloaded)))
+                   (kind    (pcase sweeprolog-dependency-directive
+                              ('use-module "use_module")
+                              ('infer (if (equal styles '(use-module))
+                                          "use_module"
+                                        (nth 2 autoloaded)))
+                              (_ (nth 2 autoloaded)))))
               (if (not pred)
                   (save-mark-and-excursion
-                    (goto-char (point-min))
-                    (sweeprolog-end-of-top-term)
-                    (while (forward-comment 1))
-                    (insert ":- " kind "("
-                            (sweeprolog--query-once "sweep"
-                                                    "sweep_file_path_in_library"
-                                                    file)
-                            ").\n\n")
+                    (goto-char last-directive-end)
+                    (insert-before-markers
+                     ":- " kind "("
+                     (sweeprolog--query-once "sweep"
+                                             "sweep_file_path_in_library"
+                                             file)
+                     ").\n")
                     (indent-region-line-by-line (save-excursion
                                                   (sweeprolog-beginning-of-top-term)
                                                   (point))
                                                 (point)))
-                (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)))
+                      (let ((close-line (line-number-at-pos (point)))
+                            (previous-line nil))
+                        (pcase (sweeprolog-last-token-boundaries)
+                          (`(open ,_ ,oend)
                            (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))))
+                           (insert pred))
+                          (`(symbol ,_ ,oend)
+                           (let ((import-list-end-marker
+                                  (copy-marker (point))))
+                             (goto-char oend)
+                             (setq previous-line (line-number-at-pos (point)))
+                             (delete-horizontal-space)
+                             (insert-before-markers (if (eolp)
+                                                        ","
+                                                      ", "))
+                             (goto-char import-list-end-marker)
+                             (insert pred)
+                             (unless (= previous-line close-line)
+                               (insert "\n"))
+                             (when (< fill-column (current-column))
+                               (goto-char import-list-end-marker)
+                               (insert "\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 ":- " kind "("
-                            (sweeprolog--query-once "sweep"
-                                                    "sweep_file_path_in_library"
-                                                    file)
-                            ", [ " pred "\n]).\n\n")
+                    (goto-char last-directive-end)
+                    (insert-before-markers
+                     ":- " kind "("
+                     (sweeprolog--query-once "sweep"
+                                             "sweep_file_path_in_library"
+                                             file)
+                     ", [" pred "]).\n")
                     (indent-region-line-by-line (save-excursion
                                                   (sweeprolog-beginning-of-top-term)
                                                   (point))
                                                 (point))
-                    (push (cons file (copy-marker (- (point) 5) t)) existing))))))
+                    (push (cons file (copy-marker (- (point) 4) t)) existing))))))
           (sweeprolog-analyze-buffer t))
       (message "No implicit autoloads found."))))