Dropping the C FFI layer left orkmode-core unused: nothing in the workspace depends on it, and the GUI will speak 9P instead. Delete the crate, drop it from the workspace, and scrub FFI references from the docs (README structure/usage, AGENTS structure/FFI/next-steps). |
||
|---|---|---|
| crates | ||
| doc | ||
| .gitignore | ||
| .gitmodules | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| VISION.md | ||
| test.org | ||
README.md
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