Capture
<prefix>c opens the template menu. :Org capture KEY selects a template directly. A count works like Emacs's prefix argument: 4<prefix>c (C-u) jumps to a template's target, 16<prefix>c (C-u C-u) to the last stored entry and 1<prefix>c (C-1) asks for the date of a date tree entry. :Org capture_here (C-0 C-c c) inserts the template at the cursor: an entry becomes a sibling of the headline there, other types go on the cursor line (before it at column 0, else after it).
The target is resolved when the capture starts, like Emacs: missing file+headline headlines and date tree nodes are created then, and the location is remembered even if the file changes (or the clock moves to another task) while you type. When the target is gone at the end (its headline was deleted), nothing is lost: the capture buffer stays open. With unnarrowed, the text is inserted into the target right away and the capture window shows the whole target file (see org-capture-unnarrowed).
Capture dates follow extend_today_until like Emacs: before that hour, %t %T %u %U and %<...> use 23:59 of the previous day and the date tree files under the previous day. A capture date without a time (the agenda day) is taken at extend_today_until o'clock; a time_prompt date keeps the current time when it is today and starts at that hour otherwise.
capture = {
templates = {
t = { description = "Task", template = "* TODO %?\n %u", target = "~/org/refile.org" },
w = "Work", -- group label for keys starting with w
wt = { description = "Work task", template = "* TODO %?", target = "~/org/work.org", headline = "Inbox" },
j = { description = "Journal", template = "* %<%H:%M> %?", target = "~/org/journal.org", datetree = true },
},
window = "split",
}
Whentemplatesis empty (the default), Emacs's fallback is used:t = { description = "Task", target = "", headline = "Tasks", template = "* TODO %?\n %u\n %a" }, which files under "Tasks" indefault_notes_file.
Template fields: description menu label template string, list of lines,{ file = "path" }(read from that file, relative toorg_directory) or a function returning a string. When empty: "* %?\n %a" for entries, "- %?" for items, "- [ ] %?" for checkitems, "| %? |" for table lines type "entry" (default), "item", "checkitem", "table-line", "plain" target file (relative toorg_directory, "" =default_notes_file), "clock", or a function returning either; defaults todefault_notes_fileheadline file+headline: under the first headline with this title (TODO keyword, priority and tags ignored), created at the end of the file when missing olp file+olp: outline path, e.g. { "Projects", "Neovim" } or "Projects/Neovim"; every node must exist datetree file+olp+datetree: true or { tree_type = ... }, underolp/headlinewhen given. The date is the capture date (agenda day,time_prompt, C-1) or today. Existing nodes are recognized by their date ("2026-09 Sept" is the September node) tree_type "day" (default), "week", "month", a list of "year", "quarter", "month", "week", "day", or a function(date) returning { { title, compare } ... } (:tree-type) regexp file+regexp: Vim regexp; the text goes where the first match ends (starts, withprepend); an entry becomes a child when the match is on a headline func / function file+function: function(bufnr) returning the line (and column) of the location, or moving the cursor there; a headline line means "under this headline" location the (function f) target: function() returning the buffer, line and column, or nothing for the cursor position in the current buffer id insert under the entry with this ID (file+id) target = "clock" insert under the currently clocked task (clock) prepend insert as the first child instead of the last empty_lines blank lines around the text, replacing the blank lines already there (also empty_lines_before / empty_lines_after; items in an existing list get at most one) table_line_pos where a table line goes, e.g. "II-3" (3 lines before the 2nd hline) or "I+1" (right after the 1st). A table is created when there is none properties table of properties added to the entry immediate_finish finish without opening the capture window jump_to_captured jump to the entry after finishing kill_buffer unload the target file afterwards when the capture loaded it refile_targetsrefile.targetsused when refiling from the capture buffer clock_in clock the entry while capturing (stops the running clock); the time is logged when the capture ends clock_keep with clock_in, keep the clock running afterwards clock_resume with clock_in, clock the interrupted task in again when the capture ends or is aborted time_prompt ask for the date used by %t/%T/%u/%U and the datetree no_save don't save the target file after capturing allow_empty finishing with no text still saves the target (by default an empty capture is refused) hook function(capture_bufnr) run when the capture window opens (not with immediate_finish) prepare_finalize function(capture_bufnr), before the text is read before_finalize function(bufnr, lnum) in the target, before saving after_finalize function(bufnr, lnum) when the capture is done on_abort function(target_bufnr) when the capture is aborted (every hook may also be a list of functions) unnarrowed edit the text in the target file itself, showing the whole file (org-capture-unnarrowed)
An entry template without stars gets "* ", item templates get "- " (and continuation lines are indented under the bullet); in an existing list the item takes the list's indentation and bullet style. Items and table lines go into the first list / table of the target entry (of the file for a plain file target); "plain" text goes at the end of the entry's text, before its children (after its planning, properties and drawers with prepend), or at the end (top) of a file.
capture.templates_contexts (org-capture-templates-contexts) makes templates available only in some buffers. Each rule is { key, rules }, or { key, other_key, rules } to use other_key's template for key there (the other key is then hidden). A template is shown when any of its rules holds; rules are tables with one of in_file, not_in_file, in_mode (filetype), not_in_mode, in_buffer, not_in_buffer (Vim regexps) or functions:
capture = { templates_contexts = {
{ "m", { { in_mode = "^mail$" } } },
{ "t", "p", { { in_file = "project" } } },
} }
Template expansions: %? cursor position %t %T active date / date and time %u %U inactive date / date and time %^t %^T %^u %^U the same, asking with the calendar %<fmt> strftime format, e.g. %<%Y-%m-%d> %a annotation: a link to the location capture was started from %A the same, asking for a description %l the link without a description %L the bare link target %i initial content (the visual selection); the text before %i on its line is repeated on every line %x clipboard (the*register, else+) %c last yank %f %F origin file name / full path %n your full name (like Emacs'suser-full-name) %k %K the clocked task's title / a link to it %^{Prompt} ask;%^{Prompt|default|opt1|opt2}offers opt1 and opt2 and uses the default for an empty answer %^C %^L ask for a clipboard value (%^L makes it a link) %\1 ... the answer to the Nth %^{...} prompt %\*1 ... the answer to the Nth prompt of any kind (%^t, %^g, ...) %^g %^G tags prompt, completing the target file's / all agenda files' tags; tags on a headline are aligned %^{PROP}p property prompt (offers the PROP_ALL values of the target) %:keyword link information: %:link, %:description, %:annotation, %:initial, %:type %[file] the contents of a file %(sexp) an Emacs Lisp form, e.g. %(format-time-string "%Y"), %(upcase "%i"); or a Lua expression, %(os.getenv("HOST")) Like Emacs,%%is not an escape: write\%for a literal "%" before an expansion character (\%t). Leading blank lines and trailing whitespace of the expanded text are removed.
%(sexp) is evaluated like Emacs's org-capture-expand-embedded-elisp, after the other escapes (inside it, %i, %:subject, ... are quoted for a Lisp string): a string result is inserted, nil inserts nothing and an error inserts %![Error: (void-function f)]. It runs on the Lisp interpreter of table formulas (org-table-calc, which also knows format-time-string, user-full-name, getenv, file-name-*, string-replace and replace-regexp-in-string) and, for other functions, in a separate emacs --batch with Org loaded (babel.emacs_lisp; nothing of your Emacs session exists there, and it cannot prompt: no org-read-date). A form whose first word is not a Lisp function the interpreter knows but that compiles as Lua is a Lua expression (the older org.nvim syntax); Lisp is tried when the Lua fails.
Capture window: <C-c><C-c> or :w finalizes (with a count, C-u C-c C-c, it then jumps to the entry), <C-c><C-k> aborts (unchanged text created for the target is dropped, preserving unrelated edits and generated headings with user-added content) and <C-c><C-w> finalizes and refiles the entry (entry templates only; also <prefix>w, <prefix>k, <prefix>r). The window splits the screen like Emacs (capture.window: "split", "float", "vsplit", "tab" or "current"). If saving the target fails, the capture stays open and can be retried without inserting a duplicate entry. Clock/bookmark finalization waits until the captured text is stored.
An unnarrowed capture inserts the expanded template into the target buffer when it starts, like Emacs, and opens the target buffer itself in the capture window, with the cursor at %?. The capture keys work in that window (in other windows showing the file, the file's own mappings keep working); :w just writes the file. Finalizing saves the file; aborting restores exactly the lines the capture inserted or changed (with whatever was typed into them), keeping edits elsewhere in the file, and drops headlines created for it. Closing the capture window ends the capture and leaves the text in the (unsaved) buffer. Only one unnarrowed capture can edit a file at a time.
:Org capture_goto_target choose a template and jump to its target
(C-u C-c c in Emacs)
:Org capture_goto_last jump to the last captured (or refiled) entry
(C-u C-u C-c c)
:Org capture_string ask for a string and capture it as the initial
text %i (org-capture-string)
:Org bookmark_jump jump to a bookmark: capture and refile save
the last location as the bookmarks named in
bookmark_names (org-bookmark-names-plist:
"org-capture-last-stored",
"org-refile-last-stored"), in
stdpath("data")/org/bookmarks.json, so the
jumps above also work in a later session
From the agenda, K captures with the date at point as the default date
(with a count of 1, C-1, at the time of the item at point or now). With
capture.use_agenda_date, the global capture key does the same there.
Besides the templates'prepare_finalize,before_finalizeandafter_finalizefunctions, every capture fires User autocmds, after the template's function, like Emacs's global hooks: OrgCapturePrepareFinalize capture buffer still open; data{ buf }({ immediate = true }forimmediate_finishtemplates, which have no capture buffer) (org-capture-prepare-finalize-hook) OrgCaptureBeforeFinalize entry stored, target not yet saved; data{ bufnr, line }(org-capture-before-finalize-hook) OrgCaptureAfterFinalize capture done; data{ bufnr, line }(org-capture-after-finalize-hook) Aborting (<C-c><C-k>) fires the prepare and after events withaborted = true, but not the before event, like org-capture-kill.
vim.api.nvim_create_autocmd("User", {
pattern = "OrgCaptureAfterFinalize",
callback = function(ev)
if not ev.data.aborted then vim.notify("captured") end
end,
})
org-protocolorg-protocol://URLs from a browser or another program capture, store links and open files in a running Neovim, like Emacsorg-protocol.el: org-protocol://capture?template=KEY&url=URL&title=TITLE&body=TEXT capture with template KEY (protocol.default_template_key, else choose);%:link,%:description,%a,%i(body) and%:<param>come from the URL org-protocol://store-link?url=URL&title=TITLE store the link for org-insert-link and yank the URL org-protocol://open-source?url=URL open the local file behind a published URL (protocol.projects, like org-protocol-project-alist: base_url, working_directory, online_suffix, working_suffix, rewrites) Old-style URLs (capture://KEY/URL/TITLE/BODY) work too, their data split onprotocol.data_separator(a Vim regex,/+or?by default; org-protocol-data-separator), andprotocol.handlersadds sub-protocols. Call it from Lua withrequire("org.protocol").handle(url)or:Org protocol <url>. :Org protocol_create ask for a base URL, working directory and suffixes and add aprotocol.projectsentry (org-protocol-create). It lasts for the session; the Lua to add to your setup() is shown (Emacs saves it to the custom file). :Org protocol_create_for_org the same with the defaults of the publishing project of the current file (org-protocol-create-for-org)
Neovim must listen on a socket (nvim --listen ~/.cache/nvim/org.sock, or v:servername) and the OS must send org-protocol: URLs to a handler that forwards them, e.g. on Linux a desktop file with MimeType=x-scheme-handler/org-protocol; and:
Exec=nvim --server ~/.cache/nvim/org.sock --remote-expr "v:lua.require'org.protocol'.handle('%u')"
then xdg-mime default org-protocol.desktop x-scheme-handler/org-protocol. On macOS register the scheme with a small app bundle (an AppleScript on open location handler running the same command). A bookmarklet:
javascript:location.href='org-protocol://capture?'+new URLSearchParams({
template:'p', url:location.href, title:document.title,
body:window.getSelection()});void(0)
Emacs's emacsclient integration (server-visit-files advice, :kill-client) has no counterpart: the handler command above plays that role.
Plain links through tags files Like Emacs org-ctags,<<targets>>in Org files can be tags: withctags.enabled = true(Emacs: org-ctags-enable), a plain link[[foo]](also[[#id]],[[*heading]],[[(ref)]]) first goes throughctags.open_link_functions, tried in order until one handles it: "find_tag" jump to the tag with :tag (CTRL-T goes back) "ask_rebuild_tags_file_then_find_tag" ask, rebuild the tags file, then look again (also without asking: "rebuild_tags_file_then_find_tag") "ask_append_topic" ask, then append a new topic* <<Foo>>to the buffer (ctags.new_topic_template,%t= the capitalized name; "append_topic" does not ask) "ask_visit_buffer_or_file" / "visit_buffer_or_file" visit NAME.org (asking to create it) "fail_silently" stop here (no search in the buffer) or functions of the link text. When none handles it, the link is searched in the buffer as usual. Tags come from Neovim's 'tags' option (by default thetagsfile next to the file or above it); Emacs usesTAGSfiles. :Org ctags_create_tags runctags.path_to_ctags(Exuberant or Universal ctags) on the file's directory, writing itstagsfile with the Org targets (ctags.tag_regexp) :Org ctags_find_tag_interactive choose a tag (completed) and jump to it; an unknown one goes through the functions above (org-ctags-find-tag-interactive) :Org ctags_find_tag, ctags_get_filename_for_tag, ctags_all_tags, ctags_open_file, ctags_visit_buffer_or_file, ctags_append_topic the other org-ctags commands, asking for their argument
RSS and Atom feeds Items of RSS 2.0 and Atom feeds are added as children of an inbox headline (org-feed.el). List the feeds in feed.feeds (org-feed-alist):
feed = {
feeds = {
{ name = "Slashdot", url = "https://rss.slashdot.org/Slashdot/slashdot",
file = "~/org/feeds.org", headline = "Slashdot Entries" },
-- the positional Emacs form works too
{ "Local", "file:///home/me/feed.xml", "~/org/feeds.org", "Local" },
},
}
file defaults to the current buffer's file; the headline (any level, tags allowed) is created at the end of the file when missing. Each update adds the items not seen before, one level below the inbox and after its last child, and records every item's GUID, a "handled" flag and a SHA-1 of the item in the :FEEDSTATUS: drawer of the inbox, as the Lisp list Emacs writes, so Emacs and Neovim can update the same file. Items removed from the feed are dropped from the drawer.
Per-feed options (Emacs keyword in parentheses): template item template, defaultfeed.default_template(:template) formatter function(entry) returning the Org text of the item, instead of the template (:formatter) filter function(entry) returning the entry (possibly modified) or nil to skip it; skipped items stay unhandled (:filter) new_handler function(entries, ctx) called with the new items instead of adding them; the cursor is on the inbox headline andctxis { bufnr, lnum, feed } (:new-handler) changed_handler function(entries, ctx) called with handled items whose text changed (:changed-handler) parse_feed "rss", "atom" or function(text) returning entries withguidanditem_full_text(:parse-feed) parse_entry "rss", "atom" or function(entry) adding the fields (:parse-entry) drawer status drawer, defaultfeed.drawer(:drawer) retrieve_method likefeed.retrieve_method, for this feed Withoutparse_feed, a feed with a<feed>root and no<item>is read as Atom, anything else as RSS. An entry is a table: RSS items have a field per<tag>value</tag>(title,link,description,pubDate, ..., entities decoded and CDATA unwrapped) andguid_permalink; Atom entries havetitle,link(the first<link href>),description(from<content>, else<summary>; xhtml content as markup),id,updated,publishedandsummary. Both haveguid,item_full_textandhandled.
Template escapes (org-feed-default-template, "\n* %h\n %U\n %description\n %a\n"): %h the title, else the first line of the description %t %T date, date and time, frompubDate(else now), active %u %U the same, inactive %a[[link]]from the guid when it is a permalink, elselink%name any field of the entry:%title,%description,%pubDate...; alone on its line, its later lines get the same indentation %(expr) a Lua expression (the entry isentry), after the escapes above;\%keeps a literal%
Options: feed.default_template, feed.drawer ("FEEDSTATUS"), feed.save_after_adding (true) and feed.retrieve_method ("curl", "wget" or a function(url) returning the text; file:// URLs and local paths are read directly). User autocmds OrgFeedBeforeAdding and OrgFeedAfterAdding (org-feed-before/after-adding-hook) fire around the changes with data = { feed, file, bufnr, count? }.
<C-c><C-x>g :Org feed_update_all update every feed (org-feed-update-all) :Org feed_update [name] update one feed (org-feed-update) <C-c><C-x>G :Org feed_goto_inbox [name] go to a feed's inbox :Org feed_show_raw [name] show the feed's XML Without a name these prompt (goto_inbox and show_raw take the only feed when there is one). Retrieval is synchronous, like Emacs.