Awesome
TRIVIAL-FORMATTER 10.0.0
What is this?
Code formatter for common lisp. Please see trivial-formatter's source code. This file is formatted by trivial-formatter itself.
Alternatives.
cl-syntax for SLIME user.
Reader Syntax Coventions for Common Lisp and SLIME
trivial-indent for SLIME user.
A very simple library to allow indentation hints for SWANK.
cl-indentify
Library and command line utility to automatically indent Common Lisp source files.
Usage
(trivial-formatter:fmt :your-system :supersede)
For detail, see spec files.
Line width.
The default depends on implementation.
(Probably 80 though.)
You can control it with an ordinary common lisp pretty printing system way, i.e. using *PRINT-RIGHT-MARGIN*
.
(let ((*print-right-margin* 100)) ; <-- Specify line width with 100.
(trivial-formatter:fmt :your-system :supersede))
Strict mode.
When you invoke debugger, some implementations (e.g. ECL) are into :cl-user package.
In such cases, the LOOP
macro backtrace form becomes ugly.
(LOOP YOUR-PROJECT::FOR YOUR-PROJECT::I YOUR-PROJECT::UPFROM 0 ...)
Using keyword symbols as loop macro keywords avoid such ugly forms.
(LOOP :FOR YOUR-PROJECT::I :UPFROM 0 ...)
In strict mode, trivial-formatter formats loop macro keywords into keyword symbols.
To enable it binds *STRICT-LOOP-KEYWORD-P*
with T
.
* (let ((trivial-formatter:*strict-loop-keyword-p* t))
(trivial-formatter:fmt :your-system :supersede))
From developer
Reader.
If your source codes have special reader macros, trivial-foramtter signals an error about unknown reader macros. In such cases, you can extend the reader with an ordinary common lisp way because trivial-formatter heavily depends on readtable especially NAMED-READTABLES. To extend it, your reader macro functions must return an intermediate object.
(let ((*readtable* (named-readtables:copy-named-readtable 'as-code)))
(set-macro-character #\! (lambda (stream char) `(,char ,(read stream))))
(read-as-code))
!hoge
=> (#\! HOGE)
For details, see CLHS and NAMED-READTABLES.
Printer.
When you make intermediate objects, you need to make pretty print functions for it. Trivial-formatter heavily depends on a pretty-printing system so you can extend with an ordinary common lisp way.
(defun !-printer (stream exp)
(format stream "~<~A~S~:>" exp))
(set-pprint-dispatch '(cons (eql #\!) (cons * null)) '!-printer)
(print-as-code '(#\! hoge))
=> !hoge
For detail, see CLHS.
Load external formatters.
Trivial-formatter can load external formatters. You can write extension codes as external formatters.
External formatters file must be named "formatters.lisp".
Trivial-formatter searches file from *external-formatters-directories*
.
<del>The default is quicklisp's local-projects directory and roswell's local-projects directory.</del>
Since to share and/or to control versions of external formatters file by a version control system (e.g. git), external-formatter directories that are directly under local-projects directories of quicklisp and roswell were added as the default search paths. (e.g. ~/.roswell/local-projects/external-formatter/)
Hence external formatters file directly placed under local-projects directories of quicklisp or roswell is deprecated from version 10.
Package trivial-formatter-user.
In trivial-formatter-user, you can use deformatter, pprint-fun-call, and pprint-linear-elt with ordinary common lisp symbols.
PPRINT-FUN-CALL
PPRINT-FUN-CALL cares about key-value pairs.
(pprint-fun-call nil '(asdf:component-pathname component :direction :output :if-does-not-exist :create :if-exists if-exists))
(ASDF:COMPONENT-PATHNAME COMPONENT
:DIRECTION :OUTPUT
:IF-DOES-NOT-EXIST :CREATE
:IF-EXISTS IF-EXISTS))
NIL
PPRINT-LINEAR-ELT
PPRINT-LINEAR-ELT
set indent current and put every CDR
element with a newline.
(pprint-linear-elt nil '(asdf:component-pathname component :direction :output :if-does-not-exist :create :if-exists if-exists))
(ASDF:COMPONENT-PATHNAME COMPONENT
:DIRECTION
:OUTPUT
:IF-DOES-NOT-EXIST
:CREATE
:IF-EXISTS
IF-EXISTS))
NIL
DEFORMATTER
DEFORMATTER care about package existence and symbol confliction and set-pprint-dispatch.
(macroexpand '(deformatter package symbol (stream exp)
(format stream "~A" exp)))
(WHEN (FIND-PACKAGE "PACKAGE")
(DEFUN #:PPRINT-SYMBOL3440 (STREAM EXP) (FORMAT STREAM "~A" EXP))
(SET-PPRINT-DISPATCH
`(CONS (MEMBER ,(UIOP/PACKAGE:FIND-SYMBOL* "SYMBOL" "PACKAGE")))
'#:PPRINT-SYMBOL3440)
'#:PPRINT-SYMBOL3440)
TRIVIAL-FORMATTER-USER:SET-PPRINT-DISPATCH
When you want to set pretty-printing functions temporarily, you need to bind *PRINT-PPRINT-DISPATCH*
and use TRIVIAL-FORMATTER-USER:SET-PPRINT-DISPATCH
instead of CL:SET-PPRINT-DISPATCH
otherwise temporal function never worked.
CL:SET-PPRINT-DISPATCH
is shadowed in the package :TRIVIAL-FORMATTER-USER
.
(deformatter sxql where (stream exp)
(let ((*print-pprint-dispatch* (copy-pprint-dispatch)))
(set-pprint-dispatch '(cons (member :and :or)) 'pprint-linear-elt)
(pprint-fun-call stream exp)))
Product's goal
License
MIT
Developed with
SBCL
Tested with
-
SBCL/2.2.4
-
ECL/20.4.24
-
CMUCL/21D
-
CCL/1.12.1 ; Failed but pprit portability issue.
-
Allegro/10.1 ; Failed but pprit portability issue.
-
CLISP/2.49 ; Failed, not supported. For details see below.
-
ABCL/1.9.0 ; Failed, not supported. For details see below.
Note
Trivial-formatter works portable at least implementations above.
But it never means works samely.
For example, the IF
format is different.
SBCL prints a newline even if elements are short, but other implementations may not.
#+sbcl
(if a
b
c)
#+(or ecl ccl)
(if a b c)
Known issue.
CLISP
CLISP is not supported. CLISP say
The Lisp Pretty Printer implementation is not perfect yet.
ABCL
PPRINT-NEWLINE issue.
ABCL is not supported due to its issues. Related issues are this.
Reading behavior for double colon keyword symbol.
Trivial formatter formats double colon keyword symbol to single colon keyword symbol as canonicalization.
::aaaaa undefined
Many implementations canonicalize it, but abcl does not canonicalize.
#+(or sbcl ccl ecl clisp cmucl acl)
* ::double-coloned
:DOUBLE-COLONED
#+abcl
* ::double-coloned
:|:DOUBLE-COLONED|
If you depend on this behavior, trivial-formatter does not fit you.
Reader.
When the reader macro conflicts, such reader macros are ignored silently. You can add new reader macros, but can not modify already existing reader macros.
FORMAT-CONTROL
Trivial-formatter can not adjust ~newline format control indentation.
Installation
To install trivial-formatter, roswell is recommended.
$ ros install hyotang666/trivial-formatter
To load trivial-formatter to running lisp environment, evaluate below in the REPL.
* (ql:quickload :trivial-formatter)
<!-- Links -->