2025-11-23

plaintext formats for notes and documents

this page presents and specifies a few lightweight plaintext formats for creating and managing notes or documents.

boundary-separated

the simplest note-taking format. each new entry is added at the top, separated by a boundary, for example an empty line. editing is fast and requires no other syntax.

example:

entry-1
entry-1

entry-2
entry-2

if entries contain empty lines, boundaries become ambiguous. other boundaries can be used:

entry-1
entry-1

---

entry-2
entry-2

indent tree

an indent-based, machine- and human-readable format for titled note blocks. top-level words act as tags or headings. indentation defines structure. no extra syntax needed. formatting like this has also been called indented plaintext.

proposed file name extension: .it.

heading
  heading
    content
    content
  heading: content content
  content
...

branches with few leaves can be combined on the same line with the head separated by a colon and space.

benefits

  • low friction - just type
  • compatible with other formats. markdown-style headings can help keep the nesting shallow
  • no syntax beyond indentation
  • low noise
  • supports nested structure
  • machine readable and convertible to other formats like markdown, pdf, and html
  • a lot of structured content fits readably on the same screen area
  • can be used with smart indenting features (example: cycling from forward 1-2 steps and then from the beginning)
  • good for list-like content. even small paragraphs can be considered list entries

drawbacks

  • not so good for free-flowing text or embedding other formats
  • does not do so well with large indented blocks and paragraphs that include empty lines

tools

as an example of how this can be processed, a number of tools are available as part of sph-script.

itpn-filter: searches in headings
itpn-from-markdown: converts from markdown to itpn
itpn-parse: syntax checks and canonicalizes itpn
itpn-to-markdown: converts to markdown

the tools take input from standard input, eg "cat input.it | itpn-to-markdown"

Usage: itpn-filter [options] search_string ...
  -a  and
  -o  or
  -n  not
  -c  print child-tree only
  -d  match at depth, examples: 0, or 1-2

markdown

a lightweight markup format standardized as commonmark. suitable for structured documents with headings, lists, and emphasis. it is mostly written as stacked blocks.

example:

# heading level 1

## heading level 2
- bullet point one
- bullet point two

benefits

  • widely supported and portable
  • readable as plain text
  • machine-readable and can be converted to pdf, html, or other formats

drawbacks

  • still requires markup prefixes (e.g. "#", "-", "*")
  • multiple alternatives for syntax are specified. for example: bullet points, code blocks, and even the whole heading structure has redundant alternative syntax.

indent tree markup

here is an example of an extendable syntax for structured documents. it includes forms that can be evaluated by custom procedures to notate things like lists, tables and more.

it is compatible with other formats like markdown and offers dynamic expression types that allow using plaintext or nested dynamic expressions either inline, for the current line, or for the current block.

a template processor compiling from this to other formats just has to parse the expressions and their arguments and then pass that to custom functions to generate suitable output in the target format.

expression types

by scope

  • inline: start and end somewhere on a line
  • indent: include all immediately following further indented lines
  • line: from their start to the end of the line

by content interpretation

  • scm: start with # and arguments have to be valid scheme syntax
  • text: start with ## and arguments are plaintext

by evaluation phase

  • ascend: itm expressions in arguments have been evaluated
  • descend: itm expressions in arguments have not been evaluated

inline expressions

inline-scm

#(identifier dynamic-expression ...)

indent-scm

#identifier dynamic-expression ...
  dynamic-expression ...
  ...

inline-text

##(identifier plaintext/itm-expression ...)

indent-text

##identifier plaintext/itm-expression ...
  plaintext/itm-expression ...
  ...

line-scm, line-text

#identifier: dynamic-expressions ...

##identifier: plaintext/itm-expressions ...

indent-descend

###identifier plaintext ...
  plaintext
  ...

the text is passed as a parsed tree without any nested expressions evaluated. this can be used, for example, to do block escaping

headings

a line before increased indent becomes a heading

this is a heading
  this is content
  and more example text
  a sub-heading
    more content

line breaks

each empty line, two newlines, creates one line break in the output

example text

more text after empty line

escaping

inline expression prefixes, colons and backslashes can be escaped with a backslash

\:
\#
\##
\###
\\

block escapes

###
  content
    content
  content