OurBigBook.com: The OurBigBook Project is creating the ultimate open source tools to publish textbooks/personal knowledge bases/Zettelkasten/digital gardens in the learn in public philosophy. It is our best shot yet at the final real-world Encyclopedia Galactica by allowing effective mind melding/collective intelligence via the topics feature.
OurBigBook CLI quick start using github.com/ourbigbook/template:
git clone https://github.com/ourbigbook/template
cd template
npm install
npx ourbigbook .
firefox out/html/index.html
Mission: to live in a world where you can learn university-level mathematics, physics, chemistry, biology and engineering from perfect free open source books that anyone can write to get famous.
Ultimate goal: destroy the currently grossly inefficient education system and replace it with a much more inspiring system where people learn what they want as fast as possible to reach their goals faster without so much useless pain.
How to get there: create a website (live at OurBigBook.com) that incentivizes learners (notably university students taking courses) to write freely licensed university-level natural science books in their own words for free. Their motivation for doing that are:
- getting their knowledge globally recognized and thus better jobs
- improving the world
- learning by teaching
Notable features:
- topics: groups the articles of different users about the same topic, sorted by upvote to achieve mind melding/collective intelligence. This makes your articles easier for others to find.
- local editing: you can store all your personal knowledge base content locally in a plaintext markup format that can be edited locally and published with OurBigBook CLI to either:This way you can be sure that even if OurBigBook.com were to go down one day (which we have no plans to as it is quite cheap to host!), your content will still be perfectly readable as a static site.
- to OurBigBook.com: to get awesome multi-user features like OurBigBook Web topics
- as HTML files to a static website: you can host yourself for free on many external providers like GitHub Pages, and remain in full control
- infinitely deep table of contents: never again be limited to only 6 levels of HTML
h6
legacy limitations! With OurBigBook Project, the sky is the limit!Furthermore, with our dynamic article tree of OurBigBook Web, every header can be the toplevel header for better SEO and user experience e.g. both the following pages show all their ancestors:
Key links:
- OurBigBook.com: reference OurBigBook Web instance
- donate to the OurBigBook Project: donate
- project announcements: Section 12.15.5. "News". Also posted in shorter form to Section 12.15.1. "Official accounts" such as:
- cirosantilli.com/ourbigbook-com: further rationale behind the project by the founder Ciro Santilli
- cirosantilli.com: showcase static demo document with interesting content, published with OurBigBook CLI. Primary inspiration for OurBigBook development.
- cirosantilli.com/oxford-nanopore-river-bacteria: a self-contained tutorial style part of the above. Note how internal links integrate seamlessly into the more global topic of biology, e.g. when talking about DNA we link to the global topic cirosantilli.com/dna.
- github.com/cirosantilli/cirosantilli.github.io and github.com/cirosantilli/cirosantilli.github.io/blob/dev/oxford-nanopore-river-bacteria.bigb: source of the above showcase documents
- Section 3.2. "Design goals": OurBigBook Markup and OurBigBook CLI feature overview
- github.com/ourbigbook/ourbigbook: OurBigBook source code
- github.com/ourbigbook/ourbigbook/issues: project issue tracker
- github.com/ourbigbook/ourbigbook/blob/master/README.bigb: source for this document
- docs.ourbigbook.com: rendered version of this document
- docs.ourbigbook.com/_obb/dist/editor: live in-browser editor demo
- github.com/ourbigbook/template: good template to get started with OurBigBook CLI, see Section 5.2. "OurBigBook CLI quick start"
- cirosantilli.com/ourbigbook-media: media for the project such as for documentation and publicity, more info: Section 12.13. "OurBigBook media repository"
To donate:
- cirosantilli.com/sponsor: give money directly to Ciro Santilli
- buy project merchandise, see: Section 12.15.2. "Merchandise"
All donated money currently just goes directly to Ciro Santilli's personal bank account, the project founder and current lead. If things ever take off we will set up a legal entity to make things cleaner. One may dream. But for now, it would just add unnecessary overhead. Related: Section 12.14. "Project governance".
Ciro announces funding milestones and transparently accounts for all donations at: cirosantilli.com/sponsor. When milestones are reached, he quits his day job and works full time on the project for a given ammount of time.
We are also happy to discuss paid contracts to implement specific features, to get in touch see: contact.
The following sections cover different ways to use tools from the OurBigBook:
- OurBigBook Web user manual: manual for OurBigBook Web, the dynamic website. With this approach, you can write content on the browser without downloading anything, and save it on our database.
- convert local
.bigb
files with either:This method allows you to publish either as: - OurBigBook Markup quick start: covers specifically OurBigBook Markup, which is the markup language you use to write content in OurBigBook, both OurBigBook Web and OurBigBook CLI.This is currently the only way to write OurBigBook content, but we would really like to add WYSIWYG editor support one day!
- cross references to any header (including e.g. h2, h3, etc. in other files), images, etc. with amazing error checking and reporting: never break internal links without knoing again, and quickly find out what broke when you do. E.g.:animal.bigbMammal.bigb
= Animal <Bats> are <flying animals>.
= Flying animal == Bat
Animal.bigb
would render something like:The following would fail and point you out the file and line of the failure:<a href="flying-animal.html#bat">Bats</a> are <a href="flying-animal.html">flying animals</a>.
- nonexistent id:
<Weird animal not documented>
- duplicate IDs:
= Animal == Dog == Cat == Dog
- nonexistent id:
- KaTeX server side mathematics, works on browsers with JavaScript disabled:
I like $\sqrt{2}$, but I adore this \x[equation-quadratic-equation]: $$ x^2 + 2x + 1 $$ {title=Quadratic equation}
- multi-file features out of the box so you don't need a separate wrapper like Jekyll to make a multi-page website:
- cross file references
- single-source multi-format output based on includes and build options:
- by default, one HTML per source with includes rendered as links between pages, e.g.:README.bigbnot-readme.bigb
= My website == h2 \Include[not-readme]
produces= Not readme == Not readme h2
index.html
andnot-readme.html
- with the
-S
,--split-headers
option, you can output each header of an input file into a separate output file. The previous filesystem would produce:Each of those pages automatically gets a table of contentsindex.html
: which contains the fullREADME.bigb
outputsplit.html
: split version of the above containing only the= My website
header and noth2
h2.html
: only contains theh2
headernot-readme.html
contains the full output ofnot-readme.bigb
not-readme-split.html
: only contains the= Not readme
headernot-readme-h2.html
: only contains the= Not readme h2
header
--embed-includes
single file output from multiple input files. Includes are parsed smartly, not just source copy pasted, e.g. included headers are shifted fromh1
toh2
correctly.On the previous sample filesystem, it would produce a single output fileindex.html
which would contain a header structure like:= My website == h2 === Not readme ==== Not readme h2
- supports both local serverless rendering to HTML files for local viewing, and server oriented rendering such as GitHub pages, e.g. cross references automatically get
.html
extension and or not. E.g.:- locally, a link
\x[not-readme]
would render as<a href="not-readme.html">
andnot-readme.bigb
producesnot-readme.html
- when publishing,
\x[not-readme]
would render as<a href="not-readme">
andnot-readme.bigb
also producesnot-readme.html
, which the server converts to justhttp://my-website.com/not-readme
- locally, a link
- cross file configuration files to factor out common page parts like headers, footers and other metadata, e.g.:
ourbigbook.liquid.html
: Liquid template used for all pages, see example at: Section 5.2.1. "Play with the template"main.scss
: CSS stylesheet generated from SASS input, see example at: Section 5.2.1. "Play with the template"ourbigbook.tex
: global LaTeX math definitions, e.g.:and then you can use:\newcommand{\abs}[1]{\left|#1\right|}
in any .bigb file of the project.$\abs{x}$
ourbigbook.json
: per repository configuration options
- table of contents that crosses input files via includes. E.g. in:README.bigbnot-readme.bigb
= My website == h2 \Include[not-readme]
the table of contents for= Not readme == Not readme h2
index.html
also contains the headers fornot-readme.bigb
producing:This means that you can split large splitDefault input files if rendering starts to slow you down, and things will still render exactly the same.- My website
- h2
- Not readme
- Not readme h2
- Not readme
- h2
- My website
- check that local files and images linked to actually exist:
\a
external
argument. E.g.:would lead to a build error.\a[i-don-exist.txt]
- associate headers to files or directories with the
\H
file
argument e.g.:would automatically add a preview of the image on the output. Display files and their metadata nicely directly on your static website rather than relying exclusively on GitHub as a file browser.Here's an example of a nice image: \x[path/to/my/image.png]{file}. = path/to/my/image.png {file} This image was taken when I was on vacation!
- advanced header/ID related features:
- ID-based header levels:
= Furry animal I like \x[furry-animal]{p}, especially my cat, here is his photo: \x[image-my-cat]. == Cat \Image[My_cat.jpg] {title=My cat}
- scopes either with directories or with within a single file:
See the important conclusion of my experiment: \x[report-of-my-experiment/conclusion] = Report of my experiment {scope} == Introduction == Middle == Conclusion
- cross reference title inflection for capitalization and pluralization, e.g.;
would render:
= Dog == Snoopy {c} \x[dog]{c}{p} are fun. But the \x[dog] I like the most is \x[snoopy]!
\x[dog]{c}{p}
asDogs
: capitalized because of{c}
and pluralized because of{p}
\x[dog]
asdogs
: auto lowercased because its header= Dog
does not have{c}
\x[snoopy]
asSnoopy
: title capitalization kept to upper case due to{c}
on the header== Snoopy
- synonyms, e.g.:would render something like:
= User interface = UI {c} {synonym} {title2} \x[user-interface]{c} is too long, I just say \x[ui].
Furthermore, this also generates a output file:<a href="#user-interface">User interface</a> is too long, I just say <a href="user-interface">UI</a>
which redirects to the ainui.html
user-interface.html
, so it serves as a way to have backward compatibility on page renames.And thetitle2
makes it appears on the main title under parenthesis, something like:<h1>User interface (UI)</h1>
- header disambiguation, e.g.:
which renders something like:
My favorite fruits are \x[apple-fruit]{p}! My favorite least favorite brand is is \x[apple-company]! \x[apple] computers are too expensive. == Apple {disambiguate=fruit} == Apple {c} {disambiguate=company} = Apple {c} {synonym}
\x[apple-fruit]{p}
:<a href="apple-fruit">apples</a>
\x[apple-company]
:<a href="apple-company">Apple</a>
\x[apple]
: also<a href="apple-company">Apple</a>
because of the synonym== Apple\n{disambiguate=fruit}
:<h2 id="apple-fruit">Apple (fruit)</h2>
== Apple\n{disambiguate=company}
:<h2 id="apple-company">Apple (company)</h2>
- tags are regular headers:
\H
child
argument,\x
child
argument= Animal == Dog {tag=domestic} {tag=cute} == Cat {tag=domestic} {tag=cute} == Bat {tag=flying} = Flying = Cute = Domestic
- unlimited header levels, levels higher than 6 are rendered in HTML as an appropriately styled
div
s with an ID:= h1 == h2 === h3 ==== h4 ===== h5 ====== h6 ======= h7 ======== h8
- generate lists of incoming links between internal headers: it shows every internal link coming into the current page
- ID-based header levels:
- automatic file upload and directory listing of non OurBigBook files:
_raw
directory, e.g.: - is written in JavaScript and therefore runs natively on the browser to allow live previews as shown at: docs.ourbigbook.com/_obb/dist/editor
- helps you with the publishing:
ourbigbook --publish
publishes in a single command to the configured target (default GitHub Pages)- OurBigBook tries to deal with media such as images and video intelligently for you, e.g.: Section 4.2.8.2. "Where to store images". E.g. you can keep media in a separate media repository,
my-media-repository
, and then by configuring onourbigbook.json
:you can use images in that repository with:"media-providers": { "github": { "default-for": ["image", "video"], "path": "media", "remote": "yourname/myproject-media" } }
instead of:\Image[My_image_basename.jpg]
\Image[https://raw.githubusercontent.com/cirosantilli/myproject--media/master/My_image_basename.jpg]
inotifywait
watch and automatically rebuild with-w
,--watch
:ourbigbook --watch input-file.bigb
- automatic code formatting:
--format-source
OurBigBook is designed entirely to allow writing complex professional HTML and PDF scientific books, blogs, articles and encyclopedias.
OurBigBook aims to be the ultimate LaTeX "killer", allowing books to be finally published as either HTML or PDF painlessly (LaTeX being only a backend to PDF generation).
It aims to be more powerful and saner and than Markdown and Asciidoctor.
Originally, OurBigBook was is meant to be both saner and more powerful than Markdown and Asciidoctor.
But alas, as Ciro started implementing and using it, he started to bring some Markdown insanity he missed back in.
And so this "degraded" slightly into a language slightly saner than Asciidoctor but with an amazing Node.js implementation that makes it better for book writing and website publishing.
Notably, we hope that our escaping will be a bit saner backslash escapes everything instead of Asciidoctor's "different escapes for every case" approach: github.com/asciidoctor/asciidoctor/issues/901
But hopefully, having starting from a saner point will still produce a saner end result, e.g. there are sane constructs for every insane one.
It is intended that this will be an acceptable downside as OurBigBook will be used primarily large complex content such as books rather than forum posts, and will therefore primarily written either:
- in text editors locally, where users have more features than in random browser textareas
- in a dedicated website that will revolutionize education, and therefore have a good JavaScript editing interface: github.com/cirosantilli/write-free-science-books-to-get-famous-website
For example, originally OurBigBook had exactly five magic characters, with similar functions as in LaTeX:and double blank newlines for paragraphs if you are pedantic, but this later degenerated into many more with insane macro shortcuts.
\
backslash to start a macro, like LaTeX{
and}
: left and right square brackets to delimit optional macro arguments[
and]
: left and right curly braces bracket to start an optional arguments
We would like to have only square brackets for both optional and mandatory to have even less magic characters, but that would make the language difficult to parse for computer and humans. LaTeX was right for once!
This produces a very regular syntax that is easy to learn, including doing:
- arbitrary nesting of elements
- adding arbitrary properties to elements
This sanity also makes the end tail learning curve of the endless edge cases found in Markdown and Asciidoctor disappear.
The language is designed to be philosophically isomorphic to HTML to:
- further reduce the learning curve
- ensure that most of HTML constructs can be reached, including arbitrary nesting
More precisely:
- macro names map to tag names, e.g.:
\\a
to<a
- one of the arguments of macros, maps to the content of the HTML element, and the others map to attributes.E.g., in a link:the first macro argument:
\a[http://example.com][Link text\]
maps to thehttp://example.com
href
of<a
, and the second macro argument:maps to the internal content ofLink text
<a>Link text<>
.
The high sanity of OurBigBook, also makes creating new macro extensions extremely easy and intuitive.
All built-in language features use the exact same API as new extensions, which ensures that the extension API is sane forever.
Markdown is clearly missing many key features such as block attributes and cross references, and has no standardized extension mechanism.
The "more powerful than Asciidoctor" part is only partially true, since Asciidoctor is very featureful can do basically anything through extensions.
The difference is mostly that OurBigBook is completely and entirely focused on making amazing scientific books, and so will have key features for that application out-of-the box, notably:and we feel that some of those features have required specialized code that could not be easily implemented as a standalone macro.
- amazing header/ToC/ID features including proper error reports: never have a internal broken link or duplicate ID again
- server side pre-rendered maths with KaTeX: all divs and spans are ready, browser only applies CSS, no JavaScript gets executed
- publish: we take care of website publishing for you out-of-the-box, no need to integrate into an external project like Jekyll
-S
,--split-headers
:- github.com/asciidoctor/asciidoctor/issues/626 feature request
- github.com/owenh000/asciidoctor-multipage third party plugin that does it
Another advantage over Asciidoctor is that the reference implementation of OurBigBook is in JavaScript, and can therefore be used on browser live preview out of the box. Asciidoctor does Transpile to JS with Opal, but who wants to deal with that layer of complexity?
Static wiki generators: this is perhaps the best way of classifying this project :-)
- github.com/gollum/gollum: already has a local server editor! But no WYSIWYG nor live preview. Git integration by default, so when you save on the UI already generates a Git commit. We could achieve that with: github.com/isomorphic-git/isomorphic-git, would be really nice. Does not appear to have built-in static generation:Does not appear to check that any links are correct.
- github.com/wcchin/markypydia
- obsidian.md/ closed source, Markdown with cross file reference + a SaaS. Appears to require payment for any publishing. 28k followers 2021: twitter.com/obsdmd. Founders are likely Canadians of Asian descent from Waterloo University: www.linkedin.com/in/lishid/ | www.linkedin.com/in/ericaxu/ also working in parallel on dynalist.io/ 2020 review at: www.youtube.com/watch?v=aK2fOQRNSxc Has offline editor with side-by-side preview. Compares with Roam and Notion, but can't find any public publishing on those, seem to be enterprise only things.
Static book generators:
- github.com/rstudio/bookdown, bookdown.org/. Very similar feature set to what we want!!! Transpiles to markdown, and then goes through Pandoc: bookdown.org/yihui/bookdown/pandoc.html, thus will never run on browser without huge translation layers. But does have an obscene amount of output formats however.
- Hugo. Pretty good, similar feature set to ours. But Go based, so hard on browser, and adds adhoc features on top of markdown once again
- en.wikipedia.org/wiki/Personal_wiki
- github.com/hplgit/doconce
- www.gwern.net/About#source is pretty interesting, uses github.com/jaspervdj/Hakyll/ + some custom stuff.
- github.com/JerrySievert/bookmarkdown
- www.gitbook.com/
- github.com/rust-lang/mdBook. Impressive integrated search feature. Like Gitbook but implemented in Rust.
- github.com/facebook/docusaurus React + markdown based, written in TypeScript. So how can it be build fast? Gotta benchmark.
- vimdoc: vimdoc.sourceforge.net/ They do have perfectly working Internal cross file references, see any page e.g. vimdoc.sourceforge.net/htmldoc/pattern.html.
- typst: github.com/typst/typst An attempt at a LaTeX killer. Has its own typesetting engine, does not simply transpile to LaTeX. Meant to be faster and simpler to write. No HTML output as of writing: github.com/typst/typst/issues/721
Less related but of interest, similar philosophy to what Ciro wants, but no explicitly reusable system:
Ciro Santilli developed OurBigBook to perfectly satisfy his writing style, which is basically "create one humongous document where you document everything you know about a subject so everyone can understand it, and just keep adding to it".
cirosantilli.com is the first major document that he has created in OurBigBook.
He decided to finally create this new system after having repeatedly facing limitations of Asciidoctor which were ignored/wontfixed upstream, because Ciro's writing style is not as common/targeted by Asciidoctor.
Following large documents Ciro worked extensively on:made the limitations of Asciidoctor clear to Ciro, and were major motivation in this work.
The key limitations have repeatedly annoyed Ciro were:
- cannot go over header level 6, addressed at: unlimited header levels
- the need for
-S
,--split-headers
to avoid one too large HTML output that will never get indexed properly by search engines, and takes a few seconds to load on any browser, which is unacceptable user experience
OurBigBook Markup is the lightweight markup language used in the OurBigBook Project project.
It works both on the OurBigBook Web dynamic website, and on OurBigBook CLI static websites from the command line.
OurBigBook Markup files use the
.bigb
extension.Paragraphs are made by simplifying adding an empty line, e.g.:
My first paragraph.
And now my second paragraph.
Third one to finish.
which renders as:
My first paragraph.And now my second paragraph.Third one to finish.
Headers are created by starting the line with equal signs. The more equal signs the deeper you are, e.g.:
On OurBigBook Web, the toplevel header of each page goes into a separate title box, so there things would just look like:
= Animal
== Mammal
=== Dog
=== Cat
== Bird
=== Pigeon
=== Chicken
- title box: "Animal"
- body:
== Mammal === Dog === Cat == Bird === Pigeon === Chicken
You can can use any header as a tag of any other header, e.g.:
= Animal
== Dog
{tag=Cute animal}
== Turtle
{tag=Ugly animal}
== Animal cuteness
=== Cute animal
=== Ugly animal
Headers have several powerful features that you can read more about under
\H
arguments, e.g. \H
synonym
argument and \H
disambiguate
argument.To link to any of your other pages, you can use angle brackets (less than/greater than) signs:
Note how capitalization and pluralization generally just work.
I have a <cute animal>. <Birds> are too noisy.
To use a custom link text on a reference, use the following syntax:
I have a <cute animal>[furry animal]. <Birds>[feathery animals] are too noisy.
External links can be input directly as:
This is a great website: https://example.com
I really like https://example.com[this website].
which renders as:
This is a great website: example.comI really like this website.
Code blocks are done with backticks
and with two ore more backticks you get a code block on its own line, and possibly with multiple code lines:
`
. With just one backtick, you get a code block inside the text:
The function call `f(x + 1, "abc")` is wrong.
which renders as:
The function callf(x + 1, "abc")
is wrong.
The function:
``
function f(x, s) {
return x + s
}
``
is wrong.
which renders as:
The function:is wrong.function f(x, s) { return x + s }
Mathematics syntax is very similar to code blocks, you can just enter you LaTeX code in it:
The number $\sqrt{2}$ is irrational.
The same goes for:
$$
\frac{1}{\sqrt{2}}
$$
which renders as:
The number is irrational.The same goes for:
We also have a bunch of predefined macros from popular packages, e.g.
\dv
from the physics
package for derivatives:
$$
\dv{x^2}{x} = 2x
$$
which renders as:
You can refer to specific equations like this:
As shown in <equation Very important equation>, this is true.
$$
\frac{1}{\sqrt{2}}
$$
{title=Very important equation}
which renders as:
As shown in Equation 3. "Very important equation", this is true.
Images and videos are also easy to add and refer to:
As shown at <image Cute chicken chick>, chicks are cute.
\Image[https://upload.wikimedia.org/wikipedia/commons/thumb/c/c9/H%C3%BChnerk%C3%BCken_02.jpg/800px-H%C3%BChnerk%C3%BCken_02.jpg?20200716091201]
{title=Cute chicken chick}
\Video[https://www.youtube.com/watch?v=j_fl4xoGTKU]
{title=Top Down 2D Continuous Game by Ciro Santilli (2018)}
which renders as:
As shown at Figure 10. "Cute chicken chick", chicks are cute.
Images can take a bunch of options, about which you can read more about at image arguments. Most should be self explanatory, here is an image with a bunch of useful arguments:
\Image[https://upload.wikimedia.org/wikipedia/commons/thumb/c/c9/H%C3%BChnerk%C3%BCken_02.jpg/800px-H%C3%BChnerk%C3%BCken_02.jpg?20200716091201]
{title=Ultra cute chicken chick}
{description=
The chicken is yellow, and the hand is brown.
The background is green.
}
{border}
{height=400}
{source=https://commons.wikimedia.org/wiki/File:H%C3%BChnerk%C3%BCken_02.jpg}
which renders as:
Lists are written by starting the line with an asterisk
*
:
* first item
* second item
* and the third
which renders as:
- first item
- second item
- and the third
A nested list:
* first item
* first item version 1
* first item version 2
* first item version 2 1
* first item version 2 2
* second item
* and the third
which renders as:
- first item
- first item version 1
- first item version 2
- first item version 2 1
- first item version 2 2
- second item
- and the third
Lists items can contain any markup, e.g. paragraphs. You just need to keep the same number of spaces, e.g.:
* first item.
Second paragraph of first item.
And a third one.
* second item
* second item v1
Another paragraph in second item v1
* second item v2
which renders as:
first item.Second paragraph of first item.And a third one.- second item
second item v1Another paragraph in second item v1- second item v2
Tables are not very different from lists. We use double pipes for headers
||
, and a single pipe |
for regular rows:
|| City
|| Sales
| Salt Lake City
| 124,00
| New York
| 1,000,000
which renders as:
City Sales Salt Lake City 124,00 New York 1,000,000
To add a title we need to use an explicit
\Table
macro as in:
See <table Sales per city> for more information.
\Table
{title=Sales per city}
[
|| City
|| Sales
| Salt Lake City
| 124,00
| New York
| 1,000,000
]
which renders as:
See Table 1. "Sales per city" for more information.
City Sales Salt Lake City 124,00 New York 1,000,000
This section documents all OurBigBook macros.
Macros are magic commands that do cool stuff, e.g.
\Image
to create an image.The most common macros also have insane macro shortcuts to keep the syntax shorter.
The general macro syntax is described at Section 4.3. "OurBigBook Markup syntax".
Insane autolink, i.e. the link text is the same as the link address:
Exact parsing rules described at: Section 4.2.1.2. "Insane link parsing rules".
The website http://example.com is cool. See also:
\Q[http://example.com/2]
which renders as:
The website example.com is cool. See also:
Note that the prefixes
http://
and https://
are automatically removed from the displayed link, since they are so common that they woudly simply add noise.Equivalent sane version:
The website \a[http://example.com] is cool.
\Q[\a[http://example.com/2]]
which renders as:
The website example.com is cool.
Insane link with custom text:
Equivalent sane version:
If the custom text is empty, an autolink is generated. This is often useful if you want your link to be followed by punctuation:
This could also be achieved with the sane syntax of course, but this pattern saves a tiny bit of typing.
The website http://example.com[example.com] is cool.
which renders as:
The website example.com is cool.
The website \a[http://example.com][example.com] is cool.
which renders as:
The website example.com is cool.
The website is really cool: http://example.com[].
which renders as:
The website is really cool: example.com.
Link to a file in the current repository:
This links to a raw view of that file.
The file \a[index.js] is cool.
which renders as:
The file index.js is cool.
Link to a directory in the current repository:
This links to an output file that contains a generated directory listing of that directory.
The directory \a[file_demo] is cooler.
which renders as:
The directory file_demo is cooler.
The link target, e.g. in:
\a[http://example.com]
href
equals http://example.com
.Important behaviors associated with this property for local links are detailed at Section 4.2.1.1.3. "
\a
external
argument":- they are checked for existence in the local filesystem
- they are modified to account for scopes with
-S
,--split-headers
Analogous to the
\x
ref
argument, e.g.:
Trump said this and that.https://en.wikipedia.org/wiki/Donald_Trump_Access_Hollywood_tape#Trump's_responses{ref}https://web.archive.org/web/20161007210105/https://www.donaldjtrump.com/press-releases/statement-from-donald-j.-trump{ref} Then he said that and this.https://en.wikipedia.org/wiki/Donald_Trump_Access_Hollywood_tape#Trump's_responses{ref}https://web.archive.org/web/20161007210105/https://www.donaldjtrump.com/press-releases/statement-from-donald-j.-trump{ref}
which renders as:
If given and true, forces a the link to be an external link.
Otherwise, the external is automatically guessed based on the address given as explained at Section 4.2.1.1.3.3. "External link".
Common use cases for the
external
argument is to link to non OurBigBook content in the current domain, e.g.:- link to the domain root path for Subdirectory deployments
- link non OurBigBook subdirectories. E.g., github.com/cirosantilli/cirosantilli.github.io/blob/master/README.bigb was rendered at cirosantilli.com, and contains links
\a[markdown-style-guide]{external}
to cirosantilli.com/markdown-style-guide, whose source lives in a separate non-OurBigBook repository: github.com/cirosantilli/markdown-style-guide/
The
\a
external
argument can be used to refer to the root of the domain. E.g. suppose that we have a subdirectory deployment under https://mydomain.com/subdir/
. Then:\a[/somepath]
refers to the directory/subdir/somepath
\a[/somepath]{external}
refers t othe directory/somepath
TODO test if it works. But we want it to be possible to deploy OurBigBook CLI static websites on subdirectories, e.g.:
If it doesn't work, it should be easy to make it work, as we use relative links almost everywhere already. Likely there would only be some minor fixes to the
https://mydomain.com/subdir/
https://mydomain.com/subdir/mathematics
--template
arguments.An external link is a link that points to a resource that is not present in the curent OurBigBook project sources.
By default, most links are internal links, e.g. it is often the case in computer programming tutorials that we want to refer to source files in the current directory. So from our
and here
README.bigb
, we could want to write something like:
Have a look at this amazing source file: \a[index.js].
which renders as:
Have a look at this amazing source file: index.js.
\a[ourbigbook]
is a internal link.A typicial external link is something like:
which points to an absolute URL.
This is great website: https://cirosantilli.com
which renders as:
This is great website: cirosantilli.com
OurBigBook considers a link relative by default if:
- it is not a URL with protocol
Therefore, the following links are external by default:and the following are internal by default:
http://cirosantilli.com
https://cirosantilli.com
file:///etc/fstab
ftp://cirosantilli.com
index.js
../index.js
path/to/index.js
/path/to/index.js
. Note that paths starting with/
refer to the root of the OurBigBook CLI deployment, not the root of the domain, see: link to the domain root path.//example.com/path/to/index.js
A link being internal has the following effects
- the correct relative path to the file is used when using nested scopes with
-S
,--split-headers
. For example, if we have:then in split header mode,= h1 == h2 {scope} === h3 \a[index.js]
h3
will be rendered toh2/h3.html
.Therefore, if we didn't do anything about it, the link toindex.js
would render ashref="index.js"
and thus point toh2/index.js
instead of the correctindex.js
.Instead, OurBigBook automatically converts it to the correcthref="../index.js"
- the
_raw
directory prefix is added to the link - existence of the file is checked on compilation. If it does not exist, an error is given.
Implemented at: github.com/ourbigbook/ourbigbook/issues/87 as
relative
, and subsequently modified to the more accurate/useful external
.The
_dir
directory tree contains file listings of files in the _raw
directory.We originally wanted to place these listings under
_raw
itself, but this leads to unsolvable conflicts when there are files called index.html
present vs the index.Analogous to the
_raw
directory, but for the \H
file
argument.OurBigBook Project places output files that are not the output of
.bigb
to .html
conversion (i.e. .html
output files) under the _raw/
prefix of the output.Internal links then automatically add the
_raw/
prefix to every link.For example, consider an input directory that contains:
notindex.bigb
= Hello
Check out \a[myfile.c].
The source code for this file is at: \a[notindex.bigb].
\Image[myimg.png]
myfile.c
int i = 1;
myimg.png
Binary!
After conversion with:
the following files would exist in the output directory:and all links/image references would work and automtically point to the correct locations under
ourbigbook .
notindex.html
: converted output ofnotindex.bigb
_raw/notindex.bigb
: a copy of the input source codenotindex.bigb
_raw/myfile.c
: a copy of the input filemyfile.c
_raw/myimg.png
: a copy of the input filemyimg.c
_raw
.Some live examples:
The reason why a Then, in a server that omits the
_raw
prefix is needed it to avoid naming conflicts with OurBigBook outputs, e.g. suppose we had the files:configure
configure.bigb
.html
extension, if we didn't have _raw/
both configure.html
and configure
would be present under /configure
. With _raw
we instead get:_raw/configure
: the input/configure
fileconfigure
: the HTML
A URL with protocol is a URL that matches the regular expression
^[a-zA-Z]+://
. The following are examples of URLs with protocol:http://cirosantilli.com
https://cirosantilli.com
file:///etc/fstab
ftp://cirosantilli.com
The following aren't:
index.js
../index.js
path/to/index.js
/path/to/index.js
//example.com/path/to/index.js
. This one is a bit tricky. Web browsers would consider this as a protocol-relative URL, which technically implies a protocol, although that protocol would be different depending how you are viewing the file, e.g. locally throughfile://
vs on a with websitehttps://
.For simplicity's sake, we just consider it as a URL without protocol.
Insane start at any of the recognized protocols are the ones shown at: Section 4.4.3. "Known URL protocols".absolutely anywhere if not escaped, e.g.:
renders something like:
To prevent expansion, you have to escape the protocol with a backslash
Empty domains like:
don't becomes links however. But this one does:
http://
https://
ahttp://example.com
a <a href="http://example.com">
\\
, e.g.:
\http://example.com
http://
http://a
Insane links end when any insane link termination character is found.
As a consequence, to have an insane link followed immediately by a punctuation like a period you should use an empty argument as in:
otherwise the punctuation will go in it. Another common use case is:
Check out this website: http://example.com[].
which renders as:
Check out this website: example.com.
As mentioned on the tutorial (http://example.com[see this link]).
which renders as:
As mentioned on the tutorial (see this link).
If you want your link to include one of the terminating characters, e.g.
]
, all characters can be escaped with a backslash, e.g.:
Hello http://example.com/\]a\}b\\c\ d world.
which renders as:
Hello example.com/]a}b\c d world.
Note that the
http://example.com
inside \a[http://example.com]
only works because we do some post-processing magic that prevents its expansion, otherwise the link would expand twice:
\P[http://example.com]
\a[http://example.com]
which renders as:
This magic can be observed with --help-macros
by seeing that the href
argument of the a
macro has the property:
"elide_link_only": true,
The following characters are the "insane link termination characters":Insane cross references and insane topic links with a single word terminate if any of these characters are found, see also: Section 4.2.1.2. "Insane link parsing rules".
- space
- newline
\n
- open or close square bracket
[
or]
- open or close curly braces
{
or}
OurBigBook Project automatically encodes all link
href
for characters that are not recommended for URLs.This way you can for example simply write arbitrary Unicode URLs and OurBigBook will escape them for you on the HTML output.
The only exception for this is the percent sign itself
%
, which it leaves untouched so that explicitly encoded URLs also work. So if you want a literal percent then you have to explicitly write it yourself as %25
.* acute a Á as raw Unicode: https://en.wikipedia.org/wiki/Á
* acute a Á explicitly escaped by user: https://en.wikipedia.org/wiki/%C3%81
which renders as:
- acute a Á as raw Unicode: en.wikipedia.org/wiki/Á
- acute a Á explicitly escaped by user: en.wikipedia.org/wiki/%C3%81
Some \b[bold] text.
which renders as:
Some bold text.
The
\br
macro inserts a visible newline between two lines without creating a paragraph.There is basically one application for this: poetry, which would be too ugly with code block due to fixed width font:
Paragraph 1 Line 1\br
Paragraph 1 Line 2\br
Paragraph 2 Line 1\br
Paragraph 2 Line 2\br
which renders as:
Paragraph 1 Line 1
Paragraph 1 Line 2Paragraph 2 Line 1
Paragraph 2 Line 2
Inline code (code that should appear in the middle of a paragraph rather than on its own line) is done with a single backtick (
and block code (code that should appear on their own line) is done with two or more backticks (
`
) insane macro shortcut:
My inline `x = 'hello\n'` is awesome.
which renders as:
My inlinex = 'hello\n'
is awesome.
``
):
``
f() {
return 'hello\n';
}
``
which renders as:
f() { return 'hello\n'; }
The sane version of inline code is a lower case
and the sane version of block math is with an upper case
c
:
My inline \c[[x = 'hello\n']] is awesome.
which renders as:
My inlinex = 'hello\n'
is awesome.
C
:
\C[[
f() {
return 'hello\n';
}
]]
which renders as:
f() { return 'hello\n'; }
The capital vs lower case theme is also used in other elements, see: block vs inline macros.
If the content of the sane code block has many characters that you would need to escape, you will often want to use literal arguments, which work just like the do for any other argument. For example:
Note that the initial newline is skipped automatically in code blocks, just as for any other element, due to: argument leading newline removal, so you don't have to worry about it.
\C[[[
A paragraph.
\C[[
And now, some long, long code, with lots
of chars that you would need to escape:
\ [ ] { }
]]
A paragraph.
]]]
which renders as:
A paragraph. \C[[ And now, some long, long code, with lots of chars that you would need to escape: \ [ ] { } ]] A paragraph.
The distinction between inline
\c
and block \C
code blocks is needed because in HTML, pre
cannot go inside P
.We could have chosen to do some magic to differentiate between them, e.g. checking if the block is the only element in a paragraph, but we decided not to do that to keep the language saner.
And now a code block outside of
\OurBigBookExample
to test how it looks directly under the \Toplevel
implicit macro:Hello
Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello
HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHello
Hello
Now with short description with math and underline:
Hello
Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello
HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHello
Hello
And now a very long inline code:
Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello
Example:
See the: <code Python hello world>.
``
print("Hello wrold")
``
{title=Python hello world}
{description=Note thow this is super short unlike the C hello world!}
which renders as:
See the: Code 2. "Python hello world".print("Hello wrold")
Example:
See the: <code C hello world>.
``
#include <stdio.h>
int main(void) {
puts("hello, world");
}
``
{title=C hello world}
which renders as:
See the: Code 3. "C hello world".#include <stdio.h> int main(void) { puts("hello, world"); }
The
Comment
and comment
macros are regular macros that does not produce any output. Capitalization is explained at: Section 4.4.2. "Block vs inline macros".You will therefore mostly want to use it with a literal argument, which will, as for any other macro, ignore any macros inside of it.
Before comment.
\Comment[[
Inside comment.
]]
After comment.
which renders as:
Before comment.After comment.
And an inline one:
My inline \comment[[inside comment]] is awesome.
\comment[[inside comment]] inline at the start.
which renders as:
My inline is awesome.inline at the start.
Insane with
Insane headers end at the first newline found. They cannot therefore contain raw newline tokens.
=
(equal sign space):
= My h1
== My h2
=== My h3
Equivalent sane:
\H[1][My h1]
\H[2][My h2]
\H[3][My h3]
Custom ID for cross references on insane headers:
= My h1
{id=h1}
== My h2
{id=h2}
=== My h3
{id=h3}
Sane equivalent:
\H[1][My h1]{id=h1}
\H[2][My h2]{id=h2}
\H[3][My h3]{id=h3}
There is no limit to how many levels we can have, for either sane or insane headers!
HTML is randomly limited to
h6
, so OurBigBook just renders higher levels as an h6
with a data-level
attribute to indicate the actual level for possible CSS styling:
<h6 data-level="7">My title</h6>
The recommended style is to use insane headers up to
h6
, and then move to sane one for higher levels though, otherwise it becomes very hard to count the =
signs.To avoid this, we considered making the insane syntax be instead:
but it just didn't feel as good, and is a bit harder to type than just smashing
= 1 My h1
= 2 My h2
= 3 My h3
=
n times for lower levels, which is the most common use case. So we just copied markdown.The very first header of a document can be of any level, although we highly recommend your document to start with a
\H[1]
, and to contain exactly just one \H[1]
, as this has implications such as:\H[1]
is used for the document title: HTML document title\H[1]
does not show on the table of contents
After the initial header however, you must not skip a header level, e.g. the following would give an error because it skips level 3:
= my 1
== my 1
==== my 4
The toplevel header of a OurBigBook file is its first header and the one with the lowest level, e.g. in a document with recommended syntax:
the header
= Animal
== Dog
=== Bull Terrier
== Cat
= Animal
is the tolevel header.Being the toplevel header gives a header some special handling described in child sections of the section and elsewhere throughout this documentation.
The toplevel header is only defined if the document has only a single header of the highest level. e.g. like the following has only a single
h2
:
== My 2
=== My 3 1
=== My 3 2
Header IDs won't show for the toplevel level. For example, the headers would render like:
rather than:
This is because in this case, we guess that the
My 2
1. My 3 1
2. My 3 2
1. My 2
1.2. My 3 1
1.2. My 3 2
h2
is the toplevel.TODO: we kind of wanted this to be the ID of the toplevel header instead of the first header, but this would require an extra postprocessing pass (to determine if the first header is toplevel or not), which might affect performance, so we are not doing it right now.
When the OurBigBook input comes from a file (and not e.g. stdin), the default ID of the first header in the document is derived from the basename of the OurBigBook input source file rather than from its title.
This is specially relevant when including other files.
For example, in file named
the ID of the header is
my-file.bigb
which contains:
= Awesome ourbigbook file
my-file
rather than awesome-ourbigbook-file
. See also: automatic ID from title.If the file is an index file other than the toplevel index file, then the basename of the parent directory is used instead, e.g. the toplevel ID of a file:
would be:
rather than:
my-subdir/README.bigb
#my-subdir
#README.bigb
For the toplevel index file however, the ID is just taken from the header itself as usual. This is done because you often can't general control the directory name of a project.
For example, a GitHub pages root directory must be named as
<username>.github.io
. And users may need to rename directories to avoid naming conflicts.As a consequence of this, the toplevel index file cannot be included in other files.
If given, makes the header capitalized by default on cross file references.
More details at: Section 4.2.20.2. "Cross reference title inflection".
This
multiple
argument marks given IDs as being children of the current page.The effect is the same as adding the
\x
child
argument argument to an under the header. Notably, such marked target IDs will show up on the tagged autogenerated header metadata section.This argument is deprecated in favor of the
\H
tag
argument.Example:
renders exactly as:
= Animal
== Mammal
=== Bat
=== Cat
== Wasp
== Flying animal
{child=bat}
{child=wasp}
\x[bat]
\x[wasp]
= Animal
== Mammal
=== Bat
=== Cat
== Wasp
== Flying animal
\x[bat]{child}
\x[wasp]{child}
The header
child
syntax is generally preferred because at some point while editing the content of the header, you might accidentally remove mentions to e.g. \x[bat]{child}
, and then the relationship would be lost.The
\H
tag
argument does the same as the \x
child
argument but in the opposite direction.If given, the current section contains metadata about file or other resource with the given URL.
If empty, the URL of the file is extracted directly from the header. Otherwise, the given URL is used.
for example:
renders a bit like:
so note how:
= path/to/myfile.c
{file}
An explanation of what this file is about.
= path/to/myfile.c
{id=_file/path/to/myfile.c}
An explanation of what this file is about.
\a[path/to/myfile.c]
``
// Contents of path/to/myfile.c
int main() {
return 1;
}
``
- Also, a
_file/
prefix is automatically added to the ID. This is needed with-S
,--split-headers
to avoid a collision between:path/to/myfile.c
: the actual file_file/path/to/myfile.c
: the metadata about that file. Note that locally the.html
extension is added as infile/path/to/myfile.c.html
which avoids the collision. But on a server deployment, the.html
is not present, and there would be a conflict if we didn't add thatfile/
prefix.
- a link to the is added automatically, since users won't be able to click it from the header, as clicking on the header will just link to the header itself
- a preview is added. The type of preview is chosen as follows:
In some cases however, especially when dealing with external URLs, we might want to have a more human readable title with a non empty
which renders something like:
file
argument:
The video \x[tank-man-by-cnn-1989] is very useful.
= Tank Man by CNN (1989)
{c}
{file=https://www.youtube.com/watch?v=YeFzeNAHEhU}
An explanation of what this video is about.
The video \x[tank-man-by-cnn-1989] is very useful.
= Tank Man by CNN (1989)
{id=_file/https://www.youtube.com/watch?v=YeFzeNAHEhU}
\Video[https://www.youtube.com/watch?v=YeFzeNAHEhU]
An explanation of what this video is about.
To create a separate file with the
could contain something like:
and it would be associated to the file:
\H
file
argument set on the toplevel header, you must put it under the special _file
input directory. For example:
_file/path/to/myfile.txt.bigb
= myfile.txt
{file}
Description of my amazing file.
path/to/myfile.txt
The content of the header
= myfile.txt
is arbitrary, as it can be fully inferenced from the file path _file/path/to/myfile.txt.bigb
. TODO add linting for it. Perhaps we should make adding a header be optional and auto-generate that header instead. But having at least an optional header is good as a way of being able to set header properties like tags.This section contains some live demos of the
\H
file
argument.An explanation of what this directory is about.
Going deeper.
An explanation of what this text file is about.
Another line.
file_demo/hello_world.js
#!/usr/bin/env node
console.log('hello world')
Going deeper.
file_demo/file_demo_subdir/hello_world.js
#!/usr/bin/env node
console.log('hello world subdir')
This is a central source file that basically contains all the functionality of the OurBigBook Library, so basically the OurBigBook Markup-to-whatever (e.g. HTML) conversion code, including parsing and rendering.
Things that are not there are things that only use markup conversion, e.g.:
- OurBigBook CLI: does conversion from command line
- OurBigBook Web
This file must be able to run in the browser, so it must not contain any Node.js specifics.
It exposes the central
convert
function for markup conversion.You should normally use the packaged
_obb/ourbigbook.js
version of this file when using ourbigbook as an external dependency.This file is large, and large text files are not previewed, as they would take up too much useless vertical space and disk memory/bandwidth.
index.js was not rendered because it is too large (> 2000 bytes)
Binary files are not rendered.
file_demo/my.bin was not rendered because it is a binary file (contains \x00) of unsupported type (e.g. not an image).
An explanation of what this image is about.
Another line.
An explanation of what this video is about.
This section shows how to use a file to an arbitrary URL.
This boolean argument determines whether renderings of a header will have section numbers or not. This affects all of:This option can be set by default for all files with:
- headers themselves
- table of contents links
- cross references with the
\x
full
argument
By default, headers are numbered as in a book, e.g.:
renders something like:
= h1
== h2
=== h3
==== h4
= h1
Table of contents
* 1. h2
* 1.1. h3
* 1.1.1. h4
== 1. h2
=== 1.1. h3
==== 1.1.1. h4
However, for documents with a very large number of sections, or deeply nested headers those numbers start to be more noise than anything else, especially in the table of contents and you are better off just referring to IDs. E.g. imagine:
1.3.1.4.5.1345.3.2.1. Some deep level
When documents reach this type of scope, you can disable numbering with the
numbered
option.This option can be set on any header, and it is inherited by all descendants.
The option only affects descendants.
E.g., if in the above example turn numbering off at
then it renders something like:
h2
:
= h1
== h2
{numbered=0}
=== h3
==== h4
= h1
Table of contents
* 1. h2
* h3
* h4
== 1. h2
=== h3
==== h4
The more common usage pattern to disable it on toplevel and enable it only for specific "tutorial-like sections". An example can be seen at:which is something like:
then it renders something like:
Note how in this case the number for
- cirosantilli.com/: huge toplevel wiki, for which we don't want numbers
- cirosantilli.com/x86-paging: a specific tutorial, for which we want numbers
= Huge toplevel wiki
{numbered=0}
== h2
=== A specific tutorial
{numbered}
{scope}
==== h4
===== h5
= Huge toplevel wiki
Table of contents
* h2
* A specific tutorial
* 1. h4
* 1.1. h5
== h2
=== A specific tutorial
==== 1. h4
===== 1.1. h5
h4
is just 1.
rather than 1.1.1.
. We only show numberings relative to the first non-numbered header, because the 1.1.
wouldn't be very meaningful otherwise.In addition to the basic way of specifying header levels with an explicit level number as mentioned at Section 4.2.6. "Header , OurBigBook also supports a more indirect ID-based mechanism with the "
parent
argument of the \H
element.We hightly recommend using
parent
for all but the most trivial documents.For example, the following fixed level syntax:
is equivalent to the following ID-based version:
= My h1
== My h2 1
== My h2 2
=== My h3 2 1
= My h1
= My h2 1
{parent=my-h1}
= My h2 2
{parent=my-h1}
= My h3 2 1
{parent=my-h2-h}
The main advantages of this syntax are felt when you have a huge document with very large header depths. In that case:
- it becomes easy to get levels wrong with so many large level numbers to deal with. It is much harder to get an ID wrong.
- when you want to move headers around to improve organization, things are quite painful without a refactoring tool (which we intend to provide in the browser editor with preview), as you need to fix up the levels of every single header.If you are using the ID-based syntax however, you only have to move the chunk of headers, and change the
parent
argument of a single top-level header being moved.
Note that when the
because the second header has level
parent=
argument is given, the header level must be 1
, otherwise OurBigBook assumes that something is weird and gives an error. E.g. the following gives an error:
= My h1
== My h2
{parent=my-h1}
2
instead of the required = My h2
.When scopes are involved, the rules are the same as those of internal reference resolution, including the leading
/
to break out of the scope in case of conflicts.Like the
which is equivalent to:
\H
child
argument, parent
also performs ID target from title on the argument, allowing you to use the original spaces and capitalization in the target as in:
= Flying animal
= Bat
{parent=Flying animal}
= Flying animal
= Bat
{parent=flying-animal}
See also: Section 4.2.6.4.5.2. "Header explicit levels vs nesting design choice" for further rationale.
When mixing both
\H
parent
argument and scopes, things get a bit complicated, because when writing or parsing, we have to first determine the parent header before resolving scopes.As a result, the follow simple rules are used:
- start from the last header of the highest level
- check if the
{parent=XXX}
is a suffix of its ID - if not, proceed to the next smaller level, and so on, until a suffix is found
Following those rules for example, a file
will lead to the following header tree with
tmp.bigb
:
= h1
{scope}
= h1 1
{parent=h1}
{scope}
= h1 1 1
{parent=h1-1}
= h1 1 2
{parent=h1-1}
= h1 1 3
{parent=h1/h1-1}
= h1 2
{parent=h1}
{scope}
= h1 2 1
{parent=h1-2}
{scope}
= h1 2 1 1
{parent=h1-2/h1-2-1}
--log headers
:
= h1 tmp
== h2 1 tmp/h1-1
=== h3 1.1 tmp/h1-1/h1-1-1
=== h3 1.2 tmp/h1-1/h1-1-2
=== h3 1.3 tmp/h1-1/h1-1-3
== h2 2 tmp/h1-2
=== h3 2.1 tmp/h1-2/h1-2-1
==== h4 2.1.1 tmp/h1-2/h1-2-1/h1-2-1-1
Arguably, the language would be even saner if we did:
rather than having explicit levels as in
\H[My h1][
Paragraph.
\H[My h2][]
]
\H[1][My h1]
and so on.But we chose not to do it like most markups available because it leads to too many nesting levels, and hard to determine where you are without tooling.
Ciro later "invented" (?)
\H
parent
argument, which he feels reaches the perfect balance between the advantages of those two options.In some use cases, the sections under a section describe inseparable parts of something.
For example, when documenting an experiment you executed, you will generally want an "Introduction", then a "Materials" section, and then a "Results" section for every experiment.
On their own, those sections don't make much sense: they are always referred to in the context of the given experiment.
The problem is then how to get unique IDs for those sections.
One solution, would be to manually add the experiment ID as prefix to every subsection, as in:
= Experiments
See: \x[full-and-unique-experiment-name/materials]
== Introduction
== Full and unique experiment name
=== Introduction
{id=full-and-unique-experiment-name/introduction}
See our awesome results: \x[full-and-unique-experiment-name/results]
For a more general introduction to all experiments, see: \x[introduction].
=== Materials
{id=full-and-unique-experiment-name/materials}
=== Results
{id=full-and-unique-experiment-name/results}
but this would be very tedious.
To keep those IDs shorter, OurBigBook provides the
scope
boolean argument property of headers, which works analogously to C++ namespaces with the header IDs.Using
scope
, the previous example could be written more succinctly as:
= Experiments
See: \x[full-and-unique-experiment-name/materials]
== Introduction
== Full and unique experiment name
{scope}
=== Introduction
See our awesome results: \x[results]
For a more general introduction to all experiments, see: \x[/introduction].
=== Materials
=== Results
Note how:
- full IDs are automatically prefixed by the parent scopes prefixed and joined with a slash
/
- we can refer to other IDs withing the current scope without duplicating the scope. E.g.
\x[results]
in the example already refers to the IDfull-and-unique-experiment-name/materials
- to refer to an ID outside of the scope and avoid name conflicts with IDs inside of the current scope, we start a reference with a slash
/
So in the example above,\x[/introduction]
refers to the IDintroduction
, and notfull-and-unique-experiment-name/introduction
.
When nested scopes are involved, cross references resolution peels off the scopes one by one trying to find the closes match, e.g. the following works as expected:
Here OurBigBook:
= h1
{scope}
== h2
{scope}
=== h3
{scope}
\x[h2]
- first tries to loop for an
h1/h2/h3/h2
, sinceh1/h2/h3
is the current scope, but that ID does not exist - so it removes the
h3
from the current scope, and looks forh1/h2/h2
, which is still not found - then it removes the
h2
, leading toh1/h2
, and that one is found, and therefore is taken
Putting files in subdirectories of the build has the same effect as adding a scope to their top level header.
Notably, all headers inside that directory get the directory prepended to their IDs.
The toplevel directory is determined as described at: the toplevel index file.
For fun and profit.
Let's break this local link: ourbigbook.
When the toplevel header is given the
scope
property OurBigBook automatically uses the file path for the scope and heaves fragments untouched.For example, suppose that file
full-and-unique-experiment-name
contains:
= Full and unique experiment name
{scope}
== Introduction
== Materials
In this case, multi-file output will generate a file called instead of
full-and-unique-experiment-name.html
, and the URL of the subsections will be just:full-and-unique-experiment-name.html#introduction
full-and-unique-experiment-name.html#materials
full-and-unique-experiment-name.html#full-and-unique-experiment-name/introduction
full-and-unique-experiment-name.html#full-and-unique-experiment-name/materials
Some quick interactive cross file link tests:
When using
-S
, --split-headers
, cross references always point to non-split pages as mentioned at cross reference targets in split headers.If the
splitDefault
boolean argument is given however:- the split header becomes the default, e.g.
index.html
is now the split one, andnosplit.html
is the non-split one - the header it is given for, and all of its descendant headers will use the split header as the default internal cross target, unless the header is already rendered in the current page. This does not propagate across includes however.
For example, consider
and
Then the following links would be generated:
README.bigb
:
= Toplevel
{splitDefault}
\x[h2][toplevel to h2]
\x[notreadme][toplevel to notreadme]
\Include[notreadme]
== h2
notreadme.bigb
:
= Notreadme
\x[h2][notreadme to h2]
\x[notreadme][notreadme to notreadme h2]
== Notreadme h2
index.html
: split version ofREADME.bigb
, i.e. does not containh2
toplevel to h2
:h2.html
. Links to the split version ofh2
, sinceh2
is also affected by thesplitDefault
of its parent, and therefore links to it use the split version by defaulttoplevel to notreadme
:notreadme.html
. Links to non-split version ofnotreadme.html
since that header is notsplitDefault
, becausesplitDefault
does not propagate across includes
nosplit.html
non-split version ofREADME.bigb
, i.e. containsh2
toplevel to h2
:#h2
, because even thoughh2
issplitDefault
, that header is already present in the current page, so it would be pointless to reload the split onetoplevel to notreadme
:notreadme.html
h2.html
split version ofh2
fromREADME.bigb
notreadme.html
: non-split version ofnotreadme.bigb
notreadme to h2
:h2.html
, becauseh2
issplitDefault
notreadme to notreadme h2
:#notreadme-h2
notreadme-split.html
: split version ofnotreadme.bigb
notreadme to h2
:h2.html
, becauseh2
issplitDefault
notreadme to notreadme h2
:notreadme.html#notreadme-h2
, becausenotreadme-h2
is notsplitDefault
The major application of this if you like work with a huge
README.bigb
containing thousands of random small topics.Splitting those into separate source files would be quite laborious, as it would require duplicating IDs on the filename, and setting up includes.
However, after this README reaches a certain size, page loads start becoming annoyingly slow, even despite already loading large assets like images video videos only on hover or click: the annoying slowness comes from the loading of the HTML itself before the browser can jump to the ID.
And even worse: this README corresponds to the main index page of the website, which will make what a large number of users will see be that slowness.
Therefore, once this README reaches a certain size, you can add the
splitDefault
attribute to it, to make things smoother for readers.And if you have a smaller, more self-contained, and highly valuable tutorial such as cirosantilli.com/x86-paging, you can just split that into a separate
.bigb
source file.This way, any links into the smaller tutorial will show the entire page as generally desired.
And any links from the tutorial, back to the main massive README will link back to split versions, leading to fast loads.
This feature was implemented at: github.com/ourbigbook/ourbigbook/issues/131
Note that this huge README style is not recommended however. Ciro Santilli used to do it, but moved away from it. The currently recommended approach is to manually create not too large subtrees in each page. This way, readers can easily view several nearby sections without having to load a new page every time.
If given, add a custom suffix to the output filename of the header when using
-S
, --split-headers
.If the given suffix is empty, it defaults to
-split
.For example, given:
a
However, if we instead wrote:
it would not be placed under:
and if we set a custom one as:
it would go instead to:
= my h1
== my h2
--split-headers
conversion would normally place my h2
into a file called:
my-h2.html
== my h2
{splitSuffix}
my-h2-split.html
== my h2
{splitSuffix=asdf}
my-h2-asdf.html
This option is useful if the root of your website is written in OurBigBook, and you want to both:
- have a section that talks about some other project
- host the documentation of that project inside the project source tree
For example, cirosantilli.com with source at github.com/cirosantilli/cirosantilli.github.io has a quick section about OurBigBook: cirosantilli.com#ourbigbook.
Therefore, without a custom suffix, the split header version of that header would go to docs.ourbigbook.com, which would collide with this documentation, that is present in a separate repository: github.com/ourbigbook/ourbigbook.
Therefore a
splitSuffix
property is used, making the split header version fall under /ourbigbook-split
, and leaving the nicer /ourbigbook
for the more important project toplevel.If given on the the toplevel headers, which normally gets a suffix by default to differentiate from the non-split version, it replaces the default
-split
suffix with a custom one.For example if you had
then it would render to:
but if you used instead:
then it would instead be:
notindex.bigb
as:
= Not index
notindex-split.bigb
= Not index
{splitSuffix=asdf}
notindex-asdf.bigb
This option is similar to
\H
title2
argument but it additionally:- creates a new ID that you can refer to, and renders it with the alternate chosen title
- the rendered ID on cross references is the same as what it is a synonym for
- the synonym header is not rendered at all, including in the table of contents
- when using
-S
,--split-headers
, a redirect output file is generated from the synonym to the main ID
Example:
renders something like:
Furthermore, if
which contains a redirection from
= Parent
== GNU Debugger
{c}
= GDB
{c}
{synonym}
I like to say \x[gdb] because it is shorter than \x[gnu-debugger].
= GNU Debugger
I like to say \a[#gnu-debugger][GDB] because it is shorter than \x[#gnu-debugger][GNU Debugger].
-S
, --split-headers
is used, another file is generated:
gdb.html
gdb.html
to gnu-debugger.html
.Implemented at: github.com/ourbigbook/ourbigbook/issues/114
Contains the main content of the header. The insane syntax:
is equivalent to the sane:
and in both cases
= My title
\H[1][My title]
My title
is the title argument.The
title
argument is also notably used for automatic ID from title.If a non-toplevel macro has the Note how those rules leave non-ASCII Unicode characters untouched, except for:as capitalization and determining if something "is a letter or not" in those cases can be tricky.
title
argument is present but no explicit id
argument is given, an Element ID is created automatically from the title
, by applying the following transformations:- do a
id
output format conversion on the title to remove for example any HTML tags that would be present in the conversion output - convert all characters to lowercase. This uses JavaScript case conversion. Note that this does convert non-ASCII characters to lowercase, e.g.
É
toé
. - if
id
normalize
latin
istrue
(the default) do Latin normalization. This converts e.g.é
toe
. - if
id
normalize
punctuation
istrue
(the default) do Punctuation normalization. This converts e.g.+
toplus
. - convert consecutive sequences of all non
a-z0-9
ASCII characters to a single hyphen-
. Note that this leaves non-ASCII characters untouched. - strip leading or trailing hyphens
- capitalization changes wher applicable, e.g.
É
toé
For toplevel headers, see: the ID of the first header is derived from the filename.
So for example, the following automatic IDs would be generated: Table 2. "Examples of automatically generated IDs".
title | id | latin normalization | punctuation normalization | comments |
---|---|---|---|---|
My favorite title | my-favorite-title | |||
Ciro's markdown is awesome | ciro-s-markdown-is-awesome | ' is an ASCII character, but it is not in a-z0-9 , therefore it gets converted to a hyphen - | ||
É你 | e你 | true | The Latin acute accented e , É , is converted to its lower case form é as per the JavaScript case conversion.The Chinese character 你 is left untouched as Chinese characters have no case, and no ASCII analogue. | |
É你 | é你 | false | Same as the previous, but é is not converted to e since Latin normalization is turned off. | |
C++ is great | c-plus-plus-is-great | true | This is the effect of Punctuation normalization. | |
I love dogs. | i-love-dogs | love is extracted from the italic tags <i>love</i> with id output format conversion. | ||
β Centauri | beta-centauri | Our Latin normalization is amazing and knows Greek! |
For the toplevel header, its ID is derived from the basename of the OurBigBook file without extension instead of from the
title
argument.TODO:
- maybe we should also remove some or all non-ASCII punctuation. All can be done with
\\p{IsPunctuation}
: stackoverflow.com/questions/13925454/check-if-string-is-a-punctuation-character but we need to check that we really want to remove all of them.
This conversion type is similar to Automatic ID from title, but it is used in certain cases where we are targeting IDs rather than setting them, notably:
Unlike
which renders something like:
Note how we added the synonym to the title only when it is not just a simple flexion variant, since
\H
title2
argument, the synonym does not show up by default next to the title. This is because we sometimes want that, and sometimes not. To make the title appear, you can simply add an empty title2
argument to the synonym header as in:
= GNU Debugger
{c}
= GDB
{c}
{synonym}
{title2}
= Quantum computing
= Quantum computer
{synonym}
= GNU Debugger (GDB)
= Quantum computing
Quantum computing (Quantum computer)
would be kind of useless would be kind of useless.Same as
is equivalent in every way to:
\x
child
argument but in the opposite direction, e.g.:
== Mammal
=== Bat
{tag=flying-animal}
=== Cat
== Flying animal
== Mammal
=== Bat
=== Cat
== Flying animal
{child=bat}
Naming rationale:So
parent
as the opposite of child is already taken to be then "main parent" via the "\H
parent
argument"- we could have renamed the
\H
child
argument totags
as in "this header tags that one", but it would be a bit confusingtags
vstag
child
vs tag
it is for now.You generally want to use
tag
instead of the \H
child
argument because otherwise some very large header categories are going to contain Huge lists of children, which is not very nice when editing.It is possible to enforce the
\H
child
argument or the \H
tag
argument in a given project with the lint
h-tag
option.The
title2
argument can be given to any element that has the title
argument.Its usage is a bit like the
description=
argument of images, allowing you to add some extra content to the header without affecting its ID.Unlike
description=
however, title2
shows up on all full
references, including appearances in the table of contents, which make it more searchable.Its primary use cases are:
- give acronyms, or other short names names of fuller titles such as mathematical/programming notationOne primary reason to not use the acronyms as the main section name is to avoid possible ID ambiguities with other acronyms.
- give the header in different languages
For example, given the OurBigBook input:
the rendered output looks like:
= Toplevel
The Toc follows:
== North Atlantic Treaty Organization
{c}
{title2=NATO}
\x[north-atlantic-treaty-organization]
\x[north-atlantic-treaty-organization]{full}
= Toplevel
The ToC follows:
* North Atlantic Treaty Organization (NATO)
== North Atlantic Treaty Organization (NATO)
North Atlantic Treaty Organization
Section 1. "North Atlantic Treaty Organization (NATO)"
Related alternatives to
title2
include:\H
disambiguate
argument when you do want to affect the ID to remove ambiguities\H
synonym
argument
Parenthesis are added automatically around all rendered
title2
.The
title2
argument has a special meaning when applied to a header with the \H
synonym
argument, see \H
title2
argument of a synonym header.When the
\H
toplevel
argument is set, the header and its descendants will be automatically output to a separate file, even without -S
, --split-headers
.For example given:
animal.bigb
= Animal
== Vertebrate
=== Dog
{toplevel}
==== Bulldog
== Invertebrate
and if you convert as:
we get the following output files:
ourbigbook animal.bigb
animal.html
: contains the headers: "Animal", "Vertebrate" and "Invertebrate", but not "Dog" and "Bulldog"dog.html
: contains only the headers: "Dog" and "Bulldog"
This option is intended to produce output identical to using includes and separate files, i.e. the above is equivalent to:
animal.bigb
= Animal
== Vertebrate
\Include[dog]
== Invertebrate
dog.bigb
= Dog
{toplevel}
== Bulldog
Or in other words: the toplevel header of each source file gets
{toplevel}
set implicitly for it by default.This design choice might change some day. Arguably, the most awesome setup is on in which source files and outputs are completely decoupled. OurBigBook Web also essentially wants this, as ideally we want to store one source per header there in each DB entry. We shall see.
If given, show a link to the Wikipedia article that corresponds to the header.
If a value is not given, automatically link to the Wiki page that matches the header exactly with spaces converted to underscores.
Here is an example with an explicit wiki argument:
==== Tiananmen Square
{wiki=Tiananmen_Square}
which looks like:
or equivalently with the value deduced from the title:
= Tiananmen Square
{wiki}
which looks like:
You can only link to subsections of wiki pages with explicit links as in:
= History of Tiananmen Square
{{wiki=Tiananmen_Square#History}}
which looks like:
Note that in this case, you either need a literal argument
to avoid the creation of an insane topic link with a single word.
{{}}
or to explicitly escape the #
character as in:
= History of Tiananmen Square
{wiki=Tiananmen_Square\#History}
Also note that Wikipedia subsections are not completely stable, so generally you would rather want to link to a permalink with a full URL as in:
Note that in this case escaping the
= Artificial general intelligence
{wiki=https://en.wikipedia.org/w/index.php?title=Artificial_general_intelligence&oldid=1192191193#Tests_for_human-level_AGI}
#
is not necessary because it is part of the insane link that starts at https://
.OurBigBook automatically adds a table of contents at the end of the first non-toplevel header of every document.
For example, on a standard document with a single toplevel header:
the ToC is rendered something like:
= Animal
Animals are cute!
== Dog
== Cat
= Animal
Animals are cute!
Table of Contents
* Dog
* Cat
== Dog
== Cat
The ToC ignores the toplevel header if you have one.
For when you want a quick outline of the header tree on the terminal, also consider the
--log headers
option.To the left of table of content entries you can click on an open/close icon to toggle the visibility of different levels of the table of contents.
The main use case covered by the expansion algorithm is as follows:
- the page starts with all nodes open to facilitate Ctrl + F queries
- if you click on a node in that sate, you close all its children, to get a summarized overview of the contents
- if you click one of those children, it opens only its own children, so you can interactively continue exploring the tree
The exact behaviour is:
- the clicked node is open:
- state 1 all children are closed. Action: open all children recursively, which puts us in state 2
- state 2: not all children are closed. Action close all children, which puts us in state 1. This gives a good overview of the children, without any children of children getting in the way.
- state 3: the clicked node is closed (not showing any children). Action: open it to show all direct children, but not further descendants (i.e. close those children). This puts us in state 1.
Note that those rules make it impossible to close a node by clicking on it, the only way to close a node os to click on its parent, the state transitions are:but we feel that it is worth it to do things like this to cover the main use case described above without having to add two buttons per entry.
- 3 -> 1
- 1 -> 2
- 2 -> 1
Clicking on the link from a header up to the table of contents also automatically opens up the node for you in case it had been previously closed manually.
OurBigBook adds some header metadata to the toplevel header at the bottom of each page. This section describes this metadata.
Although the table of contents has a macro to specify its placement, it is also automatically placed at the bottom of the page, and could be considered a header metadata section.
Lists other sections that link to the current section.
E.g. in:
the page since those pages link to the
= tmp
== tmp 1
=== tmp 1 1
=== tmp 1 2
\x[tmp-1]
== tmp 2
\x[tmp-1]
tmp-1.html
would contain a list of incoming links as:tmp-1-2
tmp-2
tmp-1
ID.Lists sections that are secondary children of the current section, i.e. tagged under the current section.
The main header tree hierarchy descendants already show under the table of contents instead.
E.g. in:
the tagged sections for:
= tmp
== Mammal
== Flying
== Animal
=== Bat
{tag=mammal}
{tag=flying}
=== Bee
{tag=flying}
=== Dog
{tag=mammal}
- Mammal will contain Bat and Dog
- Flying will contain Bat and Bee
Shows a list of ancestors of the page. E.g. in:
the ancestor lists would be for:so we see that this basically provides a type of breadcrumb navigation.
= Asia
== China
=== Beijing
==== Tiananmen Square
=== Hong Kong
- Hong Kong: China, Asia
- Tiananmen Square: Beijing, China, Asia
- Beijing: China, Asia
- China: Asia
Used to represent a thematic break between paragraph-level elements:
She pressed the button. Just like that, everything was over.
\Hr
The next morning was a gloomy one. Nobody said a word.
which renders as:
She pressed the button. Just like that, everything was over.The next morning was a gloomy one. Nobody said a word.
This macro corresponds to a misfeature of HTML/Markdown, and is not encouraged. We instead recommend creating smaller more specific headers instead to split sections, as this has all the usual advantages of allowing metadata to be associated to the header, such as
-S
, --split-headers
, topic, liked and discussions.But they people asked, and they got it.
A block image with capital 'i'
This exemplifies the following parameters:For further discussion on the effects of ID see: Section 4.2.8.1. "Image ID".
Image
showcasing most of the image properties Figure 12. "The title of my image".
Have a look at this amazing image: \x[image-my-test-image].
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
{title=The title of my image}
{id=image-my-test-image}
{width=600}
{height=200}
{source=https://en.wikipedia.org/wiki/File:Tianasquare.jpg}
{description=The description of my image.}
which renders as:
Have a look at this amazing image: Figure 12. "The title of my image".
title
: analogous to the\H
title
argument. Shows up preeminently, and sets a default ID if one is not given. It is recommended that you don't add a period.
to it, as that would show in cross references- image
description
argument source
: a standardized way to credit an image by linking to a URL that contains further image metadata
And this is how you make an inline image inline one with lower case
i
:
My inline \image[Tank_man_standing_in_front_of_some_tanks.jpg][test image] is awesome.
which renders as:
Inline images can't have captions.And now for an image outside of
\OurBigBookExample
to test how it looks directly under the \Toplevel
implicit macro: Figure 13.Here is an image without a description but with an ID so we can link to it: Figure 14.
This works because
Have a look at this amazing image: \x[image-my-test-image-2].
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
{id=image-my-test-image-2}
which renders as:
Have a look at this amazing image: Figure 14.
full
is the default cross reference style for Image
, otherwise the link text would be empty since there is no title
, and OurBigBook would raise an error.OurBigBook can optionally deduce the title from the basename of the
src
argument if the titleFromSrc
boolean argument is given, or if title-from-src
is set as the default media provider for the media type:
Have a look at this amazing image: \x[image-tank-man-standing-in-front-of-some-tanks].
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
{titleFromSrc}
which renders as:
Have a look at this amazing image: Figure 15. "Tank man standing in front of some tanks.".
If the image has neither ID nor title nor description nor
source
, then it does not get a caption at all:
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
which renders as:
If the image does not have an ID nor title, then it gets an automatically generated ID, just like every other OurBigBook output HTML element, and it is possible for readers to link to that ID on the rendered version, e.g. as:
Note that the
#_123
123
is not linked to the Figure <number>.
, but just a sequential ID that runs over all elements.This type of ID is of course not stable across document revisions however, since if an image is added before that one, the link will break. So give an ID or title for anything that you expect users to link to.
Also, it is not possible to link to such images with an cross reference, like any other OurBigBook element with autogenerated temporary IDs.
Another issue to consider is that in paged output formats like PDF, the image could float away from the text that refers to the image, so you basically always want to refer to image by ID, and not just by saying "the following image".
We can also see that such an image does not increment the Figure count:
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]{id=image-my-test-image-count-before}
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]{id=image-my-test-image-count-after}
which renders as:
If the image has any visible metadata such as
source
or description
however, then the caption does show and the Figure count gets incremented:
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]{source=https://en.wikipedia.org/wiki/File:Tianasquare.jpg}
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]{description=This is the description of my image.}
which renders as:
If you are making a limited repository that will not have a ton of images, then you can get away with simply git tracking your images in the main repository.
With this setup, no further action is needed. For example, with a file structure of:
just use the image from
./README.bigb
./Tank_man_standing_in_front_of_some_tanks.jpg
README.bigb
as:
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
which renders as:
However, if you are making a huge tutorial, which can have a huge undefined number of images (i.e. any scientific book), then you likely don't want to git track your images in the git repository.
A generally better alternative is to store images in a separate media repository, and especially store images in a separate media repository and track it as a git submodule.
In this approach, you create a separate GitHub repository in addition to the main one containing the text to contain only media such as images.
This approach is more suitable than store images inside the repository itself if you are going to have a lot of images.
When using this approach, you could of course just point directly to the final image URL, e.g. as in:
but OurBigBook allows you use configurations that allow you to enter just the image basename:
\Image[https://raw.githubusercontent.com/ourbigbook/ourbigbook-media/master/Fundamental_theorem_of_calculus_topic_page_arrow_to_full_article.png]
which renders as:
Fundamental_theorem_of_calculus_topic_page_arrow_to_full_article.png
which we will cover next.In order to get this to work, the recommended repository setup is:The directory and repository names are not mandatory, but if you place media in
./main-repo/.git
: main repository at github.com/username/main-repo./main-repo/data/media/.git/
: media repository at github.com/username/main-repo-media, and wheredata/
is gitignored.
data/media
and name its repository by adding the *-media
suffix, then ourbigbook
will handle everything for you without any further configuration in media-providers
.This particular documentation repository does have a different setup as can be seen from its ourbigbook.json. Then, when everything is setup correctly, we can refer to images simply as:
In this example, we also needed to set
\Image[Fundamental_theorem_of_calculus_topic_page_arrow_to_full_article.png]{provider=github}
which renders as:
{provider=github}
explicitly since it was not set as the default image provider in our ourbigbook.json
. In most projects however, all of your images will be in the default repository, so this won't be needed.provider
must not be given when a full URL is given because we automatically detect providers from URLs, e.g.:
\Image[https://raw.githubusercontent.com/ourbigbook/ourbigbook-media/master/Fundamental_theorem_of_calculus_topic_page.png]{provider=github}
TODO implement:
ourbigbook
will even automatically add and push used images in the my-tutorial-media
repository for you during publishing!You should then use the following rules inside This way, even though the repositories are not fully in sync, anyone who clones the latest version of the
my-tutorial-media
:- give every file a very descriptive and unique name as a full English sentence
- never ever delete any files, nor change their content, unless it is an improvement in format that does change the information contained of the image TODO link to nice Wikimedia Commons guideline page
*-media
directory will be able to view any version of the main repository.Then, if one day the media repository ever blows up GitHub's limit, you can just migrate the images to another image server that allows arbitrary basenames, e.g. AWS, and just configure your project to use that new media base URL with the
media-providers
option.The reason why images should be kept in a separate repository is that images are hundreds or thousands of times larger than hand written text.
Therefore, images could easily fill up the maximum repository size you are allowed: webapps.stackexchange.com/questions/45254/file-size-and-storage-limits-on-github#84746 and then what will you do when GitHub comes asking you to reduce the repository size?
Git LFS is one approach to deal with this, but we feel that it adds too much development overhead.
This is likely the sanest approach possible, as it clearly specifies which media version matches which repository version through the submodule link.
Furthermore, it is possible to make the submodule clone completely optional by setting things up as follows. For your OurBigBook project
yourname/myproject
create a yourname/myproject-media
with the media, and track it as a submodule under yourname/myproject/media
.Then, add to
media-providers
:
"media-providers": {
"github": {
"default-for": ["image", "video"],
"path": "media",
"remote": "yourname/myproject-media"
}
}
Now, as mentioned at
media-providers
, everything will work beautifully:ourbigbook .
local conversion will use images frommedia/
if it exists, e.g.:will render\Image[myimage.jpg]
media/myimage.jpg
. So after cloning the submodule, you will be able to see the images on the rendered pages without an internet connection.But if the submodule is not cloned, not problem, renders will detect that and automatically use GitHub images.Then, when you do:the following happen:ourbigbook --publish
\Image[myimage.jpg]
uses the GitHub URL- automatically push
media/
to GitHub in case there were any updates - also, that directory is automatically gitignore, so it won't be pushed as part of the main render and thus duplicate things
Wikimedia Commons is another great possibility to upload your images to:
\Image[https://upload.wikimedia.org/wikipedia/commons/thumb/5/5b/Gel_electrophoresis_insert_comb.jpg/450px-Gel_electrophoresis_insert_comb.jpg]
{source=https://commons.wikimedia.org/wiki/File:Gel_electrophoresis_insert_comb.jpg}
which renders as:
OurBigBook likes Wikimedia Commons so much that we automatically parse the image URL and if it is from Wikimedia Commons, automatically deduce the
source
for you. So the above image renders the same without the source
argument:
\Image[https://upload.wikimedia.org/wikipedia/commons/5/5b/Gel_electrophoresis_insert_comb.jpg]
which renders as:
And like for non-Wikimedia images, you can automatically generate a
title
from the src
by setting the titleFromSrc
boolean argument or if title-from-src
is set as the default media provider for the media type:
\Image[https://upload.wikimedia.org/wikipedia/commons/5/5b/Gel_electrophoresis_insert_comb.jpg]
{titleFromSrc}
which renders as:
And a quick test for a more complex thumb resized URL:
\Image[https://upload.wikimedia.org/wikipedia/commons/thumb/5/5b/Gel_electrophoresis_insert_comb.jpg/450px-Gel_electrophoresis_insert_comb.jpg]
which renders as:
If you really absolutely want to turn off the
but you don't want to do that for the most commonly Wikimedia Commons used license of CC BY+, do you? :-)
source
, you can explicitly set:
\Image[https://upload.wikimedia.org/wikipedia/commons/5/5b/Gel_electrophoresis_insert_comb.jpg]
{source=}
which renders as:
Upsides of using Wikimedia Commons for your images:Downsides:
- makes it easier for other writers to find and reuse your images
- automatically generates resized versions of the uploaded images into several common dimensions so you can pick the smallest one that fits your desired image height to reduce bandwidth usage
- if you have so many images that they would blow even the size of a separate media repository, this will still work
- forces you to use the Creative Commons license
- requires the content to be educational in nature
- uploading a bunch of images to Wikimedia Commons does feel a bit more laborious than it should because you have to write down so much repeated metadata for them
We do this by default because OurBigBook is meant to allow producing huge single page documents like Ciro likes it, and in this way:
- images that the user is looking at will load first
- we save a lot of bandwidth for the user who only wants to browse one section
TODO: maybe create a mechanism to disable this for the entire build with
ourbigbook.json
.For the love of God, there is no standardized for SVG to set its background color without a rectangle? stackoverflow.com/questions/11293026/default-background-color-of-svg-root-element
viewport-fill
was just left in limbo?And as a result, many many many SVG online images that you might want to reuse just rely on white pages and don't add that background rectangle.
Therefore for now we just force white background on our default CSS of block images, which is what most SVGs will work with. Otherwise, you can lose the entire image to our default black background.
For inline images however, a white background would also be very distracting compared to the nearby inline text, and it would prevent the use case of making rounded smileys, so for now we are just not forcing the background color in that case.
At some point we might just add a
color
argument to set the background color to an arbitrary value so that authors can decide what is better for each image.TODO implement: mechanism where you enter a textual description of the image inside the code body, and it then converts to an image, adds to the
-media
repo and pushes all automatically. Start with dot.Many image arguments arguments are shared between both block and inline images, but not all.
Adds a border around the image. This can be useful to make it clearer where images start and end when the image background color is the same as the background color of the OurBigBook document.
\Image[logo.svg]
{border}
{height=150}
{title=Logo of the OurBigBook Project with a border around it}
which renders as:
The
description
argument similar to the image title
argument argument, but allows allowing longer explanations without them appearing in cross references to the image.For example, consider:
In this example, the reference
and does not include the description, which only shows on the image.
See this image: \x[image-description-argument-test-1].
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
{title=Tank man standing in front of some tanks}
{id=image-description-argument-test-1}
{description=Note how the tanks are green.}
{source=https://en.wikipedia.org/wiki/File:Tianasquare.jpg}
which renders as:
See this image: Figure 25. "Tank man standing in front of some tanks".
\x[image-description-argument-test-1]
expands just to
Tank man standing in front of some tanks
The description can be as large as you like. If it gets really large however, you might want to consider moving the image to its own header to keep things slightly saner. This will be especially true after we eventually do: github.com/ourbigbook/ourbigbook/issues/180.
If the description contains any element that would take its own separate line, like multiple paragraphs or a list, we automatically add a line grouping the description with the corresponding image to make that clearer, otherwise it can be hard to know which title corresponds to a far away image. Example with multiple paragraphs:
Stuff before the image.
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
{title=Tank man standing in front of some tanks}
{id=image-description-argument-test-2}
{source=https://en.wikipedia.org/wiki/File:Tianasquare.jpg}
{description=Note how the tanks are green.
But the shirt is white.}
Stuff after the image description.
which renders as:
Stuff before the image.Stuff after the image description.
We recommend adding a period or other punctuation to the end of every description.
Analogous to the
\a
external
argument when checking if the image src
argument exists or not.By default, we fix image heights to When the viewport is narrow enough, mobile CSS takes over and forces block images to fill 100% of the page width instead, removing the scrollbar.
height=315
, and let the width
be calculated proportionally once the image loads. We therefore ignore the actual image size. This is done to:- prevent reflows as the page loads images and can determine their actual sizes, especially is the user opens the page at a given ID in the middle of the page
- create a more uniform media experience by default, unless a custom image size is actually needed e.g. if the image needs to be larger
Inline images on the other hand never get a horizontal scrollbar, they are just always capped at viewport width.
When the
height
argument is given, it changes that default height. Width is still just calculated proportionally to this new custom height.\Image[logo.svg]
{height=150}
which renders as:
\Image[logo.svg]
{height=550}
which renders as:
Here's a very long test image:
If given, make clicking an image go to the specified URL rather than the image's URL as is the default.
By default, clicking on a rendered image links to the URL of the image itself. E.g. clicking:
would open Tank_man_standing_in_front_of_some_tanks.jpg as produces
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
which renders as:
img
surrounded by something like a href="Tank_man_standing_in_front_of_some_tanks.jpg"
.If insetad we want the image to point to a custom URL, e.g. ourbigbook.com we could instead write:
and now clicking the image leads to ourbigbook.com instead.
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]{link=https://ourbigbook.com}
which renders as:
Where the image was taken from, e.g.:
\Image[https://upload.wikimedia.org/wikipedia/commons/6/68/Akha_cropped_hires.JPG]
{title=A couple}
{source=https://en.wikipedia.org/wiki/Human}
which renders as:
The
source
is automatically inferred for certain known websites, e.g.:- Wikimedia
https://upload.wikimedia.org/wikipedia/commons
Example:\Image[https://upload.wikimedia.org/wikipedia/commons/6/68/Akha_cropped_hires.JPG] {title=A couple no source}
which renders as:
The address of the image, e.g. in:
the
\Image[image.png]
src
is image.png
.Analogous to the
\a
href
argument.Analogous to the
\H
title
argument.This argument is meant to be analogous to the Image
height
argument but for images.Usage of this argument is generally discouraged, as we always set the default image height by default, so that also passing a width is either unnecessary or may lead to changes in the image's correct aspect ratio.
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
{width=150}
which renders as:
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
{width=550}
which renders as:
The
\Include
macro allows including an external OurBigBook headers under the current header.It exists to allow optional single page HTML output while still retaining the ability to:
- split up large input files into multiple files to make renders faster during document development
- suggest an optional custom output split with one HTML output per OurBigBook input, in order to avoid extremely large HTML pages which could be slow to load
\Include
takes one mandatory argument: the ID of the section to be included, much like cross references.There is however one restriction: only the toplevel headers can be pointed to. This restriction allows us to easily find the included file in the filesystem, and dispenses the need to do a first
./ourbigbook
run to generate the ID database. This works because the ID of the first header is derived from the filename.Headers of the included document are automatically shifted to match the level of the child of the level where they are being included.
If
--embed-includes
is given, the external document is rendered embedded into the current document directly, essentially as if the source had been copy pasted (except for small corrections such as the header offsets).Otherwise, the following effects happen:
- The headers of the included tree appear in the table of contents of the document as links to the corresponding external files.This is implemented simply by reading a previously generated database file much like cross file reference internals, which avoids the slowdown of parsing all included files every time.As a result, you have to do an initial parse of all files in the project to extract their headers however, just as you would need to do when linking to those headers.
- the include itself renders as a link to the included document
--embed-includes
Here is an example of inclusion of the files
The above is the recommended and slightly insaner version of:
The insaner version is a bit insaner because the
not-readme.bigb
and not-readme-2.bigb
:
\Include[not-readme]
\Include[not-readme-2]
\Include[not-readme-with-scope]
\Include[not-readme]
\Include[not-readme-2]
\Include[not-readme-with-scope]
\Include
magically discards the following newline node that follows it if it just a plaintext node containing exactly a newline. With a double newline, the newline would already have been previously taken out on the lexing stage as part of a paragraph.Section 4.2.9.3. "
\Include
example" shows what those actually render like.When you are in a subdirectory, include resolution just is simply relative to the subdirectory. E.g. we could do:
subdir/index.bigb
= Subdir
\Include[notindex]
\Include[subdir2/notindex]
subdir/notindex.bigb
= Notindex
subdir/subdir2/notindex.bigb
= Notindex
It is not currently possible to include from ancestor directories: github.com/ourbigbook/ourbigbook/issues/214.
This option is analogous to
\H
parent
argument, but for includes.For example, consider you have:
and now you want to split
= Animal
== Dog
== Cat
== Bat
Cat
to cat.bigb
.If you wrote:
Cat would be a child of Dog, since that is the previous header, which is not what we want.
= Animal
== Dog
\Include[cat]
== Bat
Instead, we want to write:
and now Cat will be a child of Animal as desired.
= Animal
== Dog
\Include[cat]{parent=animal}
== Bat
Implemented at: github.com/ourbigbook/ourbigbook/issues/127
This shows what includes render as.
Some \i[italic] text.
which renders as:
Some italic text.
The
JsCanvasDemo
macro allows you to create interactive HTML/JavaScript canvas demos easily.These demos:so you can stuff as many of them as you want on a page, and they won't cause the reader's CPU to fry an egg.
- only start running when the user scrolls over them for the first time
- stop automatically when they leave the viewport
\JsCanvasDemo[[
new class extends OurbigbookCanvasDemo {
init() {
super.init('hello');
this.pixel_size_input = this.addInputAfterEnable(
'Pixel size',
{
'min': 1,
'type': 'number',
'value': 1,
}
);
}
draw() {
var pixel_size = parseInt(this.pixel_size_input.value);
for (var x = 0; x < this.width; x += pixel_size) {
for (var y = 0; y < this.height; y += pixel_size) {
var b = ((1.0 + Math.sin(this.time * Math.PI / 16)) / 2.0);
this.ctx.fillStyle =
'rgba(' +
(x / this.width) * 255 + ',' +
(y / this.height) * 255 + ',' +
b * 255 +
',255)'
;
this.ctx.fillRect(x, y, pixel_size, pixel_size);
}
}
}
}
]]
which renders as:
new class extends OurbigbookCanvasDemo { init() { super.init('hello'); this.pixel_size_input = this.addInputAfterEnable( 'Pixel size', { 'min': 1, 'type': 'number', 'value': 1, } ); } draw() { var pixel_size = parseInt(this.pixel_size_input.value); for (var x = 0; x < this.width; x += pixel_size) { for (var y = 0; y < this.height; y += pixel_size) { var b = ((1.0 + Math.sin(this.time * Math.PI / 16)) / 2.0); this.ctx.fillStyle = 'rgba(' + (x / this.width) * 255 + ',' + (y / this.height) * 255 + ',' + b * 255 + ',255)' ; this.ctx.fillRect(x, y, pixel_size, pixel_size); } } } }
And another one showing off some WebGL:
new class extends OurbigbookCanvasDemo {
init() {
super.init('webgl', {context_type: 'webgl'});
this.ctx.viewport(0, 0, this.ctx.drawingBufferWidth, this.ctx.drawingBufferHeight);
this.ctx.clearColor(0.0, 0.0, 0.0, 1.0);
this.vertexShaderSource = `
#version 100
precision highp float;
attribute float position;
void main() {
gl_Position = vec4(position, 0.0, 0.0, 1.0);
gl_PointSize = 64.0;
}
`;
this.fragmentShaderSource = `
#version 100
precision mediump float;
void main() {
gl_FragColor = vec4(0.18, 0.0, 0.34, 1.0);
}
`;
this.vertexShader = this.ctx.createShader(this.ctx.VERTEX_SHADER);
this.ctx.shaderSource(this.vertexShader, this.vertexShaderSource);
this.ctx.compileShader(this.vertexShader);
this.fragmentShader = this.ctx.createShader(this.ctx.FRAGMENT_SHADER);
this.ctx.shaderSource(this.fragmentShader, this.fragmentShaderSource);
this.ctx.compileShader(this.fragmentShader);
this.program = this.ctx.createProgram();
this.ctx.attachShader(this.program, this.vertexShader);
this.ctx.attachShader(this.program, this.fragmentShader);
this.ctx.linkProgram(this.program);
this.ctx.detachShader(this.program, this.vertexShader);
this.ctx.detachShader(this.program, this.fragmentShader);
this.ctx.deleteShader(this.vertexShader);
this.ctx.deleteShader(this.fragmentShader);
if (!this.ctx.getProgramParameter(this.program, this.ctx.LINK_STATUS)) {
console.log('error ' + this.ctx.getProgramInfoLog(this.program));
return;
}
this.ctx.enableVertexAttribArray(0);
var buffer = this.ctx.createBuffer();
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, buffer);
this.ctx.vertexAttribPointer(0, 1, this.ctx.FLOAT, false, 0, 0);
this.ctx.useProgram(this.program);
}
draw() {
this.ctx.clear(this.ctx.COLOR_BUFFER_BIT);
this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array([Math.sin(this.time / 60.0)]), this.ctx.STATIC_DRAW);
this.ctx.drawArrays(this.ctx.POINTS, 0, 1);
}
}
Equivalent fully sane with explicit container:
\Ul[
\L[a]
\L[b]
\L[c]
]
which renders as:
- a
- b
- c
The explicit container is required if you want to pass extra arguments properties to the
This is the case because without the explicit container in an implicit
ul
list macro, e.g. a title and an ID: Ul 1:
\Ul
{id=list-my-id}
[
\L[a]
\L[b]
\L[c]
]
which renders as:
- a
- b
- c
ul
list, the arguments would stick to the last list item instead of the list itself.It is also required if you want ordered lists:
\Ol[
\L[first]
\L[second]
\L[third]
]
which renders as:
- first
- second
- third
Insane nested list with two space indentation:
The indentation must always be exactly equal to two spaces, anything else leads to errors or unintended output.
* a
* a1
* a2
* a2
* b
* c
which renders as:
- a
- a1
- a2
- a2
- b
- c
Equivalent saner nested lists with implicit containers:
\L[
a
\L[a1]
\L[a2]
\L[a2]
]
\L[b]
\L[c]
which renders as:
- a
- a1
- a2
- a2
- b
- c
Insane list item with a paragraph inside of it:
* a
* I have
Multiple paragraphs.
* And
* also
* a
* list
* c
which renders as:
- a
I haveMultiple paragraphs.
- And
- also
- a
- list
- c
Equivalent sane version:
\L[a]
\L[
I have
Multiple paragraphs.
\L[And]
\L[also]
\L[a]
\L[list]
]
\L[c]
which renders as:
- a
I haveMultiple paragraphs.
- And
- also
- a
- list
- c
Insane lists may be escaped with a backslash as usual:
\* paragraph starting with an asterisk.
which renders as:
* paragraph starting with an asterisk.
You can also start insane lists immediately at the start of a positional or named argument, e.g.:
\P[* a
* b
* c
]
which renders as:
- a
- b
- c
And now a list outside of
\OurBigBookExample
to test how it looks directly under the \Toplevel
implicit macro:- a
- b
- c
Via KaTeX server side, oh yes!
Inline math is done with the dollar sign (
and block math is done with two or more dollar signs (
$
) insane macro shortcut:
My inline $\sqrt{1 + 1}$ is awesome.
which renders as:
My inline is awesome.
$$
):
$$
\sqrt{1 + 1} \\
\sqrt{1 + 1}
$$
which renders as:
The sane version of inline math is a lower case
and the sane version of block math is with an upper case
m
:
My inline \m[[\sqrt{1 + 1}]] is awesome.
which renders as:
My inline is awesome.
M
:
\M[[
\sqrt{1 + 1} \\
\sqrt{1 + 1}
]]
which renders as:
The capital vs lower case theme is also used in other elements, see: block vs inline macros.
In the sane syntax, as with any other argument, you have to either escape any closing square brackets
or with the equivalent double open and close:
]
with a backslash \
:
My inline \m[1 - \[1 + 1\] = -1] is awesome.
which renders as:
My inline is awesome.
My inline \m[[1 - [1 + 1] = -1]] is awesome.
Equation IDs and titles and linking to equations works identically to images, see that section for full details. Here is one equation reference example that links to the following insane syntax equation: Equation 7. "My first insane equation":
$$
\sqrt{1 + 1}
$$
{title=My first insane equation}
which renders as:
and the sane equivalent Equation 8. "My first sane equation":
\M{title=My first sane equation}[[
\sqrt{1 + 1}
]]
which renders as:
Here is a raw one just to test the formatting outside of a
ourbigbook_comment
:
Here is a very long math equation:
See the: <equation Pytogoras theorem>.
$$
c = \sqrt{a^2 + b^2}
$$
{title=Pytogoras theorem}
{description=This important equation allows us to find the distance between two points.}
which renders as:
See the: Equation 11. "Pytogoras theorem".
Example:
See the: <equation Riemann zeta function>.
$$
\zeta(s) = \sum_{n=1}^\infty \frac{1}{n^s}
$$
{title=Riemann zeta function}
which renders as:
See the: Equation 12. "Riemann zeta function".
OurBigBook ships with several commonly used math macros enabled by default.
The full list of built-in macros can be seen at: default.tex.
Here's one example of using
\dv
from the physics
package for derivatives:
$$
\dv{x^2}{x} = 2x
$$
which renders as:
Our goal is to collect the most popular macros from the most popular pre-existing LaTeX packages and make them available with this mechanism.
The built-in macros are currently only available on OurBigBook CLI and OurBigBook Web, not when using the JavaScript API directly. We should likely make that possible as well at some point.
If your project has multiple
.bigb
input files, you can share Mathematics definitions across all files by adding them to the ourbigbook.tex
file on the toplevel directory.For example, if
then from any
ourbigbook.tex
contains:
\newcommand{\foo}[0]{bar}
.bigb
file we in the project can use:
$$
\foo
$$
Note however that this is not portable to OurBigBook Web and will likely never be, as we want Web source to be reusable across authors. So the ony way to avoid macro definition conflicts would be to have a namespace system in place, which sounds hard/impossible.
Ideally, you should only use this as a temporary mechanism while you make a pull request to modify the built-in math macros :-)
Besides using
ourbigbook.tex
, you can also define your own math macros directly in the source code.This is generally fragile however because it doesn't work:
- across headers on OurBigBook Web
- across different source files on OurBigBook CLI. That can be worked around with
ourbigbook.tex
on CLI, butourbigbook.tex
does not work on Web either.
If you still want to do it for some reason, first create an invisible block (with
{show=0}
) defining with a \newcommand
definition:
$$
\newcommand{\foo}[0]{bar}
$${show=0}
which renders as:
We make it invisible because this block only contains KaTeX definitions, and should not render to anything.
Analogously with
\def
, definition:
$$
\gdef\foogdef{bar}
$${show=0}
which renders as:
and the second block using it:
$$
\foogdef
$$
which renders as:
And just to test that
{show=1}
actually shows, although it is useless, and that {show=0}
skips incrementing the equation count:
$$1 + 1$${show=1}
$$2 + 2$${show=0}
$$3 + 3$${show=1}
which renders as:
Shows both the OurBigBook code and its rendered output, e.g.:
\OurBigBookExample[[
Some `ineline` code.
]]
which renders as:
Some `ineline` code.
which renders as:Someineline
code.
Its input should be thought of as a literal code string, and it then injects the rendered output in the document.
This macro is used extensively in the OurBigBook documentation.
OK, this is too common, so we opted for some insanity here: double newline is a paragraph!
Paragraph 1.
Paragraph 2.
which renders as:
Paragraph 1.Paragraph 2.
Equivalently however, you can use an explicit
\P
macros as well, which is required for example to add properties to a paragraph, e.g.:
\P{id=paragraph-1}[Paragraph 1]
\P{id=paragraph-2}[Paragraph 2]
which renders as:
Paragraph 1Paragraph 2
Paragraphs are created automatically inside macro argument whenever a double newline appears.
Note that OurBigBook paragraphs render in HTML as
which renders as a single paragraph.
div
with class="p"
and not as p
. This means that you can add basically anything inside them, e.g. a list:
My favorite list is:
\Ul[
\li[aa]
\li[bb]
]
because it is simple.
One major advantage of this, is that when writing documentation, you often want to keep lists or code blocks inside a given paragraph, so that it is easy to reference the entire paragraph with an ID. Think for example of paragraphs in the C++ standard.
Dumps its contents directly into the rendered output.
This construct is not XSS safe, see: Section 10.2. "unsafe-xss . "
Here for example we define a paragraph in raw HTML:
\passthrough[[
<p>Hello <b>raw</b> HTML!</p>
]]
which renders as:
Hello raw HTML!
And for an inline passthrough:
Hello \passthrough[[<b>raw</b>]] world!
which renders as:
Hellorawworld!
And so he said:
\Q[
Something very smart
And with multiple paragraphs.
]
and it was great.
which renders as:
And so he said:Something very smartAnd with multiple paragraphs.and it was great.
And so he said:
> Something very smart
And with multiple paragraphs.
and it was great.
which renders as:
And so he said:Something very smartAnd with multiple paragraphs.and it was great.
Example with explicit macro:
See the: <quote Hamlet what we are>.
\Q[We know what we are, but not what we may be.]
{title=Hamlet what we are}
{description=This quote refers to human's inability to know their own potential, despite understanding their current abilities.}
which renders as:
See the: Quote 1. "Hamlet what we are".We know what we are, but not what we may be.
Example with implicit syntax:
See the: <quote Hamlet what we are implicit>.
> We know what we are, but not what we may be.
{title=Hamlet what we are implicit}
{description=This quote refers to human's inability to know their own potential, despite understanding their current abilities.}
which renders as:
See the: Quote 2. "Hamlet what we are implicit".We know what we are, but not what we may be.
Example with explicit macro:
See the: <quote Julius Caesar star>.
\Q[The fault, dear Brutus, is not in our stars, but in ourselves.]
{title=Julius Caesar star}
which renders as:
See the: Quote 3. "Julius Caesar star".The fault, dear Brutus, is not in our stars, but in ourselves.
Example with implicit syntax:
See the: <quote Julius Caesar star implicit>.
> The fault, dear Brutus, is not in our stars, but in ourselves.
{title=Julius Caesar star implicit}
which renders as:
See the: Quote 4. "Julius Caesar star implicit".The fault, dear Brutus, is not in our stars, but in ourselves.
The insane syntax marks:For example:
Empty cells are allowed without the trailing space however:
- headers with
||
(pipe, pipe space) at the start of a line - regular cells with
|
(pipe, space) at the start of a line - separates rows with double newline
|| Header 1
|| Header 2
| 1 1
| 1 2
| 2 1
| 2 2
which renders as:
Header 1 Header 2 1 1 1 2 2 1 2 2
| 1 1
|
| 1 3
| 2 1
|
| 2 3
which renders as:
1 1 1 3 2 1 2 3
Equivalent fully explicit version:
Any white space indentation inside an explicit
\Table[
\Tr[
\Th[Header 1]
\Th[Header 2]
]
\Tr[
\Td[1 1]
\Td[1 2]
]
\Tr[
\Td[2 1]
\Td[2 2]
]
]
which renders as:
Header 1 Header 2 1 1 1 2 2 1 2 2
\Tr
can make the code more readable, and is automatically removed from final output due to remove_whitespace_children
which is set for \Table
.To pass further arguments to an implicit table such as
We would like to remove that explicit toplevel requirement as per: github.com/ourbigbook/ourbigbook/issues/186 The rules of when the caption shows up or not similar to those of images as mentioned at Section 4.2.8.1.1. "Image caption".
title
or id
, you need to use an explicit table
macro as in: Table 3. "My table title".
\Table
{title=My table title}
{id=table-my-table}
[
|| Header 1
|| Header 2
| 1 1
| 1 2
| 2 1
| 2 2
]
which renders as:
Header 1 Header 2 1 1 1 2 2 1 2 2
Multiple source lines, including paragraphs, can be added to a single cell with insane syntax by indenting the cell with exactly two spaces just as for lists, e.g.:
Arbitrarily complex nested constructs may be used, e.g. a table inside a list inside table:
|| h1
|| h2
|| h3
h3 2
| 11
| 12
12 2
| 13
| 21
| 22
| 23
which renders as:
h1 h2 h3h3 211 1212 213 21 22 23
| 00
| 01
* l1
* l2
| 20
| 21
| 30
| 31
| 10
| 11
which renders as:
00 01
- l1
l2
20 21 30 31 10 11
And now a table outside of
\OurBigBookExample
to test how it looks directly under the \Toplevel
implicit macro:Header 1 | Header 2 |
---|---|
1 1 | 1 2 |
2 1 | 2 2 |
And a fully insane one:
Header 1 | Header 2 |
---|---|
1 1 | 1 2 |
2 1 | 2 2 |
And now a larger one to see how the style is looking:
Header 1 | Header 2 | Header 3 | Header 4 |
---|---|---|---|
1 1 | 1 2 | 1 3 | 1 4 |
2 1 | 2 2 | 2 3 | 2 4 |
3 1 | 3 2 | 3 3 | 3 4 |
4 1 | 4 2 | 4 3 | 4 4 |
5 1 | 5 2 | 5 3 | 5 4 |
6 1 | 6 2 | 6 3 | 6 4 |
7 1 | 7 2 | 7 3 | 7 4 |
8 1 | 8 2 | 8 3 | 8 4 |
JavaScript interactive on-click table sorting is enabled by default, try it out by clicking on the header row:
Powered by: github.com/tristen/tablesort
|| String col
|| Integer col
|| Float col
| ab
| 2
| 10.1
| a
| 10
| 10.2
| c
| 2
| 3.4
which renders as:
String col Integer col Float col ab 2 10.1 a 10 10.2 c 2 3.4
Very analogous to images, only differences will be documented here.
In the case of videos, where to store images becomes even more critical since videos are even larger than images, such that the following storage approaches are impractical off the bat:As a result, then Wikimedia Commons is one of the best options much like for images:
We also handle more complex transcoded video URLs just fine:
Commons is better than YouTube if your content is on-topic there because:
\Video[https://upload.wikimedia.org/wikipedia/commons/8/85/Vacuum_pump_filter_cut_and_place_in_eppendorf.webm]
{id=sample-video-in-wikimedia-commons}
{title=Nice sample video stored in Wikimedia Commons}
{start=5}
which renders as:
\Video[https://upload.wikimedia.org/wikipedia/commons/transcoded/1/19/Scientific_Industries_Inc_Vortex-Genie_2_running.ogv/Scientific_Industries_Inc_Vortex-Genie_2_running.ogv.480p.vp9.webm]
{id=sample-video-in-wikimedia-commons-transcoded}
{title=Nice sample video stored in Wikimedia Commons transcoded}
which renders as:
- they have no ads
- it allows download of the videos: www.quora.com/Can-I-download-Creative-Commons-licensed-YouTube-videos-to-edit-them-and-use-them.
- it makes it easier for other users to find and re-use your videos
If your video does not fit the above Wikimedia Commons requirements, YouTube could be a good bet. OurBigBook automatically detects YouTube URLs for you, so the following should just work:
The
Alternatively, you can reach the same result in a more explicit and minimal way by setting
When the
Remember that you can also enable the
\Video[https://youtube.com/watch?v=YeFzeNAHEhU&t=38]
{id=sample-video-from-youtube-implicit-youtube}
{title=Nice sample video embedded from YouTube implicit from `youtube.com` URL}
which renders as:
youtu.be
domain hack URLs also work;
\Video[https://youtu.be/YeFzeNAHEhU?t=38]
{id=sample-video-from-youtube-implicit-youtu-be}
{title=Nice sample video embedded from YouTube implicit from `youtu.be` URL}
which renders as:
{provider=youtube}
and the start
arguments:
\Video[YeFzeNAHEhU]{provider=youtube}
{id=sample-video-from-youtube-explicit}
{title=Nice sample video embedded from YouTube with explicit `youtube` argument}
{start=38}
which renders as:
youtube
provider is selected, the Video address should only to contain the YouTube video ID, which shows in the YouTube URL for the video as:
https://www.youtube.com/watch?v=<video-id>
youtube
provider by default on your ourbigbook.json
with:
"media-provider" {
"youtube": {"default-for": "video"}
}
But you can also use raw video files from any location that can serve them of course, e.g. here is one stored in this repository: Video 11. "Nice sample video stored in this repository".
\Video[Tank_man_side_hopping_in_front_of_some_tanks.mp4]
{id=sample-video-in-repository}
{title=Nice sample video stored in this repository}
{source=https://www.youtube.com/watch?v=YeFzeNAHEhU}
{start=3}
which renders as:
And as for images, setting
titleFromSrc
automatically calculates a title for you:
\Video[Tank_man_side_hopping_in_front_of_some_tanks.mp4]
{titleFromSrc}
{source=https://www.youtube.com/watch?v=YeFzeNAHEhU}
which renders as:
Unlike image lazy loading, we don't support video lazy loading yet because:
- non-
youtube
videos use thevideo
tag which has noloading
property yet youtube
videos are embedded withiframe
andiframe
has noloading
property yet
Both of this cases could be worked around with JavaScript:
- non-
youtube
: setsrc
from JavaScript as shown for images: stackoverflow.com/questions/2321907/how-do-you-make-images-load-lazily-only-when-they-are-in-the-viewport/57389607#57389607.But this breaks page semantics however, we don't know how to work around that youtube
videos: same as above for theiframe
, but this should be less problematic since YouTube videos are not viewable without JavaScript anyways, and who cares aboutiframe
semantics?
The time to start playing the video at in seconds. Works for both
youtube
and non-YouTube videos.Every macro in OurBigBook can have an optional
id
and many also have a reserved title
property.When a macro in the document has a
title
argument but no id
argument given, get an auto-generated ID from the title: automatic ID from title.Usually, the most convenient way to write cross references is with the insane syntax with delimited angled braces:
More details at: insane cross reference.
<Cross references> are awesome.
which renders as:
Cross references are awesome.
The sane equivalent to this is:
Note how that is more verbose, especially because here we use both the
\x[cross-reference]{c}{p} are awesome section.
which renders as:
Cross references are awesome section.
\x
c
argument and \x
p
argument to capitalize and pluraize as desired.Another sane equivalent would be to add an explicit link body as in:
\x[cross-reference][Cross references] are awesome.
which renders as:
Cross references are awesome.
When you use an insane cross reference (
it gets expanded exactly to the sane equivalent:
so we see that the
<>
) such as in:
<Cross references> are awesome.
which renders as:
Cross references are awesome.
\x[Cross references]{magic} are alwasome
\x
magic
argument gets added. It is that argument that for example adds the missing -
, and removes the pluralization to find the correct ID cross-reference
. For more details, see the documentation of the \x
magic
argument.Like other insane constructs, insane cross references are exactly equivalent to the sane version, so you can just add other arguments after the construct, e.g.:
which gets converted to exact the same as the sane:
<Cross references>{full} are awesome.
which renders as:
Section 4.2.20. "Cross reference are awesome. "
\x[cross-reference]{full} are awesome.
which renders as:
Section 4.2.20. "Cross reference are awesome. "
In most cases it is generally more convenient to simply use the
\x
magic
argument through insane cross references instead of the c
and p
arguments as described on the rest of this section, see also: Section 4.2.20.3. "Inflection vs magic".A common usage pattern is that we want to use header titles in non-full cross references as the definition of a concept without repeating the title, for example:
== Dog
Cute animal.
\x[cats][Cats] are its natural enemies.
== Cats
This is the natural enemy of a \x[dog][dog].
\x[dog][Dogs] are cute, but they are still the enemy.
One example of a cat is \x[felix-the-cat].
=== Felix the Cat
Felix is not really a \x[cats][cat], just a carton character.
However, word inflection makes it much harder to avoid retyping the definition again.
For example, in the previous example, without any further intelligent behaviour we would be forced to re-type
\x[dog][dog]
instead of the desired \x[dog]
.OurBigBook can take care of some inflection cases for you.
For capitalization, both headers and cross reference macros have the Capitalization is handled by a JavaScript case conversion.
c
boolean argument which stands for "capitalized":- for headers,
c
means that the header title has fixed capitalization as given in the title, i.e.- if the title has a capital first character, it will always show as a capital, as is the case for most proper noun
- if it is lower case, it will also always remain lower case, as is the case for some rare proper nouns, notably the name of certain companies
This means that for such headers,c
in thex
has no effect. Maybe we should give an error in that case. But lazy now, send PR. - for cross reference macros,
c
means that the first letter of the title should be capitalized.Using this option is required when you are starting a sentence with a non-proper noun.
For pluralization, cross reference macros have the If your desired pluralization is any more complex than modifying the last word of the title, you must do it manually however.
p
boolean argument which stands for "pluralize":- if given and true, this automatically pluralizes the last word of the target title by using the blakeembrey/pluralize library.
- if given and false, automatically singularize
- if not given, don't change the number of elements
With those rules in mind, the previous OurBigBook example can be written with less repetition as:
== Dog
Cute animal.
\x[cats]{c} are its natural enemies.
== Cats
This is the natural enemy of a \x[dog].
\x[dog]{p} are cute, but they are still the enemy.
One example of a cat is \x[Felix the Cat].
=== Felix the Cat
{c}
Felix is not really a \x[cats][cat], just a carton character.
If plural and capitalization don't handle your common desired inflections, you can also just create custom ones with the
\H
synonym
argument.Now for a live example for quick and dirty interactive testing.
\x[inflection-example-not-proper]{full}
which renders as:
This is the default automatic pluralization/singularization library used by OurBigBook cross reference title inflection.
That library handles most cases well, but note that English language perfection is never possible with it as it would likely require having word databases which the authors do not wish to support, e.g. to deal with uncountable nouns such as "mathematics" correctly: github.com/plurals/pluralize/issues/60#issuecomment-310740594
The
\x
magic
argument was introduced later, and basically became a better alternative to cross reference title inflection in all but the following cases:\H
disambiguate
argument: disambiguate prevents the determination of plural inflection, e.g. in:there is currently no way to make it output= Python {disambiguate=animal} I like <python animal>.
Pythons
in the plural without resorting to either\x
p
argument or an explicit content, because if you wrote:it would just lead to Id not found, as we would try the plural vs singular onI like <pythons animal>.
animal
only.Maybe one day we can implement an even insaner system that understands that parenthesis should skipped for the inflection as in:github.com/ourbigbook/ourbigbook/issues/244I like <pythons (animal)>.
- plural headers. We only attempt to singularize arguments for now, not pluralize them. So if you had:
you would instead need to write:
My <dog> is nice. == Dogs
or:My <dog>{p=0} is nice.
My <dog>[dog] is nice.
If you use
\x
within a title
, which most commonly happens for image titles, that can generate complex dependencies between IDs, which would either be harder to implement, or lead to infinite recursion.To prevent such problems, OurBigBook emits an error if you use an
\x
without content in the title
of one of the following elements:- any header. For example, the following gives an error:
= h1 {id=myh1} == \x[myh1]
This could be solved by either adding a content to the reference:or by adding an explicit ID to the header:= h1 {id=myh1} == \x[myh1][mycontent]
= h1 {id=myh1} == \x[myh1] {id=myh2}
- non-header (e.g. an image) that links to the title of another non-headerFor non-headers, things are a bit more relaxed, and we can link to headers, e.g.:This is allowed because OurBigBook calculates IDs in two stages: first for all headers, and only later non non-headers.
= h1 \Image[myimg.jpg] {title=my \x[h1]}
What you cannot do is link to another image e.g.:and there the workaround are much the same as for headers: either explicitly set the cross reference content:\Image[myimg.jpg] {id=myimage1} {title=My image 1} \Image[myimg.jpg] {title=my \x[h1]}
or explicitly set an ID:\Image[myimg.jpg] {id=myimage1} {title=My image 1} \Image[myimg.jpg] {title=my \x[h1][My image 1]}
TODO both workaround are currently broken Image title with x to image with content incorrectly disallowed, we forgot to add a test earlier on, and things inevitably broke... Should not be hard to fix though, we are just overchecking.\Image[myimg.jpg] {id=myimage1} {title=My image 1} \Image[myimg.jpg] {id=myimage2} {title=my \x[h1]}
While it is technically possible relax the above limitations and give an error only in case of loops, it would require a bit of extra work which we don't want to put in right now: github.com/ourbigbook/ourbigbook/issues/95.
Furthermore, the above rules do not exclude infinite rendering loops, but OurBigBook detects such loops and gives a nice error message, this has been fixed at: github.com/ourbigbook/ourbigbook/issues/34
For example this would contain an infinite loop:
\Image[myimg.jpg]
{id=myimage1}
{title=\x[myimage2]}
\Image[myimg.jpg]
{id=myimage2}
{title=\x[myimage1]}
This infinite recursion is fundamentally not technically solved: the user has to manually break the loop by providing an
or:
x
content explicitly, e.g. in either:
\Image[myimg.jpg]
{id=myimage1}
{title=\x[myimage2][my content 2]}
\Image[myimg.jpg]
{id=myimage2}
{title=\x[myimage1]}
\Image[myimg.jpg]
{id=myimage1}
{title=\x[myimage2]}
\Image[myimg.jpg]
{id=myimage2}
{title=\x[myimage1][my content 1]}
A closely related limitation is the simplistic approach to
\x
id
output format.Reference to a non-first header of another file:
\x[h2-in-not-the-readme]
which renders as:
To make toplevel links cleaner, if the target header is the very first element of the other page, then the link does not get a fragment, e.g.:
and not:
while
\x[not-readme]
rendered as:
<a href="not-readme"
<a href="not-readme#not-readme"
\x[h2-in-not-the-readme]
is rendered with the fragment:
<a href="not-readme#h2-in-not-the-readme"
Reference to the first header of another file that is a second inclusion:
\x[included-by-not-readme]
which renders as:
Reference to another header of another file, with
full
:
\x[h2-in-not-the-readme]{full}.
which renders as:
Note that when full
is used with references in another file in multi page mode, the number is not rendered as explained at: Section 4.2.20.6.4.1. "\x
full
argument in cross file references".Reference to an image in another file:
\x[image-not-readme-xi]{full}.
which renders as:
Reference to an image in another file:
\x[image-figure-in-not-the-readme-without-explicit-id]{full}.
which renders as:
Remember that the ID of the toplevel header is automatically derived from its file name, that's why we have to use:
\x[not-readme]
which renders as:
instead of:
\x[not-the-readme]
Reference to a subdirectory:
\x[subdir]
\x[subdir/h2]
\x[subdir/notindex]
\x[subdir/notindex-h2]
which renders as:
Implemented at: github.com/ourbigbook/ourbigbook/issues/116Reference to an internal header of another file: h2 in not the README. By default, That header ID gets prefixed by the ID of the top header.
When using
rather than:
This is why IDs must be unique for elements across all pages.
--embed-includes
mode, the cross file references end up pointing to an ID inside the current HTML element, e.g.:
<a href="#not-readme">
<a href="not-readme.html/#not-readme">
When running in Node.js, OurBigBook dumps the IDs of all processed files to a
out/db.sqlite3
file in the out
directory, and then reads from that file when IDs are needed.When converting under a directory that contains
ourbigbook.json
, out/db.sqlite3
is placed inside the same directory as the ourbigbook.json
file.If there is no
ourbigbook.json
in parent directories, then out/db.sqlite3
is placed in the current working directory.These follows the principles described at: the current working directory does not matter when there is a
ourbigbook.json
.db.sqlite3
is not created or used when handling input from stdin.When running in the browser, the same JavaScript API will send queries to the server instead of a local SQLite database.
To inspect the ID database to debug it, you can use:
sqlite3 out/db.sqlite3 .dump
It is often useful to dump a single table, e.g. to dump the
and one particularly important query is to dump a list of all known IDs:
ids
table:
sqlite3 out/db.sqlite3 '.dump ids'
sqlite3 out/db.sqlite3 'select id from ids'
You can force
ourbigbook
to not use the ID database with the --no-db
command line optionThis section describes the philosophy of internal cross references.
In many static website generators, you just link to URL specific paths of internal headers.
In OurBigBook, internal cross references point to IDs, not paths.
For example, suppose "Superconductivity" is a descendant of "Condensed Matter Physics", and that the source for both is located at
condensed-matter-physics.bigb
, so that both appear on the same .html page condensed-matter-physics.html
.When linking to Superconductivity from an external page such as
statistical-physics.bigb
you write just <superconductivity>
and NOT <condensed-matter-physics#superconductivity>
. OurBigBook then automatically trakcs where superconductivity is located and produces href="condensed-matter-physics#superconductivity"
for you.This is important because on a static website, the location of headers might change. E.g. if you start writing a lot about superconductivity you would eventually want to split it to its own page,
superconductivity.html
otherwise page loads for condensed-matter-physics.html
would become too slow as that file would become too large.But if your links read
<condensed-matter-physics#superconductivity>
, and all links would break when you move things around.So instead, you simply link to the ID
<superconductivity>
, and ourbigbook renders links correctly for you wherever the output lands.When moving headers to separate pages, it is true that existing links to subheaders will break, but that simply cannot be helped. Large pages must be split into smaller ones. The issue can be mitigated in the following ways:
-S
,--split-headers
, which readers will eventually understand are better permalinks- JavaScript redirect to split on missing ID, which automatically redirect
condensed-matter-physics#superconductivity
tosuperconductivity
, potentially hitting a split header if the current page does not contain the HTML IDsuperconductivity
.
For OurBigBook Web, this is even more important, as we have dynamic article trees, so every header can appear on top.
If you really want to to use scopes, e.g. enforce the ID of "superconductivity" to be "condensed-matter-physics/superconductivity", then you can use the scope feature. However, this particular case would likely be a bad use case for that feature. You want your IDs to be as short as possible, which causes less need for refactoring, and makes topics on OurBigBook Web more likely to have matches from other users.
If the target
title
argument contains a link from either another cross references or a regular external hyperlink, OurBigBook automatically prevents that link from rendering as a link when no explicit body is given.This is done because nested links are illegal in HTML, and the result would be confusing.
This use case is most common when dealing with media such as images. For example in:
the
and not:
= afds
\x[image-aa-zxcv-lolol-bb]
== qwer
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
{title=aa \x[zxcv][zxcv] \a[http://example.com][lolol] bb}
== zxcv
\x[image-aa-zxcv-lolol-bb]
renders something like:
<a href="#image-aa-zxcv-lolol-bb">aa zxcv lolol bb</a>
<a href="#image-aa-zxcv-lolol-bb">aa <a href="zxcv">zxcv</a> <a href="http://example.com">lolol</a> bb</a>
Live example:
This is a nice image: \x[image-aa-zxcv-lolol-bb].
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
{title=aa \x[cross-reference-title-link-removal][zxcv] \a[http://example.com][lolol] bb}
which renders as:
This is a nice image: Figure 31. "aa zxcv lolol bb".
Capitalizes the first letter of the target title.
For more details, see: Section 4.2.20.2. "Cross reference title inflection".
Setting the
makes that header show up on the list of extra parents of the child.
child
boolean argument on a cross reference to a header as in:
\x[my-header]{child}
This argument is deprecated in favor of the
\H
tag
argument.This allows a section to have multiple parents, e.g. to include it into multiple categories. For example:
would render something like:
so note how "Bat" has a list of tags including "Flying animal", but Cat does not, due to the
= Animal
== Mammal
=== Bat
=== Cat
== Flying animal
These animals fly:
* \x[bat]{child}
These animals don't fly:
* \x[cat]
= Animal
== Mammal
=== Bat (Parent section: Mammal)
(Tags: Flying animal)
=== Cat (Parent section: Mammal)
== Flying animal (Parent section: Animal)
These animals fly:
* \x[bat]
These animals don't fly:
* \x[cat]
child
.This property does not affect how the table of contents is rendered. We could insert elements sections there multiple times, but it has the downside that browser Ctrl + F searches would hit the same thing multiple times on the table of contents, which might make finding things harder.
== My title{id=my-id}
Read this \x[my-id][amazing section].
If the second argument, the
is the same as:
content
argument, is not present, it expand to the header title, e.g.:
== My title{id=my-id}
Read this \x[my-id].
== My title{id=my-id}
Read this \x[my-id][My title].
The term refers to sections that have a parent/child relationship via either of the:rather than via the usual header hierarchy.
Secondary children show up for example on the tagged metadata section, but not on the table of contents, which is what the header hierarchy already shows.
Secondary children are normally basically used as "tags": a header such as
Bat
can be a direct child of Mammal
, and a secondary child of Flying animal
, or vice versa. Both Mammal
and Flying animal
are then basically ancestors. But we have to chose one main ancestor as "the parent", and other secondary ancestors will be seen as tags.This option first does ID target from title conversion on the argument, so you can e.g. keep any spaces or use capitalization in the title as in:
TODO the fact that this transformation is done currently makes it impossible to use "non-standard IDs" that contain spaces or uppercase letters. If someone ever wants that, we could maybe add a separate argument that does not do the expansion e.g.:
but definitely the most important use case is having easier to type and read source with the standard IDs.
= Animal
== Flying animal
{child=Big bat}
== Big bat
= Animal
== Flying animal
{childId=Big bat}
== Big bat
{id=Big bat}
Allows to link to headers with the
\H
file
argument, e.g.:
= My header
Check out this amazing file: <path/to/myfile.txt>{file}
== path/to/myfile.txt
\x[file_demo/file_demo_subdir/hello_world.js]{file}
which renders as:
\x[Tank_man_standing_in_front_of_some_tanks.jpg]{file}
which renders as:
\x[https://www.youtube.com/watch?v=YeFzeNAHEhU]{file}
which renders as:
To also show the section auto-generated number as in "Section X.Y My title" we add the optional
{full}
boolean argument to the cross reference, for example:
\x[x-full-argument]{full}.
which renders as:
{full}
is not needed for cross references to most macros besides headers, which use full
by default as seen by the default_x_style_full
macro property in --help-macros
. This is for example the case for images. You can force this to be disabled with {full=0}
:
Compare \x[image-my-test-image]{full=0} vs \x[image-my-test-image]{full=1}.
which renders as:
For example in the following cross file reference:
instead of:
This is because the number "Section 1.2" might already have been used in the current page, leading to confusion.
\x[h2-in-not-the-readme]{full}.
which renders as:
we get just something like:
Section "h2 in not the readme"
Section 1.2 "h2 in not the readme"
This argument makes writing many internal links more convenient, and it was notably introduced because it serves as the sane version of insane cross references.
If given e.g. as in:
the link treated magically as follows:
= Internal reference
\x[Internal references]{magic}
- content capitalization and pluralization are detected from the string, and implicitly set the
\x
c
argument and\x
p
argument. In the example:In this simple example, the content therefore will be exactly{c}
capitalization is set becauseInternal references
starts with an upper case characterI
{p}
pluralization is set becauseInternal references
ends in a plural word
Internal references
as in the source. But note that this does not necessarily need to be the case, e.g. if we had done:then the content would be:\x[Internal Reference]{magic}
without capitalInternal reference
R
, i.e. everything except capitalization and pluralization is ignored. This forgiving way of doing things means that writers don't need to remember the exact ideal capitalization of everything, which is very hard to remember.It also means that any more complex elements will be automatically rendered as usual, e.g. if we had:then the output would still contain the= \i[Internal] reference \x[internal reference]{magic}
<i>
italic tag.If we had a scope as in\x[my scope/Internal references]
, then each scope part is checked separately. E.g. in this case we would have upper caseInternal references
, even thoughmy scope
is lowercase, and so{c}
would be set. - the ID is calculated as follows:
- automatic ID from title conversion is performed, with you exception: forwards slashs
/
are kept, in order to make scopes work.In our case, there aren't any slashes/
, so it just givesinternal-references
. But if instead we had e.g.:\x[my scope/internal reference]{magic}
, then we would reachmy-scope/internal-reference
and notmy-scope-internal-reference
. - if there is a match to an existing ID use it.
internal-references
in the plural does not match, so go to the next step - if the above failed, try singularizing the last word as in the
\x
p
argument withp=0
before doing automatic ID from title conversion. This givesinternal-reference
, which does exist, and so we use that.
There may be some cases where you might still want to use cross reference title inflection however, see: Section 4.2.20.3. "Inflection vs magic".
A magic link can be created more succinctly by surrounding the link with "angle brackets" (
is equivalent to:
<>
), e.g.:
<Partial derivative>
\x[Partial derivative]{magic}
The
parent
argument is exactly like the \x
child
argument, but it reverses the direction of the parent/child relation.This argument is deprecated in favor of the
\H
tag
argument.The
renders something like:
ref
argument of \x
marks the link as reference, e.g.:
Trump said this and that.\x[donald-trump-access-hollywood-tape]{ref}
= Donald Trump Access Hollywood tape
Trump said this and that.<a href="donald-trump-access-hollywood-tape">*</a>
This could currently be replicated without
but later on we might add more precise reference fields like the page of a book or date fetched as Wikipedia supports.
ref
by just using:
Trump said this and that.\x[donald-trump-access-hollywood-tape][*]
Implemented at: github.com/ourbigbook/ourbigbook/issues/137
If true, then the target of a this link is called a "topic link" and gets treated specially, pointing to an external OurBigBook Web topic rather than a header defined in the current project.
For example, when rendering a static website, a link such as:
would produce output similar to:
e.g.:
\x[Albert Einstein]{topic}
\a[https://ourbigbook.com/go/topic/john-smith][John Smith]
\x[Albert Einstein]{topic}
which renders as:
This allows static website creators to easily link to topics they might not have already written about which others may have covered.
The OurBigBook Web instance linked to can be configured with
host
.Those links also work on OurBigBook Web rendering of course, and point to the current Web instance.
If an insane magic link starts with a hash sign (
#
), then it is converted to a topic link instead of a magic link.For example:
<#Albert Einstein>
which renders as:
is equivalent to:
\x[Albert Einstein]{topic}
If an insane topic link is made up of a single word then it can be written in the following even succincter notation, without the need for angle brackets:
is equivalent to:
I like #dogs
which renders as:
I like dogs
I like <#dogs>
Word separation is defined analogously to Insane link parsing rules, i.e.:
#
can start from anywhere, including the middle of words, e.g.:abc#mytopic
which renders as:would produce a link immediately preceded by the charactersabcmytopicabc
.#
ends at any insane link termination character, e.g.:
Unlike local links, it is not possible to automatically determine the exact pluralization of a topic link because:
- it would require communicating with the OurBigBook Web API, which we could in principle do, but we would rather not have static builds depend on Web instances
- topics can be written by multiple authors, and there could be both plural and singular versions of each topic ID, which makes it hard to determine which one is "correct"
Therefore, it is up to authors to specifically specify the desired pluralization of their topic links:
- by default, topic IDs are automatically singularized, e.g.:
renders something like:
<#Many Dogs>
\a[https://ourbigbook.com/go/topic/many-dog][Many Dogs]
- to prevent this automatic singularization, use
\x
p
argument with{p=1}
, e.g.:renders something like:<#Many Dogs>{p=1}
This is unfortunately always necessary for uncountable nouns such as "mathematics":\a[https://ourbigbook.com/go/topic/many-dogs][Many Dogs]
I like #mathematics{p=1}
which renders as:since our underlying pluralization library blakeembrey/pluralize cannot handle uncountable nouns reliably.I like mathematics
Pluralizes or singularizes the last word of the target title.
For more details, see: Section 4.2.20.2. "Cross reference title inflection".
Certain commonly used macros have insane macro shortcuts that do not start with backslash (
\
).Originally, Ciro wanted to avoid those, but they just feel too good to avoid.
Every insane syntax does however have an equivalent sane syntax.
The style recommendation is: use the insane version which is shorter, unless you have a specific reason to use the sane version.
Insane in our context does not mean worse. It just mean "harder for the computer to understand". But it is more important that humans can understand in the first place! It is find to make the computer work a bit more for us when we are able to.
- Section 4.2.15. "Paragraph : "
\n\n
(double newline) - Section 4.2.1. "Link : "
a http://example.com b
(space followed byhttp://
) - Section 4.2.20. "Cross reference : "
<Cross references>
(angle brackets), see: Section 4.2.20.1. "Insane cross reference " - Section 4.2.13. "Mathematics : "
$
, described at: insane code and math shortcuts - Section 4.2.4. "Code block : "
`
, described at: insane code and math shortcuts - Section 4.2.12. "List : "
*
and indentation - Section 4.2.18. "Table : "
||
,|
and indentation
The insane code and math shortcuts work very analogously and are therefore described together in this section.
The insane inline code syntax:
and is equivalent to the sane:
a `b c` d
which renders as:
ab c
d
a \c[[b c]] d
The insane block code:
and is equivalent to the sane:
a
``
b c
``
d
which renders as:
ab c
d
a
\C[[
b c
]]
d
Insane arguments always work by abbreviating:This means that you can add further arguments as usual.
- the macro name
- one or more of its positional arguments, which are fixed as either literal or non-literal for a given insane construct
For example, an insane code block with an id can be written as:
because that is the same as:
So we see that the
a `b c`{id=ef} g
a \c[b c]{id=ef} g
which renders as:
agb c
b c
argument is the very first argument of \c
.Extra arguments must come after the insane opening, e.g. the following does not work:
a {id=ef}`b c` g
This restriction things easy to parse for humans and machines alike.
Literal backticks and dollar signs can be produced witha backslash escape as in:
a \` \$ b
which renders as:
a ` $ b
It is not possible to escape backticks (
`
) inside an insane inline code, or dollar signs ($
) in insane math.The design reason for that is because multiple backticks produce block code.
The upside is that then you don't have to escape anything else, e.g. backslashes (
\
) are rendered literally.The only way to do it is to use the sane syntax instead:
a \c[[b ` c]] d
a \m[[\sqrt{\$4}]] d
which renders as:
ab ` c
da d
Within block code and math, you can just add more separators:
```
code with two backticks
``
nice
```
which renders as:
code with two backticks `` nice
OurBigBook Markup macro identifiers can consist of the following letters:Since underscores
a-z
lowercaseA-Z
uppercase0-9
_
or hyphens =
are not allowed, camel case macro names are recommended, e.g. for \OurBigBookExample
we use the name:
OurBigBookExample
Every argument in OurBigBook is either positional or named.
For example, in a header definition with an ID:
which is equivalent to the sane version:
we have:
= My asdf
{id=asdf qwer}
{scope}
\H[1][My asdf]
{id=asdf qwer}
{scope}
- two positional argument:
[1]
and[My asdf]
. Those are surrounded by square brackets[]
and have no name - two named arguments:
{id=asdf qwer}
and{scope}
.The first one has nameid
, followed by the separator=
, followed by the valueasdf qwer
.The separator=
always is optional. If not given, it is equivalent to an empty value, e.g.:is the same as:{id=}
{id}
You can determine if a macro is positional or named by using
and so we see that
--help-macros
. Its output contains something like:
"h": {
"name": "h",
"positional_args": [
{
"name": "level"
},
{
"name": "content"
}
],
"named_args": {
"id": {
"name": "id"
}
"scope": {
"name": "scope"
}
},
level
and the content
argument are positional arguments, and id
and scope
are named arguments.Generally, positional arguments are few (otherwise it would be hard to know which is which is which), and are almost always used for a given element so that they save us from typing the name too many times.
The order of positional arguments must of course be fixed, but named arguments can go anywhere. We can even mix positional and named arguments however we want, although this is not advised for clarity.
The following are therefore all equivalent:
\H[1][My asdf]{id=asdf qwer}{scope}
\H[1][My asdf]{scope}{id=asdf qwer}
\H{id=asdf qwer}{scope}[1][My asdf]
\H{scope}[1]{id=asdf qwer}[My asdf]
Just like named arguments, positional arguments are never mandatory.
Most positional arguments will default to an empty string if not given.
However, some positional arguments can have special effects if not given.
For example, an anchor with the first positional argument present (the URL), but not the second positional argument (the link text) as in:
\a[http://example.com]
which renders as:
has the special effect of generating automatic links as in:
\a[http://example.com][http://example.com]
This can be contrasted with named arguments, for which there is always a default value, notably for boolean arguments.
See also: Section 4.2.1. "Link . "
Some positional arguments are required, and if not given OurBigBook reports an error and does not render the node.
This is for example the
level
of a header.These arguments marked with the
mandatory: true
--help-macros
argument property.Name arguments marked in
--help-macros
as boolean: true
must either:- take no value and no
=
sign, in which case the value is implicitly set to1
- take value exactly
0
or1
- not be given, in which case a custom per-macro default is used. That value is the
default
from--help-macros
, or0
if such default is not given
For example, the
\x
full
argument of cross references is correctly written as:
\x[boolean-argument]{full}
which renders as:
without the =
sign, or equivalently:
\x[boolean-argument]{full=1}
which renders as:
The full=0
version is useful in the case of reference targets that unlike headers expand the title on the cross reference by default, e.g. images:
\x[boolean-argument]{full=1}
which renders as:
The name "boolean argument" is given by analogy to the "boolean attribute" concept in HTML5.
Positive nonzero integer arguments accept only the characters
[0-9]
as their input, and 0 may not be the first character. If anything else is present, an error is raised.Common arguments are argument names that are present in all macros.
Explicitly sets the ID of a macro.
In OurBigBook Markup, every single macro has an ID, which can be either:
- explicit: extracted from some input given by the user, either the
id
argument or thetitle
argument. Explicit IDs can be referenced in Internal cross references and must be unique - implicit: automatically generated numerical ID. Implicit IDs cannot be referenced in Internal cross references and don't need to be unique. Their primary application is generating on hover links next to everything you hover, e.g. arbitrary paragraphs.
The most common way to assign an ID is implicitly with automatic ID from title conversion for macros that have a
title
argument.The
id
argument allows to either override the automatic ID from title, or provide an explicit ID for elements that don't have a title
argument.Sometimes the short version of a name is ambiguous, and you need to add some extra text to make both its title and ID unique.
For example, the word "Python" could either refer to:
- the programming language: en.wikipedia.org/wiki/Python_(programming_language)
- the genus of snakes: en.wikipedia.org/wiki/Python_(genus)
The
disambiguate
named argument helps you deal more neatly with such problems.Have a look at this example:
from which we observe how
My favorite snakes are \x[python-genus]{p}!
My favorite programming language is \x[python-programming-language]!
\x[python-genus]{full}
\x[python-programming-language]{full}
= Python
{disambiguate=genus}
{parent=disambiguate-argument}
= Python
{c}
{disambiguate=programming language}
{parent=disambiguate-argument}
{title2=.py}
{wiki}
disambiguate
:- gets added to the ID after conversion following the same rules as automatic ID from title
- shows up on the header between parenthesis, much like Wikipedia, as well as in
full
cross references - does not show up on non-
full
references. This makes it much more likely that you will be able to reuse the title automatically on a cross reference without thecontent
argument: we wouldn't want to say "My favorite programming language is Python (programming language)" all the time, would we? - gets added to the default
\H
wiki
argument inside parenthesis, following Wikipedia convention, therefore increasing the likelihood that you will be able to go with the default Wikipedia value
Besides disambiguating headers, the
Note that unlike for headers,
disambiguate
argument has a second related application: disambiguating IDs of images. For example:
\x[image-the-title-of-my-disambiguate-image]{full=0}
\x[image-the-title-of-my-disambiguate-image-2]{full=0}
\x[image-the-title-of-my-disambiguate-image]{full}
\x[image-the-title-of-my-disambiguate-image-2]{full}
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
{title=The title of my disambiguate image}
\Image[Tank_man_standing_in_front_of_some_tanks.jpg]
{title=The title of my disambiguate image}
{disambiguate=2}
which renders as:
disambiguate
does not appear on the title of images at all. It serves only to create an unique ID that can be later referred to. Headers are actually the only case where disambiguate
shows up on the visible rendered output. We intend on making this application obsolete however with:This use case is even more useful when
title-from-src
is enable by default for the media-providers
entry, so you don't have to repeat titles several times over and over.The JavaScript interface sees arguments as follows:
where args is a dict such that:
function macro_name(args)
- optional arguments have the key/value pairs explicitly given on the call
- mandatory arguments have a key documented by the API, and the value on the call.For example, the link API names its arguments
href
andtext
.
Arguments that are opened with more than one square brackets
[
or curly braces {
are literal arguments.In literal arguments, OurBigBook is not parsed, and the entire argument is considered as text until a corresponding close with the same number of characters.
Therefore, you cannot have nested content, but it makes it extremely convenient to write code blocks or mathematics.
For example, a multiline code block with double open and double close square brackets inside can be enclosed in triple square brackets:
A literal argument looks like this in OurBigBook:
\C[[
\C[
A multiline
code block.
]
]]
And another paragraph.
which renders as:
A literal argument looks like this in OurBigBook:\C[ A multiline code block. ]
And another paragraph.
The same works for inline code:
The program \c[[puts("]");]] is very complex.
which renders as:
The programputs("]");
is very complex.
Within literal blocks, only one thing can be escaped with backslashes are:
- leading open square bracket
[
- trailing close square bracket
]
The rule is that:
- if the first character of a literal argument is a sequence of backslashes (
\
), and it is followed by another argument open character (e.g.[
, remove the first\
and treat the other characters as regular text - if the last character of a literal argument is a
\
, ignore it and treat the following closing character (e.g.]
) as regular text
See the following open input/output pairs:
and close examples:
\c[[\ b]]
<code>\ b</code>
\c[[\a b]]
<code>\a b</code>
\c[[\[ b]]
<code>[ b</code>
\c[[\\[ b]]
<code>\[ b</code>
\c[[\\\[ b]]
<code>\\[ b</code>
\c[[a \]]
<code>a \</code>
\c[[a \]]]
<code>a ]</code>
\c[[a \\]]]
<code>a \]</code>
If the very first or very last character of an argument is a newline, then that character is ignored if it would be part of a regular plaintext node.
For example:
generates something like:
instead of:
This is extremely convenient to improve the readability of code blocks and similar constructs.
\C[[
a
b
]]
<pre><code>a
b</code></pre>
<pre><code>
a
b
</code></pre>
The newline is however considered if it would be part of some insane macro shortcut. For example, we can start an insane list inside a quotations as in:
where the insane list requires a leading newline
\Q[
* a
* b
]
which renders as:
- a
- b
\n*
to work. That newline is not ignored, even though it comes immediately after the \Q[
opening.The macro name and the first argument, and any two consecutive arguments, can be optionally separated by exactly one newline character, e.g.:
is equivalent to:
which is also equivalent to:
This allows to greatly improve the readability of long argument lists by having them one per line.
\H
[2]
{scope}
[Design goals]
\H[2]{scope}[Design goals]
\H[2]{scope}
[Design goals]
There is one exception to this however: inside an insane header, any newline is interpreted as the end of the insane header. This is why the following works as expected:
and the
== My header 2 `some code`
{id=asdf}
id
gets assigned to the header rather than the trailing code element.If the document ends one newline, it is ignored.
If it is two or more, then that generates an error.
Every character that cannot be a macro identifier can be escaped with a backslash
\
. If you try to escape a macro identifier it of course treats the thing as a macro instead and fails, e.g. in \a
it would try to use a macro called \a
, not escape the character a
.For some characters, escaping or not does not make any difference because they don't have any meaning to OurBigBook Markup, e.g. currently
%
is always the exact same as \%
.But in non-literal macro arguments, you have to use a backslash to escape the following if you want them to not have any magical meaning:
\
: backslashes start macros\[
and\]
: open and close positional macro arguments\{
and\}
: open and close optional macro arguments- escapes for macros with insane shortcut:
<
(open angle brackets, less than sign): insane macro shortcut for insane cross references$
(dollar sign): insane macro shortcut for mathematics`
(backtick): insane macro shortcut for code blocks#
(hash): insane topic links
Furthermore, only at:you must also escape the following macros with insane shortcut:
- at the start of the document
- after a newline
- at the start of a new argument
The escape rules for literal arguments are described at: Section 4.3.3.5. "Literal arguments . "
This is good for short arguments of regular text, but for longer blocks like code blocks or mathematics, you may want to use literal arguments
Each macro argument can have certain properties associated to it.
These properties have programmatic effects, and allow users and developers to more easily understand and create new macro arguments.
Some macro arguments are disabled by default.
These are typicially arguments which felt like a good idea one day, but which we ended up regretting.
They can be enabled via
ourbigbook.json
options TODO, but doing so will make the project incompatible with OurBigBook Web, so it is not advised.A macro argument property that is
inlineOnly
can only contain inline macros. If any block macros present in the argument or its descendants, will lead to a conversion error.Some notable rules:
title
arguments are alwaywsinlineOnly
- all arguments of inline macros are
inlineOnly
There are two main rationales for enforcing these rules:
- the HTML
h1
-h6
header HTML elements can only contain phrasing content (analogout to our inline macros) for the HTML to be valid. We could chose to use styleddiv
s instead ofh
elements, but this could have a negative SEO impact. All other HTML elements could be replaced bydiv
s without issue however, the problem really is onlyh
. - on OurBigBook Web, where multiple users are working together and many titles from multiple users show on index pages, it is saner to be more restrictive on what is allowed on titles and to prevent visually very large things from being added in order to prevent bad actors or accidents from disrupting other users too much
In HTML, certain elements such as
<ul>
cannot have any text
nodes in them, and any whitespace is ignored, see stackoverflow.com/questions/2161337/can-we-use-any-other-tag-inside-ul-along-with-li/60885802#60885802.A similar concept applies to OurBigBook, e.g.:
does not parse as:
but rather as:
because the
\Ul[
\L[aa]
\L[bb]
]
\Ul[\L[aa]<NEWLINE>\L[bb]<NEWLINE>]
\Ul[\L[aa]\L[bb]]
content
argument of ul
is marked with remove_whitespace_children
and automatically removes any whitespace children (such as a newline) as a result.This also applies to consecutive sequences of
also does not include the newline between the list items.
auto_parent
macro property macros, e.g.:
\L[aa]
\L[bb]
The definition of whitespace is the same as the ASCII whitespace definition of HTML5:
\r\n\f\t
.By default, arguments can be given only once.
However, arguments with the
multiple
macro argument property set to true
can be given multiple times, and each time the argument is given, the new value is appended to a list containing all the values.An example is the
\H
tag
argument.Internally, multiple is implemented by creating a new level in the abstract syntax tree, and storing each argument separately under a newly generated dummy nodes as in:
AstNode: H
AstArgument: child
AstNode: Comment
AstArgument: content
AstNode: plaintext
AstNode: x
AstNode: Comment
AstArgument: content
AstNode: plaintext
AstNode: x
This section documents ways to classify macro arguments that are analogous to macro argument properties, but which don't yet have clear and uniform programmatic effects and so are a bit more hand wavy for now.
The
content
argument of macros contains the "main content" of the macro, i.e. the textual content that will show the most proeminently once the macro is rendered. It is usually, but not always, the first positional argument of macros. We should probably make it into an official macro argument property at some point.In most cases, it is quite obvious which argument is the
content
argument, e.g.:\i
macro: in\i[asdf qwer]
thenasdf qwer
is thecontent
argument\a
macro: in\a[https://example.com][example website]
thenexample website
is thecontent
argument
Some macros however don't have a
content
argument, especially when they don't show any textual acontent as their primary rendered output, e.g.:\Image
macro: this macro hastitle
byt not content, e.g. as in:\Image[flower.jpg]{title=}
, since the primary content is theImage
rather than any specific text
Philosophically, the
content
argument of a macro is analogous to the innerHTML
of an HTML tag, as opposed to attributes such as href=
and so on. The difference is that in OurBigBook Markup, every macro argument can contain child elements, while in HTML only the innerHTML
, but not the attributes, can.The
title
argument is an argument that gets used in automatic ID from title calculation of macro IDs.Examples:
- headers:
= My header
is equivalent to\H[1][My header]
, andMy header
is thetitle
argument, which is a positional argument in this case - images: in
\Image[flower.jpg]{title=My header}
andMy header
is thetitle
argument, which is a named argument in this case
The
description
argument is similar to the title
argument in that it adds information about some block such as an image or code block. The difference from the title is that it does not count toward automatic ID from title calculations.These are shared concepts that are used across other sections.
Some sequences of macros such as
parses exactly like:
l
from lists and tr
from tables automatically generate implicit parents, e.g.:
\Ul[
\L[aa]
\L[bb]
]
\L[aa]
\L[bb]
The children are always added as arguments of the
content
argument of the implicit parent.If present, the
auto_parent
macro property determines which auto-parent gets added to those macros.Every OurBigBook macro is either block or inline:
Some macros have both a block and an inline version, and like any other macro, those are differentiated by capitalization:
Certain common URL protocols are treated as "known" by OurBigBook, and when found they have special effects in some parts of the conversion.
The currently known protocols are:
http://
https://
Effects of known protocols include:
- insane link parsing rules: mark the start of insane links
- store images in a separate media repository: mark an image
src
to ignoreprovider
Some parts of OurBigBook use "JavaScript case conversion".
This means that the conversion is done as if by the
toLowerCase
/toUpperCase
functions.The most important fact about those functions is that they do convert non-ASCII Unicode capitalization, e.g. between
É
and é
:These conversions are also specified in the Unicode standard.
If the project toplevel directory of an OurBigBook project is also a git repository, and if
git
is installed, then the OurBigBook project is said to be a "Git tracked project".In general usages of a macro produces an element, and every element has an ID.
IDs must be unique, and they are used as the target of internal cross references.
E.g. due to Section 4.2.6.4.9.1.1. "Automatic ID from title", the elements:
would have IDs respectively:
= Animal
== Big dog
I like <big dogs>.
animal
big-dog
Such IDs are almost always rendered as HTML IDs as something like:
and can therefore be linked to in a page with the corresponding fragment:
<h1 id="animal">
<h2 id="big-dog">
animal.html#big-dog
IDs that start with an underscore
_
are reserved for OurBigBook usage, and will give an error if you try to use them, in order to prevent ID conflicts.For example:
- the table of contents uses an ID
_toc
the ID of the ToC is always fixed totoc
. If you try to use that for another element, you will get the following error: - elements without an explicit ID may receive automatically generated IDs of type
_1
,_2
and so on
If you use a reserved ID, you will get an error mesasge of type:
error: tmp.bigb:3:1: IDs that start with "_" are reserved: "_toc"
OurBigBook CLI is the executable program called
ourbigbook
which comes when you install npm install ourbigbook
. It is the main command line utility of the OurBigBook Project.Its functionality will also be exposed on GUI editor support such as Visual Studio Code to make things nicer for non-technical users.
The main functionalities of the executable are to:
- convert OurBigBook Markup files to HTML files or other formatsThe HTML files can then be either viewd from your filesystem on a browser, or uploaded and hosted very cheaply or for free so that others can see it, e.g. on GitHub Pages.
- publish your content, either to OurBigBook Web or as a static website
Or if you are a programmer: OurBigBook CLI is a Static Wiki generator that can be invoked from the command line with the
ourbigbook
executable.OurBigBook CLI is how cirosantilli.com is published.
OurBigBook Web takes as input the exact same format of OurBigBook Markup files used by OurBigBook CLI. TODO support/improve import/export to/from OurBigBook Web, see also:
-W
, --web
.The OurBigBook CLI calls the OurBigBook Library to convert each input file.
Convert a
.bigb
file to HTML and output the HTML to a file with the same basename without extension, e.g.:
ourbigbook hello.bigb
firefox out/html/hello.html
Files named
README.bigb
are automatically converted to index.html
so that they will show on both GitHub READMEs and at the website's base address:
ourbigbook README.bigb
firefox out/html/index.html
Convert all
The HTML output files are placed right next to each corresponding
.bigb
files in a directory to HTML files, e.g. somefile.bigb
to out/html/somefile.html
:
ourbigbook .
.bigb
.The output file can be selected explicitly with:
--outfile <outfie>
.Output to stdout instead of saving it to a file:
ourbigbook --stdout README.bigb
In order to resolve cross file references, this actually does two passes:
- first an ID extraction pass, which parses all inputs and dumps their IDs to the ID database
- then a second render pass, which uses the IDs in the ID database
Convert a
.bigb
file from stdin to HTML and output the contents of <body>
to stdout:
printf 'ab\ncd\n' | ourbigbook --body-only
Stdin converion is a bit different from conversion from a file in that it ignores the
ourbigbook.json
and any other setting files present in the current directory or its ancestors. Also, it does not produce any changes to the ID database. In other words, a conversion from stdin is always treated as if it were outside of any project, and therefore should always produce the same results regardless of the current working directory.Learn the syntax basics in 5 minutes: docs.ourbigbook.com/_obb/dist/editor.
First ensure that Node.js is installed in your computer. You should be able to successfully the following command successfully from a terminal:
node --version
Now let's play with an OurBigBook template locally:
That template can be seen rendered live at: cirosantilli.com/ourbigbook-generate-multifile/ Other templates are documented at:
git clone https://github.com/ourbigbook/template
cd template
npm install
npx ourbigbook .
firefox out/html/index.html
--generate
.To publish to GitHub Pages on your repository you can just fork the repository github.com/ourbigbook/template to your own github.com/johndoe/template and then:
and it should now be visible at: johndoe.github.io/template
git remote set-url origin git@github.com:johndoe/template.git
npx ourbigbook --publish
Then, every time you make a change you can publish the new version with:
or equivalently with the
git add .
git commit --message 'hacked stuff'
ourbigbook --publish .
-P, --publish-commit <commit-message>
shortcut:
ourbigbook --publish-commit 'hacked stuff'
If you want to publish to your root page johndoe.github.io instead of johndoe.github.io/template you need to rename the
master
branch to dev
as mentioned at publish to GitHub pages root page:
git remote set-url origin git@github.com:johndoe/johndoe.github.io.git
# Rename master to dev, and delete the old master.
git checkout -b dev
git push origin dev:dev
git branch -D master
git push --delete origin master
npx ourbigbook --publish
The following files of the template control the global style of the output, and you are free to edit them:
ourbigbook.liquid.html
: global HTML template in Liquid format. Available variables are documented at Section 5.5.25. "--template
"- Sass is just much more convenient to write than raw CSS.That file gets included into the global HTML template inside
ourbigbook.liquid.html
at:<link rel="stylesheet" href="{{ root_relpath }}main.css">
When you run:
it converts all files in the current directory separately, e.g.:
npx ourbigbook .
README.bigb
toout/html/index.html
, sinceREADME
is a magic name that we want to show on the root URLnot-readme.bigb
toout/html/not-readme.html
, as this one is a regular name unlikeREADME
main.scss
tomain.css
If one of the input files starts getting too large, usually the toplevel
Note however that when those individual files have a cross file reference to something defined in
to parse all files and extract all necessary IDs to the ID database. That would be optimized slightly with the
to only extract the IDs but not render, which speeds things up considerably
README.bigb
in which you dump everything by default like Ciro does, you can speed up development and just compile files individually with either:
npx ourbigbook README.bigb
npx ourbigbook not-readme.bigb
not-readme.bigb
, e.g. via \x[h2-in-not-the-readme]
, then you must have first previously done pass once with:
npx ourbigbook .
--no-render
command line option:
npx ourbigbook --no-render .
When dealing with large files, you might also be interested in the following amazing options:
To produce a single standalone output file that contains everything the viewer needs to correctly see the page do:
You can now just give the generated
npx ourbigbook --embed-resources --embed-includes README.bigb
out/html/index.html
to any reader and they should be able to view it offline without installing anything. The flags are:--embed-includes
: without this,\Include[not-readme]
shows as a link to the fileout/html/not-readme.html
which comes fromnot-readme.bigb
With the flag,not-readme.bigb
output gets embedded into the outputout/html/index.html
directly--embed-resources
: by default, we link to CSS and JavaScript that lives insidenode_modules
. With this flag, that CSS and JavaScript is copied inline into the document instead. One day we will try to handle images that way as well
Install the NPM package globally and use it from the command line for a quick conversion:
or to a file:
You almost never want to do this except when developing OurBigBook, as it won't be clear what version of
npm install -g ourbigbook
printf 'ab\ncd\n' | ourbigbook --body-only
printf 'ab\ncd\n' | ourbigbook > tmp.html
ourbigbook
the document should be compiled with. Just be a good infant and use OurBigBook with the template that contains a package.json
via npx
, OK?Furthermore, the default install of Chromium on Ubuntu 21.04 uses Snap and blocks access to dotfiles. For example, in a sane NVM install, our global CSS would live under One workaround is to use
/home/ciro/.nvm/versions/node/v14.17.0/lib/node_modules/ourbigbook/_obb/ourbigbook.css
, which gets blocked because of the .nvm
part:- forum.snapcraft.io/t/dot-files/7062
- bugs.launchpad.net/snapd/+bug/1607067
- superuser.com/questions/1546550/chromium-81-wont-display-dotfiles-anymore
- askubuntu.com/questions/1184357/why-cant-chromium-suddenly-access-any-partition-except-for-home
- askubuntu.com/questions/1214346/as-a-user-is-there-any-way-to-change-the-confinement-of-a-snap-package
--embed-resources
, but this of course generates larger outputs.To run master globally from source for development see: Section 12.2. "Run OurBigBook master". This one actually works despite the dotfile thing since your development path is normally outside of dotfiles.
Try out the JavaScript API with lib_hello.js:
npm install ourbigbook
./lib_hello.js
There are two ways to publish your OurBigBook Project content:A fundamental design choice of the OurBigBook Project is that, except for bugs, a single OurBigBook Markup source tree can be published in both of those ways without any changes.
- as a static website. This means that you generate HTML files from OurBigBook Markup files and then publish them either by:
- uploading to a static website server such as GitHub Pages by using the publish option
- converting with
--publish-target local
and sending a zip with the pages to someone to view locally
- to an OurBigBook Web instance such as OurBigBook.com. This can be done either by:
- editing on the OurBigBook Web editor directly in your browser
- uploading OurBigBook Markup files from your computer with the
-W
,--web
option
The trade-offs between the two options are highlighted at: OurBigBook Web vs static website publishing.
- static websites are cheaper to host, including many free options such as GitHub Pages.This means that you are likely to always have several free or cheap choices of where to upload your content to, making it essentially all but TEOTWAWKI-proofPages will also load slightly fatser.
- OurBigBook Web has killer multi-user features: OurBigBook Web topics, article upvotes and OurBigBook Web discussionsFurthermore, it also has some non multi-user features which cannot be feasibly implemented in a static website because they would require too much storage, on the fly generation is the only feasible way to deal with them:
- OurBigBook Web dynamic article tree
- article history. Unimplemented as of writing: github.com/ourbigbook/ourbigbook/issues/248
Its main downside is that it is more expensive to host.The OurBigBook Project will do its best to keep OurBigBook.com uploading as free as possible, but upload limits necessarily have to be more strict than those of static websites, as the underlying operating cost is larger.
The following basenames are considered "index files":
README.bigb
index.bigb
Those basenames have the following magic properties:
- the default output file name for an index file in HTML output is either:
index.html
when in the project toplevel directory. E.g.README.bigb
renders toindex.html
. Note that GitHub and many other static website hosts then automatically hide theindex.html
part from the URL, so that yourREADME.bigb
hosted athttp://example.com
will be accessible simply underhttp://example.com
and nothttp://example.com/index.html
- the name of the subdirectory in which it is located when not in the project toplevel directory. E.g.
mysubdir/index.bigb
outputs tomysubdir.html
Previously, we had placed the output inmysubdir/index.html
, but this is not as nice as it makes GitHub pages produce URLs with a trailing slash asmysubdir/
, which is ugly, see also: stackoverflow.com/questions/5948659/when-should-i-use-a-trailing-slash-in-my-url
- the default toplevel header ID of an index files is derived from the parent directory basename rather than from the source file basename
This directory is determined by first checking the presence of a
ourbigbook.json
file.If a
ourbigbook.json
is found, then the project toplevel directory is the directory that contains that file.- otherwise, if the input path is a descendant of the current working directory, then the current working directory is used, see also: the current working directory does not matter when there is a
ourbigbook.json
- otherwise, if the input path is a directory, it is used
- otherwise, the directory containing the input file is used
For example, consider the file following file structure relative to the current working directory:
path/to/notindex.bigb
In this case:
- if there is no
ourbigbook.json
file:- if we run
ourbigbook .
: the toplevel directory is the current directory.
, and sonotindex.bigb
has IDpath/to/notindex
- if we run
ourbigbook path
: same - if we run
ourbigbook path/to
: same - if we run
ourbigbook path/to/notindex.bigb
: same
- if we run
- if there is a
path/ourbigbook.json
file:- if we run
ourbigbook .
: the toplevel directory is the current directory.
because theourbigbook.json
is below the entry point and is not seen, and sonotindex.bigb
has IDpath/to/notindex
- if we run
ourbigbook path
: the toplevel directory is the directory with theourbigbook.json
,path
, and sonotindex.bigb
has IDto/notindex
- if we run
ourbigbook path/to
: same - if we run
ourbigbook path/to/notindex.bigb
: same
- if we run
This is the index file present in the project toplevel directory.
Being the toplevel index file has the following implications compared to other index files:
- its ID is derived from the header itself, not the directory, see also: the ID of the first header is derived from the filename
The "index article" is the first article of the The toplevel index file. E.g. in:
README.bigb
then "John Smith's Homepage" is the index article of the project, but "I like dogs" is not.
= John Smith's Homepage
== I like dogs
When the file or directory being converted has an ancestor directory with a
then all of the following conversions produce the same output:
ourbigbook.json
file, then your current working directory does not have any effect on OurBigBook output. For example if we have:
/project/ourbigbook.json
/project/README.bigb
/project/subdir/README.bigb
- directory conversion:
cd /project && ourbigbook .
cd / && ourbigbook project
cd project/subdir && ourbigbook ..
- file conversion:
cd /project && ourbigbook README.bigb
cd / && ourbigbook project/README.bigb
cd project/subdir && ourbigbook ../README.bigb
When there isn't a
ourbigbook.json
, everything happens as though there were an empty ourbigbook.json
file in the current working directory. So for example:- outputs that would be placed relative to inputs are still placed in that place, e.g.
README.bigb -> index.html
always stay together - outputs that would be placed next to the
ourbigbook.json
are put in the current working directory, e.g. theout
directory
Internally, the general philosophy is that the JavaScript API in index.js works exclusively with paths relative to the project toplevel directory. It is then up to callers such as ourbigbook to ensure that filesystem specifics handle the relative paths correctly.
Check the database for consistency, e.g. duplicated IDs. Don't do anything else, including ID extraction, which must have been done previously.
The initial use case was for usage in Parallel builds.
This is the most important option of the software.
It produces a copy of the HTML of cirosantilli.com/china-dictatorship to stdout.
The data is stored inside an NPM package, making it hard to censor that information, see also: cirosantilli.com/china-dictatorship#mirrors
Usage:
ourbigbook --china > china.html
firefox china.html
The
you can just go and inspect the generated HTML to see what would get pushed at:
see also: the
--dry-run
option is a good way to debug the --publish
option, as it builds the publish output files without doing any git commands that would be annoying to revert. So after doing:
ourbigbook --dry-run --publish .
cd out/publish/out/publish/
out
directory.Similar to
--dry-run
, but it runs all git commands except for git push
, which gives a clearer idea of what --publish
would actually do including the git operations, but without publishing anything:
./ourbigbook --dry-run --publish .
Makes includes render the included content in the same output file as the include is located, instead of the default behaviour of creating links.
For example given:
README.bigb
= Index
\Include[notindex]
notindex.bigb
= Notindex
A paragraph in notindex.
== Notindex 2
then for conversion with:
then the output
ourbigbook --embed-includes README.bigb
index.html
contains an output equivalent to if your input file were:
= Index
== Notindex
A paragraph in notindex.
=== Notindex 2
Note that a prior ID extraction pass is not required,
--embed-includes
just makes \Include
read files as they are found in the source.Note that a
In addition to this:
- cross file references are disabled, and the cross file ID database does not get updated.It should be possible to work around this, but we are starting with the simplest implementation that forbids it.The problem those cause is that the IDs of included headers show as duplicate IDs of those in the ID database.This should be OK to start with because the more common use case with
--html-single-page
is that of including all headers in a single document. TODO: this option is gone.
Otherwise,
include
only adds the headers of the other file to the table of contents of the current one, but not the body of the other file. The ToC entries then point to the headers of the included external files.You may want to use this option together with
--embed-resources
to produce fully self-contained individual HTML files for your project.Embed as many external resources such as images and CSS as possible into the HTML output files, rather than linking to external resources.
For example, when converting a simple document to HTML:
index.bigb
= Index
My paragraph.
with:
the output contains references to where OurBigBook is installed in our local filesystem:
The advantage of this is that we don't have to duplicate this for every single file. But if you are giving this file to someone else, they would likely not have those files at those exact locations, which would break the HTML page.
ourbigbook index.bigb
<style>
@import "/home/ciro/bak/git/ourbigbook/_obb/ourbigbook.css";
</style>
<script src="/home/ciro/bak/git/ourbigbook/_obb/ourbigbook_runtime.js"></script>
With
This way, all the required CSS and JavaScript will be present in the HTML file itself, and so readers will be able to view the file correctly without needing to install any missing dependencies.
--embed-resources
, the output contains instead something like:
<style>/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{ [[ ... A LOT MORE CSS ... ]]</style>
<script>/*! For license information please see ourbigbook_runtime.js.LICENSE.txt */ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e() [[ ... A LOT MORE JAVASCRIPT ... ]]</script>
The use case for this option is to produce a single HTML file for an entire build that is fully self contained, and can therefore be given to consumers and viewed offline, much like a PDF.
Examples of embeddings done:
- CSS and JavaScript are copy pasted in place into the HTML.The default built-in CSS and JavaScript files used by OurBigBook (e.g. the KaTeX CSS used for mathematics) are currently all automatically downloaded as NPM package dependencies to ourbigbookWithout
--embed-resources
, those CSS and JavaScript use their main cloud CDN URLs, and therefore require Internet connection to view the generated documents.The embedded version of the document can be viewed offline however.There is however a known bug: KaTeX fonts are not currently embedded, so math won't work properly. The situation is similar as for images, but a bit harder because we also need to fetch the blobs from the CSS, which is likely doable from Webpack:
Examples of embedding that could be implemented in the future:
- images are downloaded if needed and embedded as
data:
URLs.Doing this however has a downside: it would slow the page loading down. The root problem is that HTML was not designed to contain assets, and notably it doesn't have byte position indices that can tell it to skip blobs while parsing, and how to refer to them later on when they show up on the screen. This is kind of why EPUB exists: github.com/ourbigbook/ourbigbook/issues/158Images that are managed by the project itself and already locally present, such as those inside the project itself or due tomedia-providers
usually don't require download.For images linked directly from the web, we maintain a local download cache, and skip downloads if the image is already in the cache.To re-download due to image updates, use either:--asset-cache-update
: download all images such that the local disk timestamp is older than the HTTP modification date withIf-Modified-Since
--asset-cache-update-force
: forcefully redownload all assets
Keep in mind that certain things can never be embedded, e.g.:
- YouTube videos, since YouTube does not offer any download API
Always render all selected files, irrespectively of if they are known to be outdated or not.
OurBigBook stores the timestamp of the last successful ID extraction step for each file.
For ID extraction, we always skip the extraction if the filesystem timestamp of a source file is older than the last successful extraction.
For render:
- we mark output files as outdated when the corresponding source file is parsed
- we also skip rendering non-outdated files by default when you invoke ourbigbook on a directory, e.g.
ourbigbook .
, as this greatly speeds up the interactive error fixing turnaround time - we always re-render fully when you specify a single file, e.g.
ourbigbook path/to/README.bigb
However, note that skipping renders, unlike for ID extraction, can lead to some outdated pages.
This option disables the timestamp skip for rendering, so ensure that you will get a fully clean updated render.
E.g. consider if you had two files:
file1.bigb
= File 1
== File 1 1
file2.bigb
= File 2
== File 2 1
\x[file-1-1]
We then do the initial conversion:
we see output like:
indicating full conversion without skips.
ourbigbook .
extract_ids file1.bigb
extract_ids file1.bigb finished in 45.61287499964237 ms
extract_ids file2.bigb
extract_ids file2.bigb finished in 15.163879998028278 ms
render file1.bigb
render file1.bigb finished in 23.21016100049019 ms
render file2.bigb
render file2.bigb finished in 25.92908499762416 ms
But then if we just modify fil1.bigb as:
the following conversion with
and because we skipped
= File 1
== File 1 1 hacked
{id=file-1-1}
ourbigbook .
would look like:
extract_ids file1.bigb
extract_ids file1.bigb finished in 45.61287499964237 ms
extract_ids file2.bigb
extract_ids file2.bigb skipped by timestamp
render file1.bigb
render file1.bigb finished in 41.026930000633 ms
render file2.bigb
render file2.bigb skipped by timestamp
file2.bigb
render, it will still have the outdated "File 1 1" instead of "File 1 1 hacked".We could in principle solve this problem by figuring out exactly which files need to be changed when a given ID changes, and we already have to solve a similar problem due to query bundling. Also, this will need to be done sonner or later for the OurBigBook Web. But lazy now: github.com/ourbigbook/ourbigbook/issues/207, this is hard stuff.
Parse and overwrite the local .bigb OurBigBook Markup input source files with the recommended code format. E.g.:
overwrites
does that for every single file in the current directory.
ourbigbook README.bigb
README.bigb
with the recommended formatting, and:
ourbigbook .
This option uses the
bigb
output format.In order to reach a final stable state, you might need to run the conversion twice. This is not ideal but we don't have the patience to fix it. The reason is that links in image titles may expand twice. This is the usual type of two level recursion that has caused much more serious problems, see e.g.
the first conversion leads to uppercasing inside the image title:
and the second one to uppercasing the reference to the image title:
\x
within title
restrictions. E.g. starting with:
<image my big dog>
\Image[image.png]{title=My <big dog>}
= Big dog
<image my big dog>
\Image[image.png]{title=My <big Dog>}
= Big Dog
<image my big Dog>
\Image[image.png]{title=My <big Dog>}
= Big Dog
The project templates are simple ourbigbook project directories that serve as good starting point for new ourbigbook projects.
They also contain useful examples of OurBigBook Markup usage to help users get started quickly.
Generate one of the template repositories locally:
ourbigbook --generate default
: a good starter template that illustrates many key OurBigBook featuresourbigbook --generate min
: a minimal template that is still saneourbigbook --generate subdir
: a template in which OurBigBook source is located a subdirectorydocs/
:This template illustrates that everything works exactly as if OurBigBook source were in the git repository toplevel.This is a convenient setup for programming projects that want to use OurBigBook for their documentation without polluting their toplevel.
End users almost never want this, because it means that to have a sane setup you need to:so maybe we should just get rid of that option and just ensure that we can provide an up-to-date working template for the latest relase.
- install OurBigBook globally with
npm install -g ourbigbook
- generate the template
- then install OurBigBook locally again with
npm install
For now we are keeping this as it is useful to automate the updating of templates during the release procedure.
You can get an overview of all macros in JSON format with:
ourbigbook --help-macros
Give multiple times to enable a list of certain types of logs to stderr help debugging, e.g.:
Note that this follows commander.js' insane variadic argumentso syntax, and thus the
./ourbigbook --log ast tokens -- README.bigb
--
is required above. If you want to omit it for a single value you have to add the =
sign as in:
./ourbigbook --log=ast README.bigb
Values not documented in other sections:
ast
: the full final parsed abstract syntax tree as JSONast-simple
: a simplified view of the abstract syntax tree with one AstNode or AstArgument per line and showing only the most important fieldsast-pp-simple
: view snapshots of the various abstract syntax tree post process stages, more info at: conversion process overviewast-inside
: print the AST from inside theourbigbook.convert
call before it returns.This is useful to debug the program ifourbigbook.convert
blows up on the next stages before returning.db
: show database transactions done by OurBigBook, to help debug stuff like cross file referencesmem
: show process memory usage as per Node.js'process.memoryUsage()
after each--log perf
step: stackoverflow.com/questions/12023359/what-do-the-return-values-of-node-js-process-memoryusage-stand-for. Implies--log perf
.To use this options, you must run OurBigBook with the--expose-gc
command line option, e.g. with:node --expose-gc $(which ourbigbook) myfile.bigb
parse
: parsing stepstokenize
: tokenization stepstokens
: final parsed token streamtokens-inside
: likeast-inside
but for tokens.Also adds token index to the output, which makes debugging the parser way easier.
This nifty little option outputs to stderr what the header graph looks like!
It is a bit like a table of contents in your terminal, for when you need to have a look at the outline of the document to decide where to place a new header, but are not in the mood to open a browser or use the browser editor with preview.
Sample output excerpt for this document:
= h1 ourbigbook
== h2 1 quick-start
== h2 2 design-goals
=== h3 2.1 saner
=== h3 2.2 more-powerful
== h2 3 paragraphs
== h2 4 links
This option can also serve as a debug tool for header tree related features (confession: that was its original motivation!).
TODO
print performance statistics to stderr, for example
could output:
which shows how long different parts of the conversion process took to help identify bottlenecks.
./ourbigbook --log=perf README.bigb
perf start: 181.33060800284147
perf tokenize_pre: 181.4424349963665
perf tokenize_post: 318.333980999887
perf parse_start: 319.1866770014167
perf post_process_start: 353.5477180033922
perf post_process_end: 514.1527540013194
perf render_pre: 514.1708239987493
perf render_post: 562.834307000041
perf end: 564.0349840000272
perf convert_input_end 566.1234430000186
perf convert_path_pre_sqlite 566.1564619988203
perf convert_path_pre_sqlite_transaction 566.2528780028224
perf convert_path_post_sqlite_transaction 582.256645001471
perf convert_path_end 582.3469280004501
This option can also be useful to mark phases of the conversion to identify from which phase other logs are coming from, e.g. if we wanted to know which part of the conversion is making a ton of database requests we could run:
and we would see the database requests made at each conversion phase.
ourbigbook --log db perf -- README.bigb
Note that
--log perf
currently does not take sub-converts into account, e.g. include and \OurBigBookExample
both call the toplevel conversion function convert
, and therefore go through all the conversion intervals, but we do not take those it account, and just dump them all into the same toplevel interval that they happen in, currently between post_process_start
and post_process_end
.Skip the database sanity check that is normally done after the ID extraction step.
This was originally added to speed up, originally added to speed up the web upload development loop, when we knew that there were no errors in the database after a local conversion, and wanted to get to the upload phase faster, but the DB check can take several seconds for a large input.
But it then later also found usage with Parallel builds followed by a
--check-db-only
.Don't use the ID database during this run. This implies that the on-disk database is not read, and also not written to. Instead, a temporary clean in-memory database is used.
If not given, cross references render with the
.html
extension as in:
<a href=not-readme.html#h2-in-not-the-readme>
This way, those links will work when rendering locally to
.html
files which is the default behaviour of:
ourbigbook .
If given however, the links render without the
which is what is needed for servers such as GitHub Pages, which automatically remove the
.html
as in:
<a href=not-readme#h2-in-not-the-readme>
.html
extension from paths.This option is automatically implied when publishing to targets that remove the
.html
extension such as GitHub pages.Only extract IDs to fill the ID database, don't render. This saves time if you only want to render a single file which has references to other files without getting any errors.
Same as
--no-render
, but for the -W
, --web
upload stage.Web upload consists of two stages:
- extract local ids and render to split ourbigbook files. This can be disabled with
--no-render
- upload to web first on an ID extraction pass, and then a render pass.
--no-web-render
skips that render pass
Set a custom output directory for the conversion.
If not given, the project toplevel directory is used.
Suppose we have an input file
places its output at:
./test.bigb
. Then:
ourbigbook --outdir my_outdir test.bigb
my_outdir/test.html
The same would happen if we instead did a full directory conversion as in:
The output would also be placed in
ourbigbook --outdir my_outdir .
my_outdir/test.html
.This option also relocates the
would generate:
This means that the source tree remains completely clean, and every output and temporary cache is put strictly under the selected
out
directory to the target destination, e.g.:
ourbigbook --outdir my_outdir test.bigb
my_outdir/out
--outdir
.Save the output to a given file instead of outputting to stdout:
./ourbigbook --outfile not-readme.html not-readme.bigb
The generated output is slightly different than that of:
because with
./ourbigbook not-readme.bigb > not-readme.html
--outfile
we know where the output is going, and so we can generate relative includes to default CSS/JavaScript files.Default:
html
output format.The default output format. Web pages!!!
Outputs as OurBigBook Markup, i.e. the same format as the input itself!
While using
-O bigb
is not a common use case, the existence of this format has the following applications:- automatic source code formatting e.g. with
--format-source
. The recommended format, including several edge cases, can be seen in the test file test_bigb_output.bigb, which should be left unchanged by abigb
conversion. - manipulating source code on OurBigBook Web to allow editing either individual sections separatelly, or multiple sections at once
- this could be adapted to allows us to migrate updates with breaking changes to the source code more easily. Alternatively on OurBigBook Web, we might just start storing the AST instead of source, and just rendering the source whenever users want to edit it.
Can be tested interactively with:
ourbigbook --no-db -O bigb --stdout --log=ast-simple test_bigb_output.bigb
One important property of the
bigb
conversion is that is must not alter the AST, and therefore neither the final output, in any way.One good test is:
ourbigbook README.bigb &&
mv out/html/index.html out/html/old.html &&
ourbigbook --format-source README.bigb &&
ourbigbook README.bigb &&
diff -u out/html/old.html out/html/index.html
This was tracked at: github.com/ourbigbook/ourbigbook/issues/83
This output format is used an intermediate step in automatic ID from title, that unlike the regular HTML output does not have any tags.
It does not have serious applications to end users. We decided to expose it from the CLI mostly for fun, as it posed no extra work at all as it is treated internally exactly like any other conversion format.
The
id
output format conversion is very simplistic: it basically just extracts the content
argument of most macros.An important exception to that behaviour is the first argument of the
\x
macro: see \x
id
output format.For example, converting:
with the
instead of the HTML output:
\i[asdf]
id
output format produces simply:
asdf
<i>asdf</i>
This conversion type is useful in situations that users don't expect conversion to produce any HTML tags. For example, you could create a header:
and then following the automatic ID from title algorithm, that header would have the more commonly desired ID
= My \i[asdf]
my-asdf
, and not my-<i>asdf</i>
or my-i-asdf-i
.Similarly, any macro argument that references an ID undergoes
which is equivalent to:
id
output format conversion. E.g. the above header could be referenced by:
<My \i[asdf]>
\x[my-asdf]
Besides being more intuitive, this conversion also guarantees greater format portability, in case we ever decide to support other output formats besides HTML!
Macros that don't have a
content
argument are just completely removed, i.e. typically non-textual macros such as images. We could put effort in outputting their title argument correctly, but meh, not worth the effort.The
id
output format also serves as a good start generalizing OurBigBook to multiple outputs, as this is a simple format.\x
uses href
if the content is not given explicitly.Previously, if
\x
didn't have a content, we were actually rendering the \x
to calculate the ID. But then we noticed that doing so would require another parse pass, so we just went for this simpler approach. This is closely linked to \x
within title
restrictions.For example in:
= Animal
\x[image-i-like-dog]
\Image[dog.jpg]
{title=I \i[like] \x[dog]}
== Dog hacked
{id=dog}
If you wanted
image-i-like-dog-hacked
instead, you would need to explicitly give it as in:
= Animal
\x[image-i-like-dog-hacked]
\Image[dog.jpg]
{title=I like \x[dog][dog hacked]}
== Dog hacked
{id=dog}
For similar reasons as the above,
and not:
{p}
inflection with the \x
p
argument is not considered either, e.g. you would have:
= Animal
\x[image-i-like-dog]
\Image[dog.jpg]
{title=I like \x[dog]{p}}
== Dog
\x[image-i-like-dogs]
This can however be worked around with the
\x
magic
argument as in;
= Animal
\x[image-i-like-dogs]
\Image[dog.jpg]
{title=I like <dogs>}
== Dog
One day, one day. Maybe.
OurBigBook tooling is so amazing that we also take care of the HTML publishing for you!
Once a publish target is properly setup, all you have to do is run:
and your changes will be published to the default target specified in
git add README.bigb
git commit -m 'more content!'
ourbigbook --publish
ourbigbook.json
.If not specified, e.g. with the the
--publish-target
option, the default target is to publish to GitHub Pages.Only changes committed to Git are pushed.
Files that Every other Git-tracked file is pushed as is.
ourbigbook
knows how to process get processed and only their outputs are added to the published repo, those file types are:.bigb
files are converted to.html
.scss
files are converted to.css
When
--publish
is given, stdin input is not accepted, and so the current directory is built by default, i.e. the following two are equivalent:
./ourbigbook --publish
./ourbigbook --publish .
Publishing only happens if the build has no errors.
Like the
--publish
option, but also automatically:git add -u
to automatically add change to any files that have been previously git trackedgit commit -m <commit-message>
to create a new commit with those changes
This allows you to publish your changes live in a single command such as:
ourbigbook --publish-commit 'my amazing change' .
With great power comes great responsibility of course, but who cares!
Attempt to publish without converting first. Implies the
--publish
option.This can only work if there was previously a successful publish conversion done, which later failed to publish during the following steps, e.g. due to a network error.
This option was introduced for debugging purposes to help get the git commands right for large conversions that took a look time.
What type of target to publish for. The generated output of each publish target is stored under:
e.g.:
out/publish/out/<target>
out/publish/out/local
Publish to GitHub Pages. See also: Section 5.5.22.3. "Publish to GitHub Pages".
Publish as a local directory that can be zipped and sent to someone else, and then correctly viewed by a browser locally by the receiver. You can then zip it from the Linux command line for example with:
Maybe we should do the Zip step from the OurBigBook CLI as well. There is no Node.js standard library wrapper however apparently: stackoverflow.com/questions/15641243/need-to-zip-an-entire-directory-using-node-js
ourbigbook --publish --publish-target local
cd out/publish/out
zip -r local.zip local
GitHub pages is the default OurBigBook publish target.
Since that procedure is so important, it is documented directly at: play with the template.
If you want to publish your root user page, which appears at
/
(e.g. github.com/cirosantilli/cirosantilli.github.io for the user cirosantilli
), GitHub annoyingly forces you to use the master
branch for the HTML output:This means that you must place your
.bigb
input files in a branch other than master
to clear up master
for the generated HTML.ourbigbook
automatically detects if your repository is a root repository or not by parsing git remote
output, but you must setup the branches correctly yourself.So on a new repository, you must first checkout to a different branch as in:
or to move an existing repository to a non-master branch:
git init
git checkout -b dev
git checkout -b dev
git push origin dev:dev
git branch -D master
git push --delete origin master
You then will also want to set your default repository branch to
dev
in the settings for that repository: help.github.com/en/github/administering-a-repository/setting-the-default-branchIt's a GitHub bug/feature: github.com/orgs/community/discussions/52252
Maybe we should just ignore the
.github
directory when publishing, otherwise it leads to a broken link on the _dir
directory listings.TODO find some upstream discussion.
Split each header into its own separate HTML output file.
This option allows you to keep all headers in a single source file, which is much more convenient than working with a billion separate source files, and let them grow naturally as new information is added, but still be able to get a small output page on the rendered website that contains just the content of the given header. Such split pages:
- load faster on the browser
- get way better Google PageRank for title hits
- allow for full metadata display, e.g.:
- Header metadata section
- Disqus/Giscus comments
For example given an input file called
a conversion command:
would produce the following output files:
hello.bigb
and containing:
= h1
h1 content.
A link to another section: \x[h1-1].
== h1 1
h1-1 content.
== h1 1 1
h1-1-1 content.
== h1 1 2
h1-1-2 content.
ourbigbook --split-headers hello.bigb
hello.html
: contains the entire rendered document as usual.Remember that this is calledhello.html
instead ofh1.html
because the toplevel header ID is automatically derived from its filename.Each header contains a on-hover link to the single-file split version of the header.hello-split.html
: contains only the contents directly under= h1
, but not under any of the subheaders, e.g.:Theh1 content.
appears in this rendered outputh1-1-1
does not appear in this rendered output
-split
suffix can be customized with the\H
splitSuffix
argument option. The-split
suffix is appended in order to differentiate the output path fromhello.html
h1-1.html
,h1-1-1.html
,h1-1-2.html
: contain only the contents direcly under their headers, analogously tohello-split.html
, but now we don't need to worry about the input filename and collisiont, and just directly use the ID of each header
--split-headers
is implied by the --publish
option: the published website will automatically get the split pages. There is no way to turn it off currently. A pull request would be accepted, especially if it offers a ourbigbook.json
way to do it. Maybe it would be nice to have a more generalized way of setting any CLI option equivalent from the ourbigbook.json
, and an option cli
vs cli-publish
so that cli-publish
is publish only. Just lazy for now/not enough pressing use case met.By default, all cross references point to the non-split version of headers, including those found in split headers.
The rationale for this is that it gives readers the most context around the header by simply scrolling.
For example, considering the example document at The same applies to cross file references when there are multiple input files.
-S
, --split-headers
, cross references such as \x[h1-1]
would point:- from the non-split
hello.html
to the section in the current non-split file#h1-1
- from split
hello-split.html
to the same section in non-split file withhello.html#h1-1
In order to make the split version be the default for some headers, you can use the
\H
splitDefault
argument.This is something that we might consider changing with some option, e.g. keeping the split headers more self contained. But for now, the general feeling is that going to nosplit by default is the best default.
When converting a file, output output to stdout in addition to outputting to a file:
The regular output file is also saved.
convert --stdout input.bigb
Cannot be used when converting a directory.
Select a custom Liquid template file for the output.
If not given, this option defaults to the value of
template
, which if not given defaults to ourbigbook.liquid.html
.The repository of this documentation for example has a sample
ourbigbook.liquid.html
at: ourbigbook.liquid.html.If no template is present, the default template at one point was:
This will get out of sync sooner or later with the code, but this should still serve as a good base example for this documentation.
<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>{{ title }}</title>
<style>{{ style }}</style>
</head>
<body class="ourbigbook">
{{ body }}
</body>
</html>
Defined variables:
body
: the rendered bodydir_relpath
: relative path from the rendered output to the_dir
directory. Sample usage to link to the root directory listing:<div><a href="{{ dir_relpath }}{{ html_index }}">Website source code</a></div>
git_sha
: SHA of the latest git commit of the source code if in a git repositorygithub_prefix
: this variable is set only if if the "github" media provider. It points to the URL prefix of the provider, e.g. if you have in yourourbigbook.json
:then you can use media from that repository with:"media-providers": { "github": { "remote": "mygithubusername/media" },
<img src="image/x-icon" href="{{ github_prefix }}/myimage.jpg" />
html_ext
:.html
for local renders, empty for server renders.So e.g. to link to an IDmyid
you can use:<a href="{{ root_relpath }}myid{{ html_ext }}">
This will ideally be replaced with a more generic link to arbitrary ID mechnism at some point: github.com/ourbigbook/ourbigbook/issues/135html_index
:/index.html
for local renders, empty for server rendersinput_path
: path to the OurBigBook Markup source file relative to the project toplevel directory that generated this output, e.g.path/to/myfile.bigb
May be an empty string in the case of autogenerated sources, notably automatic directory listings, so you should always check for that with something like:{% if input_path != "" %} <div>Source code for this page: <a href="{{ raw_relpath }}/{{ input_path }}">{{ input_path }}</a></div> {% endif %}
is_root_relpath
. Boolean. True if the toplevel being rendered on this output file is the the index article. E.g. in:README.bigbwith split header conversion, the value of= John Smith's homepage == Mathematics
is_root_relpath
would be:index.html
: truesplit.html
: truemathematics.html
: false
root_page
: relative path to the toplevel page, e.g. eitherindex.html
,../index.html
locally or./
,../
on server oriented rendereingroot_relpath
: relative path from the rendered output to the toplevel directory.This allows for toplevel resources like CSS to be found seamlessly form inside subdirectories, specially when rendering locally.For example, for the toplevel CSSmain.css
which is generated from main.scss, we can use:<link rel="stylesheet" type="text/css" href="{{ root_relpath }}main.css">
Then, when a file is locally, for example under a subdirectorymysubdir/myfile.html
, OurBigBook will set:giving the desired:root_relpath=../
<link rel="stylesheet" type="text/css" href="../main.css">
And if the output path were instead justmyohterfile.html
,root_relpath
expands to an empty string, giving again the correct:<link rel="stylesheet" type="text/css" href="main.css">
This will ideally be replaced with a more generic link to arbitrary ID mechnism at some point: github.com/ourbigbook/ourbigbook/issues/135raw_relpath
: relative path from the rendered output to the_raw
directory. Should be used to prefix all non-OurBigBook Markup output resources, which is the directory where such files are placed during conversion, e.g.<link rel="shortcut icon" href="{{ raw_relpath }}/logo.svg" />
file_relpath
: similar toraw_relpath
, but link to the_file
output directory insteadstyle
: default OurBigBook stylesheetstitle
We pick Liquid because it is server-side safe: if we ever some day offer a compilation service, Liquid is designed to prevent arbitrary code execution and infinite loops in templates.
ourbigbook.liquid.html
is the default template file name used for --template
as mentioned at template
.true
iff the --publish-target
is a standard website, i.e. something that will be hosted publicly on a URL. This is currently true
for the following publish targets:--publish-target github-pages
false
for the following targets:--publish-target local
This template variable is useful to remove JavaScript elements that only work on public websites and not on
localhost
or file:
, e.g.:- Google Analytics
- Giscus
Read tiles from stdin line by line on a while loop and output IDs to stdout only, performing automatic ID from title conversion on each input line.
Sample usage:
outputs:
each with one second intervals between each line.
( echo 'Hello world'; sleep 1; echo 'C++ is great'; sleep 1; echo 'β Centauri' ) | ourbigbook --title-to-id
hello-world
c-plus-plus-is-great
beta-centauri
The original application of this option was to allow external non Node.js processes to be able to accurately calculate IDs from human readable titles since the non-ASCII handling of the algorithm is complex, and hard to reimplement accurately.
From Python for example one may run something like:
from subprocess import Popen, PIPE, STDOUT
import time
p = Popen(['ourbigbook', '--title-to-id'], stdout=PIPE, stdin=PIPE)
p.stdin.write('Hello world\n'.encode())
p.stdin.flush()
print(p.stdout.readline().decode()[:-1])
time.sleep(1)
p.stdin.write('bonne journeé\n'.encode())
p.stdin.flush()
print(p.stdout.readline().decode()[:-1])
This option enables actions that would allow arbitrary code execution, so you should only pass it if you trust the repository author. Enabled functionality includes:
Don't quit
ourbigbook
immediately.Instead, watch the selected file or directory for changes, and rebuild individual files when changes are detected.
Watch every
When a directory is given as the input path, this automatically first does an ID extraction pass on all files to support cross file references.
.bigb
file in an entire directory:
ourbigbook --watch .
Now you can just edit any OurBigBook file such has
README.bigb
, save the file in your editor, and refresh the webpage and your change should be visible, no need to run a ourbigbook
command explicitly every time.Exit by entering Ctrl + C on the terminal.
Watch a single file:
When a single file is watched, the reference database is not automatically updated. If it is not already up-to-date, you should first update it with:
otherwise you will just get a bunch of undefined ID errors every time the input file is saved.
ourbigbook --watch README.bigb
ourbigbook .
TODO: integrate Live Preview: asciidoctor.org/docs/editing-asciidoc-with-live-preview/ to also dispense the browser refresh.
Sync local directory to OurBigBook Web instead of doing anything else.
To upload the entire repository, run from toplevel:
ourbigbook --web
To update just all IDs in a single
This requires that all external IDs that
physics.bigb
source file use:
ourbigbook --web physics.bigb
physics.bigb
might depend on have already been previously uploaded, e.g. with a previous ourbigbook --web
from toplevel.The source code is uploaded, and conversion to HTML happens on the server, no conversion is done locally.
This option is not amazing right now. It was introduced mostly to allow uploading the reference demo content from cirosantilli.com to ourbigbook.com/cirosantilli, and it is not expected that it will be a major use case for end users for a long time, as most users are likely to just edit on OurBigBook Web directly.
Some important known limitations:
- every local file has to be uploaded every time to check if it needs rebuilding or not by comparing old vs new file contents. At Store SHA of each article + descendants and skip API re-renders for entire subtrees we describe a better Git-like Merkle tree method where entire unchanged subtress can be skipped, that will be Nirvana.
- file renaming does not work, it will think that you are creating a new file and blows up duplicates
- if there's an error in a later file, the database is still modified by the previous files, i.e. there is no atomicity. A way to improve that would be to upload all files to the server in one go, and let the server convert everything in one transaction. However, this would lead to a very long server action, which would block any other incoming request (I tested, everything is single threaded)
However, all of those are fixable, and in an ideal world, will be fixed. Patches welcome.
If you delete a header locally and then do
-W
, --web
upload, the article is currently not removed from web.Instead, we simply make its content become empty, and mark it as unlisted.
The reason for this is that the article may have metadata created by other users such as OurBigBook Web discussions, which we don't want to delete remove.
In order to actually remove the header you should follow the procedure from Section 7.1.5. "OurBigBook Web page renaming", which instead first moves all discussions over to a new article before deleting.
It is possible to mark articles as unlisted in OurBigBook Web.
This also happens automatically when doing
-W
, --web
upload for previously published articles that were deleted locally, see also: Section 5.5.29.1. "Local header deletion on web upload"Marking an article as unlisted makes it not show up by default on article listings including:Unlisted articles do however appear on listings such as:
- as descendants of an article when seen on the each article page, i.e. on the Table of contents and below due to dynamic article tree
- on global or per-user listings of latest and top article
- on topics
- lists of articles liked by given users
Ask for the password in an interactive terminal in case there was a default password that would have otherwise been chosen.
Currently the only case where this happens is
--web-test
which automatically sets a default --web-password asdf
.-W
, --web
dry run, skip any operations that would interact with the OurBigBook Web server, doing only all the local preparation required for upload.This is mostly useful for testing the OurBigBook CLI.
Upload only the selected ID with
-W
, --web
.That ID must belong to a file being converted for everything to work well. e.g.:
ourbigbook --web --web-id quantum-mechanics physics.bigb
Force ID extraction on
-W
, --web
, even if article content is unchanged.The only use case so far for this has been as a hack for incomplete database updates.
The correct approach is instead to actually re-extract server side as part of the migration. We should do this by implementing a
Article.reextract
analogous to Article.rerender
, and a helper web/bin/rerender-articles.js.Force remote render of
-W
, --web
, don't skip it if even if the render is believed to be up-to-date with source.This is analogous to -
F
, --force-render
.--web-force-render
does not skip the local pre-conversion to split bigb
format that is done before upload, only the remote render. Conversely, when used together with -W
, --web
, -F
, --force-render
does wkip the local bigb conversion, and not the remove one.Render up to a maxinum of N articles.
Useful for quick and dirty OurBigBook Web performance benchmarking, especially together with
--web-force-render
to avoid skipping over finished files.This option was originally introduced to hep testing bulk nested set updates.
Only update the nested set index after all articles have been uploaded.
There is a complex time tradeoff between using this option or not, which depends on:
- how many articles the user has
- how many articles are being uploaded
This option was initially introduced for Wikipedia bot uploads. At 104k articles, the bulk update takes 1 minute, but each individual update of an empty article takes about 6 seconds (and is dominated by the nested set update time), making this option an indispensable time saver for the initial upload in that case
Therefore in that case, for less than 10 articles you are better off without this option. But with more thatn 10 articles you would want to use it.
This rule of thumb should scale for smaller deployments as well however. E.g. at 10k articles, both individual updates and bulk updates should be 10x faster, so the "use this option for 10 or more articles" rule of thumb should still be reasonable.
Set password from CLI. Really bad idea for non-test users with fixed dummy passwords due e.g. to Bash history.
Set defaults for
is equivalent to:
You can also override those defaults by just specifying them normally, e.g. to do a different user:
--web-*
options that are useful for testing locally:
ourbigbook --web-test
ourbigbook --web --web-url http://localhost:3000 --web-user barack-obama --web-password asdf
ourbigbook --web-test --web-user donald-trump
Set a custom URL for
-W
, --web
from the command line. If not given, the canonical ourbigbook.com is used. This option is used e.g. for testing locally e.g. with:
ourbigbook --web --web-url http://localhost:3000
Also consider
--web-url
for local testing.Set the username for
If not given:
-W
, --web
from the command line, e.g.:
ourbigbook --web --web-url http://localhost:3000 --web-user barack-obama
- use the latest previous successfull web login with
ourbigbook --web
if there are any. In that case, the CLI informs you with a message of type:Using previous username: barack-obama
- otherwise, you will be prompted for it from the command line.
OurBigBook configuration file that affects the behaviour of ourbigbook for all files in the directory.
ourbigbook.json
not used for input from stdin, since we are mostly doing quick tests in that case.While
ourbigbook.json
is optional, it is used to determine the toplevel directory of a OurBigBook project, which has some effects such as those mentioned at the toplevel index file.Therefore, it is recommended that you always have a
ourbigbook.json
in your project's toplevel directory, even if it is going to be an empty JSON containing just:
{}
For example, if you convert a file in a subdirectory such as:
then and so on.
ourbigbook subdir/notindex.bigb
ourbigbook
walks up the filesystem tree looking for ourbigbook.json
, e.g.:- is there a
./subdir/ourbigbook.json
? - otherwise, is there a
./ourbigbook.json
? - otherwise, is there a
../ourbigbook.json
? - otherwise, is there a
../../ourbigbook.json
?
If we reach the root path
/
and no ourbigbook.json
is found, then we understand that there is no ourbigbook.json
file present.List of JavaScript regular expression. If a file path matches any of them, then override
ignore
and don't ignore the path. E.g., if you have several .scss
examples that you don't want to convert, but you do want to convert the main.scss
for the website itself:
"ignore": [
".*\\.scss"
]
"dontIgnore": [
"main.scss"
]
Note however that if an upper directory is ignored, then we don't recurse into it, and
dontIgnore
will have no effect.List of paths relative to the project toplevel directory that OurBigBook CLI will ignore, unless it also has a match in
dontIgnore
.Each entry is a JavaScript regular expression, and it must match the entire path from start to end to count.
If a directory is ignored, all its contents are also automatically ignored.
Useful if your project has a large directory that does not contain OurBigBook sources, and you don't want OurBigBook to mess with it.
Only ignores recursive conversions, e.g. given:
doing:
skips that directory, but
converts it because it was explicitly requested.
"ignore": [
"web"
]
ourbigbook .
ourbigbook web/myfile.bigb
Examples:
- ignore all files with a given extension;
Yes, it is a bit obnoxious to have to escape
"ignore": [ ".*\\.tmp", ]
.
and the backslash. We should use some proper globbing library like: github.com/isaacs/node-glob. But on the other hand ignore from.gitignore
makes this mostly useless, as.gitignore
will be used most of the time.
TODO: also ignore during
-w
, --watch
.Similar to
ignore
, but only ignore the files from rendering converesions such as bigb -> html, scss -> css.Unlike
ignore
, matching files are still placed under the _raw
directory and can be publicly viewed.You almost always want this option over
ignore
, with files that should not be in the repository being just ignored with your .gitignore
instead: Section 5.8.1. "Ignore from .gitignore
".Dictionary of options that control automatic ID from title generation.
If
true
, does Latin normalization on the title.Default:
true
.ASCII normalization is a custom OurBigBook defined normalization that converts many characters that look like Latin characters into Latin characters.
For now, we are using the
deburr
method of Lodash: lodash.com/docs/4.17.15#deburr, which only affects Latin-like characters.In addition to
deburr
we also convert:- en-dash and em-dash to simple ASCII dash
-
. Wikipedia Loves en-dashes in their article titles! - greek letters are replaced with their standard latin names, e.g.
α
toalpha
One notable effect is that it converts variants of ASCII letters to ASCII letters. E.g.
é
to e
removing the accent.This operation is kind of a superset of Unicode normalization acting only on Latin-like characters, where Unicode basically only removes things like diacritics.
OurBigBook normalization on the other also does other natural transformations that Unicode does not do, e.g.
æ
to ae
as encoded by deburr
and further custom replacements.TODO
lodash.deburr
:- only deals with Unicode blocks "Latin-1 Supplement" and "Latin Extended-A", notably missing Latin Extended-B, C and D, which contain some important characters. Pull requests have been ignored:so maybe we should just code our own on top.
- misses some candidates in letterlike symbols
- mathematical operators block
Bibliography:
If
true
, does Punctuation normalization on the title.Default:
true
.Some selected punctuation marks are automatically converted into their dominant corresponding pronunciations. These are:
%
:percent
&
:and
+
:plus
@
:at
−
(Unicode minus sign, U+2212, distinct from the ASCII hyphen):minus
Dashes are added around the signs if needed, e.g.:
C++
:c-plus-plus
Q&A
:q-and-a
Folding@home
:folding-at-home
Dictionary of lint options to enable. OurBigBook tries to be strict about forcing specific styles by default, e.g. forbids triple newline paragraph. But sometimes we just can't bear it :-)
Possible values:
parent
: forces headers to use\H
parent
argument to specify their levelnumber
: forces headers to not use\H
parent
argument to specify their level, i.e. to use a number or a number of=
You should basically always set either one of those on any serious project. Forgetting a
parent=
in a project that uses parent=
everywhere else is a common cause of build bugs, and can be hard to debug without this type of linting enabled.Possible values:
child
: forbids headers from using the\H
tag
argument. They should instead use the\H
child
argument.tag
: forbids headers from using the\H
child
argument. They should instead use the\H
tag
argument.
This dictionnary stores options related to headers.
Sets the default
\H
numbered
argument argument of the toplevel headers of each source file.Note that since the option is inherited by descendants, this can also affect the rendering of ancestors.
github.com/ourbigbook/ourbigbook/issues/188 contains a proposal to instead inherit this property across includes.
If you set this ourbigbook.json option:
it is possible to override it for a specific file with and explicit
{
"h": {
"numbered": true
}
}
=0
\H
numbered
argument:
= Not numbered exception
{numbered=0}
== Child also inherits not numbered
Make every link to something that is not on the current page open on a new tab instead of the current one, i.e. add
target="_blank"
to such links.This options is exactly analogous to the
numbered
option, but it affects the \H
splitDefault
argument instead of the \H
numbered
argument.If given, the toplevel output of each input source is always non-split, and a split version is not generated at all.
This of course overrides the
\H
splitDefault
argument for toplevel headers, making any links go to the non split version, as we won't have a split version at all in this case.E.g.:
ourbigbook.json
{
"h": {
"splitDefault": true,
"splitDefaultNoToplevel": true,
}
}
my-first-header.bigb
= My first header
== My second header
When converted with:
would lead only to two output files:
ourbigbook --split-headers my-first-header.bigb
- my-first-header: not split
- my-second-header: split
Without
splitDefaultNoToplevel
we would instead have:- my-first-header: split
- my-first-header-nosplit: not split
- my-second-header: split
The initial use case for this was in OurBigBook Web. If we didn't do this, then there would be two versions of every article at the toplevel of a file: split and nosplit.
This would be confusing for users, who would e.g. see two new articles on the article index every time they create a new one.
It would also mean that metadata such as comments would be visible in two separate locations.
So instead of filtering the duplicate articles on every index, we just don't generate them in the first place.
If
false
, implies --no-html-x-extension
.The initial application of this option was to Section 5.7. "Redirect from a static website to a dynamic website".
The
media-providers
entry of ourbigbook.json
specifies properties of how media such as images and videos are retrieved and rendered.The general format of
media-providers
looks like:
"media-providers": {
"github": {
"default-for": ["image"], // "all" to default for both image, video and anything else
"path": "data/media/", // data is gitignored, but should not be nuked like out/
"remote": "ourbigbook/ourbigbook-media"
},
"local": {
"default-for": ["video"],
"path": "media/",
},
"youtube": {}
}
Properties that are valid for every provider:
default-for
: use this provider as the default for the given types of listed macros.The first character of the macros are case insensitive and must be given as lower case. Therefore e.g.:image
applies to bothimage
andImage
- giving
Image
is an error because that starts with an upper case character
title-from-src
(bool
): extract thetitle
argument from thesrc
by default for media such as images and videos as if thetitleFromSrc
macro argument had been given, see also: Section 4.2.8.1. "Image ID"
Direct children of media-providers and subproperties that are valid only for them specifically:
local
: tracked in the current Git repository as mentioned at Section 4.2.8.2.1. "Store images inside the repository itself"path
: location of the cloned local repository relative to the root the main repository
github
: tracked in a separate Git repository as mentioned at Section 4.2.8.2.2. "Store images in a separate media repository"path
: analogous topath
forlocal
: a local location for this GitHub provider, where the repository can optionally be cloned.When not during a run with the--publish
option, OurBigBook checks if the path exists locally, and if it does, then it uses that local directory as the source intead of the GitHub repository.This allows you to develop locally without Internet and see the latest version of the images without pushing them.During publishing, the GitHub version is used instead.TODO make this even more awesome by finishing to implement github.com/ourbigbook/ourbigbook/issues/184:- automatically
git push
this repository during deployment to ensure that any asset changes will be available. - ignore the path from OurBigBook conversion as if added to
ignore
, and is not added to the final output, because you are already going to have a copy of it.This way you can use the sanes approach which is to track the directory as a Git submodule as mentioned at: store images in a separate media repository and track it as a git submodule, instead of either:- keeping it outside of the repository
- keeping it in the repository but explicitly ignoring it as well, which is a bit redundant
- automatically
remote
:<github-username>/<repo-name>
youtube
: YouTube videos
Default:
true
For example with:
then
would be place its output under:
instead of
{
"outputOutOfTree": false
}
ourbigbook hello.bigb
hello.html
out/html/hello.html
.Advantages of Disadvantages:
outputOutOfTree=true
:- the source tree becomes cleaner, especially when using
-S
,--split-headers
which can produce hundreds of output files from a single input file - if you want to track several
.html
source files in-tree, you don't need to add an exception to each of of them on the.gitignore
as:*.html !/ourbigbook.liquid.html
- you have to type more to open each output file on the terminal
This option is always forced to
false
when --outdir <outdir>
is given.Implemented at: github.com/ourbigbook/ourbigbook/issues/163
Path of a script that gets executed after conversion, and before upload, when running with the
--publish
option.The script arguments are:
- the publish output directory.That directory is guaranteed to exist when
prepublish
is called.Forgit
-based publish targets, all files are almost ready in there, just waiting for agit add .
that followsprepublish
.This means that you can use this script to place or remove files from the final publish output.
If the
prepublish
script returns with a non-zero exit value, the publish is aborted.If given, use this fixed date as the author and comitter date of the publish commit.
All Git date formats are accepted as documented in
man git-commit
, e.g. 2005-04-07T22:13:13
.ourbigbook.json
options that should be used only on the published output when publishing with the --publish
option.If given these options override pre-existing options on the published output.
Only options that get passed to OurBigBook Library currently take effect, options that affect e.g. only the
ourbigbook
executable don't work currently. Lazy.A custom
remoteUrl
to push build outputs to.If not given this value is extracted by default from the
origin
remote of the Git repository were the source code is located in.Generate custom redirects.
For example:
produces a file in the output called
"redirects": [
["cirodown", "ourbigbook"]
],
cirodown.html
that redirects to ourbigbook.html
.Absolute URLs are also accepted, e.g.:
produces a file in the output called
"redirects": [
["ourbigbook", "https://docs.ourbigbook.com"]
],
ourbigbook.html
that redirects to https://docs.ourbigbook.com
.When dealing with regular headers, you generally don't want to use this option and instead use the
\H
synonym
argument, which already creates the redirection for you.This JSON option can be useful however for dealing with things that are outside of your OurBigBook project.
For example, at one point, this project renamed the repository github.com/cirosantilli/cirodown to github.com/ourbigbook/ourbigbook.
Unfortunately, GitHub Pages does not generate redirects like github.com itself.
So in this case, we've added to the
which produces a file in the output called
ourbigbook.json
of the toplevel user repository github.com/cirosantilli/cirosantilli.github.io the lines:
"redirects": [
["cirodown", "ourbigbook"]
],
cirodown.html
that redirects to ourbigbook.html
.In this case,
cirodown
and ourbigbook
don't have to be any regular IDs present in the database, those strings are just used directly.TODO ideally we should check for conflicts with regular output from split headers IDs or their synonyms. But lazy.
Select the template Liquid file to use.
Serves as the default for the
template
.If this option is not given, and if a file ourbigbook.liquid.html exists in the project, then that file is used.
If ourbigbook.liquid.html exists but you don't want to use it, set the option to
null
and it won't be used.Make every internal cross reference point to the split header version of the pages of the website. Do this even if those pages don't exist, or if they are not the default target e.g. as per the
\H
splitDefault
argument.The initial application of this option was to Section 5.7. "Redirect from a static website to a dynamic website".
If this option is set, then nosplit/split header metadata links are removed, since it was hard to come up with a sensible behaviour to them, and it won't matter on web redirection where every page is nonsplit anyways.
This dict contains options related to interaction between OurBigBook CLI and OurBigBook Web deployments.
Select the default host used forDefaults to
web
publishing. Serves as the default domain for--web-url
- static website where it is used, e.g.
linkFromStaticHeaderMetaToWeb
ourbigbook.com
, the reference Web instance.Capitalized version of
host
, e.g. OurBigBook.com
.Default:
- if
host
is given, use it - otherwise,
OurBigBook.com
Shows up on
linkFromStaticHeaderMetaToWeb
as a potentially more human readable version of the hostname.Type: boolean. Default:
false
.If
true
, adds a link under the metadata section of every header of a OurBigBook CLI static website pointing to the corresponding article on OurBigBook.com, or another OurBigBook Web instance specified by the host
option.It also sends you to Heaven for supporting the project.
This option requires
username
to be set.For example, if you set:
then in the rendering of a README.bigb:
those headers would have a metadata entry pointing respectively to:
"web": {
"username": "myusername",
"linkFromStaticHeaderMetaToWeb": true
}
= Index
== My h2
{scope}
=== My h2 2
{scope}
https://ourbigbook.com/myusername
https://ourbigbook.com/myusername/my-h2
https://ourbigbook.com/myusername/my-h2/my-h2-2
In order for such links not to be broken, you should always first do a Web upload to ensure that the articles are present on OurBigBook.com.
Previously named
linkFromHeaderMeta
.Type: string.
Sets your OurBigBook.com username. This is used e.g. by
linkFromStaticHeaderMetaToWeb
.If given, prepend the given string to every single internal cross file reference output.
The initial application of this option was to Section 5.7. "Redirect from a static website to a dynamic website".
E.g. suppose that you previously had at
myoldsite.com
you had:animal.bigb
= Animal
<Dogs> don't eat <bananas>.
== Dog
plant.bigb
Originally that would render as:
= Plant
== Banana
<a href="#dog">Dogs</a> don't eat <a href="plant#banana">bananas</a>.
But then if you set in
it will instead render as:
where:
ourbigbook.json
:
{
"xPrefix": "https://mynewsite.com/"
}
<a href="#dog">Dogs</a> don't eat <a href="https://mynewsite.com/plant#banana">bananas</a>.
- dogs: untouched as it links to the same page as the current one
- bananas: the prefix is added, as it is on another page
Scopes are automatically resolved so that they will also be present in the target. E.g. in:
subdir/notindex.bigb
<notindex2>
subdir/notindex2.bigb
= Notindex2
we get on
and not:
subdir/notindex.html
:
<a href="https://mynewsite.com/subdir/notindex2.html">
<a href="https://mynewsite.com/notindex2.html">
This section describes how to generate mass redirects from a static website such as cirosantilli.com to a OurBigBook Web dynamic website such as ougbook.com/cirosantilli.
The use case of this is if you are migrating from one domain to another, and want to keep old files around to not break links, but would rather redirect users to the new preferred pages instead to gather PageRank there.
This happened in our case when Ciro felt that OurBigBook Web had reach enough maturity to be a reasonable reader alternative to the static website.
Basically what you want to do in that case is to use the following options:as in:
"publishOptions": {
"toSplitHeaders": true,
"htmlXExtension": false,
"xPrefix": "https://ourbigbook.com/cirosantilli/"
},
The following files are ignored from conversion:Note that this applies even if you try to convert a single ignored file such as:
We are strict about this in order to prevent accidentally polluting the database with temporary data.
ignore
patterns- gitignored files: Section 5.8.1. "Ignore from
.gitignore
" - a few hardcoded basenames, such as
.git
and theout
directory, seeDEFAULT_IGNORE_BASENAMES
in ourbigbook
ourbigbook ignored.bigb
If the project is a Git tracked project, the standard
git
ignore rules are used for ignores. This includes .git/info/exclude
, .gitignore
and the user's global gitingnore file if any.TODO: get this working. Maybe we should also bake it into the
ourbigbook
CLI tool as well for greater portability. Starting like this as a faster way to prototype:
rm -rf out/parallel
mkdir -p out/parallel
# ID extraction.
git ls-files | grep -E '\.bigb$' | parallel -X ourbigbook --no-render --no-check-db --outdir 'out/parallel/{%}' '{}'
./merge-dbs out/db.sqlite3 out/parallel/*/db.sqlite3
ourbigbook --check-db
# Render.
git ls-files | grep -E '\.bigb$' | parallel -X ourbigbook --no-check-db '{}'
Observed
--no-render
speedup on 1k small files from the Wikipedia bot and 8 cores: 3x. So not bad.Observed render speedup on 1k small files from the Wikipedia bot and 8 cores: none. TODO. Is this because of database contention?
The main entry point for the JavaScript API is the
ourbigbook.convert
function.An example can be seen under lib_hello.js.
Note that while doing a simple conversion is easy, things get harder if you want to take multi-file features in consideration, notably cross file reference internals.
This is because these features require interacting with the ID database, and we don't do that from the default
ourbigbook.convert
API because different deployments will have very different implementations, notably:- local Node.js run uses SQLite, an implementation can be seen in the ourbigbook file class
SqlDbProvider
- the in-browser version that runs in the browser editor of the OurBigBook Web makes API calls to the server
These are variables that affect the OurBigBook Library itself, and therefore also get picked up by OurBigBook CLI and OurBigBook Web.
For boolean environment variables, the value of "true" should use be
Every other value is considered false, including e.g.
1
, e.g. as in:
OURBIGBOOK_POSTGRES=1 ./bin/generate-demo-data.js
true
.OurBigBook Web is the software program that powers OurBigBook.com, its official flagship instance, see also: Section 7.1.8. "OurBigBook.com". OurBigBook Web is currently the main tool developed by the OurBigBook Project.
This section contains both end user documentation and developer documentation.
More subjective rationale, motivation and planning aspects of the project are documented at: cirosantilli.com/ourbigbook-com.
OurBigBook Web is a bit like Wikipedia, but where each user can have their own version of each page, and it cannot be edited by others without permission.