- 数据分析
- CLI
- 数据可视化
【免费下载链接】visidata
A terminal spreadsheet multitool for discovering and arranging data
VisiData 是一个终端电子表格多用途工具(terminal spreadsheet multitool),除了通过剪贴板复制粘贴数据外,它还内置了一整套从零创建、编辑和删除行的命令体系。本篇指南以仓库中的 ModifyGuide 为骨架,结合 modify.py 等核心源码,系统讲解增删改行的快捷键、单元格编辑模式、[M]修改状态标识,以及 SQLiteSheet、Dir Sheet 等"延迟保存(deferred saving)"表格的颜色标记与commit-sheet提交机制。读完本文,你将能在 VisiData 中熟练地批量增删行、用外部编辑器批量编辑单元格,并安全地把修改写回数据源。
一、修改操作命令全景
在 VisiData 中,除了"剪切/粘贴"(见Clipboard Guide,对应源码 clipboard.py)之外,行的创建、编辑与删除由以下几组命令支撑:
| 命令 longname | 默认按键 | 作用 | 定义位置 |
|---|---|---|---|
add-row | a | 在光标行后追加一个空行 | modify.py |
add-rows | ga | 批量追加 N 个空行(交互输入数量) | modify.py |
edit-cell | e | 编辑当前单元格内容 | sheets.py |
sysedit-cell | Ctrl+O | 在外部$EDITOR中编辑当前单元格 | features/sysedit.py |
sysedit-selected | gCtrl+O | 在外部$EDITOR中批量编辑可见列、已选行 | features/sysedit.py |
delete-row | d | 删除当前行 | clipboard.py |
delete-selected | gd | 删除所有已选行 | clipboard.py |
commit-sheet | zCtrl+S | 将延迟修改提交回数据源 | modify.py |
这些命令同样可以通过菜单触发,例如Edit > Delete > current row > delete-row、Row > Add > one row、File > Save > changes to source > commit-sheet(菜单定义见 modify.py 与 clipboard.py)。
二、添加新行:a与ga
按a执行add-row,其命令表达式为:
addRows([newRow()], index=cursorRowIndex); cursorDown(1)即通过Sheet.newRow()生成一个空白行对象,插入到当前光标行之后,并把光标下移一行,方便连续录入。按ga执行add-rows,则会先弹出一个输入框询问要添加的行数(默认值 1):
n=int(input("add # rows: ", value=1)); addRows(new_rows(n), index=cursorRowIndex); cursorDown(1)从源码 modify.py 可以看到new_rows(n)本质上是[sheet.newRow() for i in range(n)],即批量构造空白行。真正的插入逻辑在 addRows 中:
- 逐个调用
sheet.addRow(row, index=...)把行插入到指定位置之后; - 若该表格启用了延迟保存(
sheet.defer为真),则同时调用sheet.rowAdded(row)把新行登记到_deferredAdds待提交集合; - 最后调用
sheet.setModified()标记表格已被修改,并通过vd.addUndo(_removeRows)注册撤销操作。
值得注意:addRow在 sheets.py 与 sheets.py 有基础实现,而各加载器(loader)可覆盖它——例如 loaders/json.py、loaders/xlsx.py、loaders/xml.py 都有各自的addRow实现,说明"加行"在底层会与具体文件格式的写入逻辑联动。
三、编辑单元格:输入模式与快捷键
按e进入当前单元格的编辑模式,底层调用 editCell。编辑期间,输入框有自己的按键绑定(见 editCell 中的bindings字典):
Tab:完成编辑并跳到下一个单元格(在最后一列时折行跳到下一行行首);Shift+Tab:完成编辑并跳到上一个单元格(在第一列时折行跳到上一行行末);Shift+方向键:完成编辑并沿该方向移动光标,同时保留列名编辑语境(rename-col)。
如果你对输入框的按键还不熟悉,在编辑单元格时按Ctrl+G可以循环切换侧边栏(sidebar)的指南,直接查看Input Keystroke Help(输入键位帮助),这是边编辑边查阅键位表的最快方式。
用外部编辑器编辑单元格:Ctrl+O
在编辑单元格时按Ctrl+O会执行sysedit-cell,把当前单元格的完整显示值写入临时文件,调用外部$EDITOR打开(vd.launchExternalEditor,见 features/sysedit.py)。若编辑器保存后的内容与原来不同,则把新值写回该单元格。外部编辑器非常适合输入多行文本、JSON 片段等复杂内容。
批量场景更常用的是gCtrl+O(sysedit-selected),其实现syseditCells(visibleCols, onlySelectedRows)的工作流程(见 features/sysedit.py):
- 将当前表格的可见列与已选行复制为一个临时子表;
- 询问文件类型(默认取
save_filetype,通常是tsv),把子表保存到临时文件; - 用外部编辑器打开该临时文件,等编辑器退出后重新加载;
- 逐列比较编辑前后的显示值,只把真正被编辑器改动的单元格通过
col.setValuesTyped写回原表。
也就是说,gCtrl+O让你像编辑普通文本文件一样,一次批量修改几百行数据,改动自动回填。相关行为在 tests/test_editor.py 中有对应的回归测试。另外,列若被标记为只读(readonly),编辑时会直接报错cannot edit readonly column(见 editCell),只读列使用主题色color_readonly渲染(见 modify.py)。
四、删除行:d与gd
按d执行delete-row(delete_row(cursorRowIndex)),按gd执行delete-selected(deleteSelected())。
非延迟表格的delete_row逻辑(见 clipboard.py)很直观:把行从sheet.rows弹出、注册撤销(vd.addUndo(sheet.rows.insert, ...))、若是已选行则取消选中,最后调用sheet.commitDeleteRow(oldrow)立即写回数据源并setModified()。
批量删除走 deleteSelected,它基于Sheet.deleteBy(self.isSelected)完成。deleteBy(见 modify.py)是删除的核心:
- 若表格启用了延迟保存且未要求强制提交(
defer and not commit),则不真正删除行,而是对每个匹配行调用sheet.rowDeleted(r)登记到_deferredDels,行仍留在屏幕上,等待后续统一提交; - 否则直接从
sheet.rows中移除并调用sheet.commitDeleteRow(r)写回数据源; - 删除后会把光标定位到下一个未被删除的行,并通过
vd.status('deleted N rows')给出反馈。
五、修改状态标识:[M]
只要表格发生过添加、删除或编辑,VisiData 就会把该表格标记为"已修改"(hasBeenModified = True,通过setModified()设置;加载完成时会被重置为 False,见 modify.py),并在界面右下角的状态栏显示[M]标识。这是你判断当前表格是否有未落盘修改的最直观信号,也是quitguard选项和退出确认逻辑的依据。
六、延迟保存(Deferred Sheets):先标记、后提交
什么是延迟保存
部分表格类型支持deferred(延迟)保存:修改不会立即写回磁盘/数据源,而是先在内存中登记为"待提交"状态,由你显式提交。典型例子包括SQLiteSheet与Dir Sheet,从源码看它们都在类级别声明了defer = True:
- loaders/sqlite.py(SQLiteSheet)
- shell.py(DirSheet)
其他启用defer = True的还有 loaders/orgmode.py、vgit 系列表格(如 apps/vgit/log.py)等。
三类待提交变更与颜色标记
延迟保存期间,修改会分三类登记,并配有各自的主题色(colorizer 定义见 modify.py):
| 变更类型 | 数据结构 | 默认颜色 | 主题选项 |
|---|---|---|---|
| 新增行(added rows) | _deferredAdds(rowid -> row) | 绿色green | color_add_pending |
| 修改单元格(modified cells) | _deferredMods(rowid -> (row, {col: val})) | 反显黄reverse yellow | color_change_pending |
| 删除行(deleted rows) | _deferredDels(rowid -> row) | 红色red | color_delete_pending |
登记动作分别由 rowAdded、cellChanged、rowDeleted 完成。其中cellChanged有个细节:如果被编辑的单元格所在行本身是"待新增"行,则直接写入行对象而不再单独登记修改。这三个登记动作都会注册相应的撤销回调,因此在提交之前,undo(u)可以逐条回退;而一旦提交(commit)之后,撤销将不再可用(源码会给出cannot undo row addition after a commit之类的警告)。
颜色选项在 modify.py 中定义,并可在主题(theme)中定制,例如 themes/adwaita.py 的明亮配色、themes/light.py、themes/ascii8.py 与 themes/asciimono.py。这样,未提交的绿色新行、反显黄的改动单元格、红色的待删行一目了然。
提交变更:zCtrl+S(commit-sheet)
延迟表格只有在执行commit-sheet(默认键zCtrl+S,longname 为commit-sheet)后,修改才会真正写回数据源。提交前 VisiData 会汇总三类待提交变更并弹窗确认,例如add 2 rows and change 5 values and delete 1 row?。汇总逻辑来自 getDeferredChanges 与 changestr。
整个提交链路为:
commit()(modify.py)检查sheet.defer,若该表格类型不支持延迟保存则直接fail('commit-sheet is not enabled for this sheet type');- 通过
vd.confirmOverwrite(...)做存在性/覆盖确认(与overwrite选项联动,见 modify.py); putChanges()(modify.py)依次执行commitAdds()、commitMods()、commitDeletes(),分别把待新增行写入数据源、把改动值写回各列、删除待删行;- 提交完成后
hasBeenModified复位,[M]标识消失。
注意commit-sheet的命令描述是"not undoable!"——提交不可撤销,因此确认弹窗是对数据的最后一道保护。commitAdds/commitMods/commitDeletes各自的实现见 modify.py,各加载器还可覆盖commitAddRow/commitDeleteRow来适配具体文件格式。
七、相关选项(Options)速览
原指南中与本主题直接相关的选项如下:
| 选项 | 默认值 | 说明 | 定义位置 |
|---|---|---|---|
quitguard | False | 退出或关闭含未保存修改的表格前要求确认 | interface.py |
color_add_pending | green | 待新增行的颜色 | modify.py |
color_change_pending | reverse yellow | 待修改单元格的颜色 | modify.py |
color_delete_pending | red | 待删除行的颜色 | modify.py |
overwrite | c | 是否允许覆盖已存在文件(c=确认后覆盖,n/readonly=禁止) | modify.py |
quitguard:为修改数据加一道确认闸门
quitguard在 sheets.py 的退出与关表流程中生效:
- 退出整个 VisiData 时(
vd.quit),若quitguard为真且存在已修改(precious且hasBeenModified)的表格,会弹窗确认exit VisiData (N sheet(s) modified)?; - 关闭单个表格时(
confirmQuit),对已修改或显式设置了quitguard的表格分别给出quit modified sheet "..."?/quit guarded sheet "..."?的确认。
此外还有两个配套命令(sheets.py):guard-sheet(在当前表格上单独开启 quitguard)与guard-sheet-off(关闭)。quitguard也支持--quitguard命令行开关(见 main.py)。结合延迟保存的[M]状态标识,quitguard能有效防止带着未提交修改误退会话。
八、源码与测试索引
想深入了解本文涉及的实现细节,可按以下路径继续阅读:
- 修改/延迟提交核心: visidata/modify.py
- 单元格输入与编辑键位: visidata/_input.py
- 删除行实现: visidata/clipboard.py、visidata/selection.py
- 外部编辑器批量编辑: visidata/features/sysedit.py
- 退出确认与 quitguard: visidata/sheets.py
- 延迟表格示例: visidata/loaders/sqlite.py、visidata/shell.py
- 主题配色示例: visidata/themes/adwaita.py、visidata/themes/ascii8.py
- 相关测试: visidata/tests/test_commands.py(覆盖
edit-cell、add-rows等命令)、visidata/tests/test_editor.py(外部编辑器流程)
掌握"普通表格立即写入 + 延迟表格先标记后提交"这两套机制,是安全使用 VisiData 修改数据的关键:普通表格(如 CSV)的d/e/a操作即时生效且有撤销兜底;而面对 SQLite 或目录这类延迟表格时,请善用三种color_*_pending颜色实时审视待提交改动,确认无误后再按zCtrl+S落盘。
- 数据分析
- CLI
- 数据可视化
【免费下载链接】visidata
A terminal spreadsheet multitool for discovering and arranging data
相关推荐
VisiData 数据修改 API 全解析:行增删、单元格编辑、延迟提交与撤销机制
VisiData 数据修改 API 全解析:行增删、单元格编辑、延迟提交与撤销机制 导读 本文围绕 VisiData 官方 API 文档 docs/api/mo
数据分析CLI数据可视化VisiData CRUD 实战指南:创建 Sheet、行与列的增删改查操作详解
VisiData CRUD 实战指南:创建 Sheet、行与列的增删改查操作详解 导读 本文基于 VisiData 官方文档中的 CRUD 章节( docs/c
数据分析CLI数据可视化PHP-FFMpeg媒体元数据操作终极指南:添加、修改与删除标签信息
PHP FFMpeg媒体元数据操作终极指南:添加、修改与删除标签信息 在当今数字媒体时代, PHP FFMpeg媒体元数据操作 已成为处理音视频文件不可或缺的技
音视频视频处理音频处理
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考