-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NbBlock as a container #117
Comments
Sounds good, something I've noticed is that we will probably have to take extra care of stdout capturing. Right now when we create a new block there are multiple things being echo'd by the newBlock template which would get in the way of our capturing. Also if we do nbCode:
nbCode:
echo "Hello world"
echo "Hello world again" Which |
yes, that would be a possible issue (and the advice might just be: don't do that 😛), although in principle the current template |
Haha ok then 🤣 |
ah right. in principle they could be not echos but something that is based on a stdout tracked initially... but honestly I do think that (at least in the beginning) we might just discourage people of nesting inside |
Now that I think of it we really don't want to nest things in nbCode either way as the output of that block has to be placed somewhere and I'm not entirely sure where it would be, it could very well be that it screws up the code block or something 😅 so yeah that's not a problem. It would be nice to be able to show how to use nimib in nimib without writing the code as strings but we have the "wrap it in a template and nbCode the template definition" for that 😎 |
We could even automate that process with a specific template nbNimibCode(body: untyped) =
nbCode:
template temp() {.gensym.} =
body
# Highjack the nbCode block:
nb.blk.command = "nbNimibCode"
temp() and then add a step in the rendering plan of This would allow us to do: nbNimibCode:
nbText: "Hello world" without any problems with capturing stdout. |
from dicussion in #74 there might be the option of making every block a container block... |
So, my wishlist for working with container blocks is to be able to do two things:
|
I have thought a bit about the API and one thing that is problematic is when we use So how can we solve this? One idea is to expose a newNbBlock(....):
nbContainer:
# code here is run in a new "environment"
body
# nb.blk is reset to the current block by nbContainer
echo nb.blk.blocks # the contained blocks can be accessed here. Another problem is if we go the route of reassigning This is mainly some brainstorming from my side. Probably a lot of things I haven't thought about. |
My rough idea is that there is a stack of blocks and on top of the stack the current container. Every time you create a new block current block goes on top of the stack for the duration of block implementation. In principle nothing prevents the global nb to be always accessible. Of course many pieces should be adopted including code in newNbBlock. Having said that I have tried to materialize this idea in a specific api and type implementation but have not yet succeeded. I have not tried really hard though, and my feeling (maybe hope) is that there is hidden (maybe even not so hidden) an easy way to do that... |
Yes it will become a stack, but I don't think we explicitly have to create the stack data structure. It is enough if we just keep track of the parent every time we create a new container. By adding a template nbContainer(body: untyped) =
# This is the "stack" part where we save the current value
# to be able to reset them when we reach the end of the
# container and "pop" the stack:
let currentBlk = nb.blk
let currentBlocks = nb.blocks
nb.blocks = @[]
# run the containing blocks
body
# reset values and assign the blocks to the container block
nb.blk = currentBlk
nb.blk.blocks = nb.blocks
nb.blocks = currentBlocks I haven't actually tried this but it should work 🙃 And we would need a better name for the template, |
That's an interesting solution with minimal changes to existing types! By using a template you let the template create all the temporary variables for the stack without the need to manage them. I was not thinking about a template because I guess this is something we should only use once in newNbBlock and it is normally never used by the user right? But the template itself is reused many times... so that is clever! The only slight fear I have is that it might be more difficult to find out bugs if there are compiler related issues with templates (we do end up with quite a number of templates one inside the other and I do feel there are some bugs lurking there that I already ran into without quite understanding). This does not mean we cannot proceed like this, fearlessly challenging the compiler (and maybe later we might want to retreat to a safer and more explicit api...). So let's try! As for the name, even more so if it is not something that we can reuse (although we might still want to make it public), we can go with a long descriptive one such as nbUseCurrentBlockAsContainer or similar |
Btw unrelated to the container thing but since we are messing up with newNbBlock, maybe there is also a way to check if the current containing block is capturing stdOut, putting it on pause and starting it back again later... in that way we might have something that helps us solve the issue with nbCode inside other templates or this is also something that would make captured text and shown images and tables appear in the correct order. Not that I think it is a very big issue if we have all captured text before or after. Also now that I think of this, it kind of means we need to manage a sequence of outputs, so mmmh no, not really convinced that this could work, so you can discard this remark entirely (unless it gives you better ideas!). |
Exactly, it's only block-creators who will need to use this. And the nice thing is also that this change wouldn't break current code, as without using this template you just get the old behavior.
I understand your fear, but as you say, we are already nesting templates inside templates inside templates so adding another layer doesn't hurt 🤣 Do you have any concrete examples of bugs you couldn't understand related to templates?
Yes it needs to be public for library creators to access it (nimiSlides will need to use it for
I think we can use the same concept of a stack for stdout as well. Right now we unmount the ordinary stdout and attach our own file. But what if we introduced a new
This way, the innermost block that uses Furthermore, I think we should implement a So I don't think this is a bad idea, it's a good one ;) As for the placement of the output of the children, that's why we will introduce the |
I have experimented with this locally today and it seems to work. This is how an updated template nbCode*(body: untyped) =
newNbCodeBlock("nbCode", body):
captureStdout(nb.blk.output):
nbUseCurrentBlockAsContainer:
body
nb.partials["containedBlocks"] = """
{{#blocks}}
{{&.}}
{{/blocks}}
"""
nb.partials["nbCode"] = """
{{>nbCodeSource}}
{{>nbCodeOutput}}
{{>containedBlocks}}
"""
nb.renderPlans["nbCode"] = @["highlightCode", "renderContainer"] where proc renderContainer(doc: var NbDoc, blk: var NbBlock) =
var children: seq[string]
for child in blk.blocks.mitems:
children.add doc.render(child)
blk.context["blocks"] = children The stdout handling was a lot trickier, mostly because of me not understanding the low-level file API. But I think I got something working in the end. Before creating a PR and testing further, is there something in the example above that you have any comments on? |
Looks good to me!
There was a case when preparing slides for nimconf but forgot exactly what. There might be a remark in the comments... |
Ok, I will try to create a PR tomorrow then 👍 I tried looking through the NimConf files but I couldn't find any comments on this in the most recent files, and I didn't find any commit messages regarding it. So either I'm bad at reading or the comments are in an older commit. The only issue I can remember was the one with nbCode from different files, but that should be solved now when we look for the source in the correct files. |
another use case fo containers: |
currently you cannot nest block inside one another e.g. you cannot do stuff like:
the above is not a great use case, a better use case would be to create html tabs:
and also nimislides has a similar use case when it does:
as a first thought there should be 3 changes to make:
isContainer
field. If it is container you have fieldsblocks: seq[NbBlock]
,blk: NbBlock
as inNbDoc
nb
object to track who is current container, eithernb
itself or some container block (so that the newNbBlock template can be called with correct container where to add the block)it is possible that this does not break too much the api, so it could be considered for 0.3.x
The text was updated successfully, but these errors were encountered: