Skip to main content

Browse a dossier of exonotes

Project description

Demo

Home.exn from the demo dossier

Exonote / Exn

Write and render rich, scriptable, and interactive notes

This project is part of the Pyrustic Open Ecosystem.

Installation     Demo     Latest     Modules

Table of contents

Overview

Exn is a lightweight Python application for browsing a dossier of exonotes. An exonote is plain text written with an eponymous markup language inspired by Markdown and rendered with Tkinter (the default GUI library for Python).

Interactivity can be added to an exonote by embedding GUI programs written in Python with Tkinter. Additionally, all or part of an exonote can be arbitrarily generated using custom Python scripts.

This application is built with the Gaspium framework and uses Shared and Jesth extensively to manipulate data.

This project is built on top of Exonote. Solving issues in Exonote means improving Exn. Check the issues !

Dossier of exonotes

A dossier is a directory containing exonotes and resources such as attachments and Python source code. At the root of a dossier should be an index file containing an ordered list of exonotes filenames, titles, and their associated tags. The index file is generated automatically by the --build command in the command line (the order is based on the creation timestamp of the exonotes).

Exn treats each exonote with the .exn extension as the page of a virtual book, so the graphical user interface of Exn is a metaphor for a book with controls to move from one page to the next or to the previous one.

The Search feature

Exn has a search interface that allows the user to search for exonotes in the dossier by specifying tags, words or a phrase. The search mechanism has an optional regular expression mode.

Search

Search interface

On security: run untrusted exonotes

The command line interface exposes two options for running exonotes:

Option Description
-r, --restrict [<filename>] Open a note with low restriction, i.e., block the execution of embedded programs
-R, --Restrict [<filename>] Open a note with high restriction, i.e., block executable links and also the execution of embedded programs

Why not org-mode ?

Exonote supports codeblocks like in Markdown. Instead of providing the ability to execute codeblocks, which would lead to literate programming like in Emacs' org-mode, Exonote would execute a program whose source code is properly written elsewhere by calling a function with arguments.

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 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"}

Why use this project ?

Despite the existence of interesting note-taking solutions and the storm of AI-powered projects, there are compelling arguments for adopting Exonote and Exn. Let's explore some characteristics and concrete examples.

Characteristics

Here are some characteristics and their consequences:

Characteristic Consequence
Plain old text file Since an exonote is just plain text, you can always use your favorite text editor (Vim, Sublime Text, Visual Studio Code, et cetera) to write your notes. Exonotes are also de facto compatible with VCS.
Minimalism Exonote's minimalist markup language specification made Tkinter a good candidate to render it, eliminating the need for web-based technology (browser, html, css, et cetera). Hence, we got Exn, a lightweight, cross-platform app to view exonotes.
Scripting with Python Python is one of the most popular programming languages in the world. Since people like to tinker with Python, it would be fun to write scripts with this language for personal exonotes.
Embed GUI programs written with Tkinter Tcl/Tk is one of the easiest GUI toolkits to use, unsurprisingly, it's the default solution for GUI programming in Python via Tkinter. In the demo, a working calculator was built with Tkinter and embedded into an exonote.

Examples

These are few concrete examples of what can be done with Exonote and Exn:

  • create interactive courses;
  • build programming puzzles with levels and backstory;
  • make a proof of concept;
  • use the exonote.Viewer class to make rich and/or interactive documentation inside another application. Exn itself uses the default viewer in the Exonote library.
  • Whistleblowing and censorship bypass: Due to its nature, a dossier of exonotes is very convenient for disclosing information that can be easily replicated and consumed by people.
  • Decent alternative to a personal website: it is as simple as creating a GitHub repository, upload a dossier of exonote, share the link with readers, then regularly update the contents with git commit.

Note: you can define a blocklist file in $dossier/.exn to block access to a list of exonotes (filenames). This mechanism with the help of custom scripts, allows the implementation of a system of levels where certain conditions must be met before opening specific exonotes.

Demo

A demo is available that you can play with. You will need to clone the demo repository, install Exn with pip and then run it without any arguments. By default, it executes the last exonote opened or runs the home page (first exonote referenced in the index).

# 1- clone the repository
$ git clone https://github.com/pyrustic/exn-demo
$ cd exn-demo

# 2- install exn
$ pip install exn

# 3- run exn with zero restriction
$ exn

You can still run Exn with restriction:

# run exn with low restriction
$ exn -r

# run exn with high restriction
$ exn -R

Markup language

Element Description
ANCHOR Create an anchor in a specific location of an exonote that can be accessed when its name is appended to the filename of the exonote. Syntax: <anchor_name>
ATTACHMENT Insert an asset like an image. Syntax: @[optional text](path/to/assets/resource.png)
BOLD Make a text bold. Syntax: *bold*
CODE Surrounding a word or phrase with double backticks will apply a monospace font to it and also a colored background.
CODEBLOCK Same as in Markdown
DINKUS Three asterisks at the start of a blank will be centered and bolded like a dinkus.
GAP Leave at least one blank line between a group de sentences to create paragraphs.
HEADING An exonote is made up of sections, which are made up of paragraphs. A section title is the Heading and it a section can have an identifier (section id, A.K.A. sid). A header follows the same pattern as in Markdown. Syntax: # Title of section <section_id>.
ITALIC Apply italic to a text. Syntax: _my sentence_.
ITEM Use a hyphen at the beginning of a line, with or without indent, to declare an item of a list.
LINK Exonote supports link to websites, link to exonotes in the same dossier, link to anchors, and executable links (clicking such link will run a Python function. The documentation is a work in progress. Check the demo.
MONOSPACE Surround a text with backticks to apply a monospaced font to it.
NOTICE Surround a text with % to apply a green color to it.
PROGRAM Reference a function or a view class. Syntax: ${path.to.module:functionOrClass arg1 arg2 "arg arg"}
STRIKETHROUGH Surround text with ~ to strikethrough it.
TABLE Check the example below.
UNDERLINE Surround a text with __ to underline it.
VARIABLE A variable is defined at the beginning of an empty line. This line will not be rendered. The value of a variable can be used to fill in the location placeholder of an attachment or link. Syntax: [variable_name] Value.
WARNING Surround a text with %% to apply a red color to it.

This is a table:

| Col 1 | Col 2 | Col 3
| val A | val B | val C
| val D | val E | val F
| val G | val H | val I 

Note: you can add a caption to tables, attachments, and views (GUI programs) by written its content in front of a & just under the target element.

Example:

@[Alt text](path/to/image.png)
& This is a *caption* !

Command line interface

Type exn -h or exn --help in the command line to display the help text.

Usage:

$ exn
$ exn <filename>
$ exn <option> [<arg> ...]

Options:

-b, --build                     Build the index file
-r, --restrict [<filename>]     Open a note with low restriction
-R, --Restrict [<filename>]     Open a note with high restriction
-h, --help                      Show help text

Back to top

Scripting with Python

It's as simple as referencing a Python function whose module is in the dossier or virtual environment. This Python function must accept a context argument and optionally return a string that will be rendered to where the function was called.

Inside the exonote:

This is an *exonote*. 
Let's make a call to a Python function here: 
${path.to.module:func arg1 arg2 "args..."}

The called function:

def func(context):
    print(context.viewer)
    print(context.arguments)
    return "Hello World !"

Back to top

Viewer API

The viewer exposes an API to open a new exonote, refresh the current exonote, render a string to a specific location of the current exonote, scroll the current exonote to a specific location, compute a location index, modify the headings, programmatically read and modify sections, and more.

The documentation is a work in progress. Check the API here !

Back to top

Embedding GUI programs

You can embed GUI views in an exonote by referencing a class that has a build method returning a Tkinter widget. The constructor of this class must accept a context argument.

Note: It is recommended to subclass the viewable.Viewable class to create a view.

Inside the exonote:

This is an exonote.
Let's embed a view here:
${path.to.module:MyView arg1 arg2}

The view:

from viewable import Viewable

class MyView(Viewable):
    def __init__(self, context):
        super().__init__()
    
    def _build(self):
        # build the interface of the view
        pass

Back to top

Miscellaneous

Keymap

For a smooth user experience, keyboard keys are mapped to certain functions in Exn. For example, pressing F would activate the Find in Page functionality. Pressing H would open the home page. Pressing S would open the search interface. Pressing T would open the table of contents. Pressing F5 would refresh the page. Et cetera.

Note: Ctrl+Tab will open the switcher to allow you to go back to the previously opened exonote.

Quick-copy

Quickly copy the contents of a codeblock or the address of a link with a right-click over it !

Attachments

For the moments only images are supported.

Path separator

The separator symbol inside the path to an exonote or asset is the slash / symbol. Also, a path must not start with a separator.

Filenames

Exn only recognizes files with the extension .exn. Also, to reference a specific filename as a link in an exonote, you must write its path relative to the root of the folder. Filename and Path can be used as synonyms.

Example:

dossier
    exonote1.exn
    exonote2.exn
    folder
        exonote3.exn

The path to exonote3.exn is folder/exonote3.exn

The context object

The context object is a namedtuple instance whose fields are:

  • viewer: the exonote.Viewer instance which exposes the API to manipulate the representation of the currently displayed exonote;
  • arguments: list of arguments passed to this function in the exonote.

ASCII Art

The ASCII Art at the beginning of the CLI help text is made with patorjk's TAAG

Installation

Exn is cross platform and versions under 1.0.0 will be considered Beta at best. It is built on Ubuntu with Python 3.8 and should work on Python 3.5 or newer.

For the first time

$ pip install exn

Upgrade

$ pip install exn --upgrade --upgrade-strategy eager



Back to top

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

exn-0.0.11.tar.gz (35.3 kB view hashes)

Uploaded Source

Built Distribution

exn-0.0.11-py3-none-any.whl (37.6 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page