Org in Helix
Helix knows the org language already; it only needs to be told to use the
server. Helix has no plugins, so what org-lsp does comes as standard LSP:
the commands are code actions (Space a), the agenda is a file Helix
opens when the server asks, what a command asks for is picked from the
code actions or typed as a rename, and there is no calendar. Helix has no
semantic tokens either: the colors come from tree-sitter queries of
org-lsp's, for Org files and for the agenda (Colors).
Installing#
curl -fsSL https://github.com/kristijanhusak/org-lsp/releases/download/nightly/install.sh | bash -s -- helixor, in a checkout of this repository, scripts/install.sh helix
(--release v0.2.0 for a release, --source for the server built from
the checkout). The script puts the server from the nightly release in
~/.local/bin (ORG_LSP_BIN_DIR names another directory) and adds Org to
~/.config/helix/languages.toml, with the server's whole path, between two
# BEGIN org-lsp and # END org-lsp comments that it replaces when run
again; a file that sets up Org already is left as it is. It puts Org's
colors in ~/.config/helix/runtime/queries/org and org-agenda, in place
of what is there. Run it again to update.
By hand: put org-lsp on your PATH (cargo install --path server/org-lsp
in a checkout), and add editors/helix/languages.toml to
~/.config/helix/languages.toml (or a project's .helix/languages.toml):
[language-server.org-lsp]
command = "org-lsp"
[language-server.org-lsp.config]
show_document = true
message_requests = false
[[language]]
name = "org"
file-types = ["org", "org_archive"]
language-servers = ["org-lsp"]
[[language]]
name = "org-agenda"
scope = "source.org-agenda"
grammar = "org"
language-id = "org"
file-types = [{ glob = "org-lsp-view-*/Agenda.org" }]
language-servers = ["org-lsp"]and copy the queries of editors/helix/runtime/queries to
~/.config/helix/runtime/queries:
mkdir -p ~/.config/helix/runtime/queries
cp -R editors/helix/runtime/queries/org editors/helix/runtime/queries/org-agenda ~/.config/helix/runtime/queries/The two options say what Helix does without telling the server: it opens
the documents the server asks it to show (the agenda, a capture buffer, an
entry's file), and it shows no list for a server, so the choices of a
question come in the code actions instead. Without them there is no
agenda and no capture. file-types opens archive files as Org too, with
the server, as Emacs does. The second language is the agenda, which the
server writes to Agenda.org in a directory of its own (org-lsp-view-…
in the temporary directory): Org to the server (language-id) and to the
grammar, with colors of its own.
Setting it up#
The server's options go in the config table under the server, which
Helix passes to it as it is. Inlay hints show the indentation of files with
org-indent-mode, the time clocked and the … of shrunk columns. With
soft-wrap on, a line that wraps goes on under that indentation and its
own, not under a headline's title or an item's text as in Org:
[editor.lsp]
display-inlay-hints = true
[language-server.org-lsp]
command = "org-lsp"
[language-server.org-lsp.config]
show_document = true
message_requests = false
org_agenda_files = ["~/org"]
org_todo_keywords = ["TODO(t)", "NEXT(n)", "WAIT(w@/!)", "|", "DONE(d!)", "CANCELLED(c@)"]
org_log_done = "time"
org_log_into_drawer = true
[[language-server.org-lsp.config.org_capture_templates]]
key = "t"
description = "Task"
target = ["file+headline", "~/org/inbox.org", "Tasks"]
template = "* TODO %?\n %U"The server also reads the shared configuration file,
~/.config/org-lsp/config.toml, which every editor shares; config goes on
top of it. Options of your own go there when install.sh wrote the
config table, since it writes its block again on an update.
configuration.org has every option of the server with its
default. The server reads its options when it starts: run :lsp-restart
after a change.
Using it#
Space a (code_action) in an Org file lists the commands that apply at the
cursor: the TODO state, the priority, the timestamp under the cursor,
clocking, scheduling, tags, refiling, archiving, new headings, and the
agenda (Agenda commands for the menu), the TODO list and capture.
keys/helix.org lists them, and says how to put the menu on another key.
What a command asks for, Helix cannot ask itself, so the server says what it waits for in the status line:
- Press key for agenda command: pick the answer from the code actions
- a choice (a view of the agenda menu, a TODO state, a capture template, a
refile target, yes or no):
Space aagain, and the choices are first in the menu, the key of each in brackets (List of all TODO entries [t]). Another command drops the question. - Schedule: answer with a rename at the cursor
- text or a date
(
+2d,fri 10:00), typed as a rename:Space r, type the answer as the new name,Enter;-alone is an empty answer, the prompt's default. There is no calendar.
The agenda opens as a file, Agenda.org, in the window you are in, with
the cursor on today. Its commands are code actions there too: on an
entry's line the entry's first (its TODO state, dates, tags, clocking,
archiving, marks for a bulk action), then the view's (later, earlier,
today, the span, filters, log and entry text modes, the menu again). gd
on a line goes to its entry; the buffer picker (Space b) or ga goes
back to the agenda where its cursor was (:open puts it at the start).
The server changes the agenda's buffer with edits, so Helix counts it as
changed: close it with :buffer-close!, or leave with :quit-all! (or
:write it, the same text).
Moving a subtree up or down with its code action leaves the cursor where it was in the text, not on the subtree as in Emacs: Helix applies the action's edit itself, and goes to no place a server names for it. Helix gives a code action no count either: pick it again.
Helix has no keys for a server, so the agenda's keys are the code actions'
titles, and what needs to know where the cursor goes is left out: follow
mode, going to the entry in another window, column view. A document the
server shows without the focus opens in a split to the right, which takes
the focus: C-w h goes back. Capture opens its buffer, CAPTURE-….org,
in the window too; Capture: finish, abort and refile are its code
actions, and the buffer stays open once the entry is filed (Helix closes
no buffer for a server). Helix reads no file again that changes on disk,
so the date prompt's calendar, which the server writes as the day moves,
is not shown: dates are typed.
Colors#
Helix 25.07.1, its latest release, has no semantic tokens, nor has its
development branch (September 2026): the capabilities it sends a server
have no textDocument.semanticTokens, and no setting turns them on. So
the colors the server sends the other editors do not reach it. In their
place, the queries of org-lsp in queries/org/highlights.scm (with
injections.scm for the code of source blocks) and
queries/org-agenda/highlights.scm color Org files and the agenda from
their text, with the grammar Helix has for Org
(milisims/tree-sitter-org). Helix reads them in
~/.config/helix/runtime before its own, which colors little more than
headlines, blocks and drawers.
They give what the server colors elsewhere a scope of Helix's themes.
Each scope is named after what it colors, and a theme that has only the
start of it colors it with that: diff.minus.todo as diff.minus, red in
most themes, as a TODO keyword is in Emacs.
- Headlines
markup.heading.1tomarkup.heading.8by level, which themes that color onlymarkup.headingshow alike; the text of a done headlinecomment.done, a subtree taggedARCHIVEcomment.archived, an inline taskcomment.inlinetask- Keywords, priorities, tags
diff.minus.todoanddiff.plus.done,constant.numeric.priority,tag; statistics cookiesconstant.numeric.cookie,diff.plus.cookiewhen complete- Planning and timestamps
keyword.planning(SCHEDULED:,CLOCK:…),constant.numeric.timestampfor active timestamps,comment.timestampfor inactive ones- Drawers and keywords
function.drawer,variable.other.member.property;#+KEYWORD:comment.keyword, the titlemarkup.heading.title, the author, date and subtitlestring.info- Blocks
- their lines
comment.block, quote and verse blocksmarkup.quote, comment blockscomment, example blocks and LaTeX environmentsmarkup.raw.block; the code of source blocks in its language's colors - Lists and tables
markup.list,markup.list.uncheckedandmarkup.list.checked, the term of a descriptionmarkup.bold.term; table bars and rulespunctuation.special.table- Text
markup.bold,markup.italic,markup.underline,markup.strikethrough,markup.raw.inline.verbatim,markup.raw.inline.code, fixed-width linesmarkup.raw.inline.fixed; linksmarkup.link.url, footnotesmarkup.link.url.footnote, targetslabel.target, macrosfunction.macro, entitiesconstant.character.escape.entity, LaTeXmarkup.raw.inline.latex;commentfor comments- The agenda
- its title
markup.heading.agenda, the daysmarkup.heading.date, the weekend'smarkup.italic.weekend; the time gridcomment.timegridand the current timemarkup.bold.now; entries scheduleddiff.plus.scheduled, scheduled earlierdiff.delta.scheduled, with a deadline to comediff.delta.deadline, due or pastdiff.minus.deadline, donecomment.done; keywords, priorities and tags as in Org files
A theme of one's own changes them, on top of another one:
# ~/.config/helix/themes/my-org.toml, with theme = "my-org" in config.toml
inherits = "onedark"
"markup.heading.1" = { fg = "#61afef", modifiers = ["bold"] }
"markup.heading.2" = "#e5c07b"
"diff.minus.todo" = { fg = "#e06c75", modifiers = ["bold"] }
"markup.italic.weekend" = { fg = "#61afef", modifiers = ["bold"] }What the queries cannot know, they do not show:
- The grammar sees the words of a paragraph, not Org's objects: links,
emphasis and timestamps are found from the word that opens them to the
one that closes them, on one line, with their spaces left plain, and
inline code (
src_python{…}) is not in its language's colors. - TODO keywords are the usual ones (
TODO,NEXT,STARTED,WAIT,WAITING,HOLD,PROJ,SOMEDAY,INPROGRESS, and doneDONE,CANCELLED,CANCELED,CANCEL,KILL,FIXED), not those oforg_todo_keywordsor#+TODO:: others go in the#any-of?lists of the queries. The faces of particular keywords, priorities and tags, and the options of how Org looks (org_fontify_done_headline,org_emphasis_alist…), are not followed. - In the agenda, a line is told by its words, with the default leaders
(
Scheduled:,Sched. 2x:,Deadline:,In 3 d.:,2 d. ago:) and the category first: other leaders and prefix formats are not colored. Today's date, the clocked entry's line and how near a deadline is beyond its leader are not in the text, and are not shown. - Nothing is hidden (link brackets, emphasis markers, entities): Helix lets no server hide text.
What works#
| Feature | Parity | Helix | What does not work, and why |
|---|---|---|---|
| Highlighting | 100% | ❓ | Helix has no semantic tokens: Org and the agenda are colored by tree-sitter queries of org-lsp's that install.sh puts in Helix's runtime, which see the words of the text, not what the server knows. TODO keywords are the usual ones (TODO, NEXT, WAIT, DONE, CANCELLED …), not those of the settings or #+TODO:; the agenda shows neither today nor the clocked line, and its leaders and prefix are the default ones; options of how things look are not followed. Links, emphasis markers, pretty entities and sub- and superscripts are not concealed: Helix lets no server hide text; inline code is not in its language's colors. |
| Folding and visibility | 91% | ❌ | Helix has no folding. |
| Headings and structure | 96% | ❓ | Moving between headings, org-goto and Org's C-a, C-e, C-k and C-y are left out: they need keys, and Helix cannot bind a key to a server's command; nor are inserting an inline task and the commands run by Emacs (C-c *, C-c ;, cloning) among its code actions. New headings are code actions. |
| Lists and checkboxes | 93% | ❓ | RET stays Helix's own; cycled bullets and lines turned into items are left out: Helix cannot bind a key to a server's command (the commands are code actions, Space a), and those are not among them. New items are code actions. |
| TODO keywords | 100% | ❓ | States are picked from the code actions, where they come first once asked for; for a note for a state change (@), the answer is typed as a rename at the cursor (Space r), as Helix has no box of its own for a server to ask for text. Switching to another keyword set is left out in an Org file, where it is not among Helix's code actions; on an agenda line it is one. Faces of particular keywords and priorities are not shown. |
| Priorities | 100% | ✅ | |
| Tags | 88% | ❓ | Tags are typed, not set with keys pressed in turn: the answer is typed as a rename at the cursor (Space r), as Helix has no box of its own for a server to ask for text. Completion and renaming work. Faces of particular tags are not shown. |
| Properties and column view | 100% | ❓ | A property, its value and the effort are typed, without completion: the answer is typed as a rename at the cursor (Space r), as Helix has no box of its own for a server to ask for text. Column view is left out: it draws over the headlines. Custom properties are not hidden (org.custom.properties.toggle): Helix lets no server hide text. Deleting a property, cycling a property's allowed values and toggling ORDERED are left out: they are not among Helix's code actions. |
| Dates and times | 100% | ❓ | Dates are typed (+2d, fri 10:00), with no calendar: the answer is typed as a rename at the cursor (Space r), as Helix has no box of its own for a server to ask for text; Helix reads no file again that the server writes, as the calendar is. New timestamps and removing the scheduled date or the deadline are left out: they are not among Helix's code actions. Changing a timestamp works. |
| Agenda | 97% | ❓ | The agenda is a file, Agenda.org, its commands code actions, a view's choices first in them once asked for; for a search and a date, the answer is typed as a rename at the cursor (Space r), as Helix has no box of its own for a server to ask for text. Follow mode, the outline path of the cursor's entry and the entry in another window are left out: Helix tells a server no cursor moves, and knows no other window of the server's. Column view in the agenda is left out: it draws over the lines. The server's edits leave the agenda's buffer changed: :buffer-close! closes it. |
| Clocking | 100% | ❓ | No clock in the status line: Helix has no place there for a server's text. Showing the time clocked under each headline and resolving open clocks are left out: they are not among Helix's code actions. |
| Capture | 100% | ❓ | Templates are picked from the code actions, where they come first once asked for; for a template's prompts, the answer is typed as a rename at the cursor (Space r), as Helix has no box of its own for a server to ask for text. The capture buffer stays open once the entry is filed: Helix lets no server close a buffer. |
| org-protocol | 86% | ❓ | The server starts a capture itself: the template is picked from the code actions, and for its prompts the answer is typed as a rename at the cursor (Space r), as Helix has no box of its own for a server to ask for text. |
| Notes (org-roam) | 94% | ❌ | The commands are not among Helix's code actions yet. |
| A journal (org-journal) | 93% | ❌ | The commands are not among Helix's code actions yet. |
| Refile and archive | 100% | ❓ | Copying an entry to a target, going to a target and to the entry refiled last, and archiving every done subtree, are left out: they are not among Helix's code actions. Refiling picks the target from the code actions, where the targets come first once asked for. |
| Links | 96% | ❓ | Storing and inserting links in an Org file, and creating an ID, are left out: they are not among Helix's code actions there (the agenda stores a link to its line's entry); moving between links needs a key. Following works through go to definition, and through the code action Open the link or thing at the cursor for the links it cannot open in Helix (web pages, abbreviations, attachments). |
| Footnotes | 100% | ❓ | Making footnotes and their menu are left out: they are not among Helix's code actions. Following them works. |
| Tables | 100% | ❓ | Moving between fields with TAB, copying down, summing, field information creating a table and a rule with a move below it are left out: Helix cannot bind a key to a server's command (the commands are code actions, Space a), and those are not among them. The other edits are code actions in a table. A shrunk column shows its whole text and …: Helix lets no server hide text; the … of Shrink or expand the table column shows once the text changes, when Helix asks for inlay hints again (it cannot be told to sooner). |
| Table formulas | 100% | ❓ | Recalculating the current line only, iterating until the table is stable and the formula debugger are left out: they are not among Helix's code actions, which recalculate the whole table. |
| Code blocks (Babel) | 100% | ❓ | Only tangling, the block at the cursor and editing it in a file of its own are offered (code actions in a block): the file's and the subtree's evaluation, removing results, detangling and moving between blocks need keys, which Helix cannot give a server. |
| Export and publishing | 100% | ❌ | Not offered as a code action yet. |
| Citations | 82% | ❓ | Inserting citations and the BibTeX commands are not offered as code actions yet. Completion, hover and following work. |
| Diagnostics (org-lint) | 100% | ✅ | |
| Indentation and formatting | 100% | ❓ | Virtual indentation shows as inlay hints, the leading stars still showing; new lines are not indented as they are typed. With soft wrap on (soft-wrap.enable), the lines a long line wraps into line up with the prefix and its own indentation, not with a headline's title or an item's text: Helix wraps under a line's leading blanks, inlay hints among them. Numbering the headlines by command (org-num-mode) is left out: it is not among Helix's code actions; #+STARTUP: num numbers them. |
| Notes and logging | 100% | ❓ | A note is one line, with no buffer to write it in: the answer is typed as a rename at the cursor (Space r), as Helix has no box of its own for a server to ask for text. Adding a note is a code action in the agenda, not in an Org file. |
| Completion and editing helpers | 100% | ❓ | Structure templates, emphasis and drawers are not among Helix's code actions. |
| Timers | 100% | ❌ | Timers are left out: Helix cannot bind a key to a server's command (the commands are code actions, Space a), and they are not among them. |
| Attachments | 100% | ❓ | attachment: links open; the dispatcher (C-c C-a) is left out: Helix cannot bind a key to a server's command (the commands are code actions, Space a), and it is not among them. |
| Encryption | 100% | ❓ | Encrypting and decrypting by command are left out: they are not among Helix's code actions. Encrypting before saving needs an editor that sends LSP's willSaveWaitUntil. |
| Inline images and LaTeX previews | 100% | ❌ | Helix cannot show images. |
| All of Org | 97% |
✅ all that org-lsp does works there, ❓ some does not (the last column says what and why), ❌ none does, — nothing to support yet. Parity is the share of what Emacs Org does in that area that org-lsp does; parity.org lists both.
TESTING.org lists what to try by hand.