A comfortable CSV/TSV editing plugin for Neovim.
- Tabular Display: Displays CSV/TSV files in a virtual text table.
- Dynamic Updates: Automatically refreshes the table as you edit.
- Asynchronous Parsing: Smoothly handles large CSV files without blocking.
- Text Objects & Motions: Conveniently select fields or move across fields/rows.
- Comment Ignoring: Skips specified comment lines from the table display.
- Flexible Settings: Customizable delimiter and comment prefix.
- Two Display Modes:
highlight
: Highlights delimiters.border
: Uses a vertical border (β
) as delimiters.
display_mode = "highlight" | display_mode = "border" |
---|---|
![]() |
![]() |
Neovim v0.10 or newer is required.
Install the plugin using your favorite package manager.
{
"hat0uma/csvview.nvim",
---@module "csvview"
---@type CsvView.Options
opts = {
parser = { comments = { "#", "//" } },
keymaps = {
-- Text objects for selecting fields
textobject_field_inner = { "if", mode = { "o", "x" } },
textobject_field_outer = { "af", mode = { "o", "x" } },
-- Excel-like navigation:
-- Use <Tab> and <S-Tab> to move horizontally between fields.
-- Use <Enter> and <S-Enter> to move vertically between rows and place the cursor at the end of the field.
-- Note: In terminals, you may need to enable CSI-u mode to use <S-Tab> and <S-Enter>.
jump_next_field_end = { "<Tab>", mode = { "n", "v" } },
jump_prev_field_end = { "<S-Tab>", mode = { "n", "v" } },
jump_next_row = { "<Enter>", mode = { "n", "v" } },
jump_prev_row = { "<S-Enter>", mode = { "n", "v" } },
},
},
cmd = { "CsvViewEnable", "CsvViewDisable", "CsvViewToggle" },
}
Plug 'hat0uma/csvview.nvim'
lua require('csvview').setup()
csvview.nvim
are highly customizable, Please refer to the following default settings.
Default Settings
{
parser = {
--- The number of lines that the asynchronous parser processes per cycle.
--- This setting is used to prevent monopolization of the main thread when displaying large files.
--- If the UI freezes, try reducing this value.
--- @type integer
async_chunksize = 50,
--- The delimiter character
--- You can specify a string, a table of delimiter characters for each file type, or a function that returns a delimiter character.
--- e.g:
--- delimiter = ","
--- delimiter = function(bufnr) return "," end
--- delimiter = {
--- default = ",",
--- ft = {
--- tsv = "\t",
--- },
--- }
--- @type CsvView.Options.Parser.Delimiter
delimiter = {
default = ",",
ft = {
tsv = "\t",
},
},
--- The quote character
--- If a field is enclosed in this character, it is treated as a single field and the delimiter in it will be ignored.
--- e.g:
--- quote_char= "'"
--- You can also specify it on the command line.
--- e.g:
--- :CsvViewEnable quote_char='
--- @type string
quote_char = '"',
--- The comment prefix characters
--- If the line starts with one of these characters, it is treated as a comment.
--- Comment lines are not displayed in tabular format.
--- You can also specify it on the command line.
--- e.g:
--- :CsvViewEnable comment=#
--- @type string[]
comments = {
-- "#",
-- "--",
-- "//",
},
},
view = {
--- minimum width of a column
--- @type integer
min_column_width = 5,
--- spacing between columns
--- @type integer
spacing = 2,
--- The display method of the delimiter
--- "highlight" highlights the delimiter
--- "border" displays the delimiter with `β`
---@type CsvView.Options.View.DisplayMode
display_mode = "highlight",
},
--- Keymaps for csvview.
--- These mappings are only active when csvview is enabled.
--- You can assign key mappings to each action defined in `opts.actions`.
--- For example:
--- ```lua
--- keymaps = {
--- -- Text objects for selecting fields
--- textobject_field_inner = { "if", mode = { "o", "x" } },
--- textobject_field_outer = { "af", mode = { "o", "x" } },
---
--- -- Excel-like navigation:
--- -- Use <Tab> and <S-Tab> to move horizontally between fields.
--- -- Use <Enter> and <S-Enter> to move vertically between rows.
--- -- Note: In terminals, you may need to enable CSI-u mode to use <S-Tab> and <S-Enter>.
--- jump_next_field_end = { "<Tab>", mode = { "n", "v" } },
--- jump_prev_field_end = { "<S-Tab>", mode = { "n", "v" } },
--- jump_next_row = { "<Enter>", mode = { "n", "v" } },
--- jump_prev_row = { "<S-Enter>", mode = { "n", "v" } },
---
--- -- Custom key mapping example:
--- { "<leader>h", function() print("hello") end, mode = "n" },
--- }
--- ```
--- @type CsvView.Options.Keymaps
keymaps = {},
--- Actions for keymaps.
---@type CsvView.Options.Actions
actions = {
textobject_field_inner = {
function()
require("csvview.textobject").field(0, { include_delimiter = false })
end,
desc = "[csvview] Select the current field",
noremap = true,
silent = true,
},
textobject_field_outer = {
function()
require("csvview.textobject").field(0, { include_delimiter = true })
end,
desc = "[csvview] Select the current field with delimiter",
noremap = true,
silent = true,
},
jump_next_field_start = {
function()
require("csvview.jump").next_field_start()
end,
desc = "[csvview] Jump to the next start of the field",
noremap = true,
silent = true,
},
jump_prev_field_start = {
function()
require("csvview.jump").prev_field_start()
end,
desc = "[csvview] Jump to the previous start of the field",
noremap = true,
silent = true,
},
jump_next_field_end = {
function()
require("csvview.jump").next_field_end()
end,
desc = "[csvview] Jump to the next end of the field",
noremap = true,
silent = true,
},
jump_prev_field_end = {
function()
require("csvview.jump").prev_field_end()
end,
desc = "[csvview] Jump to the previous end of the field",
noremap = true,
silent = true,
},
jump_next_row = {
function()
require("csvview.jump").field(0, { pos = { 1, 0 }, anchor = "end" })
end,
desc = "[csvview] Jump to the next row",
noremap = true,
silent = true,
},
jump_prev_row = {
function()
require("csvview.jump").field(0, { pos = { -1, 0 }, anchor = "end" })
end,
desc = "[csvview] Jump to the previous row",
noremap = true,
silent = true,
},
},
}
After opening a CSV file, use the following commands to interact with the plugin:
Command | Description |
---|---|
:CsvViewEnable [options] |
Enable CSV view with the specified options. |
:CsvViewDisable |
Disable CSV view. |
:CsvViewToggle [options] |
Toggle CSV view with the specified options. |
To toggle CSV view, use the following command. By default, the delimiter is ,
for CSV files and \t
for TSV files.
:CsvViewToggle
To toggle CSV view with a custom field delimiter, a custom string delimiter and comment, use the following command.
:CsvViewToggle delimiter=, quote_char=' comment=#
Below are the core Lua functions that you can call programmatically. If you want to map these functions to key bindings, you can use the opts.keymaps
option.
require('csvview').enable()
: Enable CSV view.require('csvview').disable()
: Disable CSV view.require('csvview').toggle()
: Toggle CSV view.require('csvview').is_enabled()
: Check if CSV view is enabled.
You can move across CSV fields and rows with the following API.
-- Basic usage:
require("csvview.jump").field(0, {
pos = { 1, 2 }, -- Move to row=1, column=2
mode = "absolute", -- "absolute": interpret `pos` as absolute coords.
-- "relative": interpret `pos` as offset from the current field.
anchor = "start", -- "start": place the cursor at field start, "end" : field end.
col_wrap = true, -- Wrap to the next/previous row when exceeding column bounds.
})
Shortcuts for common movements:
-- Jump to the start of the next field like `w` motion.
require("csvview.jump").next_field_start(bufnr?)
-- Jump to the start of the previous field like `b` motion.
require("csvview.jump").prev_field_start(bufnr?)
-- Jump to the end of the next field like `e` motion.
require("csvview.jump").next_field_end(bufnr?)
-- Jump to the end of the previous field like `ge` motion.
require("csvview.jump").prev_field_end(bufnr?)
For selecting a CSV field via text objects:
require("csvview.textobject").field(0, {
include_delimiter = false -- Include the delimiter in the selection
})
Retrieve detailed information about the cursor position:
local info = require("csvview.util").get_cursor(bufnr)
-- info returns:
-- {
-- kind = "field" | "comment" | "empty_line",
-- pos = { 1, 2 }, -- 1-based [row, col] csv coordinates
-- anchor = "start" | "end" | "inside" | "delimiter", -- The position of the cursor in the field
-- text = "the field content"
-- }
This plugin provides the following events:
Event | Description |
---|---|
CsvViewAttach | Triggered after the initial metrics calculation is completed and the CsvView is attached. |
CsvViewDetach | Triggered after the CsvView is detached. |
You can hook into these events as follows:
local group = vim.api.nvim_create_augroup("CsvViewEvents", {})
vim.api.nvim_create_autocmd("User", {
pattern = "CsvViewAttach",
group = group,
callback = function()
print("CsvView is attached")
end,
})
Group | Default | Description |
---|---|---|
CsvViewDelimiter | link to Comment |
used for , |
CsvViewComment | link to Comment |
used for comment |
- Customizable delimiter character.
- Ignore comment lines.
- Motions and text objects.
- Enhanced editing features (e.g., sorting, filtering).
- Row, column, and cell change events for integration with other plugins.
- Pre- and post-processing of files, such as reading/writing Excel files.
- Displaying tables embedded in Markdown as formatted tables.
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
Distributed under the MIT License.