read-print: Read and render vertical space.
* guix/read-print.scm (<vertical-space>, vertical-space?) (vertical-space, vertical-space-height): New variables. (combine-vertical-space, canonicalize-vertical-space) (read-vertical-space): New procedures. (read-with-comments): Use it in the #\newline case. (pretty-print-with-comments): Add #:format-vertical-space and honor it. Add case for 'vertical-space?'. * guix/scripts/style.scm (format-package-definition): Pass #:format-vertical-space to 'object->string*'. * tests/read-print.scm ("read-with-comments: list with blank line") ("read-with-comments: list with multiple blank lines") ("read-with-comments: top-level blank lines") ("pretty-print-with-comments, canonicalize-vertical-space"): New tests. Add a couple of additional round-trip tests.
This commit is contained in:
parent
3eb3901d7f
commit
f687e27e03
@ -30,6 +30,11 @@
|
||||
|
||||
blank?
|
||||
|
||||
vertical-space
|
||||
vertical-space?
|
||||
vertical-space-height
|
||||
canonicalize-vertical-space
|
||||
|
||||
comment
|
||||
comment?
|
||||
comment->string
|
||||
@ -58,6 +63,26 @@
|
||||
|
||||
(define blank? (record-predicate <blank>))
|
||||
|
||||
(define <vertical-space>
|
||||
(make-record-type '<vertical-space> '(height)
|
||||
#:parent <blank>
|
||||
#:extensible? #f))
|
||||
|
||||
(define vertical-space? (record-predicate <vertical-space>))
|
||||
(define vertical-space (record-type-constructor <vertical-space>))
|
||||
(define vertical-space-height (record-accessor <vertical-space> 'height))
|
||||
|
||||
(define (combine-vertical-space x y)
|
||||
"Return vertical space as high as the combination of X and Y."
|
||||
(vertical-space (+ (vertical-space-height x)
|
||||
(vertical-space-height y))))
|
||||
|
||||
(define canonicalize-vertical-space
|
||||
(let ((unit (vertical-space 1)))
|
||||
(lambda (space)
|
||||
"Return a vertical space corresponding to a single blank line."
|
||||
unit)))
|
||||
|
||||
(define <comment>
|
||||
;; Comments.
|
||||
(make-record-type '<comment> '(str margin?)
|
||||
@ -80,6 +105,19 @@ end with newline, otherwise an error is raised."
|
||||
(&message (message "invalid comment string")))))
|
||||
(string->comment str margin?))
|
||||
|
||||
(define (read-vertical-space port)
|
||||
"Read from PORT until a non-vertical-space character is met, and return a
|
||||
single <vertical-space> record."
|
||||
(define (space? chr)
|
||||
(char-set-contains? char-set:whitespace chr))
|
||||
|
||||
(let loop ((height 1))
|
||||
(match (read-char port)
|
||||
(#\newline (loop (+ 1 height)))
|
||||
((? eof-object?) (vertical-space height))
|
||||
((? space?) (loop height))
|
||||
(chr (unread-char chr port) (vertical-space height)))))
|
||||
|
||||
(define (read-with-comments port)
|
||||
"Like 'read', but include <blank> objects when they're encountered."
|
||||
;; Note: Instead of implementing this functionality in 'read' proper, which
|
||||
@ -107,7 +145,9 @@ end with newline, otherwise an error is raised."
|
||||
eof) ;oops!
|
||||
(chr
|
||||
(cond ((eqv? chr #\newline)
|
||||
(loop #t return))
|
||||
(if blank-line?
|
||||
(read-vertical-space port)
|
||||
(loop #t return)))
|
||||
((char-set-contains? char-set:whitespace chr)
|
||||
(loop blank-line? return))
|
||||
((memv chr '(#\( #\[))
|
||||
@ -297,6 +337,7 @@ semicolons."
|
||||
(define* (pretty-print-with-comments port obj
|
||||
#:key
|
||||
(format-comment identity)
|
||||
(format-vertical-space identity)
|
||||
(indent 0)
|
||||
(max-width 78)
|
||||
(long-list 5))
|
||||
@ -306,7 +347,8 @@ included in the output.
|
||||
|
||||
Lists longer than LONG-LIST are written as one element per line. Comments are
|
||||
passed through FORMAT-COMMENT before being emitted; a useful value for
|
||||
FORMAT-COMMENT is 'canonicalize-comment'."
|
||||
FORMAT-COMMENT is 'canonicalize-comment'. Vertical space is passed through
|
||||
FORMAT-VERTICAL-SPACE; a useful value of 'canonicalize-vertical-space'."
|
||||
(define (list-of-lists? head tail)
|
||||
;; Return true if HEAD and TAIL denote a list of lists--e.g., a list of
|
||||
;; 'let' bindings.
|
||||
@ -394,6 +436,14 @@ FORMAT-COMMENT is 'canonicalize-comment'."
|
||||
port)))
|
||||
(display (make-string indent #\space) port)
|
||||
indent)
|
||||
((? vertical-space? space)
|
||||
(unless delimited? (newline port))
|
||||
(let loop ((i (vertical-space-height (format-vertical-space space))))
|
||||
(unless (zero? i)
|
||||
(newline port)
|
||||
(loop (- i 1))))
|
||||
(display (make-string indent #\space) port)
|
||||
indent)
|
||||
(('quote lst)
|
||||
(unless delimited? (display " " port))
|
||||
(display "'" port)
|
||||
|
@ -316,7 +316,8 @@ PACKAGE."
|
||||
(object->string* exp
|
||||
(location-column
|
||||
(package-definition-location package))
|
||||
#:format-comment canonicalize-comment)))))
|
||||
#:format-comment canonicalize-comment
|
||||
#:format-vertical-space canonicalize-vertical-space)))))
|
||||
|
||||
(define (package-location<? p1 p2)
|
||||
"Return true if P1's location is \"before\" P2's."
|
||||
|
@ -19,7 +19,8 @@
|
||||
(define-module (tests-style)
|
||||
#:use-module (guix read-print)
|
||||
#:use-module (guix gexp) ;for the reader extensions
|
||||
#:use-module (srfi srfi-64))
|
||||
#:use-module (srfi srfi-64)
|
||||
#:use-module (ice-9 match))
|
||||
|
||||
(define-syntax-rule (test-pretty-print str args ...)
|
||||
"Test equality after a round-trip where STR is passed to
|
||||
@ -40,6 +41,35 @@
|
||||
(call-with-input-string "(a . b)"
|
||||
read-with-comments))
|
||||
|
||||
(test-equal "read-with-comments: list with blank line"
|
||||
`(list with ,(vertical-space 1) blank line)
|
||||
(call-with-input-string "\
|
||||
(list with
|
||||
|
||||
blank line)\n"
|
||||
read-with-comments))
|
||||
|
||||
(test-equal "read-with-comments: list with multiple blank lines"
|
||||
`(list with ,(comment ";multiple\n" #t)
|
||||
,(vertical-space 3) blank lines)
|
||||
(call-with-input-string "\
|
||||
(list with ;multiple
|
||||
|
||||
|
||||
|
||||
blank lines)\n"
|
||||
read-with-comments))
|
||||
|
||||
(test-equal "read-with-comments: top-level blank lines"
|
||||
(list (vertical-space 2) '(a b c) (vertical-space 2))
|
||||
(call-with-input-string "
|
||||
|
||||
(a b c)\n\n"
|
||||
(lambda (port)
|
||||
(list (read-with-comments port)
|
||||
(read-with-comments port)
|
||||
(read-with-comments port)))))
|
||||
|
||||
(test-pretty-print "(list 1 2 3 4)")
|
||||
(test-pretty-print "((a . 1) (b . 2))")
|
||||
(test-pretty-print "(a b c . boom)")
|
||||
@ -181,6 +211,24 @@ mnopqrstuvwxyz.\")"
|
||||
`(cons \"--without-any-problem\"
|
||||
,flags)))")
|
||||
|
||||
(test-pretty-print "\
|
||||
(vertical-space one:
|
||||
|
||||
two:
|
||||
|
||||
|
||||
three:
|
||||
|
||||
|
||||
|
||||
end)")
|
||||
|
||||
(test-pretty-print "\
|
||||
(vertical-space one
|
||||
|
||||
;; Comment after blank line.
|
||||
two)")
|
||||
|
||||
(test-equal "pretty-print-with-comments, canonicalize-comment"
|
||||
"\
|
||||
(list abc
|
||||
@ -206,4 +254,30 @@ mnopqrstuvwxyz.\")"
|
||||
#:format-comment
|
||||
canonicalize-comment)))))
|
||||
|
||||
(test-equal "pretty-print-with-comments, canonicalize-vertical-space"
|
||||
"\
|
||||
(list abc
|
||||
|
||||
def
|
||||
|
||||
;; last one
|
||||
ghi)"
|
||||
(let ((sexp (call-with-input-string
|
||||
"\
|
||||
(list abc
|
||||
|
||||
|
||||
|
||||
def
|
||||
|
||||
|
||||
;; last one
|
||||
ghi)"
|
||||
read-with-comments)))
|
||||
(call-with-output-string
|
||||
(lambda (port)
|
||||
(pretty-print-with-comments port sexp
|
||||
#:format-vertical-space
|
||||
canonicalize-vertical-space)))))
|
||||
|
||||
(test-end)
|
||||
|
Loading…
Reference in New Issue
Block a user