OPEN GENEVA USER MANUAL
Interstellar Ventures
Saturday, 19 September 2015
Table of Contents
1 Geneva: The Document API
2 Geneva-mk2: Reading and Writing Mk2 Files
3 Rendering Geneva Documents
3.1 Common Rendering Interface
4 Geneva-cl: Compiling Geneva Documents from Common Lisp On-Line
Documentation
Open Geneva is an implementation of the Geneva document preparation
system written in Common Lisp. This user manual describes the
components of Open Geneva from a high level perspective and explains
their operation by example. For a complete API documentation see the
Open Geneva API.¹
Open Geneva is divided into several subsystems, each implementing a
different functionality of the system. For convenience, a “master
system” is provided, which depends on every subsystem of Open Geneva.
If you want to load and/or compile Open Geneva as a whole, then you
may use the open-geneva system. The various subsystems are described
in the sections below.
* 1. Open Geneva API (open-geneva-api.html)
1 Geneva: The Document API
At the core of Open Geneva are a set of constructors and readers used
to programatically create and inspect Geneva documents. These
functions are in the geneva package. These constructors verify the
integrity of their arguments and their return values are normalized as
defined in the Geneva Document Specification.¹
There are three different kinds of constructors: The document
constructor make-document, document element constructors
(make-pargraph for instance) and text token constructors (make-bold
etc.).
(defun make-birthday-invitation (date guest-name)
(make-document
(list
(make-section
'("Birthday Invitation")
(list
(make-paragraph
`(,(make-bold (format nil "Hi ~a!" guest-name))))
(make-paragraph
`(,(format nil "You are invited to my birthday party on ~a. "
date)
,(make-italic "Bring your friends!"))))))))
(make-birthday-invitation "Friday" "John") → document
Example: Dynamically creating a document.
The readers content-type and content-values work on document elements
as well as on text tokens and can be used to inspect the contents of a
document. Content-type returns the type of its argument and
content-values returns the components of it argument a seperate
values.
(content-type (make-bold "foo")) → :BOLD
(content-type "bar") → :PLAIN ; Strings have a CONTENT-TYPE.
(content-values (make-section
Examples: Inspecting document contents.
A document is just a list of document elements. It can be traversed by
the standard list manipulation functions.
;; Return list of element types used in document.
(defun document-features (document)
(remove-duplicates
(loop for element in document
for type = (content-type element)
if (eq type :section)
then append (multiple-value-bind (title body)
(content-values element)
`(:section ,@(document-features body)))
else collect (content-type element))))
(document-features (make-document
(make-paragraph '("foo"))
(make-paragraph '("bar")))
→ (:PARAGRAPH)
Example: Traversing a document.
A document can be printed readably by the Common Lisp printer. The
easiest way to (de)serialize a document is to use read and print.
(let ((document (make-document ...)))
(equal document
(read-from-string
(prin1-to-string document))))
→ T
Example: (De)serializing a document.
The geneva.macros package provides macro counterparts of the element
constructors and a readtable² geneva.macros:syntax which can come in
handy when dynamically creating documents. Below is the “birthday
invitation” example from above revisited using geneva.macros.
(in-readtable geneva.macros:syntax)
(defun make-birthday-invitation (date guest-name)
(document
(section ("Birthday invitation")
(paragraph (make-bold (format nil "Hi ~a!" guest-name)))
(paragraph
(format nil "You are invited to my birthday party on ~a. "
date)
;; Note the reader macro below.
#i"Bring your friends!"))))
Example: Dynamically creating documents using geneva.macros.
* 1. Geneva Document Specification (geneva-document.html)
* 2. See Named-Readtables (editor-hints.named-readtables)
2 Geneva-mk2: Reading and Writing Mk2 Files
Mk2¹ is a human readable serialization format for Geneva documents.
Open Geneva implements the Mk2 markup language in the geneva.mk2
package. Geneva documents can be read from and printed as Mk2 using
read-mk2 and print-mk2.
Note that an Mk2 file is a precise representation of a Geneva
document. The following holds true:
(let ((document (make-document ...)))
(equal document
(read-mk2 (with-output-to-string (out)
(print-mk2 document out)))))
→ T
* 1. The Mk2 Markup Language (mk2.html)
3 Rendering Geneva Documents
Open Geneva supports rendering Geneva documents as plain text, HTML
and LaTeX. The implementing functions can be loaded as the
geneva-plaintext, geneva-html and geneva-latex systems respectively.
3.1 Common Rendering Interface
The various rendering systems share a common subset of their
interface.
— Function: render-plain-text | render-html | render-latex document
&key stream title author date index-p index-caption index-headers-p
&allow-other-keys
Arguments and Values:
document—a Geneva document.
stream—a character stream. The default is standard output.
title—a string.
author—a string.
date—a string.
index-p—a generalized boolean. The default is true.
index-caption—a string. The default is "Table of Contents".
index-headers-p—a generalized boolean. The default is true.
Description:
Renders document to stream. The document rendering can optionally be
prepended by a title section and a section index. Title, author and
date are used in the title section. Index-caption can be supplied to
customize the heading of the section index. If index-p is false the
section index will be omitted. Section headers will be enumerated
unless index-headers-p is false.
Exceptional Situations:
If document is not a valid Geneva document an error of type type-error
is signaled.
4 Geneva-cl: Compiling Geneva Documents from Common Lisp On-Line
Documentation
The geneva.common-lisp package provides a function api-document which
can be used to compile Geneva documents from Common Lisp on-line
documentation. Its usage is quite simple and can be explained by
example:
(defpackage foo
(:documentation "Foo is a demo package.")
(:use :cl)
(:export :bar))
(defun foo:bar (x) "{bar} is a _NO-OP_." x)
(api-document :foo)
→ ((:SECTION ("foo")
((:PARAGRAPH ("Foo is a demo package."))
(:SECTION ("bar")
((:PARAGRAPH ("— Function: " (:BOLD "bar") " " (:ITALIC "x")))
(:PARAGRAPH ((:FIXED-WIDTH "bar") " is a "
(:ITALIC "NO-OP") ".")))))))
Creating an API document from a package.
Note that documentation strings are parsed as Mk2 files using
read-mk2.