Created
February 14, 2023 15:08
-
-
Save pietroppeter/493ff1b546f783d12c935e7fc1e25532 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# minib (a mini nimib) | |
import strformat, macros | |
import tempfile | |
proc dup*(oldfd: FileHandle): FileHandle {.importc, header: "unistd.h".} | |
proc dup2*(oldfd: FileHandle, newfd: FileHandle): cint {.importc, header: "unistd.h".} | |
macro toStr*(body: untyped): string = | |
(body.toStrLit) | |
type | |
NbBaseBlock* = ref object of RootObj | |
blocks*: seq[NbBaseBlock] | |
NbTextBlock* = ref object of NbBaseBlock | |
text*: string | |
NbCodeBlock* = ref object of NbBaseBlock | |
code*: string | |
NbOutputBlock* = ref object of NbBaseBlock | |
output*: string | |
NbImageBlock* = ref object of NbBaseBlock | |
url*: string | |
NbSummaryDetailsBlock* = ref object of NbBaseBlock | |
summary*: string | |
NbDoc* = object | |
blocks*: seq[NbBaseBlock] | |
blk*: NbBaseBlock | |
# capture stuff | |
isCapturingOutput*: bool | |
tmpFile: File | |
tmpFileName: string | |
sysStdout, curStdout: FileHandle | |
template nbStartCapture* = | |
assert not nb.isCapturingOutput | |
# replicates first half of captureStdout | |
# the stdout part of captureStdout is already done in nbInit | |
(nb.tmpfile, nb.tmpFileName) = mkstemp(mode=fmWrite) | |
discard dup2(nb.tmpFile.getFileHandle(), nb.curStdout) | |
nb.isCapturingOutput = true | |
template nbOutput*(o: string) = | |
nb.blk = NbOutputBlock(output: o) | |
nb.blocks.add nb.blk | |
template nbEndCapture* = | |
# second half of captureStdout | |
assert nb.isCapturingOutput | |
flushFile stdout | |
nb.tmpfile.flushFile() | |
nb.tmpFile.close() | |
let o = readFile(nb.tmpFileName) | |
discard dup2(nb.sysStdout, nb.curStdout) | |
if o.len > 0: | |
nbOutput(o) | |
nb.isCapturingOutput = false | |
proc render*(blocks: seq[NbBaseBlock]): string | |
method render*(blk: NbBaseBlock): string {.base.} = | |
render blk.blocks | |
method render*(blk: NbTextBlock): string = | |
&"<p>{blk.text}</p>\n" | |
method render*(blk: NbCodeBlock): string = | |
&"<pre><code class=\"nim\">{blk.code}</pre></code>\n{render blk.blocks}" | |
method render*(blk: NbOutputBlock): string = | |
&"<pre><samp>{blk.output}</pre></samp>\n" | |
method render*(blk: NbImageBlock): string = | |
&"<img src=\"{blk.url}\">\n" | |
method render*(blk: NbSummaryDetailsBlock): string = | |
&"<details><summary>{blk.summary}</summary>\n{render blk.blocks}</details>\n" | |
proc render*(blocks: seq[NbBaseBlock]): string = | |
for b in blocks: | |
result.add render b | |
proc render*(doc: NbDoc): string = | |
render doc.blocks | |
template nbInit* = | |
var nb {.inject.}: NbDoc | |
nb.sysStdout = stdout.getFileHandle() | |
nb.curStdout = dup(nb.sysStdout) | |
template checkCapture* = | |
if nb.isCapturingOutput: | |
nbEndCapture | |
nbStartCapture | |
template nbText*(t: string) = | |
checkCapture | |
nb.blk = NbTextBlock(text: t) | |
nb.blocks.add nb.blk | |
template nbImage*(u: string) = | |
checkCapture | |
nb.blk = NbImageBlock(url: u) | |
nb.blocks.add nb.blk | |
template nbCurrentBlockAsContainer*(body: untyped) = | |
let blk = nb.blk | |
let blocks = nb.blocks | |
nb.blocks = @[] | |
body | |
blk.blocks = nb.blocks | |
nb.blk = blk | |
nb.blocks = blocks | |
template nbSummaryDetails*(s: string, body: untyped) = | |
checkCapture | |
nb.blk = NbSummaryDetailsBlock(summary: s) | |
nbCurrentBlockAsContainer: | |
body | |
nb.blocks.add nb.blk | |
template nbCaptureOutput*(body: untyped) = | |
nbStartCapture | |
body | |
nbEndCapture | |
template nbCode*(body: untyped) = | |
let wasCapturing = nb.isCapturingOutput | |
if wasCapturing: | |
nbEndCapture | |
nb.blk = NbCodeBlock(code: toStr(body)) | |
nbCurrentBlockAsContainer: | |
nbCaptureOutput: | |
body | |
nb.blocks.add nb.blk | |
if wasCapturing: | |
nbStartCapture | |
when isMainModule: | |
nbInit | |
nbText: "hello" | |
nbImage: "img1" | |
nbText: "hello again" | |
nbSummaryDetails("click for details"): | |
nbText "hi" | |
nbImage "img2" | |
nbCode: | |
let a = 1 | |
echo a + 2 | |
nbCode: | |
echo "yo1" | |
nbImage "img3" | |
echo "yo2" | |
nbCaptureOutput: | |
echo "yo3" | |
nbOutput("yo4") | |
echo render nb |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 | |
yo1 | |
yo2 | |
yo3 | |
<p>hello</p> | |
<img src="img1"> | |
<p>hello again</p> | |
<details><summary>click for details</summary> | |
<p>hi</p> | |
<img src="img2"> | |
<pre><code class="nim"> | |
let a = 1 | |
echo a + 2</pre></code> | |
</details> | |
<pre><code class="nim"> | |
echo "yo1" | |
nbImage "img3" | |
echo "yo2"</pre></code> | |
<img src="img3"> | |
<pre><samp>yo4</pre></samp> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
capture is currently buggy