Org: known differences from Emacs
Table of Contents
- 1. Elements never extend past their container
- 2. Nesting depth
- 3. Overlapping planning timestamps
- 4. Link types depend on loaded libraries
- 5. Line endings
- 6. Sorting
- 7. Repeating tasks far in the past
- 8. Failing commands leave the text unchanged
- 9. Tabs in table fields
- 10. Deleting grapheme clusters
- 11. Emacs bugs Kalem does not reproduce
- 12. Table formulas
- 13. Drawers around indented regions
- 14. Emacs quirks Kalem reproduces
- 15. Export without Emacs Lisp or the network
- 16. Broken links on export
- 17. The property macro at a missing headline
- 18. table.el tables with cells spanning columns
- 19. Entities' renderings
Kalem's parser follows org-element.el (Org 9.7) and is checked against it
with kalem diff-emacs on the test corpus and on randomly mutated files; its
commands and exporters are checked the same way against Emacs's. This page
lists the places where Kalem deliberately behaves differently. The parser's
differences occur only with malformed input or input Emacs cannot parse;
the others are listed with their reasons: Emacs Lisp that Kalem does not
run, files and networks it does not reach, and choices an editor makes
differently from a batch tool.
1. Elements never extend past their container
Emacs can let an element end after the element that contains it:
- A
#+CALL:line with an unbalanced[or(makes Emacs search the rest of the buffer for the closing bracket, and the call can swallow the following lines, even past the end of its section or block. #+TBLFM:lines directly after the end of a container (for example a table at the very end of a drawer) are attached to the table.
A lossless syntax tree cannot have a child that is larger than its parent,
so Kalem ends such elements at the end of their container. kalem
diff-emacs counts these nodes as "known differences" instead of failures.
2. Nesting depth
Emacs's parser stops with a max-lisp-eval-depth error after a few hundred
levels of nesting (about 300 nested lists or 600 nested emphasis markers in
Emacs 30). Kalem parses up to MAX_DEPTH (4096) levels of elements and
objects. Anything nested deeper stays in the tree as plain text, so the file
still opens and round-trips.
3. Overlapping planning timestamps
When a planning line repeats a keyword and the timestamps overlap, as in
SCHEDULED: <2026-01-01 Thu SCHEDULED: <2026-01-02 Fri>>, Emacs may keep
two overlapping timestamp objects in different properties. Kalem keeps the
timestamp Emacs uses for each keyword, and drops a timestamp that would
overlap one it kept.
4. Link types depend on loaded libraries
In Emacs, the set of link types (and so which text is a plain link) depends
on the libraries loaded in the session. Kalem uses a fixed list: the types
registered by emacs -Q with Org, plus attachment from org-attach (see
DEFAULT_LINK_TYPES). Applications can change it through ParseContext.
5. Line endings
Files with DOS line endings (\r\n) are parsed as Emacs parses them after
decoding: the carriage returns are not part of any value. Property values
such as source block code use \n line endings. The syntax tree still
contains every byte of the file.
A file with mixed line endings (some lines ending in \r\n, others in
\n) is decoded by Emacs as a Unix file: its carriage returns stay in
the buffer as characters, so a line holding only \r is not blank and
para\n\r\nnext is one paragraph. Kalem ends a line at every \r\n,
so it reads two. The editor keeps a DOS file's \r\n in its text and
its commands insert bare line feeds, so a DOS file is mixed while it is
edited; reading it as Emacs reads a mixed file would change its meaning
at the first new line. Saving writes \r\n everywhere again.
6. Sorting
- Alphabetical sorting (
org-sort-entriesandorg-table-sort-lineswitha) compares code points, as Emacs does withorg-sort-functionset toorg-sort-function-fallback. Emacs's default,string-collate-lessp, follows the collation of the operating system's locale, so its order can differ between machines; on macOS it also ignores the request to fold case. WithoutWITH-CASE, Kalem folds case as Emacs does on GNU/Linux. The differential tests compare code points the same way. - Dates are compared as local civil times. Emacs compares seconds since the epoch, which only differs for times in the repeated hour when daylight saving time ends.
7. Repeating tasks far in the past
When a task with a ++ repeater is marked done, Emacs shifts its date one
interval at a time and asks whether to go on after ten intervals. Kalem
shifts it as far as needed without asking.
8. Failing commands leave the text unchanged
When a command fails, Kalem's transaction is discarded as a whole. Emacs
may already have changed the buffer: org-sort-entries adds a final
newline to the file before it reports "Nothing to sort", and org-todo on
a commented headline removes COMMENT before it rejects an unknown state.
9. Tabs in table fields
A field can keep a tab when text is made into a table with commas or spaces as separators. Emacs aligns such a field with tab stops, so its width depends on the column it starts at; Kalem counts a tab as one column. Converting tab-separated text, the usual case, turns the tabs into separators and is not affected.
10. Deleting grapheme clusters
Backspace and Delete remove a whole grapheme cluster: an é written as
e and a combining accent, a flag, or an emoji with a skin tone. Emacs
removes one character, leaving the rest of the cluster. The rules for
tables and tags are the same as Emacs's, applied to the cluster.
11. Emacs bugs Kalem does not reproduce
The differential tests list these cases with the reason
(tests/edit/cases.json, field known):
org-list-insert-itemignores the width of a new checkbox when it shifts the sub-items of the item it splits (M-S-RETinside an item with sub-items), and then indents the wrong lines. Kalem indents the sub-items under the new item.org-cycle-list-bulletcan leave a*bullet at column 0, which makes the item a headline, and then fails with a type error. Kalem writes the same text without the error.org-timestampnext to a timestamp, on a line with a date range after point, replaces the next timestamp and gives it the repeater of another one: its range regular expression spans several timestamps, and the replacement uses stale match data. Kalem inserts a timestamp at point.org-table-createin the middle of a line breaks the line and inserts the table after it, but then puts the rule under the first row at the original position, which is before the table, and aligns from the line above the table. Kalem creates the table at the start of the new line, indented like the broken line, with the rule after its first row.org-toggle-headingon a region that starts at an item narrows the buffer to the region and the first character of the next line before it converts the list, so the bullet of the next item can become an empty heading and the levels depend on where the region ends. Kalem turns each item of the region into a heading one level below the entry, a nested item one level deeper, a checkbox into a TODO or DONE keyword.
Footnotes (org-footnote.el, 14 of the random cases in tests/edit):
org-footnote-sort,org-footnote-normalizeandorg-footnote-renumber-fn:Nrecurse without end when a definition refers to its own label (Lisp nesting exceeds max-lisp-eval-depth); Kalem stops the recursion and goes on.org-footnote-normalizefinds an anonymous footnote nested in a definition as the last anonymous footnote of the document, which is another one when there are several, and then extracts text past the end of the buffer (Args out of range); Kalem takes the nested footnote itself.
12. Table formulas
Kalem computes #+TBLFM formulas without Emacs: it reproduces Org's
substitution of references and the part of Calc that table formulas use.
On a corpus of 928 tables recalculated by Emacs every field agrees, except
where noted here.
- Emacs Lisp formulas (
'(...)) are not evaluated. The fields they set keep their values, and Kalem names the formulas. - Calc's full algebra is not reproduced. Numbers, vectors, dates,
durations, infinities and
nanfollow Calc; formulas over text fields stay symbolic with Calc's basic simplifications (x + 2,2 a,n / (42 a)), but deeper algebra (the variance of a column with text, expanded) may be written differently. - Complex numbers in polar form (
(2; 30)), the trigonometric and hyperbolic functions of complex numbers, factorials of fractions (the gamma function), sines of very large arguments, and radix, HMS and error forms (16#FF,2@ 30' 0",3 +/- 0.1) are left as formulas. Complex numbers in rectangular form (sqrt(-4)is(0, 2)) follow Calc. - Formulas over text fields with modulo forms (
(x - 4) mod 3) follow Calc's coefficients, but where Calc leaves a sum or a product unsimplified Kalem may combine its terms or order them differently. - A formula Emacs cannot evaluate because Calc overflows its stack (a
number divided by a vector) shows
#ERRORinstead of stopping the recalculation. - Errors that stop a recalculation (an unknown field, a reference outside the table) have Kalem's own wording.
13. Drawers around indented regions
org-insert-drawer around a region indents the region with
indent-for-tab-command while the region is still active. When the
region starts or ends inside a line's indentation, org-indent-region
re-indents its lines by Org's indentation rules; Kalem wraps the lines
as they are. Nine region cases in tests/edit show it.
14. Emacs quirks Kalem reproduces
Some Emacs behaviors look like bugs but change what documents mean, so Kalem follows them for compatibility:
- In match strings,
PROP<>"<2026-11-01>"compares times for equality:org-time<>is written(\a b)=, which Emacs reads as(a b)=. - In match strings,
"<yesterday>"is compared as a string, not a time: the pattern that recognizes time operands omits it. - The
PRIORITYspecial property is the first[#X]cookie anywhere in the headline line, even inside a link in the title. org-entry-getandorg-entry-propertiesdisagree on duplicate drawer keys: the first returns the last value, the second the first.
15. Export without Emacs Lisp or the network
- Macros defined as
(eval ...)run Emacs Lisp in Emacs; Kalem expands them to nothing. #+SETUPFILE:files are read to eight levels of nesting (Emacs follows them until a file repeats); a#+SETUPFILE:that is a URL is not fetched.remote(NAME, REF)in table formulas finds a table by its#+NAMEin the same document, not by an entry'sIDor in another file.- HTML pages carry Kalem's style sheet instead of
org-html-style-default, and name Kalem as their generator; the MathJax configuration is Emacs's. - With
tex:svg(and the image typesdvisvgm,dvipngandimagemagick), formulas are drawn by the editor's math engine as inline SVG; Emacs runs LaTeX and writes image files. - With no
#+AUTHOR:, Emacs takes the author fromuser-full-name(the account's full name) for the title block,\author,pdfauthorand the HTML page'sauthormeta element; Kalem writes none, so an export does not carry the name of the account it was made on. Give#+AUTHOR:in the document, or in a#+SETUPFILE:shared by a project.
16. Broken links on export
Emacs's default for org-export-with-broken-links is nil: a link that
resolves to nothing stops the export with "Unable to resolve link".
Kalem's default is mark, so an export from the editor always
finishes, the link written as [BROKEN LINK: path] where it was. With
#+OPTIONS: broken-links:nil Kalem stops as Emacs does, and with
broken-links:t it leaves the link out.
17. The property macro at a missing headline
{{{property(NAME,SEARCH)}}} whose SEARCH names no headline stops
Emacs's export with "Macro property failed: cannot find location"; Kalem
expands it to nothing and exports the rest.
18. table.el tables with cells spanning columns
Emacs 30's table-generate-source, which ox-latex calls for a table.el
table, drops the rows after a cell that spans columns when the table
ends with such a cell (and fails on some tables with cells spanning rows
with "Invalid search bound"). Kalem writes every row, a spanning cell as
\multicolumn, and a rule under cells that span rows as \cline; on
tables without spanning cells the output is Emacs's, byte for byte.
19. Entities' renderings
Kalem reads the same entity names as Org, but what each renders as
comes from standards rather than from Org's org-entities.el (decision
D18): the HTML Standard, LaTeX and Unicode. Where those differ from
Org's choices, export and the editor follow them. A few characters
differ (\phi is LaTeX's straight ϕ and \varphi the curly φ;
\Amacr is Ā, not Ã; \diams is the suit's ♦); the LaTeX of some symbols is the math command where Org
writes a text one or the reverse; and the ASCII and Latin-1 forms, which
Org invents, are Unicode's decompositions and names (\Dagger is ++
in ASCII). In HTML a character is written with the name HTML 4.01 gives
it, as Org mostly writes it (∞, →), and the names Org
takes from later standards differ for a few (\ll is ≪, not
≪). The export cases compared with Emacs agree, and so do Worg's
files in HTML and Markdown but the two that list Org's entities in a
table (org-syntax.org's appendix, the HTML publishing tutorial's
symbols).