| Crates.io | patto |
| lib.rs | patto |
| version | 0.1.21 |
| created_at | 2024-11-23 10:43:40.061666+00 |
| updated_at | 2025-07-02 12:50:30.501845+00 |
| description | 🐙 Yet another plain text format for quick note taking and task management |
| homepage | https://github.com/ompugao/patto |
| repository | https://github.com/ompugao/patto |
| max_upload_size | |
| id | 1458380 |
| size | 838,485 |
A simple, language server-powered plain-text format for quick note-taking, outlining, and task management.
Patto Note is a text format inspired by Cosense (formerly Scrapbox), designed for quick note-taking, task management, and outlining. It works with your favorite editor, powered by the Language Server Protocol. Unlike Markdown, every newline (\n) creates a new line, and a leading hard tab (\t) itemizes the line. This simple, line-oriented structure makes it easy to outline ideas, organize tasks, and brainstorm effectively.
line property (please refer to the syntax section below)Hello world.
itemize lines with a leading hard tab `\t'
that can be nested
the second element #sampleanchor
the third element
[@quote]
quoted text must be indented with `\t'
Task Management
a task {@task status=todo}
another task with deadline {@task status=todo due=2030-12-31T23:59:00}
abbreviated version of task !2030-12-31
a completed task {@task status=done}
Decoration:
[* bold text]
[/ italic text]
[*/ bold italic text]
Links:
[other note]
link to other note in a workspace
[other note#anchor]
direct link to an anchored line
[#sampleanchor]
self note link to the anchored line (i.e., this line) #sampleanchor
url link:
[https://google.com url title]
title and url can be flipped:
[url title https://google.com]
link to an image
[@img https://placehold.co/100.png "alt string"]
Code highlight with highlight.js
[@code python]
import numpy as np
print(np.sum(10))
[` inline code `]
Math with MathJax
inline math: [$ O(n log(n)) $]
[@math]
O(n^2)\\
sum_{i=0}^{10}{i} = 55
which is rendered as follows:
A text in the form of {@XXX YYY=ZZZ} is named as line property and adds an property to the line (not the whole text).
Currently, anchor and task properties are implemented:
{@anchor name}: adds an anchor to the line. abbrev: #name{@task status=todo due=2024-12-31}: marks the line as a todo.!2024-12-31*2024-12-31-2024-12-31.pn, or :new and :set syntax=patto[ and @, lsp client will complete links and snippets respectively
:LspPattoTasks command; that will gather tasks from the notes in your workspace and show them in a location window.:LspPattoTwoHopLinks command (only in neovim, currently).Please download binaries from GitHub release
or, use cargo:
cargo install patto
This will install the following utilities:
patto-lsp: a lsp serverpatto-preview: a preview server for your patto notespatto-markdown-renderer: a format converter from patto note to markdownpatto-html-renderer: a format converter from patto note to htmlcall plug#begin()
Plug 'prabirshrestha/asyncomplete.vim'
Plug 'prabirshrestha/asyncomplete-lsp.vim'
Plug 'prabirshrestha/vim-lsp'
Plug 'ompugao/patto', {'for': 'patto'}
call plug#end()
call plug#begin()
Plug 'neovim/nvim-lspconfig'
Plug 'hrsh7th/cmp-nvim-lsp'
Plug 'hrsh7th/nvim-cmp'
Plug 'ompugao/patto'
call plug#end()
lua << EOF
require('patto')
require('lspconfig.configs').patto_lsp.setup({})
EOF
Note: we recommend neovim@nightly for non-ascii notes since PositionEncoding UTF-16 support has a bug in the current neovim stable v0.10.3. see https://github.com/neovim/neovim/issues/32105.
To be released.
please refer to todo
The differences in behavior between Markdown parsers led me to create the Patto format. For example, in GitHub Markdown, code fences can be contained within a list item, whereas in Obsidian, they cannot (ref Code Block Indentation):
print('hello')
Please use your favorite template/snippet engine of your editor. I personally use LuaSnip in neovim.
Other candidate vim plugins:
rg --vimgrep '.*@task.*todo' . | awk '{match($0, /due=([0-9:\-T]+)/, m); if (RLENGTH>0) print m[1], $0; else print "9999-99-99", $0}' |sort |cut -d' ' -f2-
# or, in vim
cgetexpr system('rg --vimgrep ".*@task.*todo" . | awk "{match(\$0, /due=([0-9T:\-]+)/, m); if (RLENGTH>0) print m[1], \$0; else print \"9999-99-99\", \$0}" |sort|cut -d" " -f2-')|copen