-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathindex.nim
344 lines (253 loc) Β· 17.3 KB
/
index.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
import nimib, strformat, nimoji
from nimib / renders import useMdBackend
from nimib / themes import noTheme
when defined(mdOutput):
echo "using Markdown backend"
nbInitMd
else:
nbInit
nb.title = "Nimib Docs"
let
repo = "https://github.com/pietroppeter/nimib"
docs = if defined(mdOutput): "https://pietroppeter.github.io/nimib" else: "."
hello = read(nb.srcDir / "hello.nim".RelativeFile)
nbText: hlMdF"""
# nimib :whale: - nim :crown: driven :sailboat: publishing :writingHand:
Nimib provides an API to convert your Nim code and its outputs to html documents.
The type of html output that is obtained by default is similar to html notebooks produced by tools
like [Jupyter](https://nbviewer.jupyter.org/url/norvig.com/ipython/Advent%20of%20Code.ipynb)
or [RMarkdown](https://rmarkdown.rstudio.com/lesson-10.html), but nimib provides this starting
directly from standard nim files. It currently does not provide any type of interactivity or automatic reloading.
If you have some nim code lying around that echoes stuff you can try how nimib works with following these steps:
* run in shell `nimble install nimib`
* add `import nimib` at the top of your nim file
* add a `nbInit` command right after that
* split your code into one or more `nbCode:` blocks
* add some text commentary in markdown through `nbText:` blocks
* add a `nbSave` command at the end
* compile and run
* open the html file that has been generated next to your nim file (same name)
* (you can use runtime option `--nbShow` to open the html file automatically in your default browser)
See below for an example of this.
Nimib strives for:
* a simple API
* sane defaults
* easy customization
The main goal of Nimib is to empower people to explore nim and its ecosystem and share with others.
This document is generated though nimib both as an index.html file and as a README.md,
you should be reading one of the two, for the other:
* [README.md]({repo})
* [index.html]({docs})
Nimib was presented at [NimConf2022](https://nim-lang.org/nimconf2022/), see the [slides](https://github.com/pietroppeter/nimconf22-nimib/) and click thumbnail to see video.
[![nimib nimconf2022 thumbnail](https://github.com/pietroppeter/nimib/raw/d4399747aa4c4435d27e0038046ad0311a92f21d/assets/nimib-nimconf-thumbnail.png)](https://www.youtube.com/watch?v=hZ7wX1kgnuc)
Nimib was also presented in [NimConf2021](https://conf.nim-lang.org),
see [video](https://www.youtube.com/watch?v=sWA58Wtk6L8)
and [slides](https://github.com/pietroppeter/nimconf2021).
The VS Codium / Code extension
[nimiboost](https://marketplace.visualstudio.com/items?itemName=hugogranstrom.nimiboost) ([Open VSX](https://open-vsx.org/extension/hugogranstrom/nimiboost))
provides syntax highlighting of embedded languages in nimib documents (eg. markdown, python, html) and a preview window of nimib documents inside the editor.
## :wave: :earthAfrica: Example Usage
First have a look at the following html document: [hello.html]({docs}/hello.html)
This was produced with `nim r {nb.cfg.srcDir}/hello`, where [{nb.cfg.srcDir}/hello.nim]({repo}/blob/main/{nb.cfg.srcDir}/hello.nim) is:
""".emojize
when not defined(mdOutput):
nbCode: discard
nb.blk.code = hello # "\n" should not be needed here (fix required in rendering)
else:
nbText &"""
```nim
{hello}
```"""
nbText: hlMdF"""
### Other examples of usage
in this repo:
* [index]({docs}/index.html): generate an HTML and a README.md at the same time (you are reading one of the two).
* [penguins]({docs}/penguins.html): explore palmer penguins dataset using ggplotnim (example of showing images).
* [numerical]({docs}/numerical.html): example usage of NumericalNim (example of custom style, usage of latex).
* [cheatsheet]({docs}/cheatsheet.html): markdown cheatsheet (example of a custom block, custom highlighting and a simple TOC).
* [mostaccio]({docs}/mostaccio.html): examples of usage of nim-mustache and of dark mode.
* [interactivity]({docs}/interactivity.html): shows the basic API of creating interactive elements using `nbJsFromCode`.
* [counter]({docs}/counters.html): shows how to create reusable interactive widgets by creating a counter button.
* [caesar]({docs}/caesar.html): a Caesar cipher implemented using `nbKaraxCode` and `karax`.
elsewhere:
* [adventofnim](https://pietroppeter.github.io/adventofnim/index.html): solutions for advent of code in nim
* [intro to binarylang](https://ajusa.github.io/binarylang-fun/intro.html): a introduction to library [binarylang](https://github.com/sealmove/binarylang) (first public usage of nimib I was aware of)
* [nblog](https://github.com/pietroppeter/nblog): a blog about nimib and its ecosystem
* [nimibook](https://github.com/pietroppeter/nimibook): a port of mdbook to nim(ib)
* [SciNim Getting Started](https://scinim.github.io/getting-started/): tutorials for nim in scientific computing
* [Norm documentation](https://norm.nim.town): documentation of a Nim ORM library.
* [NimiSlides](https://github.com/HugoGranstrom/nimib-reveal): a [reveal.js](https://revealjs.com) theme for nimib.
you are welcome to add here what you have built with nimib!
## :hammer_and_wrench: Features
> βI try all things, I achieve what I can.β β Herman Melville, Moby-Dick or, the Whale
The following are the main elements of a default nimib document:
* `nbInit`: initializes a nimib document, required for all other commands to work.
In particular it creates and injects into scope a `nb` object used by all other blocks
(see below section API for internal details).
* `nbCode`: code blocks with automatic stdout capture and capture of code source
* `nbText`: text blocks with automatic conversion from markdown to html (thanks to [nim-markdown](https://github.com/soasme/nim-markdown))
* `nbSave`: save the document (by default to html)
* styling with [water.css](https://watercss.kognise.dev/), light mode is default, dark mode available (`nb.darkMode` after `nbInit`).
* static highlighting of nim code. Highlight styling classes are the same of [highlightjs](https://highlightjs.org/)
and you can pick a different styling (`atom-one-light` is default for light mode, `androidstudio` is default for dark mode).
* (optional) latex rendering through [katex](https://katex.org/) (see below)
* a header with navigation to a home page, a minimal title and an automatic detection of github repo (with link)
* a footer with a "made with nimib" line and a `Show source` button that shows the full source to create the document.
* (optional) possibility to create a markdown version of the same document (see this document for an example: [{nb.cfg.srcDir}/index.nim]({repo}/blob/main/{nb.cfg.srcDir}/index.nim))
Customization over the default is mostly achieved through nim-mustache or changing
`NbDoc` and `NbBlock` elements (see below api).
Currently most of the documentation on customization is given by the examples.
### other blocks
You can find a complete description of the code blocks along with examples in [allblocks]({docs}/allblocks.html).
### creating custom blocks
* `newNbCodeBlock(cmd: string, body, blockImpl: untyped)`: template that can be used to create custom
code block that will need both a `body` and an implementation which might make use of `body`.
Also, the source code in `body` is read.
Example blocks created with `newNbCodeBlock` are `nbCode` and `nbTextWithCode`.
* `newNbSlimBlock(cmd: string, blockImpl: untyped)`: template that can be used to create
a custom block that does not need a separate `body`.
Example blocks created with `newNbSlimBlock` are `nbText`, `nbImage`.
See `src/nimib.nim` for examples on nimib blocks that are built using these two templates.
* a `newId` proc is available for `nb: NbDoc` object and provides an incremental integer.
It can be used in some custom blocks (it is used in `nbJsFromCode` described below).
### interactivity using nim js backend
Nimib can incorporate javascript code generated from nim code using template `nbJsFromCode`.
It also provides a template `nbKaraxCode` to add code based on [karax](https://github.com/karaxnim/karax).
See [interactivity]({docs}/interactivity.html) for an explanation of the api
and [counter]({docs}/counters.html) for examples of how to create widgets using it.
In [caesar]({docs}/caesar.html) we have an example of a karax app
that implements [Caesar cipher](https://en.wikipedia.org/wiki/Caesar_cipher).
### highlighting
Code blocks produced by `nbCode` are statically highlighted, but code in markdown code blocks are dynamically highlighted using
[highlightjs](https://highlightjs.org/). The dynamic highlighting can be disabled by running `nb.disableHighlightJs()`.
The supported languages are the ones listed as "common" [here](https://highlightjs.org/download/) plus Nim, Julia and Latex.
Highlight styling classes are the same of [highlightjs](https://highlightjs.org/)
and you can pick a different styling (`atom-one-light` is default for light mode, `androidstudio` is default for dark mode).
### latex
See [numerical]({docs}/numerical.html) for an example of latex usage.
To add latex support:
* add a `nb.useLatex` command somewhere between `nbInit` and `nbSave`
* use delimiters `$` for inline-math or `$$` for display math inside nbText blocks.
Latex is rendered with [katex](https://katex.org/) through an autodetection during document loading.
### config, command line options and interaction with filesystem
In the default situation a single nimib document
that writes or reads from filesystem will behave as a normal nim file:
the current directory is the directory from where you launch the executable.
When nimib is used to produce a website or in general a collection of document
it is useful to set up a **configuration file**.
A nimib configuration file is a file named `nimib.toml` and
it is a [toml](https://github.com/toml-lang/toml) file.
Every time `nbInit` is called nimib tries to find a config file in current directory
or in any parent directory.
Inside a config file you can define two special directory:
* `homeDir`: the directory to set as current directory.
It can be given as an absolute directory or as a relative directory.
When it is given as a relative directory it is relative with respect
to the directory of config file.
* `srcDir`: the directory where all the sources resides.
It is used to create the output filename that includes a relative path.
In this way the folder structure of nim files can be recreated in the output.
As `homeDir`, it can be set as absolute or relative (to config).
`nbInit` also parses command line options that start with `nb` or `nimib`
that allow to override the above value, skip the config file or other options.
All the options available can be seen by running any nimib file with option `nbHelp`
(execution will stop after `nbInit`).
""".emojize
nbCode:
import osproc
withDir nb.srcDir:
echo execProcess("nim r --verbosity:0 --hints:off --warnings:off hello --nbHelp")
let renderProcType = "type NbRenderProc = proc (doc: var NbDoc, blk: var NbBlock) {. nimcall .}"
nbText: hlMdF"""
The value of options are available in `nb.options` field which also
tracks further options in `nb.options.other: seq[tuple[kind: CmdLineKind; name, value: string]]`.
### define flags
nimib's behavior can be further turned via Nim's define flags:
* `-d:nimibQuiet`: Completely disables nimib's logging to stdout
* `-d:nimibCodeFromAst`: Makes nimib capture block code from AST of body (as opposed to from file source; see next section). Available since version 0.3
### Code capture
The code capture of a block like `nbCode` (or other custom blocks)
can happen in two different ways:
* `CodeAsInSource` (default since version 0.3): code for a single block
is parsed from file source (available in `nb.source`).
* `CodeFromAst` (default in versions 0.1 and 0.2): code for a single block
is rendered from AST of body. This means that only documentation comments
are shown (since normal comments are not part of the AST) and that the source show
might be different from original source.
## :honeybee: API <!-- Api means bees in Italian -->
* `nbInit` template creates and injects a `nb` variable of type `NbDoc`.
* templates like `nbCode` and `nbText` create a new object of type `NbBlock`,
these objects are added to a sequence of blocks accessible in `nb.blocks`
* the last processed block is available as `nb.blk`
* `nb.blk.output` contains the (non rendered) output of block
* `nb.blk.code` contains the source code of the block (if it was created with `newNbCodeBlock`)
* `NbBlock` is a ref object, so changing `nb.blk`, changes the last block in `nb.blocks`.
Here are two examples that show how to hijack the api:
* [nolan]({docs}/nolan.html): how to mess up the timeline of blocks :hourglass_flowing_sand:
* [pythno]({docs}/pythno.html): a reminder that nim is not python :stuck_out_tongue_winking_eye:
## Rendering
* rendering is currently based on [nim-mustache](https://github.com/soasme/nim-mustache).
This will likely be changed in a next release and in fact refactoring the rendering part of nimib
is the main target for next breaking change, see [#111](https://github.com/pietroppeter/nimib/issues/111)
* there are two rendering backends, a html one and a markdown backend.
In order to use the markdown backend one must initialize its document with `nbInitMd` instead of `nbInit`
* rendering happens during the call to `nbSave`, and two steps are performed:
1. rendering all blocks and adding them to a sequence of blocks (added to `nb.context["blocks"]`)
2. rendering the document starting from `document` partial using
* rendering of a single block depends
on a number of fields of `nb` object:
- `partials`: a `Table[string, string]` that contains the templates/partials for every command (e.g. `nb.partials["nbCode"]`);
- `templateDirs`: a `seq[string]` of folders where to look for `.mustache` templates that can complement/override
the templates in `partials`.
A common usage is to add a `head_other.mustache` template that contain additional content added to head section
of **every** document (in many repositories - including nimib - it is used to add a [plausible analytics](https://plausible.io) script)
- `renderPlans`: a `Table[string, seq[string]]` that contains the render plan (a `seq[string]`) for every step of render plan
an associated `renderProc` is called;
- `renderProcs`: a `Table[string, NbRenderProc]` that contains all available render procs by name.
(`{renderProcType}`)
* the above fields are initialized during `nbInit` with a call to `render` backend and can
be customized by a call to `theme` (`render` and `theme` have default values).
## Changelog and :pray: Thanks
In the [changelog]({repo}/blob/main/changelog.md) you find all recent changes, some early history of nimib, pointers to relevant
examples of usage of nimib and heartfelt thanks to some of the fine folks that
made this development possible.
## :sunrise: Roadmap
- add more themes such as [nimibook](https://github.com/pietroppeter/nimibook).
In particular themes for blogging and for creating general websites.
- can I use nimib to build a library directly from documentation (like in [nbdev](https://github.com/fastai/nbdev))?
- nimib executable for scaffolding and to support different publishing workflows
- server-side dynamic sites (streamlit style? take advantage of caching instead of hot code reloading)
- possibility of editing document in the browser (similar to jupyter UI, not necessarily taking advantage of hot code reloading)
- ...
completed in 0.3:
- [x] refactor rendering of blocks and simplify api extensions ([#24](https://github.com/pietroppeter/nimib/issues/24))
- [x] client-side dynamic site: interactivity of documents, e.g. a dahsboard (possibly taking advantage of nim js backend)
## :question: :exclamation: Q & A
### why the name?
corruption of [ninib](https://www.vocabulary.com/dictionary/Ninib):
> a solar deity; firstborn of Bel and consort was Gula;
> god of war and the _chase_ and agriculture; sometimes identified with biblical *Nimrod*
also:
> He explains that the seven directions were interpreted by the Babylonian theologians
> as a reference to the seven great celestial bodies, the sun and moon, Ishtar, Marduk, Ninib, Nergal and Nabu.
>
> This process, which reached its culmination in the post-Khammurabic period, led to identifying
> the planet Jupiter with Marduk, Venus with Ishtar, Mars with Nergal, Mercury with Nebo, and Saturn with Ninib.
and I should not need to tell you what [Marduk](https://jupyter.org/) is
and why [Saturn is the best planet](https://www.theatlantic.com/science/archive/2016/01/a-major-correction/422514/).
### why the whale :whale:?
why do you need a logo when you have emojis?
no particular meaning about the whale apart the fact that I like the emoji and this project is something I have been [chasing](https://en.wikipedia.org/wiki/Captain_Ahab) for a while
(and I expect to be chasing it indefinitely).
also googling `nimib whale` you might discover the existence of a cool place: [Skeleton Coast](https://en.wikipedia.org/wiki/Skeleton_Coast).
### why the emojis?
because I made a [package](https://github.com/pietroppeter/nimoji) for that and someone has to use it
### why the Q & A?
because [someone made it into an art form](https://github.com/oakes/vim_cubed#q--a)
and they tell me [imitation is the sincerest form of flattery](https://www.goodreads.com/quotes/558084-imitation-is-the-sincerest-form-of-flattery-that-mediocrity-can)
""".emojize
when defined(mdOutput):
nb.filename = "../README.md"
nbSave
else:
nbSave