Differences from Emacs
- Display: in indent mode (org-indent-mode) rows that wrap don't get the virtual indentation (Emacs sets a wrap-prefix; Neovim has no per-line one). Emphasis doesn't nest inside the same kind of emphasis or inside verbatim/code: Emacs fontifies
*a *b* c*and=x *y* z=twice, org.nvim highlights the outer span only. In the agenda clock report, links are replaced by their description in the text (Emacs keeps the link and hides its brackets). A shrunk table column shows its full fields on the cursor line in modes missing from 'concealcursor' (Visual with the default "nc"), as Neovim reveals concealed text there. An image shown in place of its link whose line wraps after it, or on the first line of a closed fold, is drawn below the line or shown as its link text (Emacs makes that screen line as tall as the image). Vim draws syntax up to 'synmaxcol' (3000) of a line: emphasis is highlighted when it ends before that column, so a long line can't leave the lines below it bold. Emphasis over two lines is highlighted only when its part on the first line is at most 'synmaxcol' characters long: looking further for the end of every marker would make drawing a long line take time quadratic in its length.
- Log notes (
*Org Note*,note_buffer) open while the command runs: a state change or rescheduling is applied once the note is stored or cancelled (Emacs changes the entry first and opens the note buffer after the command). As in Emacs, a cancelled note (C-c C-k) logs nothing and the change itself stays. An emptyadd_notenote stores nothing (Emacs stores the bare "Note taken on" heading). - Table formulas: GNU Calc is reimplemented in Lua for what tables use (org-table-calc): numbers, dates, complex numbers, HMS forms, error forms, intervals, modulo forms, vectors and matrices,
usimplifywith a table of common units, the symbolic algebra (Calc's normalization of formulas, simplify, expand, collect, subst, deriv, integ, solve) and the functions listed there. What still differs:simplifyhas Calc's rules for + - * / ^, sqrt, exp, trigonometric inverses and equations, not its whole rule set (noresimplify,factor, rewrite rules);integhandles polynomials, powers, exp, ln, sin, cos, tan, sinh, cosh of a linear argument and parts by polynomial times exp/sin/cos, not Calc's rule-based integrator (its results can differ in form: integ(sin(2 x), x) is-90 cos(2 x) / piwhere Calc writes(180 sin(x)^2 - 90) / pi; what it can't do staysinteg(...));solvefinds one solution (Calc's default) up to quartic polynomials, not by numeric search for higher degrees, and no systems of equations; division by a matrix may differ from Calc in the last float digits;usimplifyknows a subset of Calc's units; fsolve, roots, taylor, the polynomial functions (pdiv, pgcd, factor), spn/midi/freq, lud, kron, histogram and other rarer functions stay symbolic. Quoted strings ("big") are kept as text; Calc makes them vectors of character codes. Emacs Lisp formulas'(...)run on a small Lisp interpreter (the functions listed inlua/org/table/elisp.lua), not in Emacs: starting an Emacs for every field would be far too slow. Any other'(...)is a Lua expression. - Table formula errors: Emacs stops the whole recalculation on some errors (a reference outside the table,
$2=defined twice, unknown remote tables); here the field shows #ERROR (the last definition wins) and the other fields are still computed. Left sides Emacs rejects are accepted:$name=for a named column,$2..$3=and@I$2..@>$2=ranges. - Footnote sorting and renumbering leave src, example, export and comment blocks alone: a line starting with
[fn:N]inside one is code, not a definition. Emacs renumbers such lines too. - Tables in the table.el format (org-table.el) are recognized, converted, exported and edited, but the table.el editor itself (a separate large Emacs package) is not reproduced: in the <C-c>' buffer the grid is realigned when leaving Insert mode instead of while typing, cells never shrink, text is not refilled to the cell width, and the table.el cell commands (splitting, spanning and justifying cells, inserting rows and columns) are missing. Columns count characters, so double-width characters in cells break the grid. <C-c>~ outside a table inserts the new table below a non-blank line (Emacs draws it over the text at the cursor). Converting a table at the very start of the buffer puts a border after every row (Emacs misses the one after the first). Exported HTML cells are always
align="left" valign="top"(Emacs too, as the table is not recognized first). - <M-CR> in an Org table splits the field only in Insert mode (in Normal mode it goes to the field below, as with
meta_return_split_line = false), and wrapping a column acts on the Visual selection. Shrunk columns use conceal and virtual text (org-table-shrink), the header line is drawn in the 'winbar', <C-c>` edits a field in a prompt (follow-field mode uses a window) and plots use gnuplot directly (Emacs needs gnuplot.el). orgtbl-to-unicode converts Org markup in cells with a simplified exporter (verbatim, links and entities only). - Clocking (org-clock): the idle time comes from the system on macOS (ioreg) and X11 (xprintidle), elsewhere (Wayland, Windows) from Neovim's own input, so time spent in other applications counts as idle there. The mode line entry is the org-api statusline component; a click handler pops up the clock menu (org-clock-menu). Timers use counts, so a countdown's C-u (default timer) has no count form: a count is always minutes.
- Citations (org-cite): keys are chosen with
vim.ui.select, and cancelling it is Emacs' empty input;basic_complete_key_crm_separatoris a Vim regexp read at aninput()prompt (Emacs uses completing-read-multiple with an Emacs regexp); a bare key is accepted there as well as the completed "author year title" string. Neovim has no mouse-over faces: a <MouseMove> mapping highlights the key under the mouse withbasic_mouse_over_key_face(org-cite-basic-mouse-over-key-face) and turns 'mousemoveevent' on. There are no tooltips, so the help-echo text over a key (the entry, or the close keys) has no counterpart;require("org.cite").key_help(bufnr, key)returns that text. Keys are highlighted everywhere, also in source blocks. - The csl citation processor runs a Lua port of citeproc-el instead of the Emacs library; it gives citeproc-el's output on 840 of the 845 tests of the CSL test suite (the others are errors in citeproc-el and items without an id). Sort keys compare by code point (Emacs uses the system collation, which is the same on macOS but not on glibc systems). BibTeX crossref inheritance copies every missing field except the biblatex exclusions (parsebib has per-type rules).
- Bulk action
fand agenda skip functions take Lua instead of Elisp. Capture%(sexp)takes Emacs Lisp (see above) or a Lua expression. - Capture edits the text in a separate buffer that is stored at the target (resolved when the capture starts) on finalize, instead of an indirect buffer narrowed to the text already inserted in the target (Neovim has no indirect buffers), so the target file does not show the new text until the capture is finished.
unnarrowedcaptures do insert the text into the target right away (org-capture-unnarrowed). Mail and news%:keywordvalues (%:from,%:subject, ...) come from Emacs link sources (Gnus, mu4e, ...) that have no Neovim counterpart; only%:link,%:description,%:annotation,%:initialand%:typeexist. Thehooktemplate function doesn't run forimmediate_finish. With C-0 (:Org capture_here) Emacs splits the line at point; the Neovim cursor sits on a character, so the text goes before the cursor line at column 0 and after it otherwise. - The ID database can be Emacs's
org-id-locations-file(org-links), but Emacs keeps it in memory and writes it on exit, so the last editor to save wins; files are sorted by name where Emacs keeps its hash order. The refile cache (refile.use_cache) keeps line numbers instead of markers: a target whose headline moved is found again by its text, and C-0 C-c C-w (a count cannot be 0) is:Org refile_cache_clearor C-u C-u C-u C-c C-w. Agenda archives-mode and view toggles (va,v[, ...) stay on until toggled off. - Babel sessions (org-babel Sessions) are live REPLs in terminal buffers for shells, python, js/node, ruby (irb) and R; there are no sessions for julia, SQL engines or other languages. Lua blocks run inside Neovim instead of an external
luaunless thecmdofbabel.languages.luanames one (lua sessions are a Neovim environment with a prompt buffer; in Neovim a table variable is a nested Lua table, where ob-lua makeskey=valueof two-column rows). Differences from comint: the code of a block reaches the REPL as one line that runs it from a file, not line by line, so the REPL shows that line instead of the code, and a python/node block's intermediate expression values are not echoed (as with python.el's file sending). Shells start without their rc files and a shell session namedxis the buffer*x*(Emacs names itx). The R session is a plainRconsole, not ESS (noess-ask-for-ess-directory, graphics devices or:results output graphicshandling beyond what the code does itself). C-c C-v C-l runs the block in the session; Emacs only inserts it at the prompt. Timeouts (babel.timeout) give up on the result but do not interrupt the REPL. emacs-lisp blocks andelisp:links run in a separateemacs --batchprocess (or, without Emacs, on the table formula Lisp interpreter), not in the editor: they cannot see or change buffers, and nothing is kept between evaluations.:varand header Lisp forms run on the table formula Lisp interpreter, else in that separate Emacs (see org-babel). - Src edit buffers (org-babel-edit-special): the edited region of the Org buffer is neither highlighted nor read-only (edits there make
:wrefuse, see above) and a click on it does not return to the edit buffer (use:Org edit_src_continue); the hint is in the winbar, not a header line.edit_fixed_width_region_modehas no artist-mode::areas get no filetype unless one is set.edit_src_turn_on_auto_savewrites the auto-save file on 'updatetime' idle (Emacs: every 300 keystrokes or 30 idle seconds); the idle write-back (edit_src_auto_save_idle_delay) counts from the last change of the edit buffer. Association with a:sessionsends code withedit_src.send_to_session(Emacs sets the language mode's own "send to REPL" commands, like python.el's, to the session).src_tab_acts_nativelyindents with the filetype's 'indentexpr' (Vim's indentation rules, with the Org buffer's 'shiftwidth' unless the filetype sets one), not Emacs' major modes, and always with spaces.C-c C-con a#+RESULTS[hash]hash works on the whole hash, which is not shortened to 4 characters as Emacs displays it. - The ports of org-babel-languages run a new process for each block where Emacs uses an Emacs package's REPL: gnuplot (gnuplot-mode sessions), haskell (inf-haskell: ghci is fed the block and markers), ocaml (tuareg: a new
ocamltoplevel), julia (ESS), scheme (Geiser:impl's command evaluates the forms and writes the last value) and Common Lisp (org-babel-lisp-eval-fnSLIME/SLY:cmd, defaultsbcl --script, reads the form and prints its values like swank:eval-and-grab-output). The cider, inf-clojure and slime Clojure backends are not available. Julia table variables are written to a CSV file read byCSV.read(Emacs puts the CSV text itself there). The lilypond header arguments of arrange / basic mode apply as soon as the mode is toggled (Emacs sets them while evaluating, so they apply from the next block). LaTeX .png results use the Normal highlight's colors (Emacs the default face's). ob-screen'sorg-babel-screen-testwaits at mostbabel.timeout(Emacs waits forever). ob-csharp runs the built program withDOTNET_ROOTset to the directory of dotnet's SDKs when it is unset, so a .NET installed outside the default location (by dotnet-install.sh, in ~/.dotnet) is found; Emacs leaves it unset and the program fails with "You must install .NET to run this application". fish:varvalues escape\and'inside their single quotes (Emacs quotes them like POSIX shells, which changes values with backslashes). - Emacs Lisp outside of blocks (
(eval ...)macros, capture%(sexp), diary sexps,%(function)link abbreviations, header forms) runs on the table formula Lisp interpreter when it can and otherwise in a separateemacs --batch(babel.emacs_lisp) that knows nothing of your Emacs configuration unless itsargsload it; without an Emacs executable only the interpreter's subset works. - Export: see org-export-unsupported.
Links (org-links):
elisp:(sexp)links are evaluated in a separateemacs --batch(babel.emacs_lisp), not in the editor, afterlinks.confirm_elisp(a y/n prompt;links.elisp_skip_confirm_regexpskips it); a link naming a command (elisp:emacs-version) calls it interactively there, so commands that act on the editor (elisp:org-agenda) or prompt fail. Abbreviations using%(my-function)call the function in that Emacs, which must define it (load it withbabel.emacs_lisp.args); a Lua function as the abbreviation works too.help:opens Vim's :help: Emacshelp:links name Elisp functions and variables (describe-function), which do not exist here.info:runs theinfoprogram in a terminal,man:uses :Man.- Links to Emacs applications (gnus, rmail, mhe, bbdb, irc/erc, eww, w3m, calendar) can't be followed or stored: there is no such application in Neovim.
docview:opens the file. BibTeX links (org-bibtex) work:bibtex:opens the file and a link stored in a .bib buffer finds the entry.bibtex_yankreads only the yanked text (Emacs writes an older read entry when the yanked text has none),bibtex_export_to_kill_ringon a headline without an entry type warns (Emacs signals a type error), andbibtex.autogen_keysworks without a BibTeX buffer having been opened (in Emacs -Q it fails until bibtex-mode has set up its dialect). shell:runs asynchronously (Emacs's shell-command waits for the command); its stdout and stderr are appended to*Org Shell Output*one after the other rather than interleaved.links.confirm_shellasks with a y/n prompt.::/regexp/searches translate the common Emacs regexp syntax to Vim regexps; Emacs-only constructs (syntax classes other than whitespace and words, categories, backward references to point) are approximated or unsupported.- Internal links followed with a count open in another window on the same buffer; there are no indirect buffers (org-link-use-indirect-buffer-for-internals), and Vim folds are per window anyway.
- Files Neovim cannot display (images, media, office documents, PDF, HTML) open with the system application, where Emacs opens images and office documents itself (org-file-apps);
links.file_appsoverrides it. - Wildcard file links (
file:*.org) list the names of the matches in a scratch buffer instead of a Dired buffer (nols -ldetails or Dired commands).
- Diary sexps are emulated for the calendar functions of Emacs's diary library (all the
diary-*sexp functions of diary-lib, cal-hebrew, cal-china, lunar and solar and thediary-*-datefunctions),org-calendar-holiday(org-agenda-holidays) and a side-effect-free subset of Emacs Lisp (org-agenda-diary-sexp); other sexps run in a separate Emacs when there is one. The Emacs diary file is read by a port of diary-lib (org-agenda-diary-file): customdiary-date-forms, and diary comments are not supported. Entries added withiin the agenda usecalendar_date_stylefor the date forms where Emacs usesdiary-date-insertion-form. - MobileOrg (org-mobile):
mobile.directorymust be a local directory (Emacs also accepts TRAMP paths; copy the files in the push/pull hooks instead). agendas.org lists the custom commands in key order (Emacs: the order of org-agenda-custom-commands) and its agenda lines look like this agenda's.force_mobile_change = { "priority" }forces priority edits (Emacs teststagsthere). The new#+LAST_MOBILE_CHANGE:line does not make the first edit of a file fail, as it does in Emacs 9.8. - Image and LaTeX previews (org-images) need a terminal image backend. They replace the link or fragment like Emacs, but a terminal line can't grow: the image's first row is on the line and the rest in virtual lines under it, and the text shows again (with the image under the line) while the cursor is on the line so it can be edited. A fragment over several lines has its other lines hidden and its image drawn from its first line (Neovim 0.11+; before that, and with image.nvim, images stay under the line); the text after it on its last line follows the image without its highlighting.
ui.images.max_widthis in columns for "fill-column" and fractions (as Emacs) but its default fill column is 'textwidth' or 70;max_heightis an addition. LaTeX previews pick an installed process ("auto") where Emacs always uses dvipng, and add "tectonic" and "pdflatex". Preview functions return an image file (or call back with one) instead of filling an overlay.ui.images.remote(org-display-remote-inline-images) applies to http(s) image links, since there are no TRAMP files. - Column view: the overlays cover each headline line and the column is the one drawn under the cursor. Emacs puts one column on each character, so every motion jumps a column; here h l w b <Left> <Right> <BS> <Space> $ are remapped on the rows, other motions (f, t, /, mouse) still move by character. The headline lines are read-only through their keys and Insert mode: a change started from another line (
Jon the line above,dkbelow, a Visual selection, an Ex command, the agenda) still reaches them, where Emacs refuses it. Like Emacs, digits 1-9 select allowed values on a column row, so counts are not available there (0 keeps its Vim meaning; counts work on other lines). - Feeds (org-feed): feeds are fetched with curl (or wget, or a Lua function) instead of url.el, and
:parse-feed/:filter/handlers are Lua functions. Fixes over org-feed.el: a multi-line%fieldalone on its line is indented (Emacs means to but leaves the later lines at column 0), CDATA in RSS fields is unwrapped, Atom<content>without a type is text (Emacs writes "Unknownnil' content."),<summary>is used when there is no content and xhtml content is kept as markup rather than a Lisp form, the filter also applies to changed items (Emacs passes the filtered new items as changed ones) andOrgFeedBeforeAdding` fires (Emacs never runs org-feed-before-adding-hook). The inbox is not refolded after an update.
Structure editing:
- Emacs acts at point, between two characters; Normal mode has a cursor on a character. Commands that insert at point (<M-CR>, C-c RET, drawers, templates, paste) act at the end of the line in Normal mode (at its start in column 0) and never split it; in Insert mode they act at the cursor like Emacs.
- Emacs binds M-h to org-mark-element and C-x n b / C-x n e to narrowing; here <M-h> promotes and <C-x> decrements, so those are <prefix>v, <prefix>nb and <prefix>ne. Narrowing edits the region in a separate buffer instead of hiding the rest of the buffer.
- A count repeats promote / demote (<M-h>, <<); Emacs ignores it.
- Element commands work on whole lines.
- Speed commands work in Insert mode at the start of a headline (where Emacs would insert the letter); Normal mode keeps Vim's letters.
- Pretty sub/superscripts can't be raised: Unicode super/subscript characters are used when they exist, else a highlight.
- org-list-checkbox-radio-mode is the buffer-local toggle
:Org checkbox_radio_mode(no mode line lighter). - Indentation (org-indent):
=indents line by line with org-indent-line, so a list or an example block is not moved as a whole like org-indent-region (C-M-\) does;:Org indent_regiondoes that. Src block code keeps its own relative indentation instead of being indented by the language's major mode (Emacs's org-src-tab-acts-natively). - Filling (org-fill):
gqfills to 'textwidth' rather than fill-column (70); src blocks are not filled (Emacs uses the language's major mode);gqover a comment of several paragraphs fills each of them (Emacs's region fill only fills the last one); only whitespace is used as a fill prefix (Emacs also takes>and other adaptive-fill-regexp characters).
Capture, clock, archive and other commands (parity round 5):
- The global capture hooks are User autocmds (org-capture-hooks); the template functions are not called on abort as Emacs does, only the events fire (with
aborted = true). datetree_cleanupskips SCHEDULED/DEADLINE time stamps: Emacs's check for them never matches (\<DEADLINE:\>), so it files entries by their planning dates and leaves emptied day nodes behind.protocol_createadds the project for the session and shows the Lua to put insetup(); Emacs saves it with Customize.- org-ctags reads Vim
tagsfiles through the 'tags' option instead of EmacsTAGSfiles;ctags.enabledreplaces org-ctags-enable. - Files cut in a file manager and pasted with
yank_mediaare moved, copied ones copied (Emacs swaps the two). A drop is a paste of file paths in the terminal (yank.dnd_paste); attaching a dropped file usesyank.dnd_default_attach_method(Emacs'sprivateDND action). attach_from_file_managerworks in netrw and oil.nvim buffers (Emacs: org-attach-dired-to-subtree in Dired).
- The global capture hooks are User autocmds (org-capture-hooks); the template functions are not called on abort as Emacs does, only the events fire (with
- Visibility (see org-hidden-lines): hiding text between visible lines needs Neovim 0.11 (
conceal_lines); hidden lines are shared by the windows of a buffer while folds are per window; Vim fold commands don't show hidden lines; linewise commands on a closed fold act on the whole fold;catch_invisible_editswatches edits in Insert mode (Normal mode commands such asxorJare not checked; Insert mode opens a closed fold, so only hidden lines count as invisible), and <BS>, <Del> and <CR> only when no mapping turns them into other keys (Neovim 0.11). - Sparse-tree searches leave the cursor on the first match; the default org-occur-hook of Emacs (org-first-headline-recenter) moves it to the first headline. The
OrgOccurUser autocmd runs after each search (org-occur-hook). TODO keywords, tags, properties and dates (see org-todo, org-tags, org-properties, org-dates):
- C-c C-t prefix arguments are counts:
C-0(no note) andC-- 1(cancel repeaters) have no count form and are the actionstodo_without_noteandtodo_cancel_repeaters; a count of 4 always means C-u, so the 4th keyword cannot be picked by count. - A repeated C-c C-t on a
#+TYP_TODO:keyword (which walks the types instead of jumping to DONE) is one with no edit and no cursor motion since the previous one, rather than Emacs'last-commandtest. - The Emacs hooks are User autocmds (
OrgTodoStateChange,OrgTodoRepeat,OrgPropertyChanged,OrgNoteStored,OrgLogBufferSetup) that cannot change the result;todo_blockers(org-blocker-hook) can veto a change andtodo_get_default_hooks,after_todo_statistics_hooksandtodo_statistics_hooksare Lua functions (org-todo). The statistics hooks run after state changes and M-S-RET, not after capture, archiving or C-c #. - The fast tag selection menu is a floating window read one key at a time; it does not show the tags on the headline while it is open.
- Regexps in
use_tag_inheritanceanduse_property_inheritanceare Vim regexps;{...}in match strings and tag groups are Emacs regexps translated to Vim (Emacs-only constructs are approximated). property_separatorsregexps are Vim regexps, and its name lists are compared ignoring case (Emacs compares them exactly).priority_get_priority_functionalways receives the headline line (the agenda passes Emacs its formatted agenda line).- The date prompt refuses text it cannot read at all instead of using the default date, and accepts today/tomorrow/yesterday/now; the calendar is the plugin's own (no Emacs calendar/diary commands such as holidays, sunrise or diary entries in it; the agenda has the holidays, moon, sunrise and date conversion keys, org-agenda-calendar-keys, and shows the diary file, org-agenda-diary-file).
- The calendar shows one month (Emacs three): <C-v>/<M-v> move the selection as Emacs moves its cursor,
!shows the day's agenda instead of the diary entries, and the live interpretation of a typed date is drawn in the calendar instead of after the prompt. Withread_date_popup_calendar = falseno interpretation is shown, like Emacs. The calendar is not kept open after a prompt: <C-c>< inserts the date it was last left on, and today (not an error) before any calendar was shown. As the calendar is a prompt, it is never shown while a timestamp changes, so org-calendar-follow-timestamp-change has nothing to follow; itscandikeys close it. links.mouse_1_follows_linktimes the click from press to release in the Org buffer;open_at_point_globalreads links on the line (and bracket links over nearby lines), not the whole paragraph.- The custom timestamp display conceals the timestamp text: the cursor moves over the hidden characters, and the real text shows in Insert mode or with 'concealcursor' unset.
- Habit graphs are only drawn in the agenda (as in Emacs); a habit's scheduled date must have a repeater of at least one day.
- C-c C-t prefix arguments are counts:
Menus and org-mouse (org-menus, org-mouse):
- Menu entries that are toggles or radio buttons in Emacs show no check state in the menu bar (the org-mouse popups, built when shown, mark them "[X]" / "(*)"). "Complete Keyword" and "Complete Lisp Symbol" use omni completion; the CDLaTeX and RefTeX entries of the LaTeX submenu are always greyed out; "Show Org Manual" opens org, "Browse Org News" the org.nvim releases; "Which Column?" says the column (Emacs computes it silently); "Previous Keyword Set" goes to the previous set (Emacs 9.8.10 runs the next-set command there); "Reload Org" reloads the Lua modules with the options in effect, and refuses while a clock runs; "Enforce Dependencies", "Customize Feeds" and MobileOrg's "Setup" open org-customize on the option. Two agenda entries named "Archive default" are distinguished by a trailing space.
- org-mouse's link menu opens links "in Neovim" instead of Emacs; its SCHEDULED:/DEADLINE: replacement works (Emacs 9.8.10 signals void-variable org-mouse-rest). A subtree dropped on a headline's stars goes before it at its level and one dropped right of them becomes its last child, as org-mouse's own message says (Emacs 9.8.10 counts the space after the stars as a level, so the subtree lands a level deeper, and loses the subtree when dropped under a later headline). Text dropped on the buffer arrives as a paste, so org-mouse's insertion of dropped text as a list item (org-mouse-punctuation) has no counterpart.
- Customize (org-customize) lists lua/org/config/'s options and sets them for the session; there is nothing like Custom's "Save" (options live in your
setup()call). - org-lint (org-lint): invalid-id-link reports an ID found neither in the file nor in the ID locations; Emacs 9.8.10 falls back on the current file for any ID (org-id-find-id-file), so it never reports one in a file buffer. misplaced-heading reports the misplaced stars themselves; Emacs 9.8.10 reads the match position after org-element-at-point has overwritten it, so its reports land elsewhere (later on the line, or on the line after the paragraph). suspicious-language-in-src-block knows the languages with a Babel backend or a Neovim syntax or ftplugin file (
vim,json, ...), where Emacs knows those with a Babel backend or an installed major mode.