org.nvim

Migrating from nvim-orgmode

nvim-orgmode (https://github.com/nvim-orgmode/orgmode) and org.nvim read and write the same Org files, so your notes need no change. What changes is the plugin, its options and some keys. This chapter maps them, and :Org migrate_config converts a setup for you.

Swapping the plugin

Remove nvim-orgmode and add org.nvim. Don't keep both: they both define the org filetype and the :Org command. With lazy.nvim:

-- before
{
  "nvim-orgmode/orgmode",
  event = "VeryLazy",
  config = function()
    require("orgmode").setup({ org_agenda_files = "~/orgfiles/**/*" })
  end,
}
-- after
{
  "xheisenbugx/org.nvim",
  main = "org",
  lazy = false,
  opts = { agenda_files = { "~/orgfiles/**/*" } },
}

Other plugin managers: see org-installation. Then:

  • Completion: the nvim-cmp and blink.cmp source of nvim-orgmode is orgmode; org.nvim's is org (modules org.completion.cmp and org.completion.blink, see org-completion). Omni completion (<C-x><C-o>) works as before.
  • Tree-sitter: org.nvim parses and highlights Org itself and doesn't use the org tree-sitter parser of nvim-orgmode. If you added org to nvim-treesitter's ensure_installed or its highlighting, take it out so it doesn't take over the highlighting of org buffers.
  • Run :checkhealth org afterwards: it lists the options it doesn't know.

Converting a setup

:Org migrate_config [file]Read the nvim-orgmode setup in the Lua file [file] (default: the current buffer, which must be Lua; unsaved changes count) and open the org.nvim require("org").setup({ ... }) doing the same in a new scratch buffer. Save it where you keep your config or copy what you need. The file is only read, never written.

The file can call require("orgmode").setup({ ... }), return a lazy.nvim spec for nvim-orgmode (its opts, a table or a function, and its config function), or return the options table itself. It is run as Lua to get the options, in a sandbox: other requires get an inert stand-in, and the keymaps, autocommands, user commands, highlights and option changes it makes are ignored, so converting your whole plugin spec does no harm.

The result has:

  • every option converted: renamed, or rewritten where the format differs (TODO keywords, capture templates, custom agenda commands, the time grid, windows, notifications, mappings);
  • -- TODO: comments above what needs a look: a key that is also org.nvim's default for another action, a template field or block option with no equivalent, a function copied from your config whose arguments differ;
  • the options with no equivalent, each with a TODO saying why and its value commented out;
  • commented out at the end, nvim-orgmode's defaults that differ from org.nvim's (indentation, folding, logging, the tag column, keys): uncomment the ones whose behaviour you want to keep.

Functions in your options (a custom notifier, a capture headline function) are copied from the file when they are written in place as function(...) ... end; otherwise a TODO says where they are.

Options

nvim-orgmode options and their org.nvim names (org-config):

org_agenda_filesagenda_files (a list; globs work)
org_default_notes_filedefault_notes_file
org_todo_keywordstodo_keywords: one string per sequence, { "TODO NEXT | DONE" }
org_todo_repeat_to_statetodo_repeat_to_state
org_todo_keyword_facesui.todo_keyword_faces (same format)
org_deadline_warning_daysdeadline_warning_days
org_agenda_spanagenda.span
org_agenda_start_on_weekdayagenda.start_on_weekday
org_agenda_start_dayagenda.start_day
org_agenda_min_heightnone: the agenda split is sized by agenda.window_frame_fractions
org_agenda_skip_scheduled_if_doneagenda.skip_scheduled_if_done
org_agenda_skip_deadline_if_doneagenda.skip_deadline_if_done
org_agenda_text_search_extra_filesagenda.text_search_extra_files
org_agenda_custom_commandsagenda.custom_commands (org-migrate-agenda)
org_agenda_hide_empty_blocksnone: empty blocks are shown, as in Emacs
org_agenda_block_separatoragenda.block_separator
org_agenda_sorting_strategyagenda.sorting (no clocked-up / clocked-down)
org_agenda_remove_tagsagenda.remove_tags
org_agenda_time_gridagenda.time_grid: type, times, separator (time_separator with a space on each side), time_string (time_label)
org_agenda_use_time_gridagenda.time_grid.enabled
org_agenda_current_time_stringagenda.current_time_string
org_agenda_show_future_repeatsagenda.show_future_repeats (true, false or "next"; no count)
org_capture_templatescapture.templates (org-migrate-capture)
org_startup_foldedstartup_folded ("inherit": none)
org_priority_highestpriority_highest
org_priority_defaultpriority_default
org_priority_lowestpriority_lowest
org_priority_start_cycle_with_defaultpriority_start_cycle_with_default
org_archive_locationarchive_location
org_tags_columntags_column
org_use_tag_inheritanceuse_tag_inheritance
org_tags_exclude_from_inheritancetags_exclude_from_inheritance
org_use_property_inheritanceuse_property_inheritance
org_hide_leading_starsui.hide_leading_stars
org_hide_emphasis_markersui.hide_emphasis_markers
org_ellipsisellipsis
org_log_donelog_done
org_log_repeatlog_repeat
org_log_into_drawerlog_into_drawer
org_highlight_latex_and_relatedui.highlight_latex_and_related, a list: "native" is { "native" }, "entities" is { "latex", "entities" }
org_custom_exportsnone: export is built in (HTML, LaTeX/PDF, Markdown, ODT, ... and pandoc formats, org-export)
org_adapt_indentationadapt_indentation
org_startup_indentedui.indent_mode
org_indent_mode_turns_off_org_adapt_indentationui.indent_mode_turns_off_adapt_indentation
org_indent_mode_turns_on_hiding_starsnot needed: indent mode hides the leading stars, as in Emacs
org_time_stamp_rounding_minutestime_stamp_rounding_minutes = { 0, N }
org_cycle_separator_linescycle_separator_lines
org_blank_before_new_entryblank_before_new_entry
org_src_window_setupwin_split_mode, the window of edit buffers: "float", "split", "vsplit", "tab" or "current"
org_edit_src_content_indentationedit_src_content_indentation
org_edit_src_filetype_mapsrc_lang_modes
org_id_uuid_programnot needed: UUIDs are made in Lua
org_id_ts_formatid.ts_format
org_id_methodid.method
org_id_prefixid.prefix
org_id_link_to_org_use_idlinks.use_id
org_babel_default_header_argsbabel.default_header_args, without the colons: { tangle = "no" }
calendar_week_start_daynone: the calendar starts on Monday
calendar.*none
win_split_modeagenda.window and capture.window ("split", "vsplit", "float", "tab", "current"; no function)
win_borderwin_border
notifications.enablednotifications.enabled
notifications.reminder_timenotifications.reminder_time (a list)
notifications.notifiernotifications.notifier, called once per reminder with { title, body, item, minutes }
notifications.cron_*none: reminders run in Neovim (org-notifications)
notifications.*_reminder*none: timed deadlines and scheduled entries are always reminded
hyperlinks.sourceslinks.types (org-links): a follow(path) and complete() per link type
emacs_confignot needed: export doesn't use Emacs; executable_path becomes babel.emacs_lisp.command (Emacs Lisp src blocks and %(sexp))
ui.folds.colorednone: folded headlines keep their colours
ui.menu.handlernone: ui.menus = false uses vim.ui.select (org-key-menus)
ui.input.use_vim_uinone
ui.agenda.preview_windownone: <Space> shows the entry
mappings.disable_allmappings.disable_all
mappings.prefixmappings.prefix
mappings.org_return_uses_meta_returnnone: <M-CR> adds a heading, item or row in Insert mode

Defaults that differ (nvim-orgmode / org.nvim, which follows Emacs):

adapt_indentationtrue / false
startup_folded"overview" / "showeverything"
log_done"time" / false
tags_column-80 / -77
blank_before_new_entry{ heading = true, plain_list_item = false } / "auto" for both
edit_src_content_indentation0 / 2
agenda.sortingpriority-down / urgency-down (the priority and how close the deadline or scheduled date is)
agenda.block_separator"-" / "─"
win_border"single" / "rounded"

:Org migrate_config offers nvim-orgmode's values, commented out.

Capture templates

The fields description, template (a string or a list of lines), target, headline (a string or a function), prepend and regexp are the same (org-capture-templates). The others:

datetree = truethe same
datetree = { time_prompt = true }datetree = true, time_prompt = true
datetree = { tree_type = "month" }datetree = true, tree_type = "month"
datetree = { reversed = true }none: date nodes stay in date order
tree_type = "custom"tree_type = function(date) returning { { title, compare } ... }
properties = { empty_lines = N }empty_lines = N
properties = { empty_lines = { before = B, after = A } }empty_lines_before = B, empty_lines_after = A
subtemplates = { r = {...} }a key per template ("er", "eo") and the label of the group under its own key (e = "Event"), as in Emacs

In the template text:

  • %(return EXPR) (a Lua function body) is %(EXPR) (an expression, or Emacs Lisp: %(format-time-string "%Y")).
  • %n is your full name (Emacs's user-full-name), not $USER; use %(os.getenv("USER")) for the old value.
  • A relative target is relative to org_directory ("~/org").
  • %<...> date formats in a target aren't expanded: make the target a function, target = function() return os.date("~/org/%Y-%m.org") end (:Org migrate_config writes one).
  • org.nvim knows more fields: olp, id, type = "item", clock_in, immediate_finish, ... (org-capture-templates).

With no templates at all, org.nvim uses Emacs's default t template, which files tasks under a "Tasks" headline of default_notes_file.

Custom agenda commands and agenda files

org_agenda_custom_commands keeps its shape: a description and a list of blocks in types, each with a type ("agenda", "tags", "tags_todo") and a match. org.nvim accepts the org_agenda_* names in blocks, but its own are shorter (org-agenda-custom-commands):

org_agenda_overriding_headerheader
org_agenda_filesfiles (a list)
org_agenda_tag_filter_presettag_filter_preset, a list: "NOTES-REFACTOR" is { "+NOTES", "-REFACTOR" }
org_agenda_category_filter_presetcategory_filter_preset, a list: "todos" is { "+todos" }
org_agenda_sorting_strategysorting
org_agenda_remove_tagsremove_tags
org_agenda_spanspan
org_agenda_start_on_weekdaystart_on_weekday
org_agenda_start_daystart_day
org_agenda_todo_ignore_scheduledtodo_ignore_scheduled
org_agenda_todo_ignore_deadlinestodo_ignore_deadlines

In a tags_todo block, org.nvim (like Emacs) applies the todo_ignore_* options only with tags_todo_honor_ignore_options = true in the block; the converter adds it. Blocks may also be todo, search and stuck, and a command's settings apply to all its blocks.

Agenda files: "~/org/**/*" works as it is (only .org and .org_archive files are read). A directory without a glob adds its *.org files, not recursively, as in Emacs.

Keys

<prefix> is mappings.prefix, <Leader>o in both. Keys are set by action name under the same sections, mappings.org.<action>, mappings.agenda.<action>, ... (org-keymaps). A list of keys works; nvim-orgmode's desc doesn't (org.nvim names keys after their action). org.nvim also binds Emacs's keys (<C-c><C-t>, <C-c><C-s>, ...; org-emacs-keys).

Org buffers (nvim-orgmode mapping, key: org.nvim action, key):

org_refile<prefix>r: refile, the same key
org_timestamp_up_day<S-Up>: shift_up, the same key
org_timestamp_down_day<S-Down>: shift_down, the same key
org_timestamp_up<C-a>: increment, the same key
org_timestamp_down<C-x>: decrement, the same key
org_change_datecid: timestamp, org.nvim key <prefix>i.
org_priority<prefix>,: priority, the same key
org_priority_upciR: shift_up, org.nvim key <S-Up>
org_priority_downcir: shift_down, org.nvim key <S-Down>
org_todocit: todo_next, the same key
org_todo_prevciT: todo_prev, the same key
org_toggle_checkbox<C-Space>: toggle_checkbox, the same key
org_toggle_heading<prefix>*: toggle_heading, the same key
org_open_at_point<prefix>o: open_at_point, org.nvim key <prefix>o, <CR>, gx
org_edit_special<prefix>': edit_special, the same key
org_add_note<prefix>na: add_note, org.nvim key <C-c><C-z>
org_cycle<Tab>: cycle, the same key
org_global_cycle<S-Tab>: global_cycle, the same key
org_archive_subtree<prefix>$: archive_subtree, the same key
org_set_tags_command<prefix>t: set_tags, the same key
org_toggle_archive_tag<prefix>A: toggle_archive_tag, org.nvim key <prefix>hA
org_do_promote<<: promote_heading, the same key
org_do_demote>>: demote_heading, the same key
org_promote_subtree<s: promote_subtree, the same key
org_demote_subtree>s: demote_subtree, the same key
org_meta_return<Leader><CR>: meta_return, org.nvim key <M-CR>
org_return<CR> in Insert mode: none; <CR> moves to the next table row
org_insert_heading_respect_content<prefix>ih: insert_heading, the same key
org_insert_todo_heading<prefix>iT: meta_shift_return, org.nvim key <M-S-CR>
org_insert_todo_heading_respect_content<prefix>it: insert_todo_heading, the same key
org_move_subtree_up<prefix>K: move_subtree_up, the same key
org_move_subtree_down<prefix>J: move_subtree_down, the same key
org_export<prefix>e: export, the same key
org_next_visible_heading}: next_heading, org.nvim key ]]
org_previous_visible_heading{: prev_heading, org.nvim key [[
org_forward_heading_same_level]]: next_sibling, org.nvim key ][
org_backward_heading_same_level[[: prev_sibling, org.nvim key []
outline_up_headingg{: goto_parent, the same key
org_deadline<prefix>id: deadline, org.nvim key <prefix>d
org_schedule<prefix>is: schedule, org.nvim key <prefix>s
org_time_stamp<prefix>i.: timestamp, the same key
org_time_stamp_inactive<prefix>i!: timestamp_inactive, the same key
org_toggle_timestamp_type<prefix>d!: toggle_timestamp_type, no org.nvim key
org_insert_link<prefix>li: insert_link, the same key
org_store_link<prefix>ls: store_link, the same key
org_clock_in<prefix>xi: clock_in, the same key
org_clock_out<prefix>xo: clock_out, the same key
org_clock_cancel<prefix>xq: clock_cancel, the same key
org_clock_goto<prefix>xj: clock_goto, the same key
org_set_effort<prefix>xe: set_effort, the same key
org_show_helpg?: help, the same key
org_babel_tangle<prefix>bt: babel_tangle, the same key

Keys that do something else in org.nvim: <prefix>id inserts a drawer, <prefix>is a subheading, <prefix>A attaches a file, and }, { are Vim's paragraph motions again. <prefix>d sets the deadline: mapping <prefix>d! as well makes Vim wait 'timeoutlen' after <prefix>d.

Agenda (mappings.agenda):

org_agenda_laterf: later, the same key
org_agenda_earlierb: earlier, the same key
org_agenda_goto_today.: today, the same key
org_agenda_day_viewvd: day_view, the same key
org_agenda_week_viewvw: week_view, the same key
org_agenda_month_viewvm: month_view, the same key
org_agenda_year_viewvy: year_view, the same key
org_agenda_quitq: quit, the same key
org_agenda_switch_to<CR>: switch_to, the same key
org_agenda_goto<Tab>: goto, the same key
org_agenda_goto_dateJ: goto_date, org.nvim key gd
org_agenda_redor: redo, the same key
org_agenda_todot: todo, the same key
org_agenda_open_at_point<prefix>o: open_link, org.nvim key <C-c><C-o>
org_agenda_clock_goto<prefix>xj: clock_goto, org.nvim key J
org_agenda_set_effort<prefix>xe: set_effort, org.nvim key e
org_agenda_clock_inI: clock_in, the same key
org_agenda_clock_outO: clock_out, the same key
org_agenda_clock_cancelX: clock_cancel, the same key
org_agenda_clockreport_modeR: clockreport_mode, org.nvim key C, vR
org_agenda_priority<prefix>,: priority, org.nvim key ,
org_agenda_priority_up+: priority_up, the same key
org_agenda_priority_down-: priority_down, the same key
org_agenda_archive<prefix>$: archive, org.nvim key $
org_agenda_toggle_archive_tag<prefix>A: toggle_archive_tag, org.nvim key <C-c><C-x>a
org_agenda_set_tags<prefix>t: set_tags, org.nvim key :
org_agenda_deadline<prefix>id: deadline, org.nvim key d
org_agenda_schedule<prefix>is: schedule, org.nvim key s
org_agenda_filter/: filter, the same key
org_agenda_refile<prefix>r: refile, org.nvim key R
org_agenda_add_note<prefix>na: add_note, org.nvim key z
org_agenda_previewK: show, org.nvim key <Space>
org_agenda_show_helpg?: help, the same key

In the agenda, K captures, J goes to the clocked task and R refiles.

Capture, note and edit buffers:

org_capture_finalize<C-c>: capture.finalize, org.nvim key <C-c><C-c>, <prefix>w
org_capture_refile<prefix>r: capture.refile, org.nvim key <prefix>r, <C-c><C-w>
org_capture_kill<prefix>k: capture.kill, org.nvim key <prefix>k, <C-c><C-k>
org_capture_show_helpg?: help, the same key
org_note_finalize<C-c>: none; <C-c><C-c> stores the note
org_note_kill<prefix>k: none; <C-c><C-k> cancels it
org_edit_src_save_exit<prefix>': edit_src.save_exit, org.nvim key <prefix>', <C-c>'
org_edit_src_abort<prefix>k: edit_src.abort, org.nvim key <prefix>k, <C-c><C-k>
org_edit_src_save<prefix>w: none; :w writes the block back
org_edit_src_show_helpg?: help, the same key

Text objects ih, ah, ir and ar are the same (mappings.text_objects); the ones from the root heading (Oh, OH, Or, OR) have no equivalent.

Other differences

  • org.nvim follows Emacs Org 9.8: options carry Emacs's defaults and names (without the org_ prefix), and most Emacs options exist (org-config). :Org customize lists them all.
  • Export is built in: HTML, LaTeX/PDF, Beamer, Markdown, ASCII, ODT, iCalendar and Texinfo run without Emacs; pandoc adds DOCX, EPUB, ... (org-export).
  • Reminders (notifications.enabled) run inside Neovim; there is no cron mode. Plain timestamps with a time get reminders too.
  • Log notes open a small *Org Note* window: <C-c><C-c> stores the note, <C-c><C-k> cancels it.
  • <CR> on a link opens it; in Insert mode, <CR> in a table moves to the next row.
  • Menus (the agenda dispatcher, capture, export) are org.nvim's own key menus, which Esc closes (org-key-menus).