Inline variable insertion in markdown

Here is a tech demo I made years ago exploring some possibilities around rich javascript input in a code cell: jsfiddle of codemirror live widgets · GitHub

3 Likes

That’s a wonderful offer @jasongrout, thanks so much! I’d certainly join in just to learn a bit more about the APIs, and if you don’t mind, I think having a recording of this (totally informal, live, as-it-goes) could be very useful for others as well!

2 Likes

Hey I would like to help with this. I set up a doodle to start this experiment based on @jasongrout time slots suggestion.

https://doodle.com/poll/b9gga38v5q6q2pig?utm_source=poll&utm_medium=link

A technical suggestion, what about using the existing cell attachments to store the expression mime bundle.

2 Likes

@fcollonval honestly, this seems like a good idea. I considered it yesterday, but I think I was pushing harder to do something more radical. A :+1: from me!

OK, I’ve created an initial repository to prototype this, and given @fperez, @fcollonval, and @jasongrout access.

So far, this repo only contains a Markdown-it tokenizer implementation. This does work in standalone, but I noticed that I couldn’t see the set data-expression attribute in the Chrome inspector. Perhaps a sanitizer thing?

Anyway, the hard part is re-implementing a Markdown cell given that lots of the core logic is private.

1 Like

Thanks so much @agoose77 for moving forward! Exciting to see this idea re-started after so many early attempts :slight_smile:

And I’m +1 on the cell attachments approach too, I was actually pondering that as I realized that the metadata dicts could get pretty unwieldy if potentially larger outputs come in. You don’t expect a small “metadata post it” (which is how I think of them) to all of a sudden have a large base64-encoded image in it!

This will be great to explore and play with. Full disclosure: I’m so overloaded with other things in the project that I can’t realistically expect to contribute too much, but I’m delighted to be along for the ride. I’ll do my best to learn, pitch in when I can, and don’t worry about ever bottlenecking on me. If I’m not around, carry on happily with the rest of the community and I’ll catch up as I can, always grateful for people putting their energy into the project.

I won’t be able to pair for a significant amount of time in the next two weeks, but I could quickly go over my notes from above (i.e., 30-45 minutes) in the next week, and then it probably makes most sense to make sure someone that understands jlab extensions deeply is there. I could pair for a more significant amount of time (like half a day or something, and doesn’t have to be an afternoon) in the last week of September.

Great, I’d be up for both! :pray:

@fcollonval and I had a meeting today to talk about this, and we’ve got a proof-of-concept working. This still needs a lot of work, but it’s fun to play around with!

preview

@jasongrout when prototyping this, I ran into a few places where the existing API for the notebook was pushing me to shadow large parts of MarkdownCell because it was private. Where’s the best place to discuss this part of the codebase e.g. to think about improving the API?

4 Likes

That is neat @agoose77! In this prototype, do you only replace variables, or can you execute arbitrary inline statements?

This can evaluate an expression and render the result (subject to some bugs, e.g. Label widgets don’t seem to work right now). The formatting is not quite right yet either; raw text/plain is formatted as <pre> which is a block element.

Notebooks should save the MIME bundles in cell.attachments, but currently JupyterLab has some naive logic for wiping unreferenced attachments on save, so rendered outputs aren’t saved properly.

This is super cool - what can I do to help either improve this or push this forward? I bet that @rowanc1 would be interested in providing input and ideas as well as I think CurveNote has built similar kinds of functionality into their UI, so maybe they have some UX experience that’d be useful

1 Like

@fcollonval is looking into alternative Markdown syntax (which would potentially remove the jupyterlab-markup dependency (which is good for core, as I suspect moving JLab to Markdown-It would be a major change)). This would perhaps be a good area to discuss. If we don’t use something that we already parse well (like a link syntax), then we’d need to further modify our Markdown renderer.

In theory, the JLab side of things hasn’t got too much left to do for this PoC. There are a few bugs, but otherwise it works as is. The next piece of the puzzle is figuring out nbconvert. Ignoring the execute feature, nbconvert should already have the MIME bundles in the MarkdownCell.attachments metadata, so it’s a question of implementing a renderer.

We also need to discuss how things should render when there aren’t any cell attachments available (e.g. red warning emojis?!).

Sounds good - two quick thoughts:

  • Perhaps you’d be interested in this thread, which was inspired by this conversation and which I think could make it easier to support this at the execute level in nbconvert Create some extension points for notebook / cell execution · Issue #158 · jupyter/nbclient · GitHub
  • IMO the syntax choice shouldn’t be constrained at the design phase by implementation questions like “what markdown parser should we use”. That’s fine for prototypes, but ultimately we should try to use the best-possible syntax in general, not restrict it to whatever marked.js already knows how to parse
2 Likes

Nice demo, but it begs a question…

If you have a code cell:

a = 1

A markdown cell:

The value of `a` is {{ a }}

And code cell:

a = 2
print(f"The printed display of a is {{ a }}")
display(f"The displayed display of a is {{ a }}")

then you run all three cells, what does the markdown cell do?

If you now change the value of a in the first cell and run it, does the markdown cell update? What what about the other references to a? Are just the markdown cells reactive? Is cell order in the notebook relevant? (Channel your inner Joel Grus to consider the “hidden state” fallout etc! :wink:

These are indeed “things to be wary of”, but they also apply to the rest of the notebook. In Jupyter Notebooks (ignoring akernel), cell ordering is important, and side effects are entirely “supported”!

:slight_smile:

I also wonder about a markdown cell such as:

What happens to {{ a }} if we add 1 as per {{ a + 1}} or if we try to make an assignment {{ a=1; a}}

What happens if a is a mutable list or a dict? Can it be changed from the markdown cell?

I think it makes most sense if markdown can only literally display a value in terms of maintaining the integrity and transparency of the code. That said, being able to influence the format of the output value (for example formatting a float to 1dp) would be useful.

(I’ve also been pondering akernel in the context of this thread…)

1 Like

Only “expressions” can be evaluated in this context (which depends upon the interpretation of “expression” by the kernel in use). For IPython, this means statements are not legal, nor are the walrus assignments (which is an expression, but forbidden at root level).

If we make a stateful callable, e.g.
image
then we can easily introduce non-reproducible outputs. But that holds for code cells, as before :slight_smile:

If we want to start adding rules to this, then we deviate from “expression” as determined by the kernel, which becomes a lot more problematic as the frontend has to start understanding the language of the kernel.

1 Like

My model of the inline Markdown is that the inline Markdown snippets get ‘executed’ when it the cell is rendered, just as the code cell does. The inline system could allow:

  • Variables only or
  • Expressions or
  • Abitrary code.

So, your question boils down to whether one of your inline snippets raises an error or not.

Someone reasonably asked what to do about stdout, and about cell execution numbers - and I guess we could avoid those two questions by allowing variables only - but I suspect that there would quickly be a use for more complex expressions. Maybe we could mine some R notebooks to see what people have got up to there?