Code execution now uses a LanguageRegistry with built-in defaults
(bash, python, ruby, perl, javascript) that can be overridden by TOML
config files in /etc/orkmode/languages or ~/.config/orkmode/languages.
Match Emacs org-babel result formatting: fixed-width (": " prefix) for
output under 10 lines, #+begin_example blocks for 10+ lines
(org-babel-min-lines-for-block-output).
Fix insert_results duplication: the source block span end already points
to the start of the line after #+END_SRC, so searching for the next
newline skipped the existing #+RESULTS: line and prepended duplicates on
re-execution. Also handle replacing existing #+begin_example result blocks.
Fix parser: #+begin_example, comment, and export blocks were misparsed as
SourceBlock with a bogus language, causing "unsupported language" errors
on re-execution. Map them to their correct AST element kinds.
- Execute returns results and writes them to the org file
- Replaces existing #+RESULTS: block if present
- Results formatted with : prefix per org convention
- Process blocks in reverse order to preserve byte offsets
- Blank line added after results for proper separation
- execute <doc> — all blocks in document
- execute <doc> <section> — all blocks in subtree
- execute <doc> <section> <idx> — single block by index
- execute <doc> <section> <name> — block by #+NAME in section
- execute <doc> :<name> — named block anywhere in doc
Parser now extracts #+NAME: from block's affiliated keywords.
Supports bash, python, ruby, perl, and node interpreters.
Basic sandboxing via env_clear() and restricted PATH.
- Store tableData at Rectangle level to avoid scope issues
- Use ColumnLayout + RowLayout instead of GridLayout (cleaner nesting)
- Anchor left instead of center
- 8px margins, 16px column spacing
- Add ?? false fallback for hasHeader to prevent undefined errors
- Parse | delimited rows into cells
- Detect header separator (|---+---|)
- Header row: bold, text color
- Data rows: normal, placeholder color
- Same alternate background as code blocks
- Use 'contains' instead of 'starts_with' to handle combined lines
like 'SCHEDULED: <...> DEADLINE: <...>'
- Track 'seen_content' to strip planning/drawers only at the start
- Skip empty lines before content
- Continue stripping planning lines until real content appears
section_body() now filters out:
- Leading planning line (SCHEDULED/DEADLINE/CLOSED)
- Property drawers (:PROPERTIES: ... :END:)
- Any other drawers (:LOGBOOK:, etc.)
- Leading/trailing blank lines
These are displayed separately in the UI.
list() returns files AND directories. Section entries are directories only.
Files like 'title', 'keyword', 'body' were being incorrectly treated as
child sections. Using listDirs() filters to directories only.
TreeView (inherits TableView) is designed for file browsers with fixed row
heights, not structured document editing. ListView gives us:
- Full control over row heights (implicitHeight just works)
- Simpler delegate without TreeViewDelegate quirks
- Manual indentation via leftMargin based on level
- Expansion state tracked in model with hasChildren/expanded roles
- Click-to-expand triangles for sections with children
DocumentModel changed from QAbstractItemModel (tree) to QAbstractListModel
(flat list) with sections ordered depth-first. Tree structure preserved via
level, parentId, childIds fields. Expansion state controls visibility.
TreeView (inherits TableView) defaults to fixed row heights. Setting
rowHeightProvider to return -1 tells it to use each delegate's
implicitHeight, enabling variable-height rows.
- In system mode, read palette from QGuiApplication::palette() rather
than parsing kdeglobals (platform plugin already handles this)
- Don't call setPalette() in system mode — let Qt handle it
- Add isOverriding property for QML to check mode
- Use Fusion style by default for consistent palette respect
- Improved fallback logic in systemSchemePath() for dark/light detection
- Added /etc/xdg/kdeglobals as fallback for system-wide defaults
ThemeManager now supports:
- fontFamily, fontSize, fontStyle with full QFontDatabase access
- uiScale (0.5x to 4.0x) saved to theme.conf
- resetFont() to return to system defaults
SettingsDialog provides UI for:
- Color scheme selection (all installed KDE schemes)
- Font family/style/size with live preview
- UI scale slider with percentage display
OutlineView uses pointSize (scalable) instead of pixelSize (fixed).
All font sizes derived from theme.fontSize or baseFontSize.
- Add ork-server and orkmode (GUI) to install target
- Make UI build optional (only if Qt6 Qml available)
- Add ui target for explicit GUI build
- Clean ui/build directory on 'make clean'
- Update help text with requirements
- 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
A standalone Qt6/QML app in ui/ that speaks 9P to ork-server; no FFI,
no privileged path. All org logic stays in the server.
- p9client: minimal synchronous 9P2000 client over QTcp/QLocalSocket
- orkclient: QML-facing facade (read/list/listDirs/write/rdwr/docs)
- documentmodel: lazy QAbstractItemModel of the section tree, with a
BodyRole that reads /<doc>/<id>/body (planning line + :PROPERTIES:
drawer stripped, since those are shown as structural objects)
- Main.qml: document sidebar + outline; OutlineView.qml: folding
TreeView rendering keyword/priority/title/tags/timestamps as distinct
objects, with section body shown inline beneath each headline
- main.cpp: --addr/$ORK_ADDR, --selftest (headless outline dump),
--shot (headless window grab for debugging)
- CMake build; binary emitted to bin/ to avoid the QML-module-URI vs
target-name directory clash
Known issue: inline body layout still needs work (row sizing/overlap
when bodies wrap); to be iterated.
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).
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).
Client verbs for the new server capabilities, each a thin wrapper over
the base 9P operations: the structural verbs write to /ctl, and query
writes to /query and prints the matches.
Rework /ctl into a self-describing dispatch table (name, desc, fn),
inspired by the ollie 9P server: an empty write or "help" lists the
verbs, and unknown verbs report the valid set.
New control verbs, each operating on a section subtree:
- rm: delete a section and its subtree
- move up|down: reorder among siblings
- promote/demote: shift the subtree's outline level
- refile <to-doc> [parent]: move a subtree across or within documents,
re-leveling to the target depth
- archive: move a subtree to the companion <doc>.org_archive file
- lint [doc]: reparse and report per document
Add a root /query file (rdwr): write a tag:X+todo:Y+priority:Z match
expression, read back matching sections.
Implement the previously stubbed agenda today/week views with real date
filtering, using a dependency-free civil-date day-number calculation.
Subtree edits share span-based helpers (subtree_range, sibling_ranges,
shift_headline_levels, insert_at). Covered by unit tests.
Four more friendly verbs, all pure compositions of the base 9P
operations against the existing namespace (no server change):
- tag <doc> <id> <tag> [--remove]: toggle a single tag, mirroring
org-toggle-tag, instead of rewriting the whole tag list.
- prop <doc> <id> <key> [value] [--delete]: get, set, or delete one
property, mirroring org-set-property, instead of the whole drawer.
- todo <doc> <id> [state]: set the keyword, or with no argument cycle
to the next state following the /keywords sequence, like org-todo.
- tree <doc>: print the recursive section outline.
Each edit reads the relevant namespace file, modifies it, and writes it
back; all validate the section exists first for a clear error.
ork now operates solely as a 9P client against ork-server; all org
intelligence lives in the server. Remove the local file-parsing command
layer (commands.rs) and its org-ast/org-parser/orkmode-core/serde deps.
Base verbs speak raw 9P: ls, read, write, rdwr. Address resolves from
--addr, then $ORK_ADDR, then tcp://localhost:5640.
Add friendly commands, all thin compositions of the base 9P operations:
docs, sections, todos, agenda, get, set, add (--parent), mkdoc, reload.
Fix the directory-listing parser in client.rs: the stat-entry name offset
double-counted the size field (pos + 2 + 41 instead of pos + 41), so ls
returned nothing. Handle a downstream reader closing early (e.g. | head)
by treating BrokenPipe as a clean exit instead of panicking.
Dynamic child resolvers returned Some for any name, fabricating phantom
document and section directories so walks to nonexistent paths appeared
to succeed. Validate existence and return None instead:
- root resolver checks get_doc
- document resolver checks new OrkState::section_exists
- section resolver checks child_ids
Also fix create_child_section, which corrupted the org file:
- find_section_end used the parent's headline-end offset, inserting the
child before the parent's PROPERTIES/ID drawer and detaching its ID.
Use section.span.end, which covers planning, drawer, body, children.
- The child headline was written verbatim; demote it to parent.level + 1
via the new restar helper.
Add regression tests for restar and child section nesting.
- set_section_keyword/priority/title/tags
- set_section_scheduled/deadline/closed
- set_section_properties/body
- rebuild_headline helper for atomic headline updates
- Fixed replace_headline to preserve DEADLINE/:PROPERTIES: lines
- Clear read cache on write in 9P server
All writes tested working via 9p client.
Simple 9P2000 client supporting:
- Connect via Unix socket or TCP
- read/write/rdwr operations
- Directory listing
Preparation for reworking CLI to use 9P server.
- new file at root: create org file
- new file at doc level: create top-level section
- new file at section level: create child section
- All created sections get UUID in :ID: property
- body file added to doc (alias for raw)
- Test for section creation via 9P namespace
- Sections nest as directories mirroring org structure
- One file per property (title, keyword, tags, etc.)
- ID from CUSTOM_ID > ID > slug+hash
- EDSL pattern from ollie's virtfs for declarative namespace