data.nvim · Editing · vimdoc
:help data
Format and filter JSON/YAML/XML in Neovim
doc/data.txt — rendered from the plugin's own vimdoc
*data.txt* Format and filter JSON/YAML/XML in Neovim *data.nvim*
CONTENTS
1. Introduction ............................. |data-introduction| 2. Setup .................................... |data-setup| 3. Commands .................................. |data-commands| 4. Configuration ............................ |data-config| 5. Scope ..................................... |data-scope| 6. Health .................................... |data-health| 7. lib.nvim integration ...................... |data-lib| 8. Integrations .............................. |data-integrations|
1. INTRODUCTION
data.nvim reformats structured data (JSON, YAML, XML) in place, either the whole buffer or a Visual selection: pretty-print, collapse to one line (JSON/XML), or flatten nested keys onto onepath: valueline each. The input can also come from a register instead of the buffer, and the result can go to a scratch split or another register -- see |data-scope|. Requires Neovim 0.9+ andlib.nvim(hard dependency).
2. SETUP
*data.setup()*
require("data").setup({
json = { indent = 2, sep = "." },
})
Calling setup() merges your options over the defaults and defines the:JSON/:YAML/:XML/:Datauser commands. setup() is safe to call once.
3. COMMANDS
*:JSON* *:YAML* *:XML* *:Data* :[range]JSON [action] [args] [flags] :[range]YAML [action] [args] [flags] :[range]XML [action] [args] [flags] :[range]Data [action] [args] [flags] Range-aware: no range acts on the whole buffer, a Visual selection or an explicit:N,Mrange acts only on those lines. :JSON / :YAML / :XML same as pretty pretty [indent] pretty-print (default 2-space indent) compact collapse onto one line (JSON/XML only) lines [--sep=X] one "path: value" per leaf, dotted keys keys [--sep=X] only the (dotted) key paths, no values sort [indent] pretty-print with sorted object keys ndjson [indent] :JSON only: pretty-print each line as its own object to yaml :JSON only: convert the scope to YAML to json :YAML only: convert the scope to JSON filter [--sep=X] interactively filter path/value entries (needs pickers.nvim) *data-preview* *:JSON-filter---preview*filtertakes two more flags of its own: --preview show the result as a before/after diff and ask before replacing the scope --no-preview skip that, overridingpreview.filter = trueBacked by diff.nvim (optional).--previewis afilterflag only -- on any other action it is an unknown-flag error rather than a flag that does nothing:filteris the one action that loses information, and the one already built to survive an arbitrarily long gap between resolving a scope and writing it. Asked for with diff.nvim missing, NOTHING is written -- a preview that silently skips the preview would defeat the point of the flag. It applies to an in-place result only;--split/--out-regleave the scope where it is, so there is nothing to preview against, and combining them warns. *data-flags* *:JSON---reg* *:JSON---split* Every action of every verb additionally accepts four source/target flags: --reg[=<name>] read the input from a register instead of the buffer (bare form:register.default) --inplace write the result over the buffer scope --split write the result to a scratch split --out-reg[=<name>] write the result into a register The defaults follow the source: a buffer or Visual scope replaces itself, a register source opens a split. So:JSON pretty --reg=+formats the system clipboard into a new split and never touches the current buffer. The three target flags are mutually exclusive.--reg --inplacealso requires an explicit range or Visual selection -- without one, "in place" would mean the whole buffer, and replacing a whole file with register contents should not be possible by accident.--out-regrefuses Vim's read-only registers (:.%#=) by name, and reports how many lines it wrote, since a register write is otherwise invisible.--reg==is refused too, separately: reading the expression register would EVALUATE its contents, and--regshould not be the one read that runs code. Register input is CRLF-normalized -- clipboard text is usually CRLF-terminated and a stray carriage return is an artifact, not content. A CR in the middle of a line stays. A read-only buffer is still a valid source for--split/--out-reg; only the in-place write needs'modifiable'. Bare:JSON/:YAML/:XML/:Data(no action) stays whole-buffer, in-place pretty-printing -- flags need an explicit action, e.g.:JSON pretty --split. :Data offers pretty/lines/keys/sort/filter with the format auto-detected (fenced block under the cursor, the register's own first non-blank line under--reg, else the buffer's'filetype') instead of named by the command -- no compact/ndjson/to, since those already require knowing the format. A clear error, not a guess, when no signal maps to json/yaml/xml.lines/keysrender exactly one line per leaf, so control characters in a value are escaped: a newline as \n, a tab as \t, anything else in C0 as \xNN. Backslashes are deliberately NOT escaped, so a Windows path stays readable --linesis a human-readable summary, not JSON to parse back.sortandprettyare currently identical output for all three formats: neither JSON's nor YAML's decoder preserves the source's original key order and both encoders sort keys by default; XML's encoder always sorts attributes and never reorders elements. See |data-lib| and eachdata.format.*module's own doc comment. Malformed input in the resolved scope leaves the buffer untouched and reports an error notification instead of partially overwriting anything. Full cheatsheet (including<Tab>completion behavior): docs/BINDINGS.md.
4. CONFIGURATION
require("data").setup({
json = {
indent = 2, -- default indent for :JSON pretty/sort
sep = ".", -- default path separator for :JSON lines/keys
},
yaml = {
indent = 2, -- default indent for :YAML pretty/sort
sep = ".", -- default path separator for :YAML lines/keys
},
xml = {
indent = 2, -- default indent for :XML pretty/sort
sep = ".", -- default path separator for :XML lines/keys
},
fenced_scope = {
enable = true, -- see |data-integrations|
},
register = {
default = "+", -- register a bare --reg / --out-reg uses
},
target = {
split = "right", -- where --split opens: above|below|left|right|auto
},
preview = {
filter = false, -- diff before an in-place `filter` replaces the scope
view = "inline", -- inline|float|vsplit|split|tab
},
keymaps = {
preset = false, -- reserved; no default keymap preset exists yet
},
})
indent/separe also overridable per invocation (:JSON pretty 4,:YAML lines --sep=/) — the config values are only the fallback.register.defaultis what a bare--reg/--out-regresolves to;+is the system clipboard. On a Neovim with no clipboard provider a BARE--regfalls back to"and says so, while an explicitly typed--reg=+is left alone and fails with the ordinary "register is empty" message instead.target.splitpicks the direction--splitopens in; "auto" (or anything that is not one of the four directions) honors your own'splitbelow'/'splitright'.preview.filtermakes |data-preview| the default for every in-placefilter;preview.viewtakes any of diff.nvim's five views. The side-by-side three ("vsplit"/"split"/"tab") need diff.nvim ff2f424 or newer -- before it,:Diffignoredsource=for those views and put the wrong buffer on the left. Nothing here can detect an older diff.nvim, so "inline" is the default. See docs/integrations.md.
5. SCOPE
- A range (:5,12JSON compact) or a Visual selection ('<,'>JSON lines) always wins -> only those lines are decoded and replaced. - Otherwise, with the cursor inside a matching fenced code block and color_my_ascii.nvim installed -> that block's interior (|data-integrations|). - Otherwise -> the whole current buffer. ---reg[=<name>]replaces all of the above as the INPUT: the buffer is not read at all, and a range (if any) then only says where an--inplaceresult would go. See |data-flags|. Where the result goes is a separate decision from where the input came from:--inplace,--split,--out-reg[=<name>], defaulting to whichever matches the source. See |data-flags|.
6. HEALTH
:checkhealth datareports Neovim version, whetherlib.nvimis installed (required), and whether it shipslib.lua.tables.path_flatten(required bylines/keys),lib.lua.yaml.encode(required by:YAML),lib.lua.xml(required by:XML), andlib.nvim.window.open_scratch_split(required by--split). It also reports, informationally only, whether the three optional plugins are present: color_my_ascii (fenced-block scope), pickers.nvim (filter) and diff.nvim (filter --preview).
7. LIB.NVIM INTEGRATION
data.nvim is a thin editor layer: JSON decode/encode (lib.nvim.json,lib.lua.json.encode), YAML decode/encode (lib.lua.yaml), XML decode/encode (lib.lua.xml), the shared null sentinel (lib.lua.null), and the recursive path-flatteninglines/keysneed (lib.lua.tables.path_flatten) all live in https://github.com/StefanBartl/lib.nvim, not in this plugin. The:JSON/:YAML/:XML/:Datacommands themselves are built onlib.nvim.bindings.usercmd.composer.
8. INTEGRATIONS
color_my_ascii.nvim (optional): when installed and the cursor sits inside a fenced code block tagged ``json/`yaml/``xml with no explicit range given, that block's interior becomes the scope instead of the whole buffer. A total no-op without it. Disable withfenced_scope.enable = false. See docs/integrations.md. pickers.nvim (optional, required forfilterspecifically): backs:JSON/:YAML/:XML filterviapickers.refine. Every other command works without it;filterfails with a clear notification instead. See docs/integrations.md. diff.nvim (optional, required forfilter --previewspecifically): renders the before/after diff |data-preview| shows before an in-placefilterreplaces the scope, via diff.nvim's publicrequire("diff").run()API. Plainfilterand every other command work without it;--previewwith diff.nvim missing writes nothing and says so. See docs/integrations.md.