Edit Markdown and CSV tables in Neovim with lossless round-trip.
tirenvi.nvim
Markdown & CSV table editor for Neovim โ structural editing, pure text, always valid.
Supports Markdown and CSV out of the box, and can be extended to other formats via custom parsers.
Markdown (GFM)

Edit Markdown tables structurally.
Raw โ aligned โ edit โ back to raw (lossless).
CSV / TSV

Raw โ aligned โ edit โ back to raw (lossless).
Design Philosophy
- Vim-first
- Text-only buffer
- Structurally safe
- Fully reversible transformation
- No hidden metadata
- Always valid
Why?
Markdown and CSV are text โ but they represent structure.
Tirenvi lets you edit tabular data structurally, while staying in Vimโs native editing model.
You edit text. Tirenvi preserves structure.
Core Architecture
At the center is: TIR โ Tabular Intermediate Representation
flat (gfm markdown, csv, tsv, ...)
โ external parser
TIR (intermediate representation)
โ tirenvi
tir-buf (structured buffer view)
Editing happens in tir-buf format.
On save:
tir-buf โ TIR โ original flat format
Key principles:
- The buffer contains only text
- No hidden shadow buffer
- No custom buffer type
- Transformations are reversible
- TIR is the source of truth
- Buffer structure can temporarily diverge during editing
- Structural repair is explicit and controllable
Features
- Render CSV/TSV/GFM into an aligned structured view
- Preserve original file format on save
- Toggle raw โ structured view
- Immediate or deferred structural repair
- Dirty line tracking and highlighting
- Multiline cell support with preserved line breaks
- Column width control with wrapping support
- Grid-aware join that preserves column structure
- Column text objects for structural editing
- Works with native Vim motions and operators
- External parser architecture (extensible)
- No learning curve
Structural Integrity Model
Tirenvi maintains a structured internal table model while allowing temporary buffer inconsistencies.
In deferred repair mode:
- Invalid table edits are allowed temporarily
- Dirty lines are tracked incrementally
- Internal attrs/model state remains structurally valid
- Buffer structure may temporarily diverge from the model
:Tir repairsynchronizes the buffer with the internal model
- Invalid structural edits are repaired automatically
- Normal mode edits are repaired immediately
- Insert mode edits are repaired after leaving Insert
Historical undo states are not rewritten, even if they contain temporary structural inconsistencies.
Installation
lazy.nvim
{
"kibi2/tirenvi.nvim",
dependencies = {
"tpope/vim-repeat", -- optional: enables '.' repeat for column width operations
},
config = function()
require("tirenvi").setup {}
end,
}
vim-plug
Plug 'kibi2/tirenvi.nvim'
" Optional: enables '.' repeat for column width operations Plug 'tpope/vim-repeat'
Requirements
- Neovim >= 0.10
- UTF-8 environment
pip install tir-gfm-lite
pip install tir-csv
pip install tir-pukiwiki
Usage
Automatically activates based on filetype (via parser_map):
csvtsvmarkdownpukiwiki
require("tirenvi").setup({
parser_map = {
csv = { executable = "tir-csv", required_version = "0.1.4" },
tsv = { executable = "tir-csv", options = { "--delimiter", "\t" }, required_version = "0.1.4" },
markdown = { executable = "tir-gfm-lite", allowplain = true, requiredversion = "0.1.6" },
pukiwiki = { executable = "tir-pukiwiki", allowplain = true, requiredversion = "0.1.1" },
}
})
Commands
| Command | Description | | ------------------------ | ------------------------------------------------------------------- | | :Tir repair | Repair and reformat dirty tables | | :Tir repair enable | Enable automatic structural repair | | :Tir repair disable | Disable automatic structural repair | | :Tir repair toggle | Toggle automatic structural repair | | :Tir toggle | Switch raw โ structured table view | | :Tir width[=+-][count] | Adjust column width by count (=: set, +/-: increment/decrement) | | :Tir redraw | Deprecated. Will be removed in v0.5.
Use :Tir repair instead |
All native Vim editing works.
dd,yy,p,D,o,R,J, and more- Command-line command
- Visual mode command
Column Editing
Columns are structural units.
To modify a column:
- Select a column using text objects (
vil,val,v3al) - Apply standard operators (
d,p, etc.)
require("tirenvi").setup({
textobj = {
column = "l",
},
})
Operations that would break structure are automatically corrected.
Column width operations support . repeat when vim-repeat is installed.
Pipe Motions
Fast horizontal navigation across cells.
vim.keymap.set({ 'n', 'o', 'x' }, '<leader>tf', require('tirenvi').motion.f, { expr = true })
vim.keymap.set({ 'n', 'o', 'x' }, '<leader>tF', require('tirenvi').motion.F, { expr = true })
vim.keymap.set({ 'n', 'o', 'x' }, '<leader>tt', require('tirenvi').motion.t, { expr = true })
vim.keymap.set({ 'n', 'o', 'x' }, '<leader>tT', require('tirenvi').motion.T, { expr = true })
They behave like Vimโs f/F/t/T, but target table separators.
; and , continue to repeat as usual.
Note: There are two types of pipes (continuation and non-continuation), so motions may behave differently across lines.
What Tirenvi Is Not
- Not a spreadsheet
- Not a new editing mode
- Not a hidden AST editor
- Not a file-format converter
Roadmap
In Progress
- Text objects (table, row, column, cell)
Planned
- Column formatting presets
- Outline mode
Comparison
| Feature | Tirenvi | csv.vim | Spreadsheet tools | | ------------------------- | ------- | ------- | ----------------- | | Native Vim editing | โ | โ ๏ธ | โ | | Always structurally valid | โ | โ | โ ๏ธ | | No file format change | โ | โ | โ | | No custom buffer type | โ | โ | โ | | Toggle raw view | โ | โ | โ | | Markdown | โ | โ | โ | | Automatic wrapping | โ | โ | โ ๏ธ | | Grid-aware join | โ | โ | โ |
Tirenvi prioritizes structural safety with Vim purity.
Contributing
The architecture centers around:
- flat โ TIR (external)
- TIR โ tir-buf (internal)
Please open an issue before major design proposals.
License
MIT License.