name | mode | size |
---|---|---|
COPYING.md | 100644 | 1 kb |
README.md | 100644 | 5 kb |
format-string-builder.asd | 100644 | 0 kb |
format-string-builder.lisp | 100644 | 9 kb |
package.lisp | 100644 | 0 kb |
A simple package implementing a DSL for generating format strings.
- [Introduction](#introduction)
- [Api Reference](#api-reference)
- [DSL Reference](#dsl-reference)
# Introduction
## Hello World
```lisp
CL-USER> (define-message hello (name)
"Hello " :str)
CL-USER> (hello "world")
Hello world
NIL
```
```lisp
(make-format-string '(:str)) #| ==> "~a" |#
(make-format-string '((:map () :str))) #| ==> "~{~a~}" |#
(define-message print-comma-separated (values)
(:map () :str))
```
# Api Reference
```lisp
(make-format-string spec) #| function |#
```
Takes a format string specification and turns it into a string.
```lisp
(format* stream spec &rest args) #| macro |#
```
Use like CL:FORMAT, except translate a format specification to a string at macroexpansion time.
```lisp
(define-message (stream-symbol &rest format-args) &body spec) #| macro |#
```
Defines a function that takes a stream and the arguments to be
formatted and then formats the arguments to the stream. The spec is
compiled to a string at macroexpansion time, so this should be
reasonably efficient.
TODO: document the API for defining directives.
# DSL Reference
A spec consists of operators and literals. Literals are either
strings, characters or integers and they are formatted as-is via
princ. There are two kinds of operators: simple operators and compound
ones. Simple operators correspond to format control directives and
represented in the spec by keywords such as `~A` or by lists
`(keyword . modifiers)` and they expand to the corresponding
directives. Compound operators correspond to format directives that
can contain other directives such as `~{~}`. In a spec, these are
formatted like flet function definitions:
```lisp
(keyword (&rest modifiers) &body spec)
```
Compound operators are further divided into sectioned operators and
non-sectioned ones. The difference is that, in non sectioned
operators, the body is treated just as a normal spec. In sectioned
ones, the body is treated as a list of items to be divided with `~;`.
See CLHS 22.3 for a full guide to the modifiers for the various format
directives.
## Simple Format Operations
- :str --- Translates to ~a, format a lisp value for humans
- :repr --- Translates to ~s, format a lisp value in a way that can be read by the reader (?)
- :float --- Translates to ~f, format a float.
- :dec --- Translates to ~d, format a number as a base 10 number.
- :decimal --- Translates to ~d, format a number as a base 10 number.
- :hex --- Translates to ~x, format a number as a base 16 number.
- :hexadecimal --- Translates to ~x, format a number as a base 16 number.
- :oct --- Translates to ~o, format a number as a base 8 number.
- :octal --- Translates to ~o, format a number as a base 8 number.
- :currency --- Translates to ~$, format a number in a manner suitable for currency
- :exit --- Translates to ~^, leaves a iteration construct
- :end-section --- Translates to ~;, divides sections of a construct (TODO: maybe this will go away?)
- :goto --- Translates to ~*, moves within the list of arguments
- :fresh-line --- Translates to ~&, ensures we're at the beginning of a line and, possibly adds Modifier-1 linebreaks
- :ensure-line --- Translates to ~7, alias for :fresh-line
- :new-line --- Adds a linebreak
## Compound Format Operations
### Iteration
- :map --- Translates to ~{~}, iterate over a list passed in
- :rest --- Translates to ~@{~}, iterate over the rest of the arguments
- :ap --- Translates to ~:{~}, apply a list to the corresponding enclosed format directives
- :apply --- Alias for :ap
- :aprest --- Translates to ~:@{~}, apply the rest of the arguments to the corresponding enclosed format directives
- :apply-rest --- Translates to ~:@{~}, apply the rest of the arguments to the corresponding enclosed format directives
### Conditional Output (Sectioned Operators)
- :y-or-n --- Translates to ~:[~], if the argument is nil, print first spec otherwise print second
- TODO: add others here...
### Case Control
- :lowercase --- Translates to ~(~), lowercase all alphabetic characters.
- :downcase --- Translates to ~(~), alias for :lowercase
- :uppercase --- Translates to ~:@(~), uppercase all alphabetic characters.
- :upcase --- Translates to ~:@(~), alias for :uppercase
- :titlecase --- Translates to ~:(~), titlecase all alphabetic characters.
- :capitalize --- Translates to ~:(~), alias for :titlecase
- :initialcap --- Translates to ~@(~), uppercase first character
### Justification
TODO: finish documenting this and switch them to sectioned operators.
- :spread --- Translates to ~<~>
- :ljust --- Translates to ~@<~>
- :left --- Translates to ~@<~>
- :rjust --- Translates to ~:<~>
- :right --- Translates to ~:<~>
- :cjust --- Translates to ~:@<~>
- :center --- Translates to ~:@<~>
### Miscellaneous
These are not part of Format, but are defined just to be helpful
- :own-line --- Translates to ~&~%, ensure that the included text is on its own line, without unnecessary gaps.