Open-source project
hat0uma/csvview.nvim avatar
hat0uma/csvview.nvim

csvview.nvim and the case for editing CSVs as a table in Neovim

A Neovim plugin for CSV file editing.

699 stars17 forksLuaMIT

At a glance

What is it?
csvview.nvim renders a delimited file as a table using virtual text, parses it asynchronously so large files do not freeze the editor, and layers Excel-like navigation and field text objects on top. Its limits are narrow by design, fixed-length delimiters only and no regular expression support.
Who is it for?
csvview.nvim suits a Neovim user who edits delimited files often enough that the flat text view has become friction, since the table rendering, sticky headers and field motions address that directly. It does not suit someone whose data has quoted fields spanning lines with unpredictable extent, and it does not suit a workflow that relies on regular expression delimiters, because the plugin supports only fixed-length strings.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 19 days ago.
What is it written in?
Mainly Lua, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Virtual text is how the table appears without changing the buffer

csvview.nvim is a Neovim plugin for CSV and TSV editing, and the central technical choice is the tabular display using virtual text.

Virtual text is a Neovim feature that draws characters on a line without them being part of the buffer's text. That matters here for a specific reason: the file on disk is still a CSV, and editing it still happens in the same buffer, but the screen shows a grid. The columns are laid out to line up, the delimiters are marked, and the header is styled, all without the plugin rewriting a single line of the actual file.

The alternative approach, rewriting the buffer into a table and rewriting it back on save, is how many spreadsheet-like tools work and it has the obvious failure modes. A file that is also a script, or that another tool reads, comes out changed. A diff against version control becomes unreadable. The virtual text approach means the file on disk is byte-identical to what you started with unless you actually edited a cell.

The features list adds dynamic updates using asynchronous parsing, comment line handling, sticky headers, and auto-detection of delimiters and headers, plus text objects and motions. The two display modes are the last of these and the one that changes the character of the plugin in use, with highlight mode highlighting the delimiters and border mode using a vertical border character as the delimiter.

The requirement is Neovim v0.10 or newer, the licence is MIT, and the primary language is Lua.

Asynchronous parsing with a chunk size you can turn down

The asynchronous parser is the feature that makes the plugin usable on a large file, and the config comment explains exactly what the knob does.

The setting is async_chunksize, and the number of lines the asynchronous parser processes per cycle. The comment says it is used to prevent monopolization of the main thread when displaying large files, and that if the UI freezes you should try reducing this value. The default is 50.

That default is the interesting number. Fifty lines per cycle means the table is built incrementally, and the file becomes readable as the parse proceeds rather than all at once after a long pause. On a CSV with hundreds of thousands of rows, the initial view appears quickly with the first chunk and fills in behind you.

The freeze scenario the comment anticipates is real and worth understanding. If a single cycle of work is heavy enough, the editor cannot respond to input during it, and a user who has just opened a huge file and immediately pressed a key may see the editor wait. Lowering the chunk size makes each cycle cheaper and the whole thing more responsive, at the cost of taking longer to reach the end of the file.

The parser also has a lookahead limit for multi-line fields, max_lookahead with a default of 50, and the comment there gives the same kind of warning, noting that setting it too high may cause performance issues when editing files with unmatched quotes.

Delimiter detection is scored, not guessed

The delimiter configuration is the most instructive part of the default settings, because it shows the shape of the plugin's approach.

A delimiter can be given in three ways. As a single string for a fixed delimiter, as a function that dynamically returns the delimiter given a buffer number, or as a table for advanced configuration. The table form has two keys, ft which maps filetypes to specific delimiters and which has the highest priority, and fallbacks which is an ordered list of delimiters to try for automatic detection when no ft rule matches.

The fallbacks list is a comma, a tab, a semicolon, a pipe, a colon and a space. The comment explains the selection rule: the plugin tests them in sequence and uses the first one that scores highest based on the number of fields in each line. So the detection is not a heuristic on the first line alone but a comparison of field counts across lines, which is what stops a comma appearing inside a value from winning over the real tab delimiter.

The ft mapping defaults to csv for a comma and tsv for a tab, so the two filetypes Neovim already knows resolve without any guessing at all.

The limitation is stated in the same comment block and it is a hard one. Only fixed-length strings are supported as delimiters, and regular expressions such as a whitespace-plus pattern are not currently supported. A multi-character delimiter is fine, but a variable-width one is out.

Comments, quoting and the header rules

Three parsing rules decide what counts as data, and each is configurable both in the settings and on the command line when you enable the view.

The quote character defaults to a double quote, and if a field is enclosed in it the field is treated as a single field with the delimiter inside it ignored. You can override it on the command line, for example with a quote_char argument when enabling the view.

Comments work in two independent ways. There is a comments list of prefix characters, where a line starting with one of them is treated as a comment and is not displayed in the tabular format, and there is comment_lines, the number of lines at the beginning of the file to treat as comments regardless of their content, which is useful for files with a fixed header or metadata section at the top. The default comments list is empty, with hash, double dash and double slash shown commented out in the settings.

The header is controlled by header_lnum, which takes three kinds of value. True means detect the header line automatically, an integer names a specific line to use as the header on a one-based basis, and false means no header line at all with every line treated as a data row. When a header is defined it is highlighted with a specific highlight group, used for the sticky header feature if that is enabled, and excluded from normal data processing in some contexts.

The sticky header feature is what makes a long table navigable, since the header row stays visible while you scroll through the data.

Excel-like motions and field text objects

The default keymaps are the part that tells you whether this plugin was built for spreadsheets or for text.

The comments describe them as Excel-like navigation. Tab and Shift-Tab move horizontally between fields, and Enter and Shift-Enter move vertically between rows and place the cursor at the end of the field. There is a note that in terminals you may need to enable CSI-u mode to use Shift-Tab and Shift-Enter, which is the usual caveat for modifier keys in a terminal multiplexer.

There are also two text objects for selecting fields. textobject_field_inner is bound to if and textobject_field_outer to af, both in operator and visual mode. So you can select the contents of the field you are in, or the field including its delimiters, which is what you want when you want to delete a whole column value or copy it out.

The keymaps are all configurable through the same options table, with each entry carrying its key and a list of modes, so the same structure is used whether the mapping applies in normal mode, visual mode or operator pending mode. The default configuration shipped in the plugin guide sets the field text objects explicitly and the navigation keys to the four mentioned.

The plugin registers three commands, CsvViewEnable, CsvViewDisable and CsvViewToggle, so the table view is toggled per buffer rather than forced on a filetype.

Installation across the plugin managers, and the LazyVim wrinkle

The plugin works with the common managers, and the configurations differ mostly in how the setup call is made.

For lazy.nvim, the specification block names the repository, carries a module annotation and a type annotation for the options, and sets the keymaps. It also registers the three commands in a cmd entry, so the plugin loads lazily and the commands are available immediately.

For vim-plug it is two lines:

vim
Plug 'hat0uma/csvview.nvim'
lua require('csvview').setup()

For mini.deps it uses the add and later helpers, adding the plugin inside a later callback and calling setup from there:

lua
local add, later = MiniDeps.add, MiniDeps.later

later(function()
    add('hat0uma/csvview.nvim')
    require('csvview').setup()
end)

There is a specific note for LazyVim users, who should create a new file such as lua/plugins/csvview.lua and wrap the code block with return { ... }.

The repository itself is small and conventionally laid out. There is a lua/ directory for the plugin code, a plugin/ directory for the command definitions, tests/, a GUIDE.md with the user documentation, a CHANGELOG.md, a vim.yml, and two configuration files for tooling, a .stylua.toml for formatting and a selene.toml for linting.

The three releases are v1.1.0 on 2025-03-17, v1.2.0 on 2025-03-31 and v1.3.0 on 2025-09-03, with the last push on 2026-10-04.

Editorial conclusion

csvview.nvim suits a Neovim user who edits delimited files often enough that the flat text view has become friction, since the table rendering, sticky headers and field motions address that directly. It does not suit someone whose data has quoted fields spanning lines with unpredictable extent, and it does not suit a workflow that relies on regular expression delimiters, because the plugin supports only fixed-length strings. Before you configure it, read the async_chunksize setting, because it is the knob that trades responsiveness against a slow first paint on a large file, and note that the last push was on 2026-10-04 with the newest tag v1.3.0 published on 2025-09-03.

Frequently asked questions

What is csvview.nvim?

It is a Neovim plugin for comfortable CSV and TSV editing. It renders the file as a table using virtual text, so the buffer on disk is unchanged, and adds comment line handling, sticky headers, automatic delimiter and header detection, text objects for fields and Excel-like motions.

How do I install csvview.nvim?

Through your package manager of choice. The guide gives a lazy.nvim specification, two lines for vim-plug that call require('csvview').setup(), and a mini.deps version using the add and later helpers. LazyVim users are told to create a file under lua/plugins and wrap the specification in a return statement.

How does csvview.nvim detect the delimiter?

The delimiter can be a fixed string, a function of the buffer number, or a table with a filetype mapping that has the highest priority and an ordered list of fallbacks to try. The plugin tests the fallbacks in sequence and uses the one that scores highest on the number of fields per line. csv maps to a comma and tsv to a tab by default.

Does csvview.nvim support regular expression delimiters?

No. The configuration states that only fixed-length strings are supported as delimiters, and that regular expressions such as a whitespace-plus pattern are not currently supported. A multi-character fixed delimiter does work.

How do I stop csvview.nvim from freezing on a large file?

Reduce the async_chunksize setting, which is the number of lines the asynchronous parser processes per cycle and defaults to 50. The setting exists to prevent monopolization of the main thread when displaying large files. There is also a max_lookahead setting, defaulting to 50, that limits how far the parser looks ahead for the closing quote of a multi-line field.

Official sources

  1. hat0uma/csvview.nvim on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/hat0uma-csvview-nvim.svg)](https://hysenlabs.com/projects/hat0uma-csvview-nvim)

Was this useful?