orkmode/README.md

8.0 KiB

Orkmode

A standalone org-mode implementation for KDE, built with Rust (parser/core) and C++ (Qt UI).

Project Structure

orkmode/
├── Cargo.toml                    # Workspace root
├── crates/
│   ├── org-ast/                  # AST type definitions
│   │   └── src/
│   │       ├── lib.rs           # Module exports
│   │       ├── document.rs      # Document, settings
│   │       ├── headline.rs      # Section, Headline, Planning
│   │       ├── elements.rs      # Block elements (paragraph, list, table, etc.)
│   │       ├── objects.rs       # Inline objects (markup, links, etc.)
│   │       ├── timestamp.rs     # Timestamp types
│   │       └── span.rs          # Source location tracking
│   ├── org-parser/              # Tree-sitter based parser
│   │   ├── build.rs            # Compiles tree-sitter-org grammar
│   │   ├── tree-sitter-org/    # Git submodule: nvim-orgmode/tree-sitter-org
│   │   └── src/
│   │       ├── lib.rs          # Parser API
│   │       ├── convert.rs      # Tree-sitter → AST conversion
│   │       ├── ts.rs           # Tree-sitter language bindings
│   │       └── error.rs        # Error types
│   ├── ork-cli/                 # Command-line interface (9P client)
│   │   └── src/
│   │       ├── main.rs         # CLI commands (base + friendly verbs)
│   │       └── client.rs       # 9P2000 client
│   └── ork-server/             # 9P server exposing org files
│       └── src/
│           ├── bin/ork-server.rs  # Server entry point
│           ├── state.rs        # Document state, section ops, ctl verbs
│           ├── namespace.rs    # 9P namespace (docs, sections, agenda, query)
│           ├── p9.rs           # 9P protocol handling
│           └── virtfs.rs       # Virtual filesystem tree
└── ui/                          # (future) Qt/QML UI

Features

Supported Org Syntax

  • Headlines with nesting levels
  • TODO keywords (customizable via #+TODO:)
  • Priority cookies ([#A], [#B], [#C])
  • Tags
  • Property drawers
  • Planning lines (SCHEDULED, DEADLINE, CLOSED)
  • Timestamps (active, inactive, ranges, repeaters)
  • Paragraphs
  • Plain lists (unordered, ordered, checkboxes)
  • Source blocks
  • Tables
  • Drawers
  • Keywords/directives
  • Comments
  • LaTeX environments
  • Inline markup (bold, italic, etc.) - AST types ready, parsing TODO
  • Links - AST types ready, parsing TODO
  • Footnotes
  • Citations

Document Settings

Parses common #+KEYWORD directives:

  • TITLE, AUTHOR, EMAIL, DATE
  • TODO, SEQ_TODO, TYP_TODO
  • PROPERTY, STARTUP, OPTIONS
  • FILETAGS, CATEGORY, ARCHIVE

Building

Prerequisites

  • Rust 1.70+
  • C compiler (for tree-sitter grammar)

Build

# Build all crates
cargo build

# Run tests
cargo test

# Build release
cargo build --release

Usage

CLI (ork)

The ork command operates on org directories or individual files. All commands default to the current directory (.) when no path is specified. Use -R for recursive subdirectory scanning.

# List org files
ork files                     # Current directory
ork files ~/org               # Specific directory
ork files -R .                # Recursive

# Document info (aggregated across all files)
ork info                      # Current directory
ork info ~/org -R             # Recursive
ork info file.org             # Single file
ork info --json               # JSON output

# List sections
ork sections                  # All sections in cwd
ork sections --todos-only     # Only TODOs
ork sections --tag work       # Filter by tag
ork sections --depth 2        # Max depth
ork sections -R -j            # Recursive, JSON

# Query sections
ork query "tag:work"          # By tag
ork query "todo:TODO"         # By TODO state
ork query "priority:A"        # By priority
ork query "title:pattern"     # By title
ork query "file:notes"        # By filename
ork query "done:false" -j     # JSON output

# Get specific section by ID or title
ork get "my-task-id"          # Searches all files
ork get "My Task" -j          # JSON output
ork get "intro" ~/org -R      # In specific path

# List tags with counts
ork tags                      # All tags in cwd
ork tags -R --json            # Recursive, JSON

# Export as JSON
ork export --pretty           # All documents
ork export --section my-id    # Specific section

# Add section
ork add "New Task" file.org                           # To specific file
ork add "New Task" --file notes.org                   # When path is directory
ork add "New Task" file.org --todo TODO --priority A --tags "work,urgent"
ork add "New Task" file.org -n                        # Dry run

# Toggle TODO state
ork toggle "task-id"          # Searches all files
ork toggle "task-id" -n       # Dry run

# Agenda view
ork agenda                    # Current directory
ork agenda ~/org -R           # Recursive
ork agenda --days 14 --json   # 14 days, JSON

# Validate syntax
ork check                     # Current directory
ork check -R --json           # Recursive, JSON

Rust API

use org_parser::Parser;

let mut parser = Parser::new();
let doc = parser.parse(r#"
#+TITLE: My Document
#+TODO: TODO WAITING | DONE

* TODO [#A] First Task :work:
DEADLINE: <2025-01-15 Wed 14:00>

Some description.

** Subtask
- [ ] Item 1
- [X] Item 2
"#).unwrap();

// Access document properties
println!("Title: {:?}", doc.title());
println!("Sections: {}", doc.sections.len());
println!("TODOs: {}", doc.todos().count());

// Iterate sections
for section in doc.all_sections() {
    println!("{} {}", 
        "*".repeat(section.level() as usize),
        section.headline.title_text()
    );
}

9P server & client

Serve a directory of org files over 9P, then act on it with ork:

# Start the server (unix socket or tcp)
ork-server -a unix:///tmp/ork.sock -d ~/org &

# Point the client at it (or pass -a on each call)
export ORK_ADDR=unix:///tmp/ork.sock

ork docs                       # list documents
ork tree work                  # outline of work.org
ork todos                      # TODO items across all docs
ork set work my-task keyword DONE
ork refile work my-task archive --parent done-items
ork query 'tag:work+todo:TODO'

Any 9P client works too (e.g. plan9port 9p); the server owns all org logic and reads/writes the real .org files.

Architecture

Parser Design

The parser uses tree-sitter with the nvim-orgmode/tree-sitter-org grammar.

Benefits:

  • Incremental parsing: Only re-parses changed regions
  • Error recovery: Produces partial AST even with syntax errors
  • Performance: O(n) parsing, minimal memory allocation
  • Battle-tested: Used by Neovim's org-mode plugin

AST Design

The AST follows the org-element specification:

  • Document: Root node with settings and sections
  • Section: Headline + content + children
  • Elements: Block-level constructs (paragraphs, lists, blocks)
  • Objects: Inline constructs (markup, links, timestamps)

All nodes include source span information for editor integration.

Roadmap

Phase 1: Parser (Current)

  • Tree-sitter integration
  • Core AST types
  • Headline/section parsing
  • Block element parsing
  • Complete inline object parsing

Phase 2: Qt UI

  • Document rendering (read-only)
  • Syntax highlighting
  • Folding/cycling
  • Navigation

Phase 3: Editing

  • Inline editing
  • TODO state cycling
  • Tag editing
  • Property editing

Phase 4: Agenda

  • Basic agenda view
  • Day/week/month views
  • Filtering
  • Custom views

Phase 5: Advanced Features

  • Code block execution
  • Diagram rendering (mermaid, plantuml)
  • Capture templates
  • Clock/time tracking

License

GPL-3.0-or-later