let's evolve

main
Matthew Butterick 5 years ago
parent 19dc16b704
commit 5f7d05010a

@ -15,10 +15,11 @@ pollen/scribblings/mb-tools quad/pict)
quadwriter/markdown
quadwriter/markup)]
@(define-runtime-path quads.png "quads.png")
@(image quads.png #:scale 0.4)
@margin-note{Quad is a work in progress. It works, but it is unstable in the sense that I make no commitment to maintain the API in its current state.}
@section{Installing Quad}
@ -28,88 +29,26 @@ At the command line:
After that, you can update the package like so:
@verbatim{raco pkg update quad}
@margin-note{Quad is not stable, usable software. It is currently in documented-demo mode. Fiddle with it at your own risk. I make no commitment to maintain the API in its current state.}
@section{What is Quad?}
A document processor that outputs to PDF.
@section{What is Quadwriter?}
A demo language built on Quad that takes a text-based source file as input, calculates the typesetting and layout, and then outputs a PDF.
@section{What can I do with this demo?}
You can fiddle with it & then submit issues and feature requests at the @link["http://github.com/mbutterick/quad"]{Quad repo}. After a few dead ends, I think I'm headed in the right direction. But I also want to open it to comments & criticism, because that can bend the thinking in productive ways.
Also, I have about a hundred topics to add to the documentation. So I don't mind requests along the lines of ``can you document such-and-such'' — it's probably already on my list and I don't mind moving it to the front in response to human interest. At this point in its development, I find it easier to have a working version of the project and iterate, rather than leave it in some partially busted state for weeks on end.
@section{What are your plans for Quad?}
Some things I personally plan to use Quad for:
@itemlist[#:style 'ordered
@item{@bold{A simple word processor}. Quadwriter is the demo of this.}
@item{@bold{Font sample documents}. In my work as a @link["https://mbtype.com"]{type designer}, I have to put together PDFs of fonts. To date, I have done them by hand, but I would like to just write programs to generate them.}
@item{@bold{Racket documentation}. The PDFs of Racket documentation are currently generated by LaTeX. I would like to make Quad good enough to handle them.}
@item{@bold{Book publishing}. My wife is a lawyer and wants to publish a book about a certain area of the law that involves a zillion fiddly charts. If I had to do it by hand, it would take months. But with a Quad program, it could be easy.}
]
@section{What's a document processor?}
A @deftech{document processor} is a rule-driven typesetter. It takes a text-based source file as input and converts it into a page layout.
A document processor, which means that it a) computes the layout of your document from a series of formatting codes (not unlike a web browser) and then b) outputs to PDF (not unlike a word processor).
For instance, LaTeX is a document processor. So are web browsers. Quad borrows from both traditions — it's an attempt to modernize the good ideas in LaTeX, and generalize the good ideas in web browsers.
Document processors sit opposite WYSIWYG tools like Word and InDesign. There, the user controls the layout by manipulating a representation of the page on the screen. This is fine as far as it goes. But changes to the layout — for instance, a new page size — often require a new round of manual adjustments.
Document processors sit opposite WYSIWYG tools like Microsoft Word and Adobe InDesign. There, the user controls the layout by manipulating a representation of the page on the screen. This is fine as far as it goes. But changes to the layout — for instance, a new page size — often require a new round of manual adjustments.
A document processor, by contrast, relies on markup codes within the text to determine the layout programmatically. Compared to WYSIWYG, this approach offers less granular control. But it also creates a more flexible relationship between the source and its possible layouts.
Another benefit of document processors is that it permits every document to have a high-level, text-based source file that's independent of any particular output format (rather than the opaque binary formats endemic to Word, InDesign, et al.)
@subsection{Why not just use LaTeX?}
I wouldn't want to criticize software merely for being old. It's a great compliment to LaTeX that it's endured this long. But —
@itemlist[#:style 'ordered
@item{It's never made much headway beyond its original audience of scientific & technical writers.}
@item{The last 25 years of advances in digital typesetting have been implemented as a huge (occasionally tenuous) tower of patches.}
@item{The source code is increasingly opaque to today's programmers. Meaning, if LaTeX were plausibly rewritable, it would've been rewritten by now.}
]
Instead, let's take its good ideas — there are a few — and terraform a new planet.
@margin-note{Quad has no ambition to supplant LaTeX. I am not an academic writer. Those typesetting problems are not my problems. So I am not proposing to solve them. Best of luck, though.}
@subsection{Why not use more HTML/CSS?}
In principle, it's possible to generate PDF documents from a web browser. Support for paper-based layouts has been part of the CSS concept @link["https://www.w3.org/People/howcome/p/cascade.html"]{since the beginning} (though it's been lightly used).
But web browsers have some limitations:
@itemlist[#:style 'ordered
Another benefit of document processors is that it permits every document to have a high-level, text-based source file that's independent of any particular output format. Though today, Quad relies on its own PDF-rendering engine, there's no reason it couldn't render to other targets.
@item{Web browsers only render HTML, and many typesetting concepts (e.g., footnotes) don't correspond to any HTML entity. So there is a narrowing of possiblities.}
@item{Browsers are built for speed, so high-quality typesetting is off the table.}
@subsection{Why is it called Quad?}
@item{Browsers render pages inconsistently.}
In letterpress printing, a @italic{quad} was a piece of metal used as spacing material within a line.
@item{Taking off my typography-snob tiara here — browsers are unstable. What seems well supported today can be broken or removed tomorrow. So browsers can't be a part of a dependable publishing workflow that yields reproducible results.}
]
@section{What does Quad do?}
@subsection{How does Quad work?}
Quad produces PDFs using three ingredients:
@ -125,9 +64,10 @@ While there's no reason Quad couldn't produce an HTML layout, that's an easier p
Much of the font-parsing and PDF-rendering code in Quad is adapted from @link["http://github.com/foliojs/"]{FolioJS} by Devon Govett. I thank Mr. Govett for figuring out a lot of details that would've made me squeal in agony.
For the most part, neither Quad nor Quadwriter rely much on @racketmodname[racket/draw], and completely avoid its PDF-drawing functions. These facilities are provided by Pango, which has some major deficiencies in the kind of PDFs it produces (for instance, it doesn't support hyperlinks). In fact, most of the good ideas in Quad, I figured out a while ago. But then I had to embark on a multi-year yak-shave to be able to get sufficient control of PDFs.
For the most part, neither Quad nor Quadwriter rely much on @racketmodname[racket/draw], and completely avoid its PDF-drawing functions. These facilities are provided by Pango, which has some major deficiencies in the kind of PDFs it produces (for instance, it doesn't support hyperlinks).
@section{What doesn't Quad do?}
@subsection{What doesn't Quad do?}
@itemlist[#:style 'ordered
@item{Quad is not a WYSIWYG or interactive previewing tool.}
@ -138,37 +78,22 @@ For the most part, neither Quad nor Quadwriter rely much on @racketmodname[racke
]
Rather, it's designed to cooperate with tools that offer these facilities. For instance, Quadwriter is a demonstration language that provides an interface to a small set of word-processor-like features that are implemented with Quad.
@section{Theory of operation}
A document processor starts with input that we can think of as one giant line of text. It breaks this into smaller lines, and then distributes these lines across pages. Various complexities surface along the way. But that's the basic idea.
More specifically:
@itemlist[#:style 'ordered
@item{Quad starts with a source file. In this demo, we can will use the @code{#lang quadwriter} language. For the most part, it's text with markup codes (though it may also include things like diagrams and images).}
@item{Each markup entity is called a @deftech{quad}. A quad roughly corresponds to a box. ``Roughly'' because quads can have zero or negative dimension. Also, at the input stage, the contents of some quads may end up being spread across multiple non-overlapping boxes (e.g., a quad containing a word might be hyphenated to appear on two lines). The more precise description of a quad is therefore ``contiguous formatting region''. Quads can be recursively nested inside other quads, thus the input file is tree-shaped.}
@item{This tree-shaped input file is flattened into a list of @deftech{atomic} quads. ``Atomic'' in the sense that these are the smallest items the typesetter can manipulate. (For instance, the word @italic{bar} would become three one-character quads. An image or other indivisible box would remain as is.) During the flattening, tags from higher in the tree are propagated downward by copying them into the atomic quads. The result is that all the information needed to typeset an atomic quad is contained within the quad itself.
@margin-note{The input is flattened because typesetting operations are easier to reason about as a linear sequence of instructions (i.e., an imperative model). To see why, consider how you'd handle a page break within a tree model. No matter how deep you were in your typesetting tree, you'd have to jump back to the top level to handle your page break (because it affects the positioning of all subsequent items). Then you'd have to jump back to where you were, deep in the tree. That's unnatural.}}
@item{Atomic quads are composed into lines using one of two algorithms. (Each line is just another quad, of a certain width, that contains these atomic quads.) The first-fit algorithm puts as many quads onto a line as it can before moving on to the next. The best-fit algorithm minimizes the total looseness of all the lines in a paragraph (also known as the @link["http://defoe.sourceforge.net/folio/knuth-plass.html"]{KnuthPlass linebreaking algorithm} developed for TeX). Best fit is slower, of course.}
@section{What is Quadwriter?}
@item{Once the lines are broken, extra space is distributed within each line according to whether the line should appear centered, left-aligned, justified, etc. The result is a list of quads that fills the full column width.}
A demo app built with Quad. It takes a text-based source file as input, calculates the typesetting and layout, and then outputs a PDF.
@item{Lines are composed into pages.}
@item{Before the typeset markup is passed to the renderer, it goes through a simplification phase — a lot of adjacent quads will have the same formatting characteristics, and these can be consolidated into runs of text.}
@subsection{What can I do with this demo?}
@item{The renderer walks through the markup and positions and draws each quad, using information in the markup attributes to determine position, color, font, size, style, etc.}
You can fiddle with it & then submit issues and feature requests at the @link["http://github.com/mbutterick/quad"]{Quad repo}. After a few dead ends, I think I'm headed in the right direction. But I also want to open it to comments & criticism, because that can bend the thinking in productive ways.
]
Also, I have about a hundred topics to add to the documentation. So I don't mind requests along the lines of ``can you document such-and-such'' — it's probably already on my list and I don't mind moving it to the front in response to human interest. At this point in its development, I find it easier to have a working version of the project and iterate, rather than leave it in some partially busted state for weeks on end.
@section{Enough talk — let's rock}
@section{Quadwriter tutorial}
Open DrRacket (or the editor you prefer) and start a new document with @code{#lang quadwriter} as the first line:
Open DrRacket (or the editor you prefer) and start a new document with @code{#lang quadwriter/markup} as the first line:
@fileblock["test.rkt"
@ -214,7 +139,7 @@ A Q-expression is an @seclink["X-expressions" #:doc '(lib "pollen/scribblings/po
In the demos that follow, the input language will change slightly. But the PDF will be rendered the same way (by running the source file) and you can always look at @racket[doc].
@subsection{Soft rock: Quadwriter & Markdown}
@subsection{Quadwriter & Markdown}
I @link["https://docs.racket-lang.org/pollen/second-tutorial.html#%28part._the-case-against-markdown%29"]{don't recommend} that writers adopt Markdown for serious projects. But for goofing around, why not.
@ -249,7 +174,7 @@ And they love to code
You are welcome to paste in bigger Markdown files that you have laying around and see what happens. As a demo language, I'm sure there are tortured agglomerations of Markdown notation that will confuse to @racket[quadwriter/markdown]. But with vanilla files, even big ones, it should be fine.
A question naturally arises: would it be possible to convert any Markdown file, no matter how sadistic, to PDF? As a practical matter, I'm sure such things exist already. I have no interest in being in the Markdown-conversion business. As a theoretical matter: the problem I foresee is that Markdown — like the HTML that it lightly disguises — can have formatting entities that are nested indefinitely deep. The idea of making a layout engine that can handle that just becomes the equivalent of reinventing a web-browser engine.
@margin-note{Would it be possible to convert any Markdown file, no matter how sadistic, to PDF? As a practical matter, I'm sure such things exist already. I have no interest in being in the Markdown-conversion business.}
Back to the demo. Curious characters can do this:
@ -281,15 +206,8 @@ To see this:
This is part of the @tech{Q-expression} that the source file produces. This Q-expression is passed to Quadwriter for layout and rendering.
If you know about the duality of X-expressions and XML, you might wonder if we could create an equivalent text-based markup language for Q-expressions — let's call it QML. Sure, why not:
@repl-output{
<q line-height="17"><q break="paragraph"></q><q font-family="fira-sans-light" first-line-indent="0" display="block" font-size="20" line-height="24.0" border-width-top="0.5" border-inset-top="9" inset-bottom="-3" inset-top="6" keep-with-next="true" id="did-you-know">Did you know?</q> ···
}
There's nothing interesting about QML — it's just a way of cosmetically encoding a Q-expression as a string. We could also convert our Q-expression to, say, JSON. Thus, having noted that QML can exist, and @racket[quadwriter] could support this input, let's move on.
@subsection{Hard rock: Quadwriter & markup}
@subsection{Quadwriter & markup}
Suppose Markdown is just not your thing. You prefer to enter your markup the old-fashioned way — by hand. I hear you. So let's switch to the @racket[quadwriter/markup] dialect. First we try our simple test:
@ -336,7 +254,7 @@ Curious characters can prove that this is so by again typing at the REPL:
This Q-expression is exactly the same as the one that resulted with the @racket[quadwriter/markdown] source file.
@subsection{Heavy metal: Quadwriter & Q-expressions}
@subsection{Quadwriter & Q-expressions}
@racket[quadwriter/markdown] showed high-level notation (= a generous way of describing Markdown) that generated a Q-expression. Then @racket[quadwriter/markup] showed a mid-level notation that generated another (identical) Q-expression.
@ -449,44 +367,8 @@ And again, use this Q-expression as the source for a new @racket[quadwriter] pro
Which yields the same PDF result. (If you've spent any time with 90s HTML markup, the above probably looks familiar.)
@subsection{Q-expression PS}
In @code{#lang quadwriter}, we enter our Q-expression in the usual Racket list notation. What if we wanted to use the text-based notation of @racket[quadwriter/markup]? Sure — we can convert our Q-expression to that notation, and invoke the @racket[quadwriter/markup] dialect:
@fileblock["test.rkt"
@codeblock|{
#lang quadwriter/markup
◊q[#:line-height "17"]{◊q[#:break "paragraph"]
◊q[#:font-family "fira-sans-light" #:first-line-indent "0"
#:display "block" #:font-size "20" #:line-height "24.0"
#:border-width-top "0.5" #:border-inset-top "9"
#:inset-bottom "-3" #:inset-top "6" #:keep-with-next "true"
#:id "did-you-know"]{Did you know?}◊q[#:break "paragraph"]
◊q[#:keep-first "2" #:keep-last "3" #:line-align "left"
#:font-size-adjust "100%" #:character-tracking "0"
#:hyphenate "true" #:display "g146739"]{
◊q[#:font-bold "true" #:font-size-adjust "100%"]{Brennan} and
◊q[#:font-bold "true" #:font-size-adjust "100%"]{Dale} like:}
◊q[#:break "paragraph"]◊q[#:inset-left "30.0"]{
◊q[#:list-index "•"]{◊q[#:font-italic "true"
#:font-size-adjust "100%"]{Fancy} sauce}
◊q[#:break "paragraph"]◊q[#:list-index "•"]{
◊q[#:font-italic "true" #:font-size-adjust "100%"]{Chicken}
fingers}}◊q[#:break "paragraph"]
◊q[#:display "block" #:background-color "aliceblue"
#:first-line-indent "0" #:font-family "fira-mono"
#:font-size "11" #:line-height "14" #:border-inset-top "10"
#:border-width-left "2" #:border-color-left "#669"
#:border-inset-left "0" #:border-inset-bottom "-4"
#:inset-left "12" #:inset-top "12"
#:inset-bottom "8"]{◊q[#:font-family "fira-mono"
#:font-size "10" #:bg "aliceblue"]{And they love to
code}}
◊q[#:break "paragraph"]}
}|
]
Don't panic — you'll never have to actually do this in @racket[quadwriter]. It's just to show that it's possible.
@subsection{Quadwriter as a library}
@subsection{Quadwriter: the upshot}
@ -517,12 +399,12 @@ Part of the idea of @racket[quad] is to make typographic layout & PDF generation
@section{Why is it called Quad?}
@section{Quadwriter markup reference}
In letterpress printing, a @italic{quad} was a piece of metal used as spacing material within a line.
@section{Quad life}
@section{Quad: the details}
As mentioned above, The @racket[quad] library itself knows as little as it can about typography and fonts and pictures. Nor does it even assert a document model like Scribble. Rather, it offers a generic geometric represntation of layout elements. In turn, these elements can be combined into more useful pieces (e.g., @racket[quadwriter]).
@ -579,9 +461,27 @@ Once the quads have been positioned, they are passed to the renderer, which recu
Though every quad has a size field, this is just the size used during layout and positioning. Quad doesn't know (or care) about whether the drawing stays within those bounds.
@section{What are your plans for Quad?}
Some things I personally plan to use Quad for:
@itemlist[#:style 'ordered
@item{@bold{A simple word processor}. Quadwriter is the demo of this.}
@item{@bold{Font sample documents}. In my work as a @link["https://mbtype.com"]{type designer}, I have to put together PDFs of fonts. To date, I have done them by hand, but I would like to just write programs to generate them.}
@item{@bold{Racket documentation}. The PDFs of Racket documentation are currently generated by LaTeX. I would like to make Quad good enough to handle them.}
@item{@bold{Book publishing}. My wife is a lawyer and wants to publish a book about a certain area of the law that involves a zillion fiddly charts. If I had to do it by hand, it would take months. But with a Quad program, it could be easy.}
]
@(linebreak)
@(linebreak)
@(linebreak)
@italic{``A way of doing something original is by trying something
so painstaking that nobody else has ever bothered with it.'' — Brian Eno}
Loading…
Cancel
Save