Show HN: Exn – Write and render rich, scriptable, and interactive notes
github.com
github.com
Exonote supports codeblocks like in Markdown. Instead of providing the ability to execute codeblocks, which would lead to literate programming [1] like in Emacs' org-mode, Exonote would execute a program whose source code is properly written [2] elsewhere by calling a function with arguments.
I thought it would be nice to separate prose and source code and embed a program by simply referencing it with a minimalist syntax the same way an image is embedded in Markdown.
This is how an image is embedded in Exonote:
@[title](path/to/img.png)
This is how a program is embedded in Exonote: ${path.to.module:functionOrClass arg1 arg2 "foo bar"}
[1] https://en.wikipedia.org/wiki/Literate_programming[2] By properly written source code, I mean a regular Python package with tree structure, modularity, Python ".py" file extension, et cetera. Thus, with a minimalist syntax, one can embed not only a program whose source code is written in a directory inside an exonotes dossier, but also a program whose distributable package is installed in the current Python virtual environment.
I'm Alex, a tech enthusiast. I'm excited to show you Exonote [1] and Exn [2], two projects I'm working on.
Years ago I crafted Litemark [3] and Codegame [4], two projects for creating codegames, which are programming puzzles with a backstory. A codegame is made up of levels stored in plain old text files as prose written with Litemark, a markup language inspired by Markdown [5]. The player would open the Codegame app to access the first level of the game, read the prose, and then submit Python code to solve the puzzle. The submitted code is evaluated by the Codegame app, then the return compared to the expected result previously defined by the author for this level. A correct answer would unlock the next level.
The idea behind Litemark and Codegame has evolved to embrace more possibilities, leading to the creation of Exonote and Exn which are no longer limited to "programming puzzles with a backstory".
Exonote is a Markdown-inspired markup language for writing rich, scriptable, and interactive notes. An eponymous Python package is available on PyPI to serve as the reference library. The lowercase word 'exonote' could be used as a common noun for a document written with this markup language.
This markup language makes it possible to add interactivity to notes by embedding GUI programs written with Tkinter [6]. Additionally, all or part of an exonote can be arbitrarily generated using custom Python scripts.
On top of Exonote, with Tkinter I built Exn, a lightweight Python desktop application to browse a dossier of exonotes. A dossier is a directory that contains plain old text files with the ".exn" extension (exonotes), assets (images for examples), and Python source code.
Exn's graphical user interface is a metaphor for a book whose pages are exonotes. Thus, the left and right arrow keys allow the reader to navigate from one page to another. The order of the pages is determined by an index file which can be generated automatically from the command line. This file contains the list of exonotes (ordered by their creation timestamp), their titles, and their tags.
Exn also has a built-in search engine that supports regular expressions [7], a Table of Contents (ToC) builder, a 'switcher' (Ctrl+Tab) and other cool stuff.
By expanding the original Litemark/Codegame idea, I unwittingly introduced a security risk. Suppose Bob doesn't have a personal website but has a GitHub repository that he uses as the public dossier for his exonotes. Alice is a tech savvy who knows what exonotes are and would love to explore the contents of the dossier with Exn. But she worries about the security risk of running untrusted code.
To solve this problem without going on an endless sandbox over-engineering journey, I added to Exn two command line options to browse a folder with low and high restriction. Low restriction mode blocks the execution of embedded programs while high restriction mode not only does the same but also blocks executable links (preventing the user from inadvertently running code by clicking on an executable link).
There is more to say about this (double) project, such as the Viewer API to manipulate the live representation of an exonote from a Python script.
This project is functional, still a work in progress with precarious documentation. I'm planning to add a nice plugin mechanism (at the moment it's only possible to change colors and font size of elements) so people can customize Exn (themes, et cetera) or add new functions.
A demo [8] is available to play around with and there is also a "Why use this project" section in the README which contains some interesting stuff not covered in this post.
I would like to know what you think [9] of Exonote and Exn. Your questions, criticisms, and suggestions are welcome !
Postscript: I found by serendipity that the third most popular post on HN (Mechanical Watch by Bartosz Ciechanowski) [10] looks like what I thought was a cool example of what can be done with Exonote/Exn. I had imagined a bike enthusiast working on a prototype on the weekends, taking notes, inserting relevant hyperlinks and images, building interactive 3D models of different parts of the bike and embedding them into the notes, et cetera. It would be a dossier of exonotes describing from scratch how the bike was built, with an astonishing level of detail. This person could keep this dossier private forever or publish it online. Once released, depending on the dossier's license, it can evolve much like open source software.
[1] https://github.com/pyrustic/exonote
[2] https://github.com/pyrustic/exn
[3] https://github.com/pyrustic/litemark
[4] https://github.com/pyrustic/codegame
[5] https://en.wikipedia.org/wiki/Markdown
[6] https://en.wikipedia.org/wiki/Tkinter
[7] https://en.wikipedia.org/wiki/Regular_expression
[8] https://github.com/pyrustic/exn#demo