Skip to content

Instantly share code, notes, and snippets.

@pietroppeter
Created February 14, 2023 15:08
Show Gist options
  • Save pietroppeter/493ff1b546f783d12c935e7fc1e25532 to your computer and use it in GitHub Desktop.
Save pietroppeter/493ff1b546f783d12c935e7fc1e25532 to your computer and use it in GitHub Desktop.
# 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
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>
@pietroppeter
Copy link
Author

capture is currently buggy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment