The vision predated the 9P pivot and the GUI direction. Correct it: - Architecture: clients (GUI, CLI, Emacs/vim, agents) speak 9P to ork-server; drop the C FFI layer entirely. - Replace "keyboard-first, mouse optional" with "the document is the control surface": actions live on objects, mouse and keyboard equal, no menu trees or button walls. - Add an explicit Editing Model: structured render, per-section raw-text editing with reparse-on-commit, and direct-manipulation structural edits that each map to one 9P operation. - Refresh milestones (v0.1 parser/CLI and v0.2 9P server/client done; GUI is next) and the rationale (add the "Why 9P" section). |
||
|---|---|---|
| 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
│ ├── orkmode-core/ # Core library with FFI
│ │ └── src/
│ │ ├── lib.rs # High-level API
│ │ └── ffi.rs # C FFI for Qt integration
│ └── ork-cli/ # Command-line interface
│ └── src/
│ ├── main.rs # CLI entry point
│ └── commands.rs # Command implementations
└── 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()
);
}
C/C++ FFI
#include "orkmode.h"
// Parse a document
OrkDocument* doc = ork_parse("* Hello World");
if (doc) {
// Get as JSON
char* json = ork_document_to_json(doc);
printf("%s\n", json);
ork_string_free(json);
// Get title
char* title = ork_document_title(doc);
if (title) {
printf("Title: %s\n", title);
ork_string_free(title);
}
// Cleanup
ork_document_free(doc);
}
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