Coffee Space


Listen:

Code Highlighting Part 3

Preview Image

Previously I wrote about how the code highlighter works for the website, and it has mostly remained identical to this.

I read an article recently (that I unfortunately lost) about how one website can run JS as if it were a Jupypter Notebook, which I thought is cool - but not very future proof. The whole idea of future-proof content is that even if the language were to die, methods change, the ideas and algorithms can still be used.

I decided to extend the pandoc highlight filter to allow for running Python (the easiest language to support), such that I now have the ability to write the code throughout a page and build a narrative around it.

Use

Instead of using the following to write Python code:

0001 ```python
0002 print("hello")
0003 ```

I can instead use:

0004 ```python-exec
0005 print("hello")
0006 ```

In practice, it looks like this:

0007 print("hello")
hello

As you can now see, the result of writing that execution now appears below the code it ran.

It is quite limited, admittedly, but we can do some cool things with it. For example, we can declare a variable:

0008 a = 3 # first num
0009 b = 2 # second num

Then do something with it later:

0010 print("a = " + str(a))
0011 print("b = " + str(b))
0012 c = a * b
0013 print("a x b = " + str(c))
a = 3
b = 2
a x b = 6

This also applied to things such as functions:

0014 def factorial(n) :
0015   if n > 1 :
0016     return n * factorial(n - 1)
0017   return n

And again, using them later:

0018 print("8! = " + str(factorial(8)))
0019 print("16! = " + str(factorial(16)))
0020 print("32! = " + str(factorial(32)))
0021 print("64! = " + str(factorial(64)))
0022 print("128! = " + str(factorial(128)))
8! = 40320
16! = 20922789888000
32! = 263130836933693530167218012160000000
64! = 126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000
128! = 385620482362580421735677065923463640617493109590223590278828403276373402575165543560686168588507361534030051833058916347592172932262498857766114955245039357760034644709279247692495585280000000000000000000000000000000

Implementation

By default, each block runs in an exec() call with its own globals dictionary. It is essentially able to do anything else, so cannot be considered safe for user input.

There is on the other hand a timeout of 10 seconds for each block using Unix signals - but this can be overridden using a try/except block to prevent termination. Ideally the code is small and well considered, if serious computation is needed, this should not be performed during the website build process, but instead offline elsewhere.

Code written in the python-exec block should be carefully considered, as it could do literally anything the normal user can do.

Future

I still need to tidy up the CSS so that it is more obvious what is output and what is not, but I will tackle this some other time 1.

As I hinted at previously, I would like to explore how different algorithms and code works and document this for others (and myself 2).


  1. I will wait till it annoys me too much.↩︎

  2. There has been quite a few times I have had to reference my notes on here to figure out how I previously achieved something.↩︎