style: Add support for "newline forms".

This allows us to express cases where a newline should be inserted
immediately after the head symbol of a list.

* guix/scripts/style.scm (%newline-forms): New variable.
(newline-form?): New procedure.
(pretty-print-with-comments): Handle "newline forms".
* tests/style.scm: Add test.
This commit is contained in:
Ludovic Courtès 2022-01-03 11:04:40 +01:00
parent 208a7aa17b
commit 6f892630ae
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
2 changed files with 50 additions and 6 deletions

View file

@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2021-2022 Ludovic Courtès <ludo@gnu.org>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -163,6 +163,19 @@ (define %special-forms
('with-output-to-file 2) ('with-output-to-file 2)
('with-input-from-file 2))) ('with-input-from-file 2)))
(define %newline-forms
;; List heads that must be followed by a newline. The second argument is
;; the context in which they must appear. This is similar to a special form
;; of 1, except that indent is 1 instead of 2 columns.
(vhashq
('arguments '(package))
('sha256 '(origin source package))
('base32 '(sha256 origin))
('git-reference '(uri origin source))
('search-paths '(package))
('native-search-paths '(package))
('search-path-specification '())))
(define (prefix? candidate lst) (define (prefix? candidate lst)
"Return true if CANDIDATE is a prefix of LST." "Return true if CANDIDATE is a prefix of LST."
(let loop ((candidate candidate) (let loop ((candidate candidate)
@ -188,6 +201,14 @@ (define (special-form-lead symbol context)
(and (prefix? prefix context) (- level 1)))) (and (prefix? prefix context) (- level 1))))
alist)))) alist))))
(define (newline-form? symbol context)
"Return true if parenthesized expressions starting with SYMBOL must be
followed by a newline."
(match (vhash-assq symbol %newline-forms)
(#f #f)
((_ . prefix)
(prefix? prefix context))))
(define (escaped-string str) (define (escaped-string str)
"Return STR with backslashes and double quotes escaped. Everything else, in "Return STR with backslashes and double quotes escaped. Everything else, in
particular newlines, is left as is." particular newlines, is left as is."
@ -377,6 +398,7 @@ (define new-column
(column (if overflow? (column (if overflow?
(+ indent 1) (+ indent 1)
(+ column (if delimited? 1 2)))) (+ column (if delimited? 1 2))))
(newline? (newline-form? head context))
(context (cons head context))) (context (cons head context)))
(if overflow? (if overflow?
(begin (begin
@ -384,17 +406,26 @@ (define new-column
(display (make-string indent #\space) port)) (display (make-string indent #\space) port))
(unless delimited? (display " " port))) (unless delimited? (display " " port)))
(display "(" port) (display "(" port)
(let* ((new-column (loop column column #t context head)) (let* ((new-column (loop column column #t context head))
(indent (if (or (>= new-column max-width) (indent (if (or (>= new-column max-width)
(not (symbol? head)) (not (symbol? head))
(sequence-would-protrude? (sequence-would-protrude?
(+ new-column 1) tail)) (+ new-column 1) tail)
newline?)
column column
(+ new-column 1)))) (+ new-column 1))))
(define column (when newline?
(print-sequence context indent new-column tail #f)) ;; Insert a newline right after HEAD.
(display ")" port) (newline port)
(+ column 1)))) (display (make-string indent #\space) port))
(let ((column
(print-sequence context indent
(if newline? indent new-column)
tail newline?)))
(display ")" port)
(+ column 1)))))
(_ (_
(let* ((str (if (string? obj) (let* ((str (if (string? obj)
(escaped-string obj) (escaped-string obj)

View file

@ -465,6 +465,19 @@ (define file
;; Regular indentation for 'replace' here. ;; Regular indentation for 'replace' here.
(replace \"gmp\" gmp))") (replace \"gmp\" gmp))")
(test-pretty-print "\
(package
;; Here 'sha256', 'base32', and 'arguments' must be
;; immediately followed by a newline.
(source (origin
(method url-fetch)
(sha256
(base32
\"not a real base32 string\"))))
(arguments
'(#:phases %standard-phases
#:tests? #f)))")
(test-end) (test-end)
;; Local Variables: ;; Local Variables: