Welcome to Edna

Edna is a note taking app for developers and power users. A cross between Obsidian and Notational Velocity.

Keyboard shortcuts

Ctrl + P               Open, create or delete a note
Ctrl + K               
Ctrl + O               
Alt + 0                
                       
Ctrl + Shift + P       Command Palette
Ctrl + Shift + K       
Ctrl + Shift + O       
                       
Ctrl + B               Navigate to a block
Ctrl + H               Open recent note (from history)
Alt + N                Create a new scratch note
Ctrl + Enter           Add new block below the current block
Alt + Enter            Add new block before the current block
Ctrl + Shift + Enter   Add new block at the end of the buffer
Alt + Shift + Enter    Add new block at the start of the buffer
Ctrl + Alt + Enter     Split the current block at cursor position
Ctrl + L               Change block language
Ctrl + Down            Goto next block
Ctrl + Up              Goto previous block
Ctrl + A               Select all text in a note block
                       Press again to select the whole buffer
Ctrl + Alt + Up/Down   Add additional cursor above/below
Alt + Shift + F        Format block content
                       Supports Go, JSON, JavaScript, HTML, CSS and Markdown
Ctrl + E               Smart Code Run
Alt + Shift + R        Run function with block content
                       Supports Go
Ctrl + F               Search / replace within a note

Why Edna?

Notes and blocks

In Edna a note is divided into blocks. Each block has a type: markdown, plain text, math block, JavaScript code, Go code etc.

Use:

Use keyboard shortcuts to create blocks, move between blocks.

No installation required

Edna is a web-based application but can store notes on disk, like a desktop app (when using Chrome or Edge).

You can use it offline (without network connection) and for desktop-like experince you can install a desktop shortcut.

Miminalist UI, lots of functionality

UI is optimized for writing. Editor uses most of the space.

To acess more functionality:

Speed

Edna is optimized for speed of writing, creating new notes, switching between notes.

Like in Notational Velocity, you can switch between notes, create and delete notes in the same note switcher UI.

Press Ctrl + P for note switcher and:

Context menu

Right-click for context menu.

For native context menu do Ctrl + right-click. This is useful when spell checking to correct mis-spellings.

Switch to recently opened note

Press Ctrl + E to switch to a note from list of recently opened notes.

Last 9 recently opened notes can be opened with 0 ... 9 shortcut.

To switch to previous note: press Ctrl + E and Enter.

Quick access shortcut

You can assign Alt + 1 to Alt + 9 for quickly accessing notes:

Default shortcuts are:

Notes with quick access shortcut are shown at the top of note selector (Ctrl + P).

Syntax highlighting of blocks

Blocks are syntax highlighted based on their type.

Formatting of blocks

You can format current block using:

We support formatting of Go, JSON, JavaScript, HTML, CSS and Markdown blocks.

Multiple notes

Open another note

or:

Create a new note

Or: context menu: Create New note.

Create a new scratch note

Alt + N to create temporary scratch note. We'll pick a unique name scratch-<n>

Delete a note

Context menu: This Note / Delete or:

A scratch note cannot be deleted.

Rename a note

context menu: This Note / Rename

Quick access shortcut

You can assign Alt + 1 to Alt + 9 keyboard shortcuts for quickly opening up to 10 notes.

Notes with assigned shortcut show up at the top of note switcher.

Open recent note

Press Ctrl + E to open a note from history. You can press 0 to 9 to open one of the last 10 notes.

Default notes

At first run we create 3 default notes:

You can delete them (except the scratch note).

scratch note is meant for temporary notes.

inbox for storing things to process later e.g. links to YouTube videos to watch later or web pages to read later.

daily journal is for daily notes. We auto-create a block for each day.

Storing notes on disk

By default notes are stored in the browser (localStorage).

If your browser supports file system access (currently Chrome and Edge) you can store notes on disk.

You can do one time export from localStorage to a directory on disk:

You can have multiple directories with notes. Think of each directory with notes as a separate Workspace.

Use context menu Notes storage / Switch to notes in directory to switch to notes in a different directory. If it's an empty directory, without existing notes, we'll create default scratch note.

You can go back to storing notes in the browser with context menu Notes storage / Switch to browser (localStorage). Unlike going from browser => directory, it doesn't import the notes from directory.

Accessing notes on multiple computers

If you pick a directory managed by Dropbox or One Drive or Google Drive etc. then you'll be able to access notes on multiple computers.

On the first computer export notes from browser to disk:

On other computers:

Please note that that the last written version wins. If you switch really quickly between computers, before the directory with notes has been replicated, you might over-write previous content.

Encryption

When storing notes on disk, you can encrypt them with a password.

The password is only stored in your browser (in local storage). It never leaves your computer.

Encryption and decryption takes place on your computer.

If you lose the password, you'll lose access to your notes.

Don't lose the password.

Notes are encrypted with ChaCha20-Poly1305 algorithm via kiss-crypto library.

Picking good password

Good password is:

We recommend passwords that are long, memorable phrases.

Example: Blue bear attacked a tiny dog.

Such passwords are easier to type and remember than typical "8a$7y!glo" passwords.

Running code

Run code blocks

If current block is Go or JavaScript block, you can run it:

The output of execution will be shown in a new block created below the executed block.

For Go:

A starting point:

package main

import "fmt"

func main() {
	fmt.Println("Hello, 世界")
}

For JavaScript:

Examples of JavaScript code and its output.

"foo";

Last expression is string "foo" so the output will be foo.


let a = [1, 2, 3];

There is no last expression so the output will be undefined


let a = [1, 2, 3];
a;

Last expression is an array a so output is 1,2,3.


let a = [1, 2, 3];
JSON.stringify(a);

Last expression is an array formatted as json so output is [1,2,3].


We also capture console.log(), console.warn(), console.debug(), console.error() calls.

console.log("hello");

Output is:

undefined
console output:
hello

async function main() {
  return "foo";
}
main();

The last expression is return value of main() function, so output is foo.

We handle async functions.

Run JavaScript functions over content

You can run JavaScript functions with the content of a current block or a selection.

The function gets the content as argument, can traform it, and we show the output in a block below.

For example a function can sort the lines in a block, calculate md5 hash or transform it to upper case. The possibilities are literally limitless.

To run a JavasScript function with content of block:

To run a JavasScript function with selection:

If you want to see all built-in functions use:

You can see what built-in functions are available, how they are implemented and use them as an example of how to write your own functions.

This functionality is inspired by https://boop.okat.best/ so our built-in functions come from Boop.

Write your own functions

You can write custom JavaScript functions that operate on text (content of the block or a selection), transform it in some way to create an output block.

For example you can write a function that sorts lines of text.

To write custom functions create a special edna: my functions note:

Each JavaScript block is a function.

The code must be implemented as function main(input) { ... your code }.

We use the same format as https://boop.okat.best/.

input is an object:

{
  text: string,
  fullText: string,
  postInfo: (message: string) => void,
  postError: (message: string) => void,
}

To return value you assign it to input.text and input.fullText. postInfo() and postError() functions show a notification message.

We show input.text or input.fullText as output block if, after execution, it differs from the original value.

Why text and fullText? I have no idea, I just copied Boop and that's how their API works.

In my implementation text and fullText are the same.

You also need to provide metadata at the top in the format:

/**
{
  "api":1,
  "name":"Add Slashes",
  "description":"Escapes your text.",
  "author":"Ivan",
  "icon":"quote",
  "tags":"add,slashes,escape"
}
**/

Don't get cute and reformat it any way or change /** and **/ to something else. Best to copy it and change values.

Currently the important fields are name, and description because they are shown in function selection dialog.

In future I might add more api versions, but at the moment there's just 1.

Here's the simplest function that returns foo as a result:

/**
{
  "api":1,
  "name":"Show foo",
  "description":"Returns string 'foo'",
  "author":"Chris",
  "icon":"quote",
  "tags":""
}
**/

async function main(input) {
  input.text = "foo";
}

As you can see, we support async functions.

Using external libraries

You can use any JavaScript library available via https://esm.sh or https://www.jsdelivr.com/ (or similar).

Here's an example function that uses camelCase functio from lodash package imported from https://esm.sh

async function main(input) {
  let lodash = (await import("https://esm.sh/[email protected]")).default;
  input.text = lodash.camelCase(input.text);
}

Debugging tip: sometimes module exports functions direct, sometimes as default.

To figure this out for a library, in browser's dev tools console do:

let m = (await import("https://esm.sh/[email protected]"))

then inspect the m object in console to see available functions.

Share your JavaScript functions with others

Share your functions with other via https://github.com/kjk/edna/discussions/categories/share-javascript-functions

Smart Run

Ctrl + E is a shortcut for smart run, which has the following logic:

Use Alt + Shift + R to force Run function with block content command.

Exporting notes to a .zip file

Edna files are just text files with .edna.txt extension.

You can export all the notes to a .zip file.

Context menu: Export notes to zip file menu.

We pack all the notes into a .zip file and initiate auto-download as edna.notes.export-YYYY-MM-DD.zip file to browser's downloads directory.

You can then e.g. restore the notes by unzipping it to a directory and opening that directory in Edna with Notes storage / Switch to notes in a directory context menu.

Lists with TODO items

In Markdown blocks, lists with [x] and [ ] are rendered as checkboxes:

// code blocks
// Edna is great for storing code snippets
// this is a javascript block
// change type of block with `Ctrl + L`
// or `Block: Change Language` command in command palette (`Ctrl + P`)
// you can format it with `Alt + Shift + F`
let x = 5
console.log("x is", x)

Privacy and security

Your notes are private and secure.

Notes are stored on your computer: in the browser (local storage) or on disk.

For additional security, you can encrypt notes with a password.

The code is open source so you can audit it.

No lock in

The notes are stored in plain text files on disk (or in localStorage under note:${name} key)

Blocks are marked with \n∞∞∞${type}\n e.g. \n∞∞∞markdown\n marks the beginning of markdown block.

You can edit the notes in any text editor (just be mindful of the above block markers).

You can back them up, store in git repositories, write scripts to process them.

They are not locked in a proprietary Edna format.

How I use Edna

Edna is flexible and you should find your own way of using it.

I use Edna daily::

Open source

Edna is open source: https://github.com/kjk/edna

To report a bug or request a feature: https://github.com/kjk/edna/issues

Contact

You can contact me via https://blog.kowalczyk.info/contactme

You can find more software by me on https://arslexis.io

Credits

Edna is a fork of Heynote with the following differences:

There's a spirit of Notational Velocity and Simplenote in Edna in how it allows quickly creating notes and switching between them.

Edna is built on CodeMirror, Svelte 5, Math.js, Prettier.