Subject: [PATCH 4/5] style: Add '--styling' option.

From: Ludovic Courtès <[email-masked]>
Date: Mon, 3 Jan 2022 12:24:38 +0100

* guix/scripts/style.scm (format-package-definition): New procedure.
(%options, show-help): Add "--styling".
(%default-options): Add 'styling-procedure'.
(guix-style): Honor it.
* tests/style.scm (with-test-package)
("input labels, 'safe' policy")
("input labels, 'safe' policy, nothing changed")
("input labels, margin comment")
("input labels, margin comment on long list")
("input labels, line comment")
("input labels, modify-inputs and margin comment"): Pass "-S inputs".
* etc/indent-code.el: Remove.
* doc/contributing.texi (Formatting Code): Mention "guix style" instead
of "etc/indent-code.el".
(Submitting Patches): Add item for "guix style".
* doc/guix.texi (Invoking guix style): Document "-S" and update.
---
 doc/contributing.texi  |  18 +++----
 doc/guix.texi          |  60 +++++++++++++++++----
 etc/indent-code.el     | 120 -----------------------------------------
 guix/scripts/style.scm |  43 +++++++++++++--
 tests/style.scm        |  17 ++++--
 5 files changed, 111 insertions(+), 147 deletions(-)
 delete mode 100755 etc/indent-code.el

diff --git a/doc/contributing.texi b/doc/contributing.texi
index 72f5ce1e0e..9f97788c0b 100644
--- a/doc/contributing.texi
+++ b/doc/contributing.texi
@@ -959,17 +959,11 @@ If you do not use Emacs, please make sure to let your editor knows these
 rules.  To automatically indent a package definition, you can also run:
 
 @example
-./etc/indent-code.el gnu/packages/@var{file}.scm @var{package}
+./pre-inst-env guix style @var{package}
 @end example
 
 @noindent
-This automatically indents the definition of @var{package} in
-@file{gnu/packages/@var{file}.scm} by running Emacs in batch mode.  To
-indent a whole file, omit the second argument:
-
-@example
-./etc/indent-code.el gnu/services/@var{file}.scm
-@end example
+@xref{Invoking guix style}, for more information.
 
 @cindex Vim, Scheme code editing
 If you are editing code with Vim, we recommend that you run @code{:set
@@ -1038,6 +1032,10 @@ Run @code{guix lint @var{package}}, where @var{package} is the
 name of the new or modified package, and fix any errors it reports
 (@pxref{Invoking guix lint}).
 
+@item
+Run @code{guix style @var{package}} to format the new package definition
+according to the project's conventions (@pxref{Invoking guix style}).
+
 @item
 Make sure the package builds on your platform, using @code{guix build
 @var{package}}.
@@ -1175,8 +1173,8 @@ Examples of unrelated changes include the addition of several packages,
 or a package update along with fixes to that package.
 
 @item
-Please follow our code formatting rules, possibly running the
-@command{etc/indent-code.el} script to do that automatically for you
+Please follow our code formatting rules, possibly running
+@command{guix style} script to do that automatically for you
 (@pxref{Formatting Code}).
 
 @item
diff --git a/doc/guix.texi b/doc/guix.texi
index b72a3d1263..01d4c14e9c 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -12771,8 +12771,16 @@ otherwise.
 
 The @command{guix style} command helps packagers style their package
 definitions according to the latest fashionable trends.  The command
-currently focuses on one aspect: the style of package inputs.  It may
-eventually be extended to handle other stylistic matters.
+currently provides the providing styling rules:
+
+@itemize
+@item
+formatting package definitions according to the project's conventions
+(@pxref{Formatting Code});
+
+@item
+rewriting package inputs to the ``new style'', as explained below.
+@end itemize
 
 The way package inputs are written is going through a transition
 (@pxref{package Reference}, for more on package inputs).  Until version
@@ -12803,7 +12811,7 @@ Package Variants}, for more info on @code{modify-inputs}).
 
 In the vast majority of cases, this is a purely mechanical change on the
 surface syntax that does not even incur a package rebuild.  Running
-@command{guix style} can do that for you, whether you're working on
+@command{guix style -S inputs} can do that for you, whether you're working on
 packages in Guix proper or in an external channel.
 
 The general syntax is:
@@ -12813,15 +12821,48 @@ guix style [@var{options}] @var{package}@dots{}
 @end example
 
 This causes @command{guix style} to analyze and rewrite the definition
-of @var{package}@dots{}.  It does so in a conservative way: preserving
-comments and bailing out if it cannot make sense of the code that
-appears in an inputs field.  The available options are listed below.
+of @var{package}@dots{} or, when @var{package} is omitted, of @emph{all}
+the packages.  The @option{--styling} or @option{-S} option allows you
+to select the style rule, the default rule being @code{format}---see
+below.
+
+The available options are listed below.
 
 @table @code
 @item --dry-run
 @itemx -n
 Show source file locations that would be edited but do not modify them.
 
+@item --styling=@var{rule}
+@itemx -S @var{rule}
+Apply @var{rule}, one of the following styling rules:
+
+@table @code
+@item format
+Format the given package definition(s)---this is the default styling
+rule.  For example, a packager running Guix on a checkout
+(@pxref{Running Guix Before It Is Installed}) might want to reformat the
+definition of the Coreutils package like so:
+
+@example
+./pre-inst-env guix style coreutils
+@end example
+
+@item inputs
+Rewrite package inputs to the ``new style'', as described above.  This
+is how you would rewrite inputs of package @code{whatnot} in your own
+channel:
+
+@example
+guix style -L ~/my/channel -S inputs whatnot
+@end example
+
+Rewriting is done in a conservative way: preserving comments and bailing
+out if it cannot make sense of the code that appears in an inputs field.
+The @option{--input-simplification} option described below provides
+fine-grain control over when inputs should be simplified.
+@end table
+
 @item --load-path=@var{directory}
 @itemx -L @var{directory}
 Add @var{directory} to the front of the package module search path
@@ -12840,9 +12881,10 @@ guix style -e '(@@ (gnu packages gcc) gcc-5)'
 styles the @code{gcc-5} package definition.
 
 @item --input-simplification=@var{policy}
-Specify the package input simplification policy for cases where an input
-label does not match the corresponding package name.  @var{policy} may
-be one of the following:
+When using the @code{inputs} styling rule, with @samp{-S inputs}, this
+option specifies the package input simplification policy for cases where
+an input label does not match the corresponding package name.
+@var{policy} may be one of the following:
 
 @table @code
 @item silent
diff --git a/etc/indent-code.el b/etc/indent-code.el
deleted file mode 100755
index bdea8ee8bf..0000000000
--- a/etc/indent-code.el
+++ /dev/null
@@ -1,120 +0,0 @@
-:;exec emacs --batch --quick --load="$0" --funcall=main "$@"
-;;; indent-code.el --- Run Emacs to indent a package definition.
-
-;; Copyright © 2017 Alex Kost <[email-masked]>
-;; Copyright © 2017 Ludovic Courtès <[email-masked]>
-;; Copyright © 2020 Maxim Cournoyer <[email-masked]>
-;; Copyright © 2020 Tobias Geerinckx-Rice <[email-masked]>
-
-;; This file is part of GNU Guix.
-
-;; GNU Guix is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Guix is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This scripts indents the given file or package definition in the specified
-;; file using Emacs.
-
-;;; Code:
-
-;; Load Scheme indentation rules from ".dir-locals.el".
-(with-temp-buffer
-  (scheme-mode)
-  (let ((default-directory (file-name-as-directory load-file-name))
-        (enable-local-variables :all))
-    (hack-dir-local-variables)
-    (hack-local-variables-apply)))
-
-;; Add indentation info for Scheme constructs that are not Guix-specific.
-;; This is normally provided by Geiser but this file is for people who may not
-;; be running Geiser, so we just copy it here (from 'geiser-syntax.el').
-(defmacro guix-syntax--scheme-indent (&rest pairs)
-  `(progn ,@(mapcar (lambda (p)
-                      `(put ',(car p) 'scheme-indent-function ',(cadr p)))
-                    pairs)))
-
-(guix-syntax--scheme-indent
- (and-let* 1)
- (case-lambda 0)
- (catch defun)
- (class defun)
- (dynamic-wind 0)
- (guard 1)
- (let*-values 1)
- (let-values 1)
- (let/ec 1)
- (letrec* 1)
- (match 1)
- (match-lambda 0)
- (match-lambda* 0)
- (match-let scheme-let-indent)
- (match-let* 1)
- (match-letrec 1)
- (opt-lambda 1)
- (parameterize 1)
- (parameterize* 1)
- (receive 2)
- (require-extension 0)
- (syntax-case 2)
- (test-approximate 1)
- (test-assert 1)
- (test-eq 1)
- (test-equal 1)
- (test-eqv 1)
- (test-group-with-cleanup 1)
- (test-runner-on-bad-count! 1)
- (test-runner-on-bad-end-name! 1)
- (test-runner-on-final! 1)
- (test-runner-on-group-begin! 1)
- (test-runner-on-group-end! 1)
- (test-runner-on-test-begin! 1)
- (test-runner-on-test-end! 1)
- (test-with-runner 1)
- (unless 1)
- (when 1)
- (while 1)
- (with-exception-handler 1)
- (with-syntax 1))
-
-
-(defun main ()
-  (pcase command-line-args-left
-    (`(,file-name ,package-name)
-     ;; Indent the definition of PACKAGE-NAME in FILE-NAME.
-     (find-file file-name)
-     (goto-char (point-min))
-     (if (re-search-forward (concat "^(define\\(\\|-public\\) +"
-                                    package-name)
-                            nil t)
-         (let ((indent-tabs-mode nil))
-           (beginning-of-defun)
-           (mark-sexp)
-           (untabify (point) (mark))
-           (indent-sexp)
-           (save-buffer)
-           (message "Done!"))
-       (error "Package '%s' not found in '%s'"
-              package-name file-name)))
-    (`(,file-name)
-     ;; Indent all of FILE-NAME.
-     (find-file file-name)
-     (let ((indent-tabs-mode nil))
-       (untabify (point-min) (point-max))
-       (indent-region (point-min) (point-max))
-       (save-buffer)
-       (message "Done!")))
-    (x
-     (error "Usage: indent-code.el FILE [PACKAGE]"))))
-
-;;; indent-code.el ends here
diff --git a/guix/scripts/style.scm b/guix/scripts/style.scm
index 00680daa23..47549c7e4a 100644
--- a/guix/scripts/style.scm
+++ b/guix/scripts/style.scm
@@ -685,6 +685,29 @@ (define matches?
             (list package-inputs package-native-inputs
                   package-propagated-inputs)))
 
+
+;;;
+;;; Formatting package definitions.
+;;;
+
+(define* (format-package-definition package
+                                    #:key policy
+                                    (edit-expression edit-expression))
+  "Reformat the definition of PACKAGE."
+  (unless (package-definition-location package)
+    (leave (package-location package)
+           (G_ "no definition location for package ~a~%")
+           (package-full-name package)))
+
+  (edit-expression
+   (location->source-properties (package-definition-location package))
+   (lambda (str)
+     (let ((exp (call-with-input-string str
+                  read-with-comments)))
+       (object->string* exp
+                        (location-column
+                         (package-definition-location package)))))))
+
 (define (package-location<? p1 p2)
   "Return true if P1's location is \"before\" P2's."
   (let ((loc1 (package-location p1))
@@ -711,6 +734,15 @@ (define %options
         (option '(#\e "expression") #t #f
                 (lambda (opt name arg result)
                   (alist-cons 'expression arg result)))
+        (option '(#\S "styling") #t #f
+                (lambda (opt name arg result)
+                  (alist-cons 'styling-procedure
+                              (match arg
+                                ("inputs" simplify-package-inputs)
+                                ("format" format-package-definition)
+                                (_ (leave (G_ "~a: unknown styling~%")
+                                          arg)))
+                              result)))
         (option '("input-simplification") #t #f
                 (lambda (opt name arg result)
                   (let ((symbol (string->symbol arg)))
@@ -731,6 +763,9 @@ (define %options
 (define (show-help)
   (display (G_ "Usage: guix style [OPTION]... [PACKAGE]...
 Update package definitions to the latest style.\n"))
+  (display (G_ "
+  -S, --styling=RULE     apply RULE, a styling rule"))
+  (newline)
   (display (G_ "
   -n, --dry-run          display files that would be edited but do nothing"))
   (display (G_ "
@@ -751,7 +786,8 @@ (define (show-help)
 
 (define %default-options
   ;; Alist of default option values.
-  '((input-simplification-policy . silent)))
+  `((input-simplification-policy . silent)
+    (styling-procedure . ,format-package-definition)))
 
 
 ;;;
@@ -778,11 +814,12 @@ (define (parse-options)
          (edit     (if (assoc-ref opts 'dry-run?)
                        edit-expression/dry-run
                        edit-expression))
+         (style    (assoc-ref opts 'styling-procedure))
          (policy   (assoc-ref opts 'input-simplification-policy)))
     (with-error-handling
       (for-each (lambda (package)
-                  (simplify-package-inputs package #:policy policy
-                                           #:edit-expression edit))
+                  (style package #:policy policy
+                         #:edit-expression edit))
                 ;; Sort package by source code location so that we start editing
                 ;; files from the bottom and going upward.  That way, the
                 ;; 'location' field of <package> records is not invalidated as
diff --git a/tests/style.scm b/tests/style.scm
index 8022688419..7dae543860 100644
--- a/tests/style.scm
+++ b/tests/style.scm
@@ -78,7 +78,8 @@ (define file
         (string-append directory "/my-packages.scm"))
 
       ;; Run as a separate process to make sure FILE is reloaded.
-      (system* "guix" "style" "-L" directory "my-coreutils")
+      (system* "guix" "style" "-L" directory "-S" "inputs"
+               "my-coreutils")
       (system* "cat" file)
 
       (load file)
@@ -237,6 +238,7 @@ (define file
         (string-append directory "/my-packages.scm"))
 
       (system* "guix" "style" "-L" directory "my-coreutils"
+               "-S" "inputs"
                "--input-simplification=safe")
 
       (load file)
@@ -258,6 +260,7 @@ (define file
         (string-append directory "/my-packages.scm"))
 
       (system* "guix" "style" "-L" directory "my-coreutils"
+               "-S" "inputs"
                "--input-simplification=safe")
 
       (load file)
@@ -284,7 +287,8 @@ (define file
                         " ;another one\n")))
       (system* "cat" file)
 
-      (system* "guix" "style" "-L" directory "my-coreutils")
+      (system* "guix" "style" "-L" directory "-S" "inputs"
+               "my-coreutils")
 
       (load file)
       (list (package-inputs (@ (my-packages) my-coreutils))
@@ -317,7 +321,8 @@ (define file
                         " ;margin comment\n")))
       (system* "cat" file)
 
-      (system* "guix" "style" "-L" directory "my-coreutils")
+      (system* "guix" "style" "-L" directory "-S" "inputs"
+               "my-coreutils")
 
       (load file)
       (list (package-inputs (@ (my-packages) my-coreutils))
@@ -338,7 +343,8 @@ (define file
         ((",gmp\\)(.*)$" _ rest)
          (string-append ",gmp)\n   ;; line comment!\n" rest)))
 
-      (system* "guix" "style" "-L" directory "my-coreutils")
+      (system* "guix" "style" "-L" directory "-S" "inputs"
+               "my-coreutils")
 
       (load file)
       (list (package-inputs (@ (my-packages) my-coreutils))
@@ -364,7 +370,8 @@ (define file
         ((",acl\\)(.*)$" _ rest)
          (string-append ",acl) ;another one\n" rest)))
 
-      (system* "guix" "style" "-L" directory "my-coreutils")
+      (system* "guix" "style" "-L" directory "-S" "inputs"
+               "my-coreutils")
 
       (load file)
       (list (package-inputs (@ (my-packages) my-coreutils))
-- 
2.33.0