csvi

package module
v1.23.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 11, 2026 License: MIT Imports: 24 Imported by: 4

README

Csvi - A terminal CSV editor

Go Test License Go Reference GitHub

( <English> / <Japanese> )

Csvi is a terminal-based CSV editor for UNIX-like systems and Windows.

image

Key Features

  • Minimal changes on save
    Csvi keeps the original formatting for every unmodified cell: quotes, line endings (LF/CRLF), BOM, encoding, and field/record separators.
    Only actual edits are saved—making it ideal for clean diffs and safe edits to production data.

  • vi-style and Emacs-style keybindings
    Move the cursor like in vi, and edit cells using Emacs-style key bindings.
    (Since v1.21.1, Ctrl-G is used instead of Esc to cancel cell editing.)

  • Reads from both file and standard input
    You can pipe CSV data into Csvi or open a file directly.

  • Fast startup and background loading
    Opens large files quickly without blocking the interface.

  • Visual feedback for edits
    Modified cells are underlined.
    Press u to undo a cell's change and restore its original value.

  • Shows original format details
    The bottom line of the screen shows technical info: quoting, encoding, field separators, and more—just as they appeared in the original file.

  • Flexible encoding support

    • UTF-8 (default)
    • UTF-16
    • Current Windows code page (auto-detected)
    • Any encoding from the IANA registry using -iana NAME
  • Color scheme options

    • Default colors assume a dark background.
    • Use -rv for light backgrounds, or set NO_COLOR to disable color output (https://no-color.org/ )

Video by @emisjerry

Install

Manual Installation

Download the binary package from Releases and extract the executable.

⚠️ Note: The macOS build is experimental and not yet tested. Please let us know if you encounter any issues!

Use eget installer (cross-platform)
brew install eget        # Unix-like systems
# or
scoop install eget       # Windows

cd (YOUR-BIN-DIRECTORY)
eget hymkor/csvi
Use scoop-installer (Windows only)
scoop install https://raw.githubusercontent.com/hymkor/csvi/master/csvi.json

or

scoop bucket add hymkor https://github.com/hymkor/scoop-bucket
scoop install csvi
Use "go install" (requires Go toolchain)
go install github.com/hymkor/csvi/cmd/csvi@latest

Note: go install places the executable in $HOME/go/bin or $GOPATH/bin, so you need to add this directory to your $PATH to run csvi.

Usage

$ csvi {options} FILENAME(...)

or

$ cat FILENAME | csvi {options}

Note: When reading from standard input, saving commands like w write to - (standard output) by default.

Options

  • -help this help
  • -h int the number of fixed header lines
  • -c use Comma as field-separator (default when suffix is .csv)
  • -t use TAB as field-separator (default when suffix is not .csv)
  • -semicolon use Semicolon as field-separator
  • -iana string IANA-registered-name to decode/encode NonUTF8 text
  • -16be Force read/write as UTF-16BE
  • -16le Force read/write as UTF-16LE
  • -auto string auto pilot (for testcode)
  • -nonutf8 do not judge as UTF-8
  • -w widths set the widths of cells (e.g., -w 14,0:10,1:20 to set the first column to 10 characters wide, the second column to 20 characters wide, and all others to 14 characters wide)
  • -fixcol forbid insertion or deletion of cells (disables i, a, and some of d-prefixed deletion commands)
  • -p Protect the header line
  • -readonly Read Only Mode
  • -rv Enable reverse-video display (invert foreground and background colors)
  • -ofs string String used as the separator between cells in the output
  • -exteditor string External editor used with Shift+R
  • -o filename preset output filename in the save prompt (used with standard input)
  • -delimiter string Specify the field separator
  • -version Print version and exit
Line Endings

By default, the editor uses the line ending detected from the input file. If no input data is provided, it falls back to the OS default line ending. You can override this behavior with the following options:

  • -lf Use LF (\n) as the default line ending for newly added lines.
  • -crlf Use CRLF (\r\n) as the default line ending for newly added lines.

These options are mutually exclusive. Specifying both will result in an error.

Key-binding

  • Move Cursor
    • h, , Shift+TAB (move cursor left)
    • j, Ctrl+N, , Enter (move cursor down)
    • k, Ctrl+P, (move cursor up)
    • l, , TAB (move cursor right)
    • <, gg (move to the beginning of file)
    • >,G (move to the end of file)
    • 0, ^, Ctrl+A (move to the beginning of the current line)
    • $,Ctrl+E (move to the end of the current line)
    • PgUp, Ctrl+B (move up one page)
    • PgDn, Ctrl+F (move down one page)
  • Search
    • / (search forward for a partial match)
    • ? (search backward for a partial match)
    • n (repeat the previous search forward)
    • N (repeat the previous search backward)
    • * (search forward for the next cell that exactly matches the current one)
    • # (search backward for the previous cell that exactly matches the current one)
  • Edit
    • i (insert a new cell before the current one)
    • a (append a new cell after the current one)
    • r,Meta+F2 (replace the current cell with the built-in readline)
    • R (replace the current cell with the external editor)
    • x (clear the current cell)
    • dl, d+SPACE, d+TAB, dv (delete cell and shift cells on the right)
    • dd, dr (delete the current line)
    • dc, d| (delete the current column)
    • w (write to a file or STDOUT('-'))
    • o (append a new line after the current one)
    • O (insert a new line before the current one)
    • " (enclose or remove double quotations if possible)
    • u (restore the original value of the current cell)
    • yl, y+SPACE, y+TAB, yv (copy the values of the current cell to kill-buffer)
    • yy, yr, Y (copy the values of the current row to kill-buffer)
    • yc, y| (copy the values of the current column to kill-buffer)
    • p (paste the values of kill-buffer after the current cell, row or column)
    • P (paste the values of kill-buffer before the current cell, row or column)
    • Meta+p (overwrite the current cell/row/column with the content of the kill-buffer)
  • Display settings
    • L (reload the file using a specified encoding)
    • Ctrl+L (Repaint)
    • ] (widen the column at the cursor)
    • [ (narrow the column at the cursor)
  • Quit: q or Meta+q

Meta means either Alt+key or Esc followed by key.

Environment Variables

NO_COLOR

If the environment variable NO_COLOR is set to any value with at least one character, Csvi disables colored output. This follows the standard proposed by NO_COLOR.

RUNEWIDTH_EASTASIAN

Specifies the display width for Unicode characters classified as ambiguous width.

  • Double-width: set RUNEWIDTH_EASTASIAN=1
  • Single-width: set RUNEWIDTH_EASTASIAN=0 (any non-1 value with at least one character is also valid)
COLORFGBG

When the environment variable is defined in the form (FG);(BG) and the foreground (FG) is less than the background (BG), Csvi automatically uses color settings suitable for light backgrounds (equivalent to the -rv option).

Csvi normally uses the terminal's default colors via the escape sequences ESC[39m and ESC[49m. Thus, the (FG);(BG) values are not directly applied; they are only used to determine whether gray background lines should be adjusted toward light or dark shades.

GOREADLINESKK

When the environment variable GOREADLINESKK specifies dictionary files, the built-in SKK[^SKK] Kana-to-Kanji conversion via go-readline-skk is enabled.

  • Windows

    • set GOREADLINESKK=SYSTEMJISYOPATH1;SYSTEMJISYOPATH2...;user=USERJISYOPATH
    • Example: set GOREADLINESKK=~/Share/Etc/SKK-JISYO.L;~/Share/Etc/SKK-JISYO.emoji;user=~/.go-skk-jisyo
  • Linux

    • export GOREADLINESKK=SYSTEMJISYOPATH1:SYSTEMJISYOPATH2...:user=USERJISYOPATH

(Note: ~ is automatically expanded to %USERPROFILE% on Windows, even in cmd.exe.)

[^SKK]: Simple Kana to Kanji conversion program. One of the Japanese input method editors.

Use as a Go package

package main

import (
    "fmt"
    "os"
    "strings"

    "github.com/mattn/go-colorable"

    "github.com/hymkor/csvi"
    "github.com/hymkor/csvi/uncsv"
)

func main() {
    source := `A,B,C,D
"A1","B1","C1","D1"
"A2","B2","C2","D2"`

    cfg := &csvi.Config{
        Mode: &uncsv.Mode{Comma: ','},
    }

    result, err := cfg.Edit(strings.NewReader(source), colorable.NewColorableStdout())

    if err != nil {
        fmt.Fprintln(os.Stderr, err.Error())
        os.Exit(1)
    }

    // // env GOEXPERIMENT=rangefunc go run example
    // for row := range result.Each {
    //     os.Stdout.Write(row.Rebuild(cfg.Mode))
    // }
    result.Each(func(row *uncsv.Row) bool {
        os.Stdout.Write(row.Rebuild(cfg.Mode))
        return true
    })
}

Changelog

Contributing

  • Bug reports and improvement suggestions are welcome. You may write them in either English or Japanese.
  • Please write comments in the code and commit messages in English.
  • If a develop branch exists at the time of your pull request, please target it. Otherwise, master is fine.
  • Test code and documentation updates that accompany code changes are appreciated, but not required. They can be added later if necessary.

Acknowledgements

Author

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsRevertVideoWithEnv added in v1.15.1

func IsRevertVideoWithEnv() bool

func MonoChrome added in v1.15.0

func MonoChrome()

func RevertColor added in v1.15.0

func RevertColor()

Types

type Application added in v1.9.5

type Application struct {
	*Config
	// contains filtered or unexported fields
}

func (*Application) Back added in v1.9.5

func (app *Application) Back() *RowPtr

func (*Application) Close added in v1.23.1

func (app *Application) Close()

func (*Application) CurrentCol added in v1.22.0

func (app *Application) CurrentCol() int

func (*Application) CurrentRow added in v1.22.0

func (app *Application) CurrentRow() *RowPtr

func (*Application) Each added in v1.9.5

func (app *Application) Each(callback func(*uncsv.Row) bool)

func (*Application) Front added in v1.9.5

func (app *Application) Front() *RowPtr

func (*Application) IsDirty added in v1.22.0

func (app *Application) IsDirty() bool

func (*Application) Len added in v1.9.5

func (app *Application) Len() int

func (*Application) MessageAndGetKey added in v1.20.0

func (app *Application) MessageAndGetKey(message string) (string, error)

func (*Application) RemovedRows added in v1.9.5

func (app *Application) RemovedRows(callback func(*uncsv.Row) bool)

func (*Application) Write added in v1.9.5

func (app *Application) Write(data []byte) (int, error)

type CellValidatedEvent added in v1.10.0

type CellValidatedEvent struct {
	Text string
	Row  int
	Col  int
}

type CellWidth added in v1.15.0

type CellWidth struct {
	Default int
	Option  map[int]int
}

func NewCellWidth added in v1.15.0

func NewCellWidth() *CellWidth

func (*CellWidth) Get added in v1.15.0

func (cw *CellWidth) Get(n int) int

func (*CellWidth) Parse added in v1.15.0

func (cw *CellWidth) Parse(s string) error

func (*CellWidth) Set added in v1.15.0

func (cw *CellWidth) Set(at, value int) bool

type CommandResult added in v1.9.5

type CommandResult struct {
	Message string
	Quit    bool
}

type Config

type Config struct {
	*uncsv.Mode
	CellWidth   *CellWidth
	HeaderLines int
	Pilot
	FixColumn       bool
	ReadOnly        bool
	ProtectHeader   bool
	Message         string
	KeyMap          map[string]func(*KeyEventArgs) (*CommandResult, error)
	OnCellValidated func(*CellValidatedEvent) (string, error)
	Titles          []string
	OutputSep       string
	SavePath        string
	ExtEditor       func(string, *Application) (string, error)
}

func (Config) Edit added in v1.9.2

func (cfg Config) Edit(dataSource io.Reader, ttyOut io.Writer) (*Result, error)

func (Config) EditFromStringSlice added in v1.15.0

func (cfg Config) EditFromStringSlice(fetch func() ([]string, bool), ttyOut io.Writer) (*Result, error)

type KeyEventArgs added in v1.10.0

type KeyEventArgs struct {
	*Application

	// Deprecated: use CurrentRow() instead
	CursorRow *RowPtr

	// Deprecated: use CurrentCol() instead
	CursorCol int
}

type Pilot

type Pilot interface {
	Size() (int, int, error)
	GetKey() (string, error)
	ReadLine(out io.Writer, prompt, defaultText string, c candidate.Candidate) (string, error)
	GetFilename(io.Writer, string, string) (string, error)
	Close() error
}

type Result added in v1.9.3

type Result struct {
	*Application
}

type RowPtr

type RowPtr struct {
	*uncsv.Row
	// contains filtered or unexported fields
}

func (*RowPtr) Clone

func (r *RowPtr) Clone() *RowPtr

func (*RowPtr) Index added in v1.10.0

func (r *RowPtr) Index() int

func (*RowPtr) InsertAfter

func (r *RowPtr) InsertAfter(val *uncsv.Row) *RowPtr

func (*RowPtr) InsertBefore

func (r *RowPtr) InsertBefore(val *uncsv.Row) *RowPtr

func (*RowPtr) Next

func (r *RowPtr) Next() *RowPtr

func (*RowPtr) Prev

func (r *RowPtr) Prev() *RowPtr

func (*RowPtr) Remove

func (r *RowPtr) Remove() *uncsv.Row

type ScopedInterrupt added in v1.23.1

type ScopedInterrupt struct {
	// contains filtered or unexported fields
}

func NewScopedInterrupt added in v1.23.1

func NewScopedInterrupt() *ScopedInterrupt

func (*ScopedInterrupt) Close added in v1.23.1

func (si *ScopedInterrupt) Close()

func (*ScopedInterrupt) NotifyContext added in v1.23.1

func (si *ScopedInterrupt) NotifyContext(ctx context.Context) (context.Context, context.CancelFunc)

Directories

Path Synopsis
cmd
csvi command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL