Go to file
Levi Neely e129f9ee94 Fix overlapping text in OutlineView
- Replace manual Item+anchoring with ColumnLayout for proper height calc
- Remove redundant bodyMeasure Text and bodyWidth property
- Add proper top/bottom margins using rowPad constant
- Body row now uses RowLayout with Layout.fillWidth
2026-10-01 08:50:52 +02:00
crates Remove dead orkmode-core (FFI) crate 2026-09-30 22:27:50 +02:00
doc Add complete section properties to 9P namespace 2026-09-30 14:16:18 +02:00
ui Fix overlapping text in OutlineView 2026-10-01 08:50:52 +02:00
.gitignore Add v0.3 read-only Qt6/QML GUI (9P client) 2026-10-01 02:02:53 +02:00
.gitmodules Initial commit: org-mode parser and CLI 2026-09-30 09:43:21 +02:00
AGENTS.md Add v0.3 read-only Qt6/QML GUI (9P client) 2026-10-01 02:02:53 +02:00
Cargo.lock Remove dead orkmode-core (FFI) crate 2026-09-30 22:27:50 +02:00
Cargo.toml Remove dead orkmode-core (FFI) crate 2026-09-30 22:27:50 +02:00
LICENSE Initial commit: org-mode parser and CLI 2026-09-30 09:43:21 +02:00
Makefile Add Makefile 2026-09-30 09:46:41 +02:00
README.md Add v0.3 read-only Qt6/QML GUI (9P client) 2026-10-01 02:02:53 +02:00
VISION.md Update VISION to the 9P architecture and editing model 2026-09-30 22:21:10 +02:00
test.org Initial commit: org-mode parser and CLI 2026-09-30 09:43:21 +02:00

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/                          # Qt6/QML GUI (9P client, no FFI)
    ├── CMakeLists.txt          # Qt6 build (Core/Gui/Qml/Quick/Network)
    ├── src/
    │   ├── main.cpp            # Entry point; --addr, --selftest
    │   ├── p9client.{h,cpp}    # Minimal synchronous 9P2000 client
    │   ├── orkclient.{h,cpp}   # QML-facing façade over the 9P client
    │   └── documentmodel.{h,cpp}  # Lazy QAbstractItemModel section tree
    └── qml/
        ├── Main.qml            # Window, document sidebar, outline
        └── OutlineView.qml     # Folding TreeView with structural styling

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)
  • Qt 6.3+ and CMake 3.21+ (for the GUI)

Build

# Build all crates
cargo build

# Run tests
cargo test

# Build release
cargo build --release

GUI

The GUI is a separate Qt6/CMake project that talks to ork-server over 9P.

cmake -S ui -B ui/build -DCMAKE_BUILD_TYPE=Release
cmake --build ui/build -j

# Run against a running ork-server (see below)
./ui/build/bin/orkmode -a unix:///tmp/ork.sock

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)
  • Structural styling (keywords, priorities, tags, timestamps)
  • Folding/cycling
  • Navigation
  • Syntax highlighting for section bodies

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