Repository: saulpw/visidata Branch: develop Commit: 3d1b6b96c5b9 Files: 995 Total size: 20.4 MB Directory structure: gitextract_wcvjea1d/ ├── .codespellrc ├── .devcontainer/ │ ├── Dockerfile │ ├── devcontainer.json │ ├── launch.json │ ├── post-create.sh │ └── settings.json ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── feature-request.md │ │ ├── loader-request.md │ │ └── question.md │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows/ │ ├── main.yml │ ├── vdsql.yml │ └── vgit.yml ├── .gitignore ├── .gitmodules ├── .gitpod.Dockerfile ├── .gitpod.yml ├── .mailmap ├── .theia/ │ └── settings.json ├── AGENTS.md ├── CHANGELOG.md ├── CLAUDE.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile.alpine ├── Dockerfile.darkdraw.alpine ├── LICENSE.gpl3 ├── MANIFEST.in ├── Makefile ├── README.md ├── bin/ │ ├── filter-doc.py │ ├── vd │ ├── vd2to3.vdx │ └── viewtsv.py ├── dev/ │ ├── DOCS.md │ ├── GIT.md │ ├── OPTIONS.md │ ├── PERFORMANCE.md │ ├── README.md │ ├── STYLE.md │ ├── TESTING.md │ ├── build-container │ ├── checklists/ │ │ ├── add-aggregator.md │ │ ├── add-command.md │ │ ├── feature.md │ │ ├── manual-tests.md │ │ └── release.md │ ├── debian/ │ │ ├── changelog │ │ ├── control │ │ ├── copyright │ │ ├── manpages │ │ ├── rules │ │ ├── source/ │ │ │ ├── format │ │ │ └── local-options │ │ ├── upstream/ │ │ │ └── metadata │ │ └── watch │ ├── design/ │ │ ├── 000-notes.md │ │ ├── 160-longnames.md │ │ ├── 169-settings.md │ │ ├── 173-benchmark.md │ │ ├── 174-keycols.md │ │ ├── 175-design-terms.md │ │ ├── 176-miscrules.md │ │ ├── 181-benchmark-data.md │ │ ├── 232-input.md │ │ ├── 260-push.md │ │ ├── README.md │ │ └── path.md │ ├── diff-test.sh │ ├── formats.jsonl │ ├── formats.vd │ ├── hooks/ │ │ └── pre-push │ ├── mkman.sh │ ├── mkpandas-df.py │ ├── quit.vdx │ ├── requirements-dev.txt │ ├── run-tests-individually.sh │ ├── test-all.sh │ ├── test-stdin-replay.vdx │ ├── test.sh │ ├── types.jsonl │ ├── vduplot.vdx │ ├── visidata-brew.rb │ ├── workshop-outline.md │ ├── zsh-completion.in │ └── zsh-completion.py ├── docs/ │ ├── README.md │ ├── api/ │ │ ├── Makefile │ │ ├── _static/ │ │ │ ├── .gitkeep │ │ │ └── css/ │ │ │ └── custom.css │ │ ├── async.rst │ │ ├── canvas.rst │ │ ├── columns.rst │ │ ├── commands.rst │ │ ├── conf.py │ │ ├── data.rst │ │ ├── extensible.rst │ │ ├── guides.rst │ │ ├── index.rst │ │ ├── interface.rst │ │ ├── loaders.rst │ │ ├── make.bat │ │ ├── modify.rst │ │ ├── modules.rst │ │ ├── options.rst │ │ ├── plugins.rst │ │ ├── requirements.txt │ │ ├── runtime.txt │ │ ├── sheets.rst │ │ └── style.rst │ ├── casts/ │ │ ├── expand-cols.cast │ │ ├── pivot-graphs.cast │ │ ├── pivot.cast │ │ ├── save-restore.cast │ │ ├── split-regex.cast │ │ └── types.cast │ ├── colors.md │ ├── columns.md │ ├── contributing.md │ ├── crud.md │ ├── customize.md │ ├── dirsheet.md │ ├── edit.md │ ├── formats.md │ ├── freq.md │ ├── gmail.md │ ├── graph.md │ ├── graphics.md │ ├── group.md │ ├── index.md │ ├── internal_formats.md │ ├── join.md │ ├── loading.md │ ├── macros.md │ ├── menu.md │ ├── mouse.md │ ├── move.md │ ├── navigate.md │ ├── pipes.md │ ├── plugins.md │ ├── rows.md │ ├── save-restore.md │ ├── shell.md │ ├── split.md │ ├── test.md │ ├── usage.md │ └── viewtsv.md ├── platform/ │ ├── windows/ │ │ ├── vdwin-installer.md │ │ ├── vdwin.py │ │ └── vdwin.spec │ └── www/ │ ├── Dockerfile │ ├── Makefile │ └── visidatarc ├── plugins/ │ ├── geocoding.py │ ├── pcap/ │ │ ├── iana-ports.tsv │ │ └── wireshark-oui.tsv │ └── vtask.py ├── pyrightconfig.json ├── requirements.scm ├── requirements.txt ├── ruff.toml ├── sample_data/ │ ├── 1794685.fec │ ├── 2m.tsv │ ├── StatusPR.csv │ ├── UTF-8-demo.txt │ ├── a.tsv │ ├── accidents.sav │ ├── arrays.hdf5 │ ├── arrays.npz │ ├── b.tsv │ ├── benchmark.arrow │ ├── benchmark.csv │ ├── benchmark.fixed │ ├── benchmark.jsonl │ ├── benchmark.lsv │ ├── benchmark.npy │ ├── benchmark.ods │ ├── benchmark.psv │ ├── benchmark.xml │ ├── benchmark.yml │ ├── brakes.xpt │ ├── co3.dta │ ├── co3.stata │ ├── color-merged-cells.xlsx │ ├── countries │ ├── date-error-test.xlsx │ ├── empty-cell.xlsx │ ├── empty-table.html │ ├── errors.csv │ ├── freshwater-mammals.toml │ ├── goog.npy │ ├── gtm.f5log │ ├── hello.mnu │ ├── issue1308.html │ ├── messenger.pcap │ ├── numeric-cols.tsv │ ├── officials.jsonla │ ├── pr2815.jsonl │ ├── sample-sales-reps.xlsx │ ├── sample.arrow │ ├── sample.arrows │ ├── sample.conllu │ ├── sample.geojson │ ├── sample.parquet │ ├── sample.tsv │ ├── sample.vds │ ├── saulpw-008.xd │ ├── sensors.h5 │ ├── shapefile/ │ │ ├── WA_State_Boundary.cpg │ │ ├── WA_State_Boundary.dbf │ │ ├── WA_State_Boundary.prj │ │ ├── WA_State_Boundary.shp │ │ ├── WA_State_Boundary.shx │ │ └── WA_State_Boundary.xml │ ├── smiths-json.grep │ ├── smiths-standard.grep │ ├── states.yml │ ├── sunshinelist.html │ ├── test-fixed-leadingspaces.txt │ ├── test-unicode-display.tsv │ ├── test.fixed │ ├── test.jsonl │ ├── test.msgpack │ ├── test.msgpackz │ └── test.usv ├── setup.py ├── snippets/ │ ├── gender.py │ ├── geolocate.py │ └── rank.py ├── tests/ │ ├── .visidata/ │ │ └── .gitignore │ ├── .visidatarc │ ├── 1410a.vdj │ ├── 1410b.vdj │ ├── 1410c.vdj │ ├── add-col-dup-attrs.vdj │ ├── addcol-iter.vdj │ ├── addcol_window.vd │ ├── aggregators-cols.vdj │ ├── aggregators-errors.vd │ ├── aggregators-set.vd │ ├── append.vd │ ├── avg-nulls.vd │ ├── bulk-rename-cols.vd │ ├── capture-col-named.vd │ ├── column-copy.vd │ ├── column-name-__name__.csv │ ├── column-name-__name__.vd │ ├── column-name-_fields.csv │ ├── column-name-_fields.vd │ ├── column-name-length.csv │ ├── column-name-length.vd │ ├── concat-origin.vdx │ ├── curcol.vd │ ├── data1.tsv │ ├── data2.tsv │ ├── data3.tsv │ ├── date_add.vd │ ├── describe-error.vd │ ├── describe-through.vd │ ├── describe.vd │ ├── diff-join.vdj │ ├── dup-rows-attrs.vd │ ├── edit-fixed.vdx │ ├── edit-joinkey-1.vd │ ├── edit-joinkey-2.vd │ ├── edit-joinregular-1.vd │ ├── edit-joinregular-2.vd │ ├── edit-type.vd │ ├── empty-unfurl-2.vd │ ├── empty-unfurl.vd │ ├── error-passthru.vd │ ├── errors-311.vd │ ├── exp-digits.vdj │ ├── extend.vd │ ├── fill-nested.vdj │ ├── fill-zero.json │ ├── fill-zero.vdj │ ├── fill.vdj │ ├── format-enum-freeze.vd │ ├── format-enum.vd │ ├── freeze-json.vd │ ├── freeze-sheet-attrs.vd │ ├── freq-dive-except.vdx │ ├── freq-error.vd │ ├── freq-fmtstr.vd │ ├── freq-same-int.vd │ ├── freq-summary.vd │ ├── freqtbl-nested-dive-selected.vdx │ ├── freqtbl-openrow.vd │ ├── frozen-attrs.vd │ ├── full-join.vd │ ├── gMelt.vd │ ├── getitem.vd │ ├── golden/ │ │ ├── 1410a.tsv │ │ ├── 1410b.tsv │ │ ├── 1410c.tsv │ │ ├── add-col-dup-attrs.tsv │ │ ├── addcol-iter.tsv │ │ ├── addcol_window.tsv │ │ ├── aggregators-cols.tsv │ │ ├── aggregators-errors.tsv │ │ ├── aggregators-set.tsv │ │ ├── append.tsv │ │ ├── avg-nulls.tsv │ │ ├── bulk-rename-cols.tsv │ │ ├── capture-col-named.tsv │ │ ├── column-copy.tsv │ │ ├── column-name-__name__.csv │ │ ├── column-name-_fields.csv │ │ ├── column-name-length.csv │ │ ├── concat-origin.tsv │ │ ├── curcol.tsv │ │ ├── date_add.tsv │ │ ├── describe-error.tsv │ │ ├── describe-through.tsv │ │ ├── describe.tsv │ │ ├── diff-join.tsv │ │ ├── dup-rows-attrs.tsv │ │ ├── edit-fixed.fixed │ │ ├── edit-joinkey-1.tsv │ │ ├── edit-joinkey-2.tsv │ │ ├── edit-joinregular-1.tsv │ │ ├── edit-joinregular-2.tsv │ │ ├── edit-type.tsv │ │ ├── empty-unfurl-2.tsv │ │ ├── empty-unfurl.tsv │ │ ├── error-passthru.tsv │ │ ├── errors-311.tsv │ │ ├── exp-digits.tsv │ │ ├── extend.tsv │ │ ├── fill-nested.jsonl │ │ ├── fill-zero.json │ │ ├── fill.jsonl │ │ ├── format-enum-freeze.tsv │ │ ├── format-enum.json │ │ ├── format-enum.tsv │ │ ├── freeze-json.tsv │ │ ├── freeze-sheet-attrs.tsv │ │ ├── freq-dive-except.tsv │ │ ├── freq-error.tsv │ │ ├── freq-fmtstr.tsv │ │ ├── freq-same-int.tsv │ │ ├── freq-summary.tsv │ │ ├── freqtbl-nested-dive-selected.tsv │ │ ├── freqtbl-openrow.tsv │ │ ├── frozen-attrs.tsv │ │ ├── full-join.tsv │ │ ├── gMelt.tsv │ │ ├── getitem.tsv │ │ ├── hide-uniform.tsv │ │ ├── histogram.tsv │ │ ├── import-python.tsv │ │ ├── inner-join.tsv │ │ ├── invalid_unicode_sqlite.tsv │ │ ├── issue1308.tsv │ │ ├── issue1346.tsv │ │ ├── issue1377.tsv │ │ ├── issue1377b.tsv │ │ ├── issue2015.tsv │ │ ├── issue2190.tsv │ │ ├── issue2227.tsv │ │ ├── issue2316.tsv │ │ ├── issue2476.csv │ │ ├── issue2524-curcol.tsv │ │ ├── issue350.tsv │ │ ├── issue655.tsv │ │ ├── issue733.tsv │ │ ├── issue964-inner-join.tsv │ │ ├── join-cols-single-sheet.tsv │ │ ├── join-concat.tsv │ │ ├── join-different-types.tsv │ │ ├── join-extend-mult.tsv │ │ ├── join-merge.tsv │ │ ├── join-non-unique-cols.tsv │ │ ├── listofdictobj.tsv │ │ ├── load-2d-matrix.tsv │ │ ├── load-conllu.jsonl │ │ ├── load-csv.tsv │ │ ├── load-dir.tsv │ │ ├── load-fec.tsv │ │ ├── load-fixed-header0.tsv │ │ ├── load-fixed-leadingspaces.tsv │ │ ├── load-fixed.tsv │ │ ├── load-grep-json.grep │ │ ├── load-grep-standard.grep │ │ ├── load-h5.tsv │ │ ├── load-html.tsv │ │ ├── load-http-flaky.tsv │ │ ├── load-json.tsv │ │ ├── load-jsonla.tsv │ │ ├── load-lsv.lsv │ │ ├── load-lsv.tsv │ │ ├── load-msgpack.tsv │ │ ├── load-msgpackz.tsv │ │ ├── load-numpy.tsv │ │ ├── load-ods.tsv │ │ ├── load-pandas-2.csv │ │ ├── load-pandas-3.tsv │ │ ├── load-pandas.tsv │ │ ├── load-parquet.tsv │ │ ├── load-png.tsv │ │ ├── load-sqlite-view.tsv │ │ ├── load-sqlite.tsv │ │ ├── load-stata.tsv │ │ ├── load-toml.tsv │ │ ├── load-usv.tsv │ │ ├── load-xlsx.tsv │ │ ├── load-xml.tsv │ │ ├── load-xpt-n311.tsv │ │ ├── load-yaml.tsv │ │ ├── load-zip.tsv │ │ ├── load_npy.tsv │ │ ├── load_xlsx.tsv │ │ ├── melt-error.tsv │ │ ├── messenger-nosave.dot │ │ ├── monthly-revenue.tsv │ │ ├── numeric-cols.tsv │ │ ├── numeric-names.tsv │ │ ├── numeric_binning.tsv │ │ ├── outer-join-1.tsv │ │ ├── outer-join-2.tsv │ │ ├── pandas_loader_dup_selected.tsv │ │ ├── petsdiet.tsv │ │ ├── pivot-error.tsv │ │ ├── pivot-noaggr.tsv │ │ ├── pivot.tsv │ │ ├── pr2302.tsv │ │ ├── pr2308.json │ │ ├── pr2372.tsv │ │ ├── pr2400.tsv │ │ ├── pr2614.tsv │ │ ├── pr2647.tsv │ │ ├── pr2688a.tsv │ │ ├── pr2688b.tsv │ │ ├── pr2815.json │ │ ├── pr2855.tsv │ │ ├── prefer-visible-col.tsv │ │ ├── pull2140.tsv │ │ ├── rank-sheetrank-sorted-cols.tsv │ │ ├── record-aggr.tsv │ │ ├── remove-errors.tsv │ │ ├── rows-select-expr.tsv │ │ ├── save-benchmarks.csv │ │ ├── save-benchmarks.html │ │ ├── save-benchmarks.json │ │ ├── save-benchmarks.jsonl │ │ ├── save-benchmarks.md │ │ ├── save-benchmarks.npy │ │ ├── save-benchmarks.rst │ │ ├── save-benchmarks.txt │ │ ├── save-geojson.geojson │ │ ├── save-json.csv │ │ ├── save-json.html │ │ ├── save-json.json │ │ ├── save-json.jsonl │ │ ├── save-json.md │ │ ├── save-json.tsv │ │ ├── save-json.txt │ │ ├── save-jsonla.jsonla │ │ ├── save-usv.usv │ │ ├── setcol_fake.tsv │ │ ├── setcol_precision_less.tsv │ │ ├── setcol_precision_more.tsv │ │ ├── sort-levels.tsv │ │ ├── sortorder.tsv │ │ ├── sqlite_withoutrowid.tsv │ │ ├── stdin-replay.tsv │ │ ├── stdin.tsv │ │ ├── sum-freq-table.tsv │ │ ├── test_quartiles.tsv │ │ ├── transform-cols.tsv │ │ ├── type-customdate.tsv │ │ ├── unfurl-dict.tsv │ │ ├── unfurl-empty-false.tsv │ │ ├── unfurl-empty.tsv │ │ ├── unfurl-list.tsv │ │ ├── xlsx-color-cells.tsv │ │ ├── xlsx-empty-cell.tsv │ │ ├── xlsx-header.tsv │ │ └── xlsx-merged-cells.tsv │ ├── graph-cursor-nosave.vd │ ├── graph-sincos-nosave.vdj │ ├── graphpr-nosave.vd │ ├── hide-uniform.vdj │ ├── histogram.vd │ ├── import-python.vd │ ├── inner-join.vd │ ├── invalid_unicode_sqlite.vd │ ├── issue1308.vdx │ ├── issue1346.html │ ├── issue1346.vdx │ ├── issue1377.vdj │ ├── issue1377b.vdj │ ├── issue2015.vdj │ ├── issue2190.vdj │ ├── issue2225-nosave.vdx │ ├── issue2227.html │ ├── issue2227.vdx │ ├── issue2316.vd │ ├── issue2476.vdj │ ├── issue2524-curcol.vdj │ ├── issue2890-parquet-addrow-nosave.vdx │ ├── issue2901-defer-edit-nosave.vdx │ ├── issue3015-nosave.vdx │ ├── issue3022-nosave.vdx │ ├── issue350.json │ ├── issue350.vdj │ ├── issue655.vdx │ ├── issue733.vd │ ├── issue964-inner-join.vd │ ├── issue964a.csv │ ├── issue964b.csv │ ├── join-cols-single-sheet.vd │ ├── join-concat.vdj │ ├── join-different-types.vd │ ├── join-extend-mult.vd │ ├── join-merge-1.jsonl │ ├── join-merge-2.jsonl │ ├── join-merge.vd │ ├── join-non-unique-cols.vd │ ├── joining_error.xlsx │ ├── joining_error_interesting_records.csv │ ├── known-broken.vdx │ ├── listofdictobj.vd │ ├── load-2d-matrix.vdj │ ├── load-conllu.vdj │ ├── load-dir.vd │ ├── load-fec.vdj │ ├── load-fixed-header0.vdx │ ├── load-fixed-leadingspaces.vdx │ ├── load-fixed.vd │ ├── load-grep-json.vd │ ├── load-grep-standard.vd │ ├── load-h5.vd │ ├── load-html.vd │ ├── load-http-flaky.vd │ ├── load-json.vd │ ├── load-jsonla.vdj │ ├── load-lsv.vd │ ├── load-msgpack.vd │ ├── load-msgpackz.vd │ ├── load-numpy.vdj │ ├── load-ods.vd │ ├── load-pandas-2.vd │ ├── load-pandas-3.vd │ ├── load-pandas.vd │ ├── load-parquet.vd │ ├── load-png.vdj │ ├── load-sqlite-view.vd │ ├── load-sqlite.vd │ ├── load-stata.vd │ ├── load-toml.vd │ ├── load-usv.vd │ ├── load-xlsx.vd │ ├── load-xml.vdj │ ├── load-xpt-n311.vdj │ ├── load-yaml.vd │ ├── load-zip.vd │ ├── load_npy.vdj │ ├── long-title-xlsx-nosave.vd │ ├── macros/ │ │ ├── golden/ │ │ │ └── test_macro.tsv │ │ └── test_macro.vd │ ├── melt-error.vd │ ├── messenger-nosave.vd │ ├── monthly-revenue.vd │ ├── numeric-cols.vdj │ ├── numeric-names.vd │ ├── numeric_binning.vd │ ├── outer-join-1.vd │ ├── outer-join-2.vd │ ├── output/ │ │ └── .gitignore │ ├── pandas_loader_dup_selected.vd │ ├── petsdiet.vd │ ├── pivot-error.vd │ ├── pivot-noaggr.vd │ ├── pivot.vdj │ ├── pr2302.vdj │ ├── pr2308.vdj │ ├── pr2372.tsv │ ├── pr2372.vdj │ ├── pr2400.vdj │ ├── pr2614.vdj │ ├── pr2647.vdj │ ├── pr2688a.vdj │ ├── pr2688b.vdj │ ├── pr2815.vdj │ ├── pr2855.vdj │ ├── prefer-visible-col.vd │ ├── pull2140.vdj │ ├── quantum-sum-manual.vdj │ ├── quit-perf.vdj │ ├── rank-sheetrank-sorted-cols.vdj │ ├── record-aggr.vd │ ├── remove-errors.vd │ ├── rows-select-expr.vd │ ├── save-benchmarks.vd │ ├── save-geojson.vd │ ├── save-json.vd │ ├── save-jsonla.vdj │ ├── save-usv.vd │ ├── setcol_fake.vdj │ ├── setcol_precision_less.vdj │ ├── setcol_precision_more.vdj │ ├── small.json │ ├── sort-levels.tsv │ ├── sort-levels.vd │ ├── sortorder.vdj │ ├── sqlite_withoutrowid.vd │ ├── sum-freq-table.vd │ ├── test-delimiter.sh │ ├── test-macros.sh │ ├── test-perf.sh │ ├── test-pytest.sh │ ├── test-roundtrip.sh │ ├── test-smoke.sh │ ├── test-startpos.sh │ ├── test-startup-time.sh │ ├── test-stdin-replay.sh │ ├── test-stdin.sh │ ├── test-vdx.sh │ ├── test-zsh-syntax.sh │ ├── test_quartiles.vd │ ├── testenv.sh │ ├── transform-cols.vd │ ├── type-customdate.vdj │ ├── unfurl-dict.vd │ ├── unfurl-empty-false.vd │ ├── unfurl-empty.jsonl │ ├── unfurl-empty.vd │ ├── unfurl-list.vd │ ├── xdg/ │ │ └── data/ │ │ └── visidata/ │ │ ├── 1.vdj │ │ └── macros.jsonl │ ├── xlsx-color-cells.vd │ ├── xlsx-empty-cell.vd │ ├── xlsx-header.vd │ └── xlsx-merged-cells.vd └── visidata/ ├── __init__.py ├── __main__.py ├── _input.py ├── _open.py ├── _types.py ├── _urlcache.py ├── aggregators.py ├── apps/ │ ├── __init__.py │ ├── galcon/ │ │ ├── Dockerfile.galcon-client │ │ ├── Dockerfile.galcon-server │ │ ├── README.md │ │ ├── galcon-server.py │ │ ├── galcon.py │ │ ├── requirements.txt │ │ └── setup.py │ ├── vdsql/ │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── MANIFEST.in │ │ ├── README.md │ │ ├── __about__.py │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── _ibis.py │ │ ├── bigquery.py │ │ ├── clickhouse.py │ │ ├── demos/ │ │ │ └── clickhouse-demo.vdx │ │ ├── requirements-extra.txt │ │ ├── requirements.txt │ │ ├── setup.py │ │ ├── snowflake.py │ │ ├── test.sh │ │ ├── tests/ │ │ │ ├── dup-limit.vdj │ │ │ ├── freq-open-selected.vdj │ │ │ ├── freq.vdj │ │ │ ├── golden/ │ │ │ │ ├── dup-limit.jsonl │ │ │ │ ├── freq-open-selected.jsonl │ │ │ │ ├── freq.jsonl │ │ │ │ ├── scoop.jsonl │ │ │ │ ├── select-col-regex.jsonl │ │ │ │ ├── select-expr-cast-type.tsv │ │ │ │ ├── select-expr.jsonl │ │ │ │ ├── select-row-dup.jsonl │ │ │ │ ├── toggle.jsonl │ │ │ │ ├── unselect-regex.tsv │ │ │ │ └── unselect.jsonl │ │ │ ├── scoop.vdj │ │ │ ├── select-col-regex.vdj │ │ │ ├── select-expr-cast-type.vdj │ │ │ ├── select-expr.vdj │ │ │ ├── select-row-dup.vdj │ │ │ ├── toggle.vdj │ │ │ ├── unselect-regex.vdj │ │ │ └── unselect.vdj │ │ └── vdsql │ └── vgit/ │ ├── CHANGELOG.md │ ├── README.md │ ├── USECASES.md │ ├── __init__.py │ ├── __main__.py │ ├── abort.py │ ├── blame.py │ ├── branch.py │ ├── config.py │ ├── diff.py │ ├── gitsheet.py │ ├── grep.py │ ├── log.py │ ├── main.py │ ├── remote.py │ ├── repos.py │ ├── setup.py │ ├── stash.py │ ├── status.py │ ├── statusbar.py │ ├── tests/ │ │ ├── git_branch_test.vdx │ │ └── git_remote_test.vdx │ ├── vgit │ └── vgit-guide.md ├── basesheet.py ├── bezier.py ├── canvas.py ├── canvas_text.py ├── choose.py ├── clean_names.py ├── clipboard.py ├── cliptext.py ├── cmdlog.py ├── color.py ├── column.py ├── ddw/ │ ├── input.ddw │ └── regex.ddw ├── ddwplay.py ├── deprecated.py ├── desktop/ │ ├── org.visidata.VisiData.metainfo.xml │ └── visidata.desktop ├── editor.py ├── errors.py ├── experimental/ │ ├── __init__.py │ ├── daw/ │ │ ├── CLAUDE.md │ │ ├── README.md │ │ ├── TODO.md │ │ ├── __init__.py │ │ ├── merge_transcripts.py │ │ ├── mpv.py │ │ ├── vdaw.py │ │ └── xmd2json.py │ ├── diff_sheet.py │ ├── digit_autoedit.py │ ├── gdrive.py │ ├── google.py │ ├── gsheets.py │ ├── helloworld.py │ ├── live_search.py │ ├── liveupdate.py │ ├── llm.py │ ├── mark.py │ ├── noahs_tapestry/ │ │ ├── __init__.py │ │ ├── clues.json │ │ ├── flame.ddw │ │ ├── menorah.ddw │ │ ├── puzzle0.md │ │ ├── puzzle1.md │ │ ├── puzzle2.md │ │ ├── puzzle3.md │ │ ├── puzzle4.md │ │ ├── puzzle5.md │ │ ├── puzzle6.md │ │ ├── puzzle7.md │ │ ├── puzzle8.md │ │ ├── solutions.json │ │ ├── tapestry.ddw │ │ └── tapestry.py │ ├── rownum.py │ ├── slide_cells.py │ ├── sort_selected.py │ └── vimcompat.py ├── expr.py ├── extensible.py ├── features/ │ ├── __init__.py │ ├── addcol_audiometadata.py │ ├── addcol_histogram.py │ ├── canvas_save_svg.py │ ├── change_precision.py │ ├── cmdpalette.py │ ├── colorbrewer.py │ ├── colorsheet.py │ ├── command_server.py │ ├── currency_to_usd.py │ ├── customdate.py │ ├── dedupe.py │ ├── describe.py │ ├── expand_cols.py │ ├── fill.py │ ├── freeze.py │ ├── go_col.py │ ├── graph_seaborn.py │ ├── graph_zoom_y.py │ ├── hint_types.py │ ├── hlsearch.py │ ├── icon.py │ ├── incr.py │ ├── join.py │ ├── known_cols.py │ ├── layout.py │ ├── melt.py │ ├── normcol.py │ ├── open_config.py │ ├── open_syspaste.py │ ├── ping.py │ ├── procmgr.py │ ├── pypkg.py │ ├── random_sample.py │ ├── rank.py │ ├── regex.py │ ├── reload_every.py │ ├── rename_col_cascade.py │ ├── repeat.py │ ├── repl.py │ ├── replay_bulk.py │ ├── scroll_context.py │ ├── select_equal_selected.py │ ├── setcol_fake.py │ ├── slide.py │ ├── sparkline.py │ ├── status_source.py │ ├── sysedit.py │ ├── sysopen_mailcap.py │ ├── term_extras.py │ ├── transpose.py │ ├── type_ipaddr.py │ ├── type_url.py │ ├── unfurl.py │ └── window.py ├── form.py ├── freqtbl.py ├── fuzzymatch.py ├── graph.py ├── guide.py ├── guides/ │ ├── AggregatorsSheet.md │ ├── ClipboardGuide.md │ ├── ColumnsGuide.md │ ├── CommandsSheet.md │ ├── DirSheet.md │ ├── ErrorsSheet.md │ ├── FrequencyTable.md │ ├── GrepSheet.md │ ├── JsonSheet.md │ ├── MacrosSheet.md │ ├── MeltGuide.md │ ├── MemorySheet.md │ ├── MenuGuide.md │ ├── ModifyGuide.md │ ├── MovementGuide.md │ ├── PivotGuide.md │ ├── RegexGuide.md │ ├── SelectionGuide.md │ ├── SlideGuide.md │ ├── SortGuide.md │ ├── SplitpaneGuide.md │ ├── TypesSheet.md │ ├── WindowFunctionGuide.md │ └── XsvGuide.md ├── help.py ├── hint.py ├── indexsheet.py ├── input_history.py ├── interface.py ├── keys.py ├── loaders/ │ ├── __init__.py │ ├── _pandas.py │ ├── api_airtable.py │ ├── api_matrix.py │ ├── api_reddit.py │ ├── api_zulip.py │ ├── archive.py │ ├── arrow.py │ ├── claude.py │ ├── conll.py │ ├── csv.py │ ├── eml.py │ ├── f5log.py │ ├── fec.py │ ├── fixed_width.py │ ├── frictionless.py │ ├── geojson.py │ ├── google.py │ ├── graphviz.py │ ├── grep.py │ ├── hdf5.py │ ├── html.py │ ├── http.py │ ├── imap.py │ ├── jrnl.py │ ├── json.py │ ├── jsonla.py │ ├── lsv.py │ ├── mailbox.py │ ├── markdown.py │ ├── mbtiles.py │ ├── msgpack.py │ ├── mysql.py │ ├── npy.py │ ├── odf.py │ ├── orgmode.py │ ├── pandas_freqtbl.py │ ├── parquet.py │ ├── pcap.py │ ├── pdf.py │ ├── png.py │ ├── postgres.py │ ├── psv.py │ ├── rec.py │ ├── s3.py │ ├── sas.py │ ├── scrape.py │ ├── shp.py │ ├── spss.py │ ├── sqlite.py │ ├── texttables.py │ ├── toml.py │ ├── tsv.py │ ├── ttf.py │ ├── unzip_http.py │ ├── usv.py │ ├── vcf.py │ ├── vds.py │ ├── vdx.py │ ├── xlsb.py │ ├── xlsx.py │ ├── xml.py │ ├── xword.py │ └── yaml.py ├── macos.py ├── macros.py ├── main.py ├── mainloop.py ├── man/ │ ├── parse_options.py │ └── vd.inc ├── memory.py ├── menu.py ├── metasheets.py ├── modify.py ├── motd.py ├── mouse.py ├── movement.py ├── optionssheet.py ├── path.py ├── pivot.py ├── plugins.py ├── pyobj.py ├── rename_col.py ├── save.py ├── search.py ├── selection.py ├── settings.py ├── sheets.py ├── shell.py ├── sidebar.py ├── sort.py ├── statusbar.py ├── stored_list.py ├── tests/ │ ├── __init__.py │ ├── benchmark.csv │ ├── conftest.py │ ├── sample.tsv │ ├── test_cliptext.py │ ├── test_commands.py │ ├── test_completer.py │ ├── test_date.py │ ├── test_edittext.py │ ├── test_features.py │ ├── test_fixed_width.py │ ├── test_keystrokes.py │ ├── test_menu.py │ ├── test_parsepos.py │ └── test_path.py ├── text_source.py ├── textsheet.py ├── theme.py ├── themes/ │ ├── __init__.py │ ├── adwaita.py │ ├── ascii8.py │ ├── asciimono.py │ └── light.py ├── threads.py ├── tuiwin.py ├── type_currency.py ├── type_date.py ├── type_floatsi.py ├── undo.py ├── utils.py ├── vdobj.py ├── vendor/ │ ├── __init__.py │ └── appdirs.py ├── windows.py └── wrappers.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .codespellrc ================================================ [codespell] skip = .git,*.pdf,*.svg,*.tsv,man,formats.jsonl,sample_data,*.cast,golden # some ad-hoc or less common word spellings or vars used # `F`requency and such ignore-regex = `[A-Z]`[a-z]+\b ignore-words-list = vertexes,wil,ned,parms,datas,sav,inport,miniscule ================================================ FILE: .devcontainer/Dockerfile ================================================ FROM python:3 ================================================ FILE: .devcontainer/devcontainer.json ================================================ { "name": "VisiData", "dockerFile": "Dockerfile", "extensions": [ "ms-python.python" ], "postCreateCommand": ".devcontainer/post-create.sh" } ================================================ FILE: .devcontainer/launch.json ================================================ { "version": "0.2.0", "configurations": [ { "name": "Python: vd launch", "type": "python", "request": "launch", "program": "${workspaceFolder}/bin/vd", "args": [ "-f", "pandas", "${workspaceFolder}/sample_data/benchmark.csv" ], "console": "integratedTerminal" }, { "name": "Python: vd attach", "type": "python", "request": "attach", "processId": "${command:pickProcess}" } ] } ================================================ FILE: .devcontainer/post-create.sh ================================================ #!/bin/bash make install-dev setup-vscode ================================================ FILE: .devcontainer/settings.json ================================================ { "python.pythonPath": "/usr/local/bin/python", "python.testing.pytestArgs": [ "visidata" ], "python.testing.unittestEnabled": false, "python.testing.nosetestsEnabled": false, "python.testing.pytestEnabled": true } ================================================ FILE: .gitattributes ================================================ www/asciinema-player.js binary ================================================ FILE: .github/FUNDING.yml ================================================ github: saulpw patreon: saulpw ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create an issue if anything doesn't appear to be working right. title: '' labels: bug assignees: '' --- **Small description** **Data to reproduce** [Please include a small amount of sample data that demonstrates the issue.] **Steps to reproduce** [If the issue takes more than a few commands, please attach a [saved commandlog](http://visidata.org/docs/save-restore/).] **Expected result** **Actual result with screenshot** [If there is an error message, please include the full stack trace shown with `Ctrl+E` or `vd --debug`.] **Configuration** - Does this issue reproduce without any plugins or configuration (using the `-N` CLI flag)? - Does this issue reproduce with either the [latest release](https://www.visidata.org/releases/), or with the [develop branch](https://www.visidata.org/install/#update-visidata-from-an-existing-installation)? **Additional context** - What platform and version are you using (Linux, MacOS, Windows)? - Which version of Python? - Which terminal are you using (for display and input issues)? ================================================ FILE: .github/ISSUE_TEMPLATE/feature-request.md ================================================ --- name: Feature request about: Provide feedback on how you want VisiData to grow in the future. title: '[] ' labels: wishlist assignees: '' --- We want to hear your ideas about where VisiData can go and anything you think could be made smoother. We consider all ideas that are feasible, but please don't be offended if we close it--we generally limit our open issues to bugs and small concrete feature requests that are part of the planned roadmap. If you want to propose a command, please include: - [] what should the helpstring say - [] where should this command go in the menu system ================================================ FILE: .github/ISSUE_TEMPLATE/loader-request.md ================================================ --- name: Loader request about: Suggest a loader that supports a new data format title: "[loader] " labels: feature request assignees: '' --- We love to build loaders with people that are familiar with the format and how it is used. Knowing about quirks and variations and usage-in-the-wild is very hepful. To that end, a new loader can be created quite quickly with the following: 1) A small sample representative dataset in that format. 2) A basic Python script which queries and dumps the data (possibly using an external package). ================================================ FILE: .github/ISSUE_TEMPLATE/question.md ================================================ --- name: Question about: Ask a question you have about VisiData. title: '[question]' labels: question assignees: '' --- If you think your question would benefit from input from anyone in the community (e.g. 'How do I X in VisiData') consider [opening a Discussion instead](https://github.com/saulpw/visidata/discussions/new/choose). If you think it would benefit from a more synchronised back-and-forth with Saul, consider joining us in libera.chat (#visidata) or [discord](https://bluebird.sh/chat). ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ - [ ] If contributing a core loader, [the loader checklist](https://visidata.org/docs/contributing#loader) was referenced. - [ ] If registering an external plugin, [the plugin checklist](https://visidata.org/docs/contributing#plugins) was referenced. ================================================ FILE: .github/workflows/main.yml ================================================ name: visidata-ci-build on: pull_request: branches: - stable - develop push: branches: - stable - develop jobs: full-tests: strategy: matrix: python-version: ["3.9", "3.14"] runs-on: ubuntu-slim timeout-minutes: 20 steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} cache: 'pip' - name: Install VisiData with test dependencies run: make install-test - name: Run tests run: make test unit-tests: strategy: matrix: python-version: ["3.10", "3.11", "3.12", "3.13"] runs-on: ubuntu-slim timeout-minutes: 10 steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} cache: 'pip' - name: Install VisiData with test dependencies run: make install-test - name: Run unit tests run: make test ================================================ FILE: .github/workflows/vdsql.yml ================================================ name: vdsql-testing on: pull_request: branches: - stable - develop push: branches: - stable - develop jobs: run-tests: strategy: matrix: python-version: ["3.10", "3.14"] runs-on: ubuntu-slim steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.pythonversion }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install VisiData run: make install - name: Install vdsql run: pip3 install visidata/apps/vdsql/ - name: Ensure it starts up run: vdsql --version - name: Run tests run: make test-vdsql ================================================ FILE: .github/workflows/vgit.yml ================================================ name: vgit-testing on: pull_request: branches: - stable - develop push: branches: - stable - develop jobs: run-tests: strategy: matrix: python-version: ["3.9", "3.10", "3.11"] runs-on: ubuntu-slim steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.pythonversion }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install VisiData run: make install - name: Install vgit run: pip3 install visidata/apps/vgit/ - name: Ensure it starts up run: vgit --version - name: Create visidatarc run: touch ~/.visidatarc - name: Import vgit run: echo "import visidata.apps.vgit" >> ~/.visidatarc - name: Run tests run: make test-vgit ================================================ FILE: .gitignore ================================================ __pycache__ .tox/ .idea/ .vscode/ visidata.egg-info/ *.egg-info/ *v_env* *~ *.swp *.swo *dist *_build build/ tags /tests/log/ # Mac files .DS_Store .direnv .envrc .meta # Generated man pages (run `make man` to build) visidata/man/vd.1 visidata/man/visidata.1 visidata/man/vd.txt docs/man.md ================================================ FILE: .gitmodules ================================================ [submodule "deps/pyxlsb"] path = deps/pyxlsb url = https://github.com/saulpw/pyxlsb.git [submodule "deps/requests-cache"] path = deps/requests-cache url = https://github.com/saulpw/requests-cache.git ================================================ FILE: .gitpod.Dockerfile ================================================ FROM python:3 ================================================ FILE: .gitpod.yml ================================================ image: file: .gitpod.Dockerfile tasks: - init: pip install -r ./dev/requirements-dev.txt && pip install -e . ================================================ FILE: .mailmap ================================================ # .mailmap - Consolidate git author identities # See: https://git-scm.com/docs/gitmailmap # # Format: Canonical Name Old Name # Lines map alternative identities to canonical form for git shortlog, blame, etc. # AJ Kerrigan AJ Kerrigan AJ Kerrigan # Anja Kefala Anja Kefala anjakefala Anja Kefala anjakefala Anja Kefala Kefala Anja Kefala # David Branner (was misconfigured as "Your Name") David Branner Your Name # geekscrapy (also committed as molley) geekscrapy molley geekscrapy # pacien pacien # Saul Pwanson Saul Pwanson saulpw Saul Pwanson Saul Pwanson ================================================ FILE: .theia/settings.json ================================================ { "python.testing.pytestArgs": [ "visidata" ], "python.testing.unittestEnabled": false, "python.testing.nosetestsEnabled": false, "python.testing.pytestEnabled": true } ================================================ FILE: AGENTS.md ================================================ # Repository Guidelines ## Start Here (Progressive Disclosure) - Read `CLAUDE.md` first for the primary contributor workflow and architecture context. - Use focused deep dives only when needed: - `dev/STYLE.md` for coding patterns and API conventions. - `dev/GIT.md` for commit and branch practices. - `dev/DOCS.md` for documentation syntax and style. - `dev/PERFORMANCE.md` for profiling and optimization work. - Human gate is required: all AI-assisted code must be reviewed, approved, and tested by a human before merge or PR. ## Project Structure - `visidata/`: main package (`features/`, `loaders/`, `apps/`, `themes/`). - `tests/`: functional replay tests (`.vd/.vdj/.vdx`) and `tests/golden/` outputs. - `visidata/tests/`: Python unit tests. - `docs/` and `dev/`: user and developer documentation. ## Build, Test, and Development Commands - `python3 -m pip install .`: install local package. - `python3 -m pip install ".[test]"`: install optional test dependencies. - `vd --version`: startup sanity check. - `pytest -sv visidata/tests/`: run unit tests. - `dev/test.sh -j 4`: run functional cmdlog tests and compare `tests/golden/`. - `vd . --batch`: quick load smoke test. ## Coding and Command Conventions - Follow `dev/STYLE.md` for naming, quoting, decorators, and sheet/column patterns. - Use the canonical command pattern shown in `CLAUDE.md`: - `BaseSheet.addCommand('', 'command-name', 'code', 'help text')` - For class placement decisions and exceptions, defer to `dev/STYLE.md`. ## Testing Guidelines - Update `tests/*.vd*` for workflow-visible behavior changes. - Update `visidata/tests/` for isolated Python logic. - Before PR: run `pytest -sv visidata/tests/` and `dev/test.sh -j 4`. ## Commit & Pull Request Guidelines - Base PRs on `develop` (not `stable`). - Follow existing short, imperative subjects; optional scope prefixes like `[test]`, `[docs]`, `[vdsql]`. - Keep commits focused and include tests/docs for behavior changes. - PRs should include problem, approach, risks, and linked issues; add screenshots/gifs and reproducible `.vd` scripts for UI changes. - Follow CAA and copyright assignment requirements in `CONTRIBUTING.md`. ================================================ FILE: CHANGELOG.md ================================================ # VisiData version history # v3.4 (unreleased) Thanks to @midichef for many bugfixes and improvements. ## New Features - [commands] add `define-command` and `document` for current row (#655) - [repl] add embedded ptipython REPL (#2736) - [edit] add `vd.editCellBindings` for user-customizable cell editing keybindings (#2986) - [keys] prettykeys overhaul: all bindings now use human-readable key names (#2594) - [selection] add `select-to-prev-selected` and `select-to-next-selected` commands - [profile] add `--profile` flag for main thread profiling - [vimcompat] add vimcompat experiment with go-page-half bindings @daviewales (#2927) - [packages] add Python packages sheet - [daw] add vdaw: experimental transcript-based audio editor - [colors] add conversion functions to/from xterm256 ## Improvements - [column] add `color_readonly` option; better status for non-writable columns (#2936) - [column] mark expanded columns and custom columns as writable (#2936) - [edit-cell] fail early on readonly column (#2936) - [input] add Ctrl+Bksp, Alt+Bksp, Alt+d bindings (#2500) - [keys] add Ctrl+Shift+Up/Down and Alt+NumPad prettykeys - [cmdlog] expose CommandLogJsonl (#2940) - [indexsheet] bind cancel row to zCtrl+C (#2938) - [menu] add show-cursor and show-expr (#2848) - [dedupe] enable custom sheet name suffixes - [incr] use setValuesTyped to allow setting of non-numeric columns - [modify] add Progress to setValuesTyped - [movement] add go-screen-* commands (#2797) - [graph] accept refline input for multiple xcols; better error checking - [graph][seaborn] add title and axis labels @meestahp - [aggregator] show summary labels in first non-aggregated column if right edge not on screen - [types] add numtype, use for avg/median aggregators @pequiste (#2868) - [aggregators] copy formatter/displayer col attrs to AggrColumn - [aggregators] preserve type returned by mean/avg/median instead of coercing to int @pequiste - [icons] show icons with sheets: Dir, FreqTable, Graph - [canvas_text] add maxXY from darkdraw, fix g sliders - [clipboard api] add get/setClipboardRows and get/setClipboardCols - [help] refer to visidata clipboard as "internal clipboard" (#2864 #2865) - [memory] move open-memos to BaseSheet - [mouse api] add vd.enableMouse; ignore if no curses.mousemask (#2913 #2851) - [config] respect XDG_CONFIG_HOME and XDG_CACHE_HOME on macOS @maxim-uvarov-ai-assistant - [xdg] use user_data_dir for StoredLists like input_history (#2889) - [statusbar] make lstatus_max truncation preserve vd markup (#2908) - [shell] add options.max_threads for asynccache used by addcol-shell - [asynccache/shell] make asynccache/addcol-shell thread-safe and runnable in macros and replay (#2826) - [xlsx] add hlink/folHLink to color list (#2948) - [syscopy] add cursorFullDisplay for complex objects (#2806) ## Loaders - [vdsql] add postgres_schema option to show tables from multiple schemas (#2027) - [vdsql] show SQL in sidebar (#2200) - [vdsql] aliases for .ddb, .sqlite, .db (#2259) - [vdsql] bump ibis version (#2410 #2682) - [vdsql] fix join compatibility with Ibis >= 9.0 @terencelaurent (#2899) - [airtable] update loader to work with latest pyairtable library @mplattner - [conll] update loader to work with pyconll v4.0 - [eml/pcap] enable loaders for mhtml, cap, pcapng, ntar file types - [html] for # of header rows, use options.header - [mysql] fix connecting with no password @pequiste - [http] add default user agent (#2880) ## Bugfixes - [pandas] fix loader bugs @weichm (#2968) - [mainloop] do not exit if rightstatus throws an exception - [mainloop] reset numTimeouts when there are unfinishedThreads @iamleot (#2931) - [canvas] delete in linear time instead of quadratic - [canvas] properly handle labels containing markup - [column] fix col width calc for data with markup - [column] fix width that formatValue used for list/dict/tuple - [loaders] stop truncating markup in fixed-width data - [column] stop truncating col names holding markup - [input] fix cursor x when editing data with markup - [input] fix use of rowidx before it is set - [input] fix perf pegging cpu (#2911) - [input] allow editing header of readonly column - [palette] when no choices match, show warning on Enter - [palette] align choices with prompt before Tab is pressed - [palette] clarify that TAB precedes ENTER - [settings] prevent lockup when keystroke is same as longname - [mainloop] for bindkey cmd, show longname in fail msg; catch fail() from execCommand - [repeat] use queueCommand instead of replayOne (#2932) - [popen] kill leftover processes that have NOT finished - [exit] kill subprocesses before os._exit - [modify] clear modified status after load to prevent overvigilant quitguard - [cmdlog] replay commands on hidden columns (#2849) - [cmdlog] make vdj shebang work on macOS @ilyagr (#2870) - [status] do not show previous longname after unbound key (#2779) - [join] fail on concat of sheets with unequal # of cols - [sync] mark finished thread reliably with endTime - [freqtbl] disable paste-before and paste-after - [path] remove progress in iter (#2323) - [path] handle filenames ending in . in Python 3.14 (#2887) - [macro] fix vd attempts to use deleted macros @haoyeau (#2893) - [clipboard] fix wrong api usage - [http] fix default user agent (#2880) - [canvas] fix division by zero when col's only value is a large float (#2884) - [movement] fix desc of scroll-up/down/left/right amount - [fuzzymatch] stringify non-str values - [debug] do not avoid cleanup if options.debug - [aggr] catch nonexistent aggr in addcol-aggregate - [reload] reload_or_replace function should be on BaseSheet - [open-row] allow pandas to open row as sheet (#2925) - [postgres] unquote url.password in postgres loader @egwynn - [theme] remove nonexistent color from light theme - [shell] move open-row from incorrect Open toplevel menu - [mainloop] fix undo of first user alteration to a replayed cmdlog - [curses] fix crash on startup on NetBSD wscons tty consoles @rsmirnov90 (#2851) ## API - [threads] add asyncsingle_queue decorator # v3.3 (2025-09-07) - added options.disp_help_flags; deprecated options.disp_expert - these feature flags are supported: cmdpalette hints nometacols guides inputkeys inputfield all - see helpstr for more details - set option to '' to turn off all help overlays - fix: include missing files in MANIFEST.in @chenrui333 Thanks to @midichef for most of the other bugfixes and improvements. ## Improvements - [csv] auto-detect CSV format when csv_delimiter is specified @dennisangemi - [basesheet-] start new column names fresh for each sheet - [form-] after confirm, Esc/^C/^Q/q show disconfirm msg - [cmdpalette-] add instruction to use Esc to cancel - [cmdpalette-] keep case of results, allow case-sensitive search - [cmdpalette-] scroll choices with PageUp/PageDown - [cmdpalette-] hide choices that do not match input - [save-] suggest 'stdin' as filename base instead of '-' - [sheets-] on reload, fetch fresh data for URLs - [tar-] add cols for ext and file type desc, use name as keycol - performance improvements - display improvements ## Bugfixes - [archive-] fix extracting to a chosen path - [archive-] fix error extracting to overwrite existing file - [archive-] fix loading zip files from inside archive files - [cliptext-] fix display of empty markup as several blank lines - [cliptext-] restore display translation of unprintable chars - [sheets-] remove calcSingleColLayout use of inaccurate visibleRows - [plugins liveupdate-] fix broken addcol-new - [curses-] fix crash on startup on NetBSD (and probably other \*BSD) wscons tty consoles, which do not expose "mousemask" in their system curses implementations. @rsmirnov90 - [input-] fix editText for files on command line with -b -i -p (#2840) - [plugin-] fix autoload for Python versions < 3.10 - [macro-] fix corruption when saving macros after deletion #2787 - [reload-] wait for any previous reload_rows to finish #2808 - [resize-] fix resize-col-half for new columns with no rows #2795 - [sheet-] fix reload on sheets without col layout #2790 - [status] fix error when no help_sidebars ## Cosmetic - [freqtbl-] stop printing status for selection on source sheet - [input-] handle screen resize during inputMultiple(), editCell(), input() # API - [threads-] add asyncsingle_queue decorator # v3.2 (2025-06-15) Thanks to @midichef for many bugfixes and improvements. ## Improvements * [config] XDG for default visidata_dir #2716 (#2755) - [dev] add Python 3.13 test coverage - [windows] install vd.cmd #2619 @ptyork * [windows] Enable Windows clipboard in WSL #1920 @daviewales - [windows] update windows-curses version to 2.4.1 #2119 * [windows] fix mouse support #2676 @ptyork - [sort] allow z[ and z] to reverse col sort dir or ignore col - [sort] replay sort-add/-change ordering from cmdlog input arg - [sort] add sort order to ColumnsSheet #2649 * [loaders psv] add simple .psv loader based on Tsv sheet #2727 * [loaders numpy] support 2d matrices (#2724) @maxfl ### Commands * [aggr] addcol-aggregate and addcol-rank-sheet - [edit] add sysedit-cell command, using external editor - [errors] add sysopen-error command to view vd source code in editor - [freeze] add setcol-freeze, bind to z' #2260 - [graph] add zoom-all-y #2751 - [join] add per-jointype commands #2603 - [layout] bind g- to hide-uniform-cols #2577 #2735 - [syscopy] add syscol-colname #2760 ### Options - [draw] add options.color_multiline_bottom #2715 - [graph] add options.color_graph_refline - [disp] Rename options.disp_pixel_random to options.disp_graph_pixel_random @cool-RR ### Tweaks * [cmdpalette-] fix scoring of space-separated search terms * [cmdpalette-] make fuzzy match case-insensitive * [docs] Add WindowFunctionGuide and AggregatorSheet guides #2558 @thejud * [theme] update light theme #2729 * [status] remove non-precious sheets from sheetlist #2573 - [input-] fix word locator for Ctrl+Right motion - [input-] allow edit of cell in hidden column #2749 - [errors-] make ErrorSheet/ErrorsSheet into singletons - [threads-] make threads-all show a singleton sheet - [threads-] allow repeated toggling of profiling - [IndexSheet] move gC and gI to IndexSheet #2603 - [main-] enable cell editing for interactive batch mode #2639 - [loaders hdf5] guess types(hdf5), understand unsigned int type @maxfl - [loaders archive,sqlite-] guess sqlite/tar/zip filetypes confidently - [loaders vds-] save/restore column-specific properties via getstate/setstate #2699 ## Bugfixes - [aggr-] allow undo for aggregate-col/cols - [aggr-] cap runtime when formatting memo status - [canvas-] stop infinite refresh for graphs with many points - [cmdlog-] save prev replay when starting new replay #2531 - [deprecated-] show warning when using deprecated commands #2215 - [features-] reload_every: wait for reload before looping - [features-] sysedit: modify cell only if editor changes value (#2656) * [freqtbl-] fix excessive memory usage for undo of selections #2759 - [incr-] addcol-incr-step as expected #2769 - [input-] preserve None cells on external editor quit - [join-] fix putValue for merge rows absent in any source sheet - [layout-] change resize-cols-max into a toggle #2782 - [macro-] only record commands that are replayable - [mailcap] install dead battery for mailcap in python 3.13 #2576 - [main-] prevent hang when vd -p - reads from terminal - [npy-] fix bug truncating cols wider than window #2783 - [open-] fix open-file for - in cmdlogs #2582 - [open-] fix opening a dir with an filetype extension - [reload-] have reload-modified check for earlier changes #2551 - [save-] fix error string - [sheets-] record key-col toggle for replay as key-col-on/-off - [sort-] fix undo when sheet has a previous ordering - [undo-] fix undo editing cells in ValueColumn, ExpandedColumn, ColumnSourceAttr #2765 - [vdsql-] ensure each thread in vdsql tracks its single connection ## Cosmetic - [cliptext-] truncate sheet names handling full-width chars - [column-] do not rjustify non-numeric values #2750 - [csv-] warn when guessed option differs from default #2690 - [dir-] sort by filename, after sorting by modtime - [errors-] fix error-recent always showing "no error" - [fixed loader] use empty str for null_value in fixed width sheet - [form-] fix underlining of substrings by FormCanvas - [help- sidebar-] prevent sidebar flicker #2630 - [help] fix duplicate help descriptions #2762 - [input-] fix editline() for characters having screen width > 1 - [input-] speed up pasting long strings into line editor - [input-] fix off-by-1 when drawing at right edge of screen - [main-] format vd_cli exceptions to be caretless - [menu-] remove duplicate Help entry #2714 - [menu] replace hint with motd - [reload-] tolerate stale columns in drawcache during allAggregators #2607 #2763 - [save-] warn if no save destination given #2580 - [status] use sheet.icon on sheetlist #2772 - [threads-] catch error trying to start a second profiler # v3.1 (2024-10-14) - drop support for Python 3.7 #2231 - [vdsql] bump ibis dep to v8 - [test] fix minimum pandas version to 1.5.3 ## Improvements - [sidebar] Ctrl+G to cycle sidebar (including off) in both main and input modes #2202 - [sidebar help] rightmost statusline ({vd.sidebarStatus}) shows number of help sidebars (clickable to toggle sidebar) - [sheet tabs] left statusline sheet tabs (clickable to jump to sheet) #2030 - [aggregators] immediate async summary of column aggregators on bottom rows #2209 - [graph] reflines at user-defined x or y #2487 - [guides] add several guides (thanks to @thejud @reagle @ajkerrigan @anjakefala) - [expressions] much cleanup - `row["colname"]` to refer to a specific column by name, without needing to be a valid identifier #2539 - `_row` is underlying row object - support curcol in g= and select and search expressions #2524 - $curcol for addcol-sh - globals include most symbols from math by default; also datetime and date both as the vd.date subclass - [input] memory variables included as autocomplete keys #2509 ## Tweaks - [history] create visidata_dir (default ~/.visidata/) if not exists to enable input history by default #2298 - [cli] "-p -" replays stdin as a .vdj file - [guide] allow front matter in guide .md files; "sheettype" metadata to associate with a sheet - [cmdpalette] do not fuzzymatch keys that start with _ - [interface] hidden columns minutely visible past right of sheet; `_` to re-expand #2394 - [interface] record all commands in macro (even replay=False); add status indicator when recording #2435 - [interface] clickable cell error symbol - [interface] default theme color improvements, including a slight bg glow for cursor column - [aggregators] add keymin; handle corner cases #2308 - many small interface improvements: error messages, clarifications, edge cases, guardrails. (thanks to @midichef for many of these) ## Options - max_rows to stop loading early #2356 - [xlsx] add xlsx_color_cells (default: True); set to False to disable xlsx cell colorizers - regex_skip is now replayable - disp_multiline_focus to only expand cursor row when multiline enabled #2205 - disp_expert (int); set to 1 to enable advanced interface elements and unhide advanced columns by default; set to 5 (or greater) to disable input palette and help sidebars - pass disp_wrap_* to textwrap for multiline display #2506 - rename note_* to disp_note_* #2381 - separate color_longname into color_longname_status and color_longname_guide ## Commands - addcol-histogram to make histogram from any numeric column #2208 - exec-longname-simple for single-line (non-palette) input - go-col-name to go to a column by name - [dir] open-row-filetype to open row using the given filetype - [graph] plot-source-selected on ColumnsSheet #2424 - [experimental] sort-selected-asc/desc #2295 - deprecate view-cell #2381 - unfurl finishes with column cursor on unfurled column ## API - [command] addCommand(..., replay=False) to not add to cmdlog - [sort] add Sheet.ordering property as list[tuple[Column,bool]] #2295 - [path] note nonstandard behavior of RepeatFile.read() - [input] allow different record kwarg for different fields in inputMultiple ## Loaders - [msgpack] new loader #2419 - [grep] new loader for output of grep/ripgrep #2443 - [csv] display loading/saving progress - [csv] handle more dialect parameters from Sniffer - [csv tsv] remove default regex_skip of hash lines #2458 - [eml] save email parts without filenames #2376 - [fixed] skip separating space in fixed_width loader #2255 - [json] remove column type inference #2475 #2131 - [json] warn if some cols/sheets were not saved #2199 - [markdown] use col_href as link for col - [ods] strip empty cells/rows from end #2440 - [rec] roundtrippable - [sas] allow edits to source sheet - [save] derived null in text formats should be empty string #2476 - [save] handle empty delimiter when options.safety_first - [text] do not strip lines of whitespace #2328 - [tsv] allow empty regex_skip - [tsv] allow saving with NUL delimiters - [tsv] if field or row delimiter is NUL, disable regex skipping - [vds] allow sheets with no rows #2342 - [xml] save XML as utf-8 instead of utf-8-sig #2520 ## Bugfixes - [command] addcol-sh: ensure arguments are properly quoted #2415 - [selection] make toggle thread-safe for FreqTableSheet #1671 - [undo] prevent undo of command that created sheet #2244 - [undo] cmdlog always use rowidx, not rowkey #2246 - [cliptext] fix onclick url #2466 - [mouse] fix mouse-disable #2379 - [sort] do not modify Sheet._ordering #2254 - [bindings] do not re-prettykeys; call prettykeys for all bindkey() too #2247 - [terminal] add no-op for ANSI focus-in and focus-in #2247 - [sort] add _ordering to Sheet class instead of __init__ #2190 - [transpose] allow to set values #2548 - [sheet] make 20 tabs clickable #2030 - [macro] do not record macro inner steps #2531 - [filetype] use correct case for file extension determination #2263 - [replay] stop stderr batch progress when interactive #2251 - [replay] wait for replay to start before stderr progress #2251 - [replay] fix rare duplication of replay cmds #2392 - and many more # v3.0.2 (2024-01-15) ### Fixes and minor improvements - [cli] add `--guides` to open the guide index - [cmdpalette] only first 10 suggestions should have shortcut keys #2242 - [draw] use default bg on col hdr sep - [input] draw help sidebar on top of sheet/updater #2241 - [graph] sort by x and y columns when diving (PR by @midichef #2226) - [guides] improve formatting of command and options in sidebar + guides - [replay] stop stderr batch progress when entering interactive mode #2251 - [shell] clean up DirSheet sidebar - [sidebar] grab user's keystroke of sidebar-toggle for helpstring #2250 - [sort] a better fix for maintaining sort ordering on sheet copies #2190 #2254 - [tests] add "test" extras for installing PyPI packages needed to run tests # v3.0.1 (2024-01-07) ### Fixes and minor improvements - [color] add `color_longname` to use instead of `color_keystrokes` #2219 - [columns] add `displayer` attribute to saved column state - [cmdpalette] Enter executes first row, if partially typed out #2219 - [cmdpalette] add sidebar for longname and aggregator palette #2219 - [guide] add `show-command-info` to display command info for a keystroke #2228 - [keys] add `*BtnUp` pretty keys for `BUTTON#_RELEASED` #2219 - [dup-selected] dup-selected should unselect all rows in copied sheet #2225 - [expr] fix KeyError crash with invalid inputs in `expr` for Python 3.12 #2179 - [help] fix columns sheet sidebar - [loaders html] ignore parsing exceptions on invalid urls #2227 - [sheets] limit end separators to rightmost visible column of sheet (PR by @midichef #2237) - [sidebar] fix fmtstr for case where source is BaseSheet #2239 - [sort] maintain ordering on sheet copies #2190 - [test] update unit tests to use packaged sample.tsv and benchmark.csv #2218 - [threads] do not try to cancel already finished thread #2235 - [tests] add `assert-expr` and `assert-expr-row` to evaluate Python expressions, and assert result is truthy - [tests] parametrize feature tests (PR by @ajkerrigan #2230) # v3.0 (2023-12-30) - [reorg] move independent modules into visidata/{features|experimental|themes} - [sidebar] add sidebar #2064 - #1733 for full description/discussion - will contain a stack list of status messages - color syntax is [:bold]footext[/] - supports `[:code]`, `[:bold]`, `[:italic]`, `[:underline]`, `[:onclick]` (makes a clickable link), `[heading]` - [:] at terminal clears; [/] at terminal pops - supports basic markdown for colouring - toggle with `sidebar-toggle` (bound to `b`) - make bottom msg entirely clickable - make dedent and header parsing standard - add `options.disp_sidebar` - make sheet name clickable to open **Sheets Stack** - make options clickable - add `open-sidebar` (bound to `gb`) to open sidebar in new sheet - display sheet and feature help documentation in sidebar - added bundles of Guide Sheets - open Guide Sheets into a full VisiData sheet with `Enter` - added `options.disp_help` (default: 2), an integer and to set novice/expert mode. (#1961) When `disp_help` is: - -1: status messages aren't shown - 0: no help is shown - 1: sidebar sheet help is shown - 2: help is shown for the input widget on the sidebar (this was condensed and moved from the former input help panel) #2085 #1961 - put input help on sidebar; `disp_help` from -1 to 3 - mark options to be excluded if `disp_help` greater than `option.max_help` - add contextual help while editing options in **OptionsSheet** - `Ctrl+G` cycles input help sidebar - [guide] add GuideIndex toc and open-guide-index - add guides for macros, selection, errors - [filetype] add guesser to sniff filetype from data #130 #1759 #1881 #1880 #1883 #1978 - add support for Python 3.12 #1934 - migrate pkg_resources to importlib_resources (PR by @zormit and @anjakefala #1968 #1911) - [threads] no new threads while prev cmd still running #1148 - [batch] add progress every half second to batch mode #1182 - [replay] implemented a single-thread replay mechanism #1575 #2102 - much simpler architecturally, but loses the ability to pause/resume, and show 1/N progress (now just shows number of queued commands remaining). - replay in general should be more stable and possibly faster. - Ctrl+N is now no-op for similar functionality to replay-advance - replay-advance command itself is removed - removed options.replay_movement and its functionality - options.replay_wait (-w on CLI) now works by setting the curses timeout, which will affect the display update frequency for all async commands. previously was hard-coded. try -w 0.001 while loading a big file to see a very rapid update. - add options.overwrite='n' mode #1805 - replace `options.confirm_overwrite` with `options.overwrite`, which can be 'n' (no/never), 'y' (yes/always), 'c' (confirm) - add vd.confirmOverwrite() - inputPath/inputFilename will not suggest the existing value or complete filenames if overwrite not y or c - add --ro/--readonly cli flag (opposite of existing -y) - add [RO] readonly marker on right status after [M] modified - add command palette (PR by @moritz #2059 #247) - press Space to exec command by longname and bring up command palette - type to match by longname and/or description - uses fzf's fuzzymatch algo - press Tab/Shift+Tab to cycle through commands #2154 - Enter to execute highlighted command - 0-9 to execute numbered command - `options.disp_cmdpal_max` for number of suggestions - `options.color_cmdpalette` for base color - `chooseAggregators` and `jointype` also use palette #1027 #2195 - chooseAggregators still allows selection of multiple aggregators - `options.color_match` is color for matching chars in palette chooser - convert input history to use StoredList #2142 - rename lastInputs.jsonl to input_history.jsonl #2142 - remove `options.input_history` - will automatically record if `options.visidata_dir` exists - convert macros to use StoredList #2142 - cannot save macros if `options.visidata_dir` does not exist - rename `options.visidata_dir`/macros.tsv' to `options.visidata_dir`/macros.jsonl' - add vd2to3.vdx script to port from 2.x macros to 3.x macros - [aggregators] sum uses start value from type of first value for Python 3.8+ #1996 #1999 #2009 - [build] add a .desktop for VisiData #1738 - [choose] add type for join/aggregators history #2075 - [cli] add `-i` to run interactive mode after batch #1714 - [clipboard] implement a more universal paste that uses positional columns #1377 - [columns] add `setcol-precision-more` and `-less` #1609 #1650 - works on float, floatsi, currency, date columns - [commands] allow space-seperated keystrokes #2067 - [confirm] make yes/no buttons clickable #1740 #2075 - [cosmetic] standardize `__repr__` for sheets and columns (PR by cool-RR #2091 #1757) - [describe] default width=10 for describe columns - [dir] set name of '.' to current dir name #1775 - [dir] set name relative to previously loaded directory #1775 - [dir] get default save name from sheet name #1775 - [dir] rename `options.dir_recurse:bool` to `options.dir_depth:int` #1715 - [display] add `resize-height-input` (`zv`) and `resize-height-max` (`gzv`) #1307 - [encoding] use `options.save_encoding` for lsv, geojson, texttable savers - [encoding] change default options.encoding to utf-8-sig to detect/remove BOM #200 #908 #909 #1711 - [expand] change default depth of expand-col(s)-depth to 0 (PR by @cool-RR #1809) - [expand] change sampling warning to aside #1054 #2066 - [expand] ignore non-cursor types in mixed-type columns - [features] procmgr to view/manage processes, memory/cpu stats - [features] ping to traceroute a hostip - [features] add `addcol-histogram` #2052 - display a histogram-like column for any column of ints - [features] add `contract-cols-depth` etc (bound to `g)`, `z)`, `gz)` #1695 - [features] add contract-source-cols bound to ) #1702 - [features] reload-modified calls `reload_rows`, adding support for tail #1686 - [features] add `addcol-audiometadata` from vmutagen plugin - adds metadata column for audio files - [features] to **DirSheet** add `sysopen-mailcap` - opens using mailcap entry for current row, guessing mimetype - [features] add `addcol-source` to add current column to source sheet #988 - [features] incorporate dedupe plugin by @jsvine - `select-duplicate-rows` selects each row in current sheet that is a duplicate of a prior row - `dedupe-rows` pushes a new sheet with only non-duplicate rows of current sheet - [features] incorporate normcol (by @jsvine) - `normalize-col-names` normalizes the names of all *non-hidden* columns - [features] add server to listen for commands on `options.server_addr` and `options.server_port` (if set) - [features] add Sheet.knownCols to preconfigure of columns by name #1488 ``` Sheet.knownCols.timestamp.type = date DirSheet.knownCols.directory.width = 0 ``` - [freq] add select-first command - [freq] base histogram width on column width #1807 - [freq] set default disp_histogram to U+25A0 BLACK SQUARE (■)) (PR by @daviewales #1949 #1807) - [themes] ascii8 disp_histogram to * - [freq] add `open-preview` for split pane of source rows at cursor #1086 - [graph] colorbrewer palette chooser (thanks @er1kb) - [graph] add commands to open external graph with matplotlib #1056 - [help] remove `Enter` binding for **HelpSheet** to `exec-command` - [history] remove cmdlog_histfile - [input] change `Ctrl+G` to toggle `options.disp_help` - [input] add `Ctrl+N` to insert prettykeys of literal keystroke - [input] allow percentage of starting value for input into commands - [input] `inputMultiple` saves/remembers dict input - [input] `Tab`/`Shift+Tab` move left/right in edit-mode like excel #2169 - [join] allow selecting of join columns from all columns sheet #1224 - unbind `&` for **ColumnsSheet** `join-cols` - [join] join now works with typed values, not display values #2015 - [join] improve warning for typing source key columns before joining #2117 - [join] clarify ensureLoaded status message #2137 - [keys] add shifted function prettykeys (Ctrl+Shift+F1 etc) - [layout] stop errors: hide-col on empty sheet, inputMultiple (PR by @midichef #1963) - [linux] change default system clipboard cmd to wl-copy if the user is using wayland (PR by @rj1 #1763) - [loaders] add `options.regex_skip` for text formats to allow e.g. comment skipping #1559 - Added default values for `regex_skip` to existing source sheets like tsv/csv/lsv/json/jsonla. - Use --regex-skip='' (or otherwise set the option to '') to disable this behavior. - [loaders] add mailbox formats mbox/maildir/mmdf/babyl/mh loader (as supported by Python mailbox stdlib) - [loaders] .jrnl format (jrnl.sh) loader+saver - [loaders] add reddit API loader - [loaders] add matrix API loader - [loaders] add orgmode loader - [loaders] add scraper - table of HTML elements as parsed by `beautifulsoup4` - [loaders] add Parquet writer (PR by @mr-majkel #2053 #2044) - [loaders] add s3 loader (built by @ajkerrigan) - open Amazon S3 paths and objects - [loaders] add support for jsonla (JSONL arrays) format (PR by @daviewales #1730) #1726 - [loaders] add zulip API loader - [loaders] add airtable API loader - [loaders] add .fec loader by @jsvine - [loaders] add f5log loader by @bitwisecook - [loaders] add a toml loader (PR by @ajkerrigan #1894 #1580 #1587) - [loaders] add .conll loader by @polm - [loaders html] display title/aria-label/caption/summary (PR by @midichef #2146) - [loaders http] replace requests with urllib #1808 #1704 - [loaders http] guess filetype based on magic bytes #1760 - [loaders jsonl] allow slash comments (PR by @geekscrapy #2025) - [loaders jsonl] deduce numeric column as float, not int #2131 #1698 - [loaders png] use 2x2 unicode blocks instead of braille - [loaders shell] allow deleting of directories unless `options.safety_first=True` #1965 - [loaders sqlite] save list/dict as json #1589 - [loaders sqlite] add `exec-sql` command to input query #1719 - [loaders xlsx] add cell colorizers from source #1718 - [loaders xlsx] add `column_letter` to meta columns - [loaders xml] ignore comments - [macros] allow deleting of macro with commit on **MacrosSheet** #1569 - [macros] add longname/keystrokes to **MacrosSheet** #1569 #1741 - [macros] add help sidebar to end macro input #1569 #1741 - [menu] move Edit>Add-rows to Row>Add - [menu] add `go-row-number` to menu #1766 - [menu] move commit-sheet under File>Save - [menu] add resize-cols-input to Columns -> Resize (PR by @njthomas #1887) - [modules] include module name in Option/Command sheets - [motd] default motd is "Support VisiData" instead of blank - [mouse] onclick with url launches $BROWSER with url; add `displayer_url` #2031 - [open] try using options.filetype for path #1710 - useful for configuring default filetype when reading from stdin - [open] add `reopen-last-closed` which reopens the most recently closed sheet (PR by @cool-RR #1813) #1811 - [open-syspaste] create new table from system clipboard #1680 - [open-syspaste] enable filetype selection (PR by @daviewales #1717) - [options] add `option.json_ensure_ascii` (default: True) (PR by @joaosousa1 #1776) #1772 - option for non-ASCII characters to be saved to JSON, on False will encode to utf-8 - [path] change most uses of Path.name to Path.base_stem #2188 - Path.name is the same as .base_stem for now - [plugins] remove external Plugins Sheet; only show installed plugins - [profile] dump profile to cwd when profiling enabled - [forms] provide help text for color, encoding, encoding errors, and regex #1961 - [reload] support tail with `reload-modified` #1686 - [reload] add `reload-rows` which preserves existing columns + cursor position #1655 #1683 #1663 - [melt] refactor to support `reload-rows` #2101 - [regex] use inputMultiple to allow changing regex_flags #1925 - [regex] use `inputRegex` (which has regex help) for all regex commands - [rename-col] add `options.rename_cascade` #2088 - if True, columns renames are cascaded into expressions - [replay] has been refactored to be sync, instead of a separate async process #1773 #1714 - [save] add `options.save_encoding (default: 'utf-8') to differentiate from `options.encoding` when saving a file #1708 - [save] add saver for STATA files (PR by @raffaem #1563) - [save] keep headers in txt as tsv if only one sheet and more than a single column #2173 - [save] add status when save finished #2157 - [selected] add `onclick` to "selection status" to quickly `dup-selected` - [sheet] add `select-equal-selected` (unbound) to select rows with values in current column in already selected rows #1327 - [sheet] add `clean-names` (unbound) to set options.clean_names on sheet and clean visible column names - [sheet] remove left-click for sheets-stack #2030 #1656 - [sheet] add `open-source` (bound to backtick) to open source sheet - [setcol-fake] add `setcol-fake` (unbound) adds a column of Faker generated 'faketypes' - [sparkline] add `addcol-sparkline` (unbound): adds a sparkline of all numeric columns - [status] downgrade sheet "finished loading" to debug - [tests] call all test_func(vd) defined in modules during pytest - [tests] run all unit tests in CI - [tests] add test for loading a directory #1798 - [themes] add options.theme and visidata/themes directory of additional themes (light, ascii8, asciimono) #1682 #1691 - [themes] keystrokes/code now with gray bg - [types] add `ipaddr` and `ipnet` types`. add `type-ipaddr` and `type-ipnet` commands (unbound) (PR by @ajkerrigan #1946 #1782 #1910) - also add `select-supernets` (unbound) which selects rows where the CIDR block value includes the input address space - [types] add `type-url` and `open-url` #2031 - [types] add `type-datetime` #1572 #1380 #397 - [ui] change menu, status, and other colors to be more visible - [ui] add `options.disp_scroll_context` to keep *n* more lines above/below cursor on screen - [ui] add version to menu status - [undo] options.undo can only be set globally - [usd] provide USD(s) function to convert string like '£300' or '205 AUD' to equivalent US$ as float - [windows] change default system clipboard command to clip.exe - [zip] add `sysopen-row` (`Ctrl+O`) to open file in `$EDITOR` #1708 ## experimental features (must be imported manually) - [diff] got moved to experimental - [inplace] optional replacement commands which update the new Column live as you write the expression - [livesearch] add `dup-search` and `dup-search-cols` which search for regex forwards, creating a duplicate sheet with matching rows live - [mark] mark rows to more easily move cursor to them - [noahs] add basic structure for Noah's Tapestry data game - [rownum] addcol-rownum and addcol-delta - [slide-cells] shift cells in cursor row to the right - add loaders gdrive and gsheets # deprecated - [dev] deprecate `col.setValueSafe` and `sheet.checkCursorNoExceptions` - [regex] deprecate `addcol-subst` and `setcol-subst` - `addcol-regex-subst` and `setcol-regex-subst` use inputMultiple, instead of more fragile search/replace one-line input - [regex] deprecate `split-col` and `capture-col` - [keys] change ScrollWheelUp to ScrollUp etc - [multiline] rename `visibility-sheet` to `toggle-multiline` - [utils] deprecate `onExit` context manager ## bugfixes - [aggregators] use statistics.median for more correct median #1914 - [aggregators] fix cancelling of long-running aggregators #1036 - [canvas] fix clicks on labels and unplotted canvs (PR by @midichef #1984) - [canvas] put a max limit on y-axis label width (PR by @midichef #2177) - [chooser] choose only exactly matching strings (PR by @daviewales #1902) - [cli] support `options.encoding_errors` for stdin #2047 - [clipboard] warn when pasting before copying (PR by @midichef #1793) - [clipboard] improve error when deleting row on empty sheet (PR by @midichef #2006) - [clipboard] save to tempfile, do not confirm - [clipboard] save as given filetype - [cliptext] fix double-width char display #1918 - [cliptext] do not crash with x<0 #2138 - [cliptext] do not crash with miniscule widths #2138 - [cmdlog] check for empty cursor column when adding a column (PR by @midichef #1783) - [cmdlog] ensure record of global options in all cmdlogs - [cmdlog] do not log undos for non-loggable commands #1827 - [colorizers] fix custom colorizers showing in sheet context #1225 - [columns] speed up getMaxWidth for wide columns (PR by @midichef #1747) #1728 - [columns] fix allColumnsSheet to ignore non-TableSheet - [confirm] remove flicker in alacritty #2040 - [confirm] commit on sheet without source should always confirm - [currency] fix currency_neg option - [curses] ignore early keys pressed before curses is initialised if Esc present #1993 - [cursor] cursorColIndex now returns None if empty #1803 - [deps] add requests-cache submodule to root visidata #1748 - [dir] support '..' and resolve dirname relative to CWD #1801 - if user uses `open-dir-parent` outside of the CWD, switch to absolute paths - [display] fix visibility with col.height>1 - [expr] more informative 'column not modifiable' error message #1764 - [extensible] do not copy over existing attribute #2190 - [fill] allow filling with values that are logically false (PR by @midichef #1794) - [freq] fix names for openRow #1777 - [freq] correctly group null/error values for `options.numeric_binning` #1410 - [graph] fix graph ranges for xmax, ymax < 1 (PR by @midichef #1752) #1673 #1697 - [graph] fix data on edges being drawn offscreen (PR by @midichef #1850) - [graph] fix graph legend drawn too early (PR by @midichef #1980) - [graph] fixes to various graphing edge cases (PR by @midichef #1896) - [graph] fix top margin location and simplify y-coordinate calculation (PR by @midichef #1915) - [graph] labels: add tick symbol, int precision, right margin (PR by @midichef #1931) - [graph] fix legend display of full-width characters (PR by @midichef #1958) - [graph] widen left margin to hold y-axis labels (PR by @midichef #1998) - [graph] update fixPoint() to use inverted-y coordinates (PR by @midichef #2139 #2111) - [index] add longname for g< and g> #2011 - [input] fix Ctrl+T swap on empty string #1684 - [input] fix Ctrl+V with special keystrokes #1799 - [input] erase status bar after prompt #1947 - [input] fix toggle input help #1971 #1994 - [input] include history for unfocused items #1947 - [inputsingle-] loop until keystroke (do not timeout) - [join] fail if differing number of keycols #1678 - [join] fix join-merge (PR by @yphillip #1923 #1843) - [jsonl] include all columns in first row, even if null - [keystrokes] only check duplicate prefixes from allPrefixes #1829 - [keys] add `Shift+Tab` - [layout] fail if `hide-col` on empty sheet - [loaders fixed] use maxWidth for saving if larger than column width #1849 - [loaders fixed] don't truncate wide columns with fixed width saver (PR by @daviewales #1890) - [loaders http] add `options.http_ssl_verify` to replace `options.http_req_verify` #1939 - [loaders http] fix parsing link header (PR by @Midichef #1924 #1898) - [loaders html] fix failure from colspan with only td tags (PR by @midichef #2002) - [loaders html] prevent error when parsing an empty table (PR by @midichef #2140) - [loaders imap] enable imap and fix folder name extraction (PR by @justin2004 #1917) - [loaders json] include null columns in first row, in more cases (PR by @midichef #2109) - [loaders jsonl] save None as null #2183 - [loaders mysql] unquote password before sending to client (PR by @dufferzafar #1933) - [loaders pandas] handle read methods that produce a list of dataframes (PR by @ajkerrigan #1990 #1986) - [loaders parquet] stringify source to handle both URLs and local paths (PR by @ajkerrigan #1913) - [loaders parquet] show string value for Parquet `large_string` (PR by @daviewales #2018 #2003) - [loaders parquet] fix parquet reading from zip or s3 (PR by @takacsd #2133) - [loaders parquet] handle parquet directories (PR by @mr-majkel #2160 #2159) - [loaders pivot] fix missing anytype import - [loaders postgres] quote schema and table name (PR by @isosphere #2129) - [loaders pyobj] similar sheet names for dive-/open- and pyobj- #1988 - [loaders pyobj] do not skip properties that raise - [loaders png] fix `rgb_to_attr` to return str colornum - [loaders rec] support %sort; continue loading on exception #2022 - [loaders sav] use fork of `savReaderWriter` for the sake of Python 3.10+ support #1867 - [loaders sqlite] prevent creation of ./- file when reading from stdin (PR by @midichef #1945) - [loaders sqlite] explicitly fail when file is not on disk - [loaders tsv] use options.encoding for reading files - [loaders ttf] implement `closePath()` to draw missing lines (PR by @midichef #1979) - [loaders vds] save hidden columns also (PR by @pacien #2093 #2089) - [loaders vds] fix 'keyerror: exprcolumn' for .vds (PR by @pacien #2036 #2045) - [loaders vds] fix .csv to .vds conversion #2037 - [loaders xlsx] saver now replaces illegal characters instead of aborting #1402 - [loaders xml] silence FutureWarning from lxml (PR by @midichef #2149) - [loaders xml] fix file loading (PR by @midichef #2148) - [loaders yaml] support tuples in YAML files (PR by @cool-RR #1824) #1822 - [loaders zip] fix loading and extracting files locally + remotely #2127 - [macos] do not bind empty string to anything - [macros] add prompt for cancelling macro #1810 #1812 - [macros] specify a clearer message #1810 - [macros] append newline to macros.tsv if necessary #1569 - [macros] save file as longname/keystroke #2084 - [main] print version string once, not twice (PR by @midichef #1837) - [main] remove forced unload before interactive mode #1943 - [menu] use "Alt+x" keybinding instead of "^[x" - [metasheets] do not use options.encoding for internal sheet saving - [misc] remove trailing commas from addCommand (PR by @midichef #1962) - [modify] do not call saveSheets on commit - [modify] commitMods do not call putValue for changes to added/deleted rows - also fix ItemColumn.putValue and AttrColumn.putValue to call parent Column.putValue before setting the value on the row - [modify] confirm() overwrite on root sheet source path - [modify] always set col.defer - [modify] do not fail on Column.putValue if no setter - [mouse] fix mouse-click on bottom pane - [open] silence ResourceWarnings for unclosed files (PR by @midichef #2152) - [options] disable adding rows (PR by @midichef #1944) - [options] fix option editing - [options] fix helpstr display when editing - [paste] add new rows to sheet if necessary - [path] set name to '.' for givenpath of '.' #1768 - [path] fix progress bar for compression formats #1175 #1255 - [path] fix open() using both binary and text mode (PR by @midichef #1955) - [path] binary mode does not take newline argument - [pyobj] fix pyobj-cell #2001 - [regex] issue warning when no columns to add #1778 - [regex] check for regex capture group #1778 - [rename-col] skip gratuitous rewrites when undoing (PR by @pacien #2092) - [replay] turn off confirm dialogs during replay - [replay] clearCaches before moving cursor #1773 - [replay] enable confirm in interactive batch mode (PR by @midichef #1751) - [replay] do not push sheet if not already pushed #1681 - [save] handle saving 0 sheets #1720 - [save] fix confirm message on commit #2090 - [scroll-cells] do not error scrolling offscreen column #1908 - [search] handle no rows and invalid regex (PR by @midichef #2125) - [settings] clear cache correctly before set - [sheets] fix NameError for mincolidx #1672 - [sheets] add confirm for `quit-sheet-free` (PR by @midichef #1755) - [sheets] make sure addColumn called on all columns - not just dynamically-created columns - addColumn is needed to set .sheet and .defer, among other things - [sheets] fix reload() for tsv sheets with key columns (PR by @midichef #1997) - [sheets] fix recursion crash of Python >= 3.8, <3.9.10 (PR by #midichef #1722) #1696 - [sheets] pop columns kwarg so raw list not set via final update() in constructor - [sheets] fix slowness from adding rows during getMaxWidth (PR by @midichef #1982) - [sheets] no longer insert column in draw() in debug mode (PR by @midichef #1995) - [sheets] fix errors on sheets with no columns (PR by @midichef #2124) - [sheets] fix splitcell to handle attribute/text pairs (PR by @ajkerrigan #2020) - [sheets] recreate sort columns for copied sheet (PR by @midichef #2192 #2190) - [shell] fix copying of a directory #1970 - [status] fix Alt+Shift+Shift+X #1828 - [status] update right status before exec #996 - [status] add caller/module to statuses, and print on --debug #2037 - [status] catch all exceptions during drawing #2174 - [sort] show sort arrow for sort columns described by name (PR by @midichef #1876) - [syscopy] always copy as utf-8 - [term] allow non-color term like vt102 - [threads] allow @AsyncThread funcs to have status kwarg - [threads] remove non-sheet threads from unfinishedThreads (do not sync on them) - [quit-sheet-free] re-entering a subsheet left using quit-sheet-free should reload the subsheet #1679 - [ui] integrate scrollfix from @geekscrapy #1441 - [undo] ensure undo is sheet-specific for duped/copied sheets #1780 - [undo] fix undo for first modification on a sheet-specific HelpSheet #1820 - [undo] fix the removal of [M] (modified mark) after undo #1800 - [undo] remove last matching cmdlog row, instead of first (PR by @midichef #2010) - [unzip-http] fix recursion error when fetching remote zipfile (PR by @midichef #2116 #2110) - [vdx] fix save error - [windows] add Alt+ keybindings for powershell #1630 - [windows] limit windows-curses version to 2.3.0 (PR by @bartbroere #1901 #1841) - asottile noticed this was a regression in the last windows-curses release in this issue: zephyrproject-rtos/windows-curses#41 - [windows] update windows-curses version to support Python 3.11 #2062 - [windows] fix syspaste (PR by @midichef #1921 #1920) - [windows] fallback to `scr.getch` if no `scr.get_wch` #192 - handles `AttributeError: '_curses.curses window' object has no attribute 'get_wch'` - [windows] tempfiles must be closed before reopening #2118 - [zsh] fix zsh completion (PR by @dbaynard #1960 #1959) ## performance - [startup] delay import of `urllib.request`, `pkg_resources`, and `dateutil` - [startup] remove `unittest.mock` - [draw] `drawcache` make_formatter - [test] use lambda instead of Mock for addstr - [] `Column.formatValue` inline fmtstr - [settings] `@lru_cache` sheet obj in `SettingsMgr._mappings` - fastpath getitemdeep - fallback to getattrdeep if len(row) < index - [sort] move `addProgress` outside of sortkey - [parquet] cache large strings and cap at 1MB #2003 #1068 - [modify] check col/row before isChanged - [status] move getStatusSource into features to improve startup perf ## api - [cli] printout gone; use `builtins.print` - [color] use `ColorAttr` throughout #2061 #2017 - separate out fg/bg - allow bg and fg to take precedence independently - fixes issues with forced bg=black on sidebar for warning, and statusbar for working - [guides] add API for getting and adding guides - add vd,getGuide and vd.addGuide - add Helpers for formatting commands and options - [help] add HelpSheet to globals - [hint] add hint mechanism to find best `Sheet.hint_function` - add hints for types - [input] add vd.injectInput and vd.getCommandInput - [keys] use prettykeys for allPrefixes #1592 - [menu] vd.addMenuItems with convenient string syntax - [modify] Sheet.commitAddRow and Sheet.commitDeleteRow - [modules] vd.importModule, vd.importSubmodules, vd.importExternal, vd.setPersistentOptions - add importExternal for most loaders and features #1739 #1765 - [path] filesize can taken any Path-like - [pivot freq] re-add FreqTableSheet and PivotSheet to globals #1731 - [sheet] add vd.addCommand as alias for BaseSheet.addCommand - [tests] add vd.resetVisiData - [vdx] runvdx() to execute vdx strings - rename vd.draw_sheet to vd.drawSheet - change order of parameters for vd.subwindow to (x,y,w,h) - change order of args to onMouse to x,y - add vd.aside for a silent status message - add GlobalsSheetsSheet to globals - vd.queueCommand can take input,sheet,row,col kwargs #1681 - add `@visidata.stored_property` to persist property # v2.11.1 (2023-07-16) - [tests] fix tests for Python >=3.11 - [path] update for Python 3.12 API (reported by @QuLogic #1934) ## Improvements and bugfixes - [chooser] choose only exactly matching strings in chooser (PR by @daviewales #1902) - [columns] speed up `getMaxWidth()` for wide columns, and correct some edge cases (PR by @midichef #1747) - [freqtbl] Default `disp_histogram` to U+25A0 BLACK SQUARE (■)) (PR by @daviewales #1949) - [loaders fixed] do not truncate wide columns with fixed-width saver (PR by @daviewales #1890) - add missing import `copy` - [graph] fix graph ranges for xmax, ymax < 1 (PR by @midichef #1752) - [graph] fix data on edges being drawn offscreen (PR by @midichef #1850) - [input] fix `Ctrl+T` swap on empty input (reported by @gfrmin #1684) - [inputsingle] loop until keystroke (do not timeout) - [fill] allow filling with values that are logically false (PR by @midichef #1794) - [macos] do not bind empty string to any keybinding - [paste] add new rows to sheet if insufficient rows - [path Dirsheet] set name to '.' for givenpath of '.' (reported by @geekscrapy #1768) - [path] fix progress for compressed files (reported by @bitwisecook #1255 #1175) - [replay] clearCaches before moving cursor (reported by @mokalan #1773) - [save] handle saving 0 sheets (reported by @reagle #1266 #1720) - [settings] clear cache correctly before set - [undo] fix so that undo is Sheet-specific on copied sheets (reported by @geekscrapy #1780) - [undo] undoing `zd` now removes `[M]` (modification mark) (reported by @Freed-Wu #1800) # v2.11 (2023-01-15) - [ci] drop support for Python 3.6 (related to https://github.com/actions/setup-python/issues/543) - [ci] add support for Python 3.11 (#1585) - [dirsheet] add `open-dir-parent` (bound to backtick) - [join] add new "concat" jointype to behave similar to "append" but keeps first sheet type and columns (requested by @frosencrantz #1598) - [zip] add multisave for `.zip` (save each sheet in options.save_filetype format into given .zip file) - [sysedit] add `sysedit-selected` (bound to `g Ctrl+O`) (requested by @Delapouite #1596) - edit cells in multiple rows in `$EDITOR` - only handles cell modifications, not added or deleted rows ## Improvements - [aggregators] add 95 and 99 percentile (p95 and p99) - [fill-col] speed up `fill-col` for sheets with many empty cells (PR by @midichef #1657) - [loaders hdf5] add support for arrays of scalars (requested by @linwaytin #1602) - [graph] fail if no numeric xcols are given - [open-cell-file] warn when file or url in cell does not exist (requested by @geekscrapy #1540) - [sqlite] add passthrough options (reported by @cwarden #1622) - [sqlite] add options.sqlite_onconnect to be executed before running any statement (requested by @cwarden #1622) - [xml] add passthrough options for xml_parser; default xml_parser_huge_tree=True (PR by @midichef #1668) ## Bugfixes - [columns] `dup-sheet` now carries over attributes of columns added by `add-column` - [columns] **SettableColumn** should not be deferred (reported by @frosencrantz #1568) - [customdate] recognise type-customdate as numeric (requested by @tdussa #1613) - [describe] fix custom describe aggregators (reported by @edupont #1574) - [dirsheet] fix incorrect filename with multiple extensions (reported by @kunliugithub #1571) - [display] show `disp_oddspace` for surrogate escapes (reported by @geekscrapy #1544) - [graph] fix div-by-zero with only one y-value (reported by @midichef #1673) - [install] ensure setuptools files have appropriate permissions (reported by @icp1994 #1591) - [install] update data files in setup.py based on PEP 420 (reported by @Oblomov #1675) - [keystrokes] add `kDN` and `kUP` to translation table (reported by @djpohly #1336) - [loaders html] fix loading of relative links in html table (reported by @frosencrantz #1599) - [loaders xlsx] store `None` as empty string in `save_xlsx` (reported and PR by @dbaynard #1626 #1629) - [macros] override CLI parsing options for MacrosSheet (reported by @frosencrantz #1607) - [macros] query again for keystroke if used by existing macro (#1658) - [macros] do not include `nonLogged` commands in macro (reported by @geekscrapy #1569) - [macros] add reload for **MacroSheet** (reported by @geekscrapy #1569) - [menu] 2x ESC should exit menu - [mouse] fix mouse-clicks on statusbar when splitpane is off (reported by @frosencrantz #1625) - [numpy] fix loader - [open_txt] fix Exception with `open-config` when no `~/.visidatarc` (reported by @gunchev #1611) - [pdb] fix entering of pdb breakpoints for Python 3.9+ (reported by @jasonwirth #1317) - [sheets] sort all sheets on global **Sheets Sheet** (reported by @franzhuang #1620) - [types] format int/vlen as true int (reported by @xlucn #1674) - [unzip-http] fix file extraction (`x`) on remote zip file - [unzip-http] handle files smaller than 64K (reported by @frosencrantz #1567) - [zsh-completion] fixed (reported by @pigmonkey #1583; PR by @Freed-Wu #1646) ## API - raise Exception from causes in utils.py (PR by @cool-RR #1633) - add `HistogramColumn` to allow overrides (requested by @andycraig #1621) - easier external numeric types with `@vd.numericType()` decorator (inspired by @s1291 #1394) - [frequency table] `dive-rows` renamed to `dive-selected` # v2.10.2 (2022-10-08) - add .vdx, a simplified new cmdlog format - add `-N`/`--nothing` command to disable loading .visidatarc and plugin addons - add `addcol-aggr` to add an aggregator column to the **FreqTable** without needing to regenerate it (requested by @geekscrapy #1541) ## Improvements - [cli] load commandline file arguments from the start (requested by @reagle #1471) - [cli] `--config=''` now does not try to load any config - [open] rename `zo` `open-cell` command to `open-cell-file` - [loaders whl] load python .whl (reported by @frosencrantz #1539) ## Bugfixes - [cli] fix for empty arg - [DirSheet] fix bug where `Enter` no longer opened a file from the **DirSheet** (reported by @frosencrantz #1527) - [input paste] fix pasting via a Path via `Ctrl+Y` into input (reported by @frosencrantz #1546) - [menu] allow VisiData to run without menu - [mouse] catch any curses.getmouse() errors (reported by @geekscrapy #1553) - [performance] allow vd to be truly idle (reported by WizzardUU #1532) - [plugins_autoload] catch error for environment having invalid package metadata (reported by @jsdealy #1529) - [plugins_autoload] catch exception if plugin fails to load - [plugins-autoload] fix check for if plugins_autoload is set in args - [plugins-autoload] update for importlib-metadata 5.0 API (reported by @jkerhin #1550) - [pyobj] undo rename of `open-row`/`open-cell` (were renamed to `open-X-pyobj`) (revert of eff9833e6A) - [sheets] ensure IndexSheets are precious, and that **SheetsSheet** is not (reported by @frosencrantz #1547) - [unzip-http] extracting a file now checks for overwrite (reported by @frosencrantz #1452) - [windows clipboard] fix piping to clip command through stdin (thanks @daviewales for the fix; reported by @pshangov #1431) ## API - expose `CommandLogBase` (was `_CommandLog`) - [options] allow FooSheet.options instead of .class_options - add separate non-async `select_row`, `toggle_row`, and `unselect_row` for selection of single rows - the before/after decorators now do not fail if api functions they are decorating do not already exist # v2.10.1 (2022-09-14) ## Improvements - [docs] document `-d` option (thanks @abitrolly for PR #1515) - [freq] disable histogram if `disp_histlen` or `disp_histogram` set to 0 or empty string - [guard] add `guard-sheet-off` which unsets `options.quitguard` on current sheet (thanks @hanfried for PR #1517) - [menu] add `BUTTON1_CLICKED` (same as `BUTTON1_PRESSED`) - [open] add `zo` to open file or url from path in current cell ## Bugfixes - fix Guix build problems (reported by @ryanprior #1499) - add support for sheet names with multiple `.` (periods) in the name (requested by @geekscrapy #1494) - [cmdlog] add more portable shebang in vdj - [date] fix custom date greater than or equal to comparison - [macros] fix `macro-record` (#1513) - [macros] refresh `macro-sheet` upon macro addition - [macros] ensure macros are set upon startup - [plugins] update usd plugin api (thanks @hanfried for PR #1510) - [repeat] fix `repeat-` (#1513) - [status] reduce priority of active colouring (reported by @geekscrapy #804) ## API - add `ExpandedColumn` to globals - add `Extensible.before` and `Extensible.after` - `def foo` decorated with `@VisiData.before` will run it before `vd.foo()` - `def foo` decorated with `@VisiData.after` will run it immediately after # v2.10 (2022-08-28) - [plugins] load all entry points in `visidata.plugins` group before config load - add entry_points={'visidata.plugins': 'foo=foo'} to plugin load plugin automatically when launching VisiData - [deps] require `importlib_metadata` >= 3.6 - following https://github.com/pypa/twine/pull/732 ## Improvements - [draw] redraw only every 100 ms if any keys pending (requested by @ansoncg #1459) - [IndexSheet] shown name is only final name component - [loaders html] add table of all links on page (requested by @dufferzafar #1424) - [loaders html] `open-row` on **LinksSheet** to open url (requested by @dufferzafar #1424) - [options] add `options.http_req_*` to send headers/etc to requests (requested by @daviewales #1446) - [options pyobj] add `options.fmt_expand_dict` and `options.fmt_expand_list` for formatting expanded list and dict column names (requested by @joe-opensrc #1457) - [threads-sheet] add `z Ctrl+T` (`threads-sheet`) to open **ThreadsSheet** for current sheet - [threads-sheet] add `g Ctrl+C` (`cancel-all`) to **ThreadsSheet** - [zsh] add scripts for zsh completion (PR by @Freed-Wu #1455) - tutorial: https://visidata.org/docs/shell/ ## Bugfixes - [addcol-] set cursor at added column for `addcol-new`/`addcol-bulk` (reported by @jsvine #1445) - [cmdlog] `Ctrl+S` from a **CommandLog** now defaults to `.vdj` (reported by @jsvine #1443) - [display] format entire string for undetermined width (reported by and fixed by @jsvine #1442) - [formatter] fix len format strings - [LastInputsSheet] catch other exceptions during reload - [loader npz] fix .npz loader (reported by @Shahin-rmz #1440) - [loader geojson] fix plotting and saving geojson files (fixed by @mwayne #1477) - [loader geojson] improve feature property manipulation (fixed by @mwayne #1477) - [menu] upon menu item keypress, move to item (reported by @reagle #1470) - [menu] fix `ALT+` navigation while within menu (reported by @reagle #1470) - now requires two `ESC` to exit - [open] allow binary files from archives (reported by @frosencrantz #1430) - [save] do not save unknown filetype as `save_filetype` - [save visidatarc] only save rows on **OptionsSheet** to visidatarc - [sheets] fix name reconstruction for files with multiple and no suffixes (#1450) - [sheets] do not include empty name parts in sheet name - [unzip-http] **FreqTableSheet** `open-row` now loads links (reported by @frosencrantz #1458) - [zip] use correct rowdef in extract (reported by @frosencrantz #1430) - [zip] do not create directory for extract ## snippets - add snippets/scrolloff.py which mimics vim's scrollof context lines (requested by @gennaro-tedesco #1441) ## vdplus - `open-memusage` was moved to vdplus ## API - add InferColumnsSheet - it infers the columns and their types from the rows it gets which are dicts - used by json, npy loader - add vd.printout and vd.printerr for builtins.print to stdout and stderr - add `vd.view()` - fix Extensible.init() to work with classes with no `__init__` - add `Sheet.sidebar` and `Sheet.sidebar_title` properties ## Deprecated - remove VisiDataSheet - remove vdmenu # v2.9.1 (2022-07-21) - [unzip-http] move urllib3 to optional dependencies # 2.9 (2022-07-20) - [ux] add confirming modal dialog - only "y" required to confirm - add XDG support (thanks @jck for the PR #1420) - `options.config` default is now `"$XDG_CONFIG_HOME"/visidata/config.py` if `$XDG_CONFIG_HOME` is set and `config.py` exists. If not, falls back to the standard `$HOME/.visidatarc`. - vendor [appdirs.py](https://github.com/ActiveState/appdirs/blob/master/appdirs.py) - [cmdlog] support variables in .vdj (requested by @jungle-boogie #1364) - in the .vdj, write variables like so: `${variableName}` - then on the CLI: `vd -p foo.vdj variableName=bar` - [loaders arrow] new Apache Arrow IPC loader/saver (requested by @d-miketa #1369) (requires `pyarrow`) - add `.arrow` (file) and .arrows (streaming) formats - add more native `parquet` loader via `pyarrow` - preliminary "windowing" for referencing x rows before and y rows after in an expression (requested by @maxigit #1399, @MMesch #1129, @samuelludwig #1210) - press `w` (longname: `addcol-window`) followed by two numbers: the number of rows to aggregate *before* and *after* the current row. - there will be a new column, `foo_window`, where each row contains a list of aggregated rows. after that, e.g. `=` `sum(foo_window)` to get a running total for each row - add `setcol-format-enum` which takes e.g. `A=apple B=banana` and uses that as a mapping when formatting a column. - vendor `https://github.com/saulpw/unzip-http`; allows the downloading of individual files from a .zip file over http without downloading the entire archive (requires `urllib3` package) - add `save-source` to save a root sheet directly to its source - add `setcol-formatter` to specify formatting function used for Column (default: `generic` formats based on type and fmtstr). Can be `json` or `python` or a custom formatter ## Improvements - [cli] when `-v` or `-h` VisiData now does not read config or do anything else (requested by @geekscrapy #1340) - [cmdlog] set `.vdj` to be the default cmdlog format - [replay] allow column names to be numbers (reported by @frosencrantz #1309) - if wishing to reference a column index, required to be an int in a .vdj cmdlog - [cmdlog] when saving cmdlogs, type column indices as integers, and column names as strings - If replaying, and *col* is an `int`, the CmdLog will index by position. - If *col* is a `str` it will index by column name. - [display] preview first n elements of a list/dict cell - [regex] add unbound `addcol-` commands - [rtl] improvements to right-to-left text display (requested by @dotancohen #1392) - [man] have `vd --help` open the .txt manpage by default (requested by @halloleo #1332) - [mouse] invert scroll wheel direction (requested by @marcobra #1351) - [performance] improvements to plotting of empty canvas, multiline display, and draw-ing functions - [plugins] notify when plugin update available (thanks @geekscrapy for PR #1355) ## Bugfixes - [aggregators] fail on setting an unknown aggregator in **Columns Sheet** (reported by @geekscrapy #1299) - [aggregators] handle `delete-cell` case for aggregators column in **Columns Sheet** (reported by @geekscrapy #1299) - [aggregators] fix quartile aggregators (reported by @pnfnp #1312) - [aggregators] fix copying of aggregators when duplicating a sheet (reported by @frosencrantz #1373) - [canvas] do not use "other" label when there are exactly 9 columns being plotted (reported by @tdussa #1198) - [cli] fix `+:subsheet:col:row:` when `load_lazy` is False - [delete-row] clear deleted rows from `selectedRows` (reported by @geekscrapy #1284) - [exec-longname] output warning, if longname does not exist - [expr] prefer visible columns over hidden columns (reported by @frosencrantz #1360) - [freeze-sheet] carry over column attributes for freeze-sheet (reported by @frosencrantz #1373) - [import-python] use command-specific history (reported by @frosencrantz #1243) - [IndexSheet] fix renaming of sheet names from an IndexSheet (reported by @aborruso #1339) - [input] handle history for non-string input values (reported by @frosencrantz #1371) - [loaders pandas] fix (`dup-selected`) `"`of selected rows for **Pandas Sheet** (reported and fixed by @jasonwrith #1315 #1316) - [loaders usv] swap delimiters (reported by @frosencrantz #1383) - [loaders usv] save delimiter override options (reported by @frosencrantz #1383) - [loaders usv] fix saving header with usv row delimiter (reported by @frosencrantz #1383) - [loaders xlsx] fix clipboard on XlsxSheets (reported by @jungle-boogie #1348) - [macros] fix macro-record keystroke setting (reported by @fatherofinvention #1280) - [mouse] stay disabled after input (reported by @holderbp #1401) - [mouse] fix for pypy3 (thanks @LaPingvino for PR - [quitguard] refinement of quit-sheet protection (reported by @geekscrapy #1037, #1381) - [save-selected] get sheet names for saving from selected rows (reported by @aborruso #1339) - [shell] strip trailing whitespace in `z;` output (reported by @justin2004 #1370) - [tty] fix bug where piping async output into stdin broke visidata keyboard input (reported by @ovikk13 #1347) - [undo] fix issue where undoing a reload blanks the current sheet; do not set undos for reload sheet (#1302) - [unset-option] fix issue where Exception is raised on the next undo-able command run after `unset-option` (reported by @ajkerrigan #1267) - [windows] require `windows-curses` installation on Windows (thanks @ajkerrigan for PR #1407; reported by @schiltz3 #1268, @aagha #1406) ## API - add Column.formatter (generic, json, python) - add SqliteQuerySheet to globals - `vd.loadConfigFile()` no longer needs a filename argument, and will use `options.config` by default (#211) - use `newline="` for csv.writer (thanks @daviewales for PR #1368) - make `ItemColumn` a proper class for inheritance - add `openJoin` and `openMelt` to allow overriding by plugin sheetsS - addColumn takes `*cols` (reported by @pyglot #1414) ## Deprecated - deprecate old vdmenu system - remove `Shift+V` command # 2.8 (2021-12-15) ## Improvements - [plugins] include pip stderr in warning - [plugins] use returncode to determine if pip install failed, before adding to imports (thanks @geekscrapy for PR #1215) - [cmdlog] add sheet creation command to cmdlog (requested by @aborruso #1209) - [open] strip whitespace from the beginning and end of inputted filenames - [options] `options.input_history` and `options.cmdlog_histfile` can now be an absolute paths (requested by @geekscrapy #1200) - relative paths are relative to `options.visidata_dir` - [splitwin] automatically switch to pane where sheet is pushed to ## Bugfixes - [curses] suppress invalid color errors in Python 3.10 (thanks @ajkerrigan for reporting #1227 and for PR #1231) - Adapt to [Python 3.10 curses changes](https://docs.python.org/3/whatsnew/3.10.html#curses) which can raise a `ValueError` on invalid color numbers. - [curses cosmetic] simplify error message, if curses fails to initialise - [loaders json] skip blank lines in json files, instead of stopping at them (thanks @geekscrapy for PR #1216) - [loaders jsonl] fix duplicate columns when loading fixed columns sheets in jsonl format (report by @0ceanlight) - example of formats with fixed columns is darkdraw's `DrawingSheet` - [loaders fixed] fix saver (thanks @geekscrapy for PR #1238) - [loaders postgres] fix recognition of postgres loader (reported by @ryanmjacobs #1229) - [loaders sqlite] fix the loading of sqlite VIEWs for sqlite version 3.36.0+ (reported by @frosencrantz #1222) - [help-commands] now lists commands only for the current sheet (reported by @geekscrapy #1217) - [textcanvas] ENTER on canvas should push copied source sheet for points within cursor - [pivot freq] use `options.histogram_bins` from source sheet - [curses cosmetic] fix issue where if a curses initialisation Exception is called, a second Exception follows - [quit-sheet-free] fix bug where quit-sheet-free, when multiple sheets opened in CLI, was not working (reported by @geekscrapy #1236) - [options] fix instance where local options sheet was called, instead of global options sheet (thanks @geekscrapy for PR #1241) ## API - add standard Python `breakpoint()` to drop into the pdb debugger - export `run()` to global api - add CsvSheet, ZipSheet, TarSheet to global api (thanks @geekscrapy for PR #1235) # 2.7.1 (2021-11-15) - Bugfix: fix Enter on helpmenu (reported by @geekscrapy #1196) # 2.7 (2021-11-14) ## Improvements - [movement] bind Home/End to go-top/go-bottom (thanks @geekscrapy #1161) - [api] add vd.urlcache as alias for urlcache global (thanks @geekscrapy for PR #1164) - [plugins] do not continue installation if main package fails pip install (thanks @geekscrapy for PR #1194) - [plugins] allow for plugin records without SHA256; warn if absent (thanks @geekscrapy for PR #1183) - [load_lazy] do not load subsheets, if `sheet.options.load_lazy` is True (thanks @geekscrapy for PR #1193) - [save] confirm when `save_foo` function does not exist and saver fallsback to `options.save_filetype` (reported by @geekscrapy #1180) - [save] `options.save_filetype` default now 'tsv' - several cosmetic improvements ## Loaders - [lsv] add `lsv` filetype for simple awk-like records (requested by @fourjay #1179) - [ods] add `odf` filetype for Open Document Format spreadsheets - [xlsx] add extra columns (`cellobject`, `fontcolor`, `fillcolor`) if `options.xlsx_meta_columns` (default False) (thanks @hoclun-rigsep for PR #1098) - [sqlite] allow query/insert (no modify/delete yet) for `WITHOUT ROWID` tables (requested by @stephancb #1111) ## Bugfixes - [savers compression formats] fix corruption when saving to compression formats (#1159) - fix "ModuleNotFoundError: no module named 'plugins'" error on startup (#1131 #1152) - [windows] fix issue with Enter key on Windows (reported by @hossam-houssien #1154) - [draw] fix multiline rows by making height fixed for all rows (reported by @geekscrapy #916) - [DirSheet] fix bug where fix key column sheets (e.g. DirSheet, SqliteIndexSheet) keycols were not being saved in batchmode (reported by @geekscrapy #1181) - [async] make sure all threads started on sheet are cancelable (reported by @geekscrapy #1136) - [AttrDict] fix bug with setting value on nested AttrDict - [dup-X-deep] fix error with async_deepcopy (thanks @pstuifzand for fix) - [join] fix 'inconsistent-keys' issue when joining between XlsxSheet with typed columns and CsvSheet with untyped columns (reported by @davidwales #1124) - [sqlite] handle sqlite column names with spaces (thanks @davidskeck for PR #1157) - [sqlite] use `options.encoding` and `options.encoding_errors` for decoding of sqlite db text (reported by @WesleyAC #1156) - [xlsx] add handling for EmptyCell instances (thanks @hoclun-rigsep for PR #1121) - [xlsx] gate sheet name cleaning on `options.clean_names` (reported by @davidwales #1122) - [macos] fix bindings for `Option`+key - [random-rows] fix import (reported by @geekscrapy #1162) - [save-selected] better default save filename (reported by @geekscrapy #1180) - [save] fix bug where saving multiple sheets to a single non-embeddable format did not result in fail (reported by @geekscrapy #1180) - [slide] fix Shift slide-down and Shift slide-up with arrow keys (reported by @a-y-u-s-h #1137) - [replay] fix replay where `join-sheets` operation hangs (reported by @agjohnson #1141) - [undo] no more KeyError when Undoing modifications (reported by @geekscrapy #1133) - [unfurl-col] fix unfurl-col on cells containing exceptions (reported by @jsvine #1171) # 2.6.1 (2021-09-28) ## Bugfixes - [editor] fix sysopen-row (thanks @frosencrantz #1116) - [loaders fixed] fix saver (#1123) - [loaders shell] fix copy-files - [loaders sqlite] fix import error on exception (thanks @jsvine #1125) # 2.6 (2021-09-19) ## Major feature - [menu] new hierarchical menu system - `Alt+F`, `Alt+E`, etc to open submenus (`Alt+` underlined capital letter in toplevel menu) - `Ctrl+H` to activate Help menu (manpage now at `gCtrl+H`) - `q` or `Esc` to exit menu - Enter to expand submenu item or execute command - or left mouse click to activate and navigate menu - only show commands available on current sheet - sheet-specific commands highlighted with `options.color_menu_spec` - new options: - `disp_menu`: display menu if inactive (default True). Can still activate menu with Ctrl+H/Alt+F - `disp_menu_keys`: whether to display shortcuts inline (default True) - `disp_menu_fmt`: upper right display on menu bar (like `disp_status_fmt`/`disp_rstatus_fmt`) - theme colors: `color_menu` `color_menu_active` `color_menu_spec` `color_menu_help` - theme chars: `disp_menu_boxchars` `disp_menu_more` `disp_menu_push` `disp_menu_input` `disp_menu_fmt` ## Interface changes - [expand-col] only expand to one level - [slide] remove slide row/col with mouse - [macos] add bindings for Option+key to Alt+key - [modified] limit use of sheet protection (thanks @geekscrapy #1037) - [python] rebind g^X to new import-python command (what exec-python was mostly used for) - [npy] add `npy_allow_pickle` option (default False) - [join] rename join-sheets on IndexSheet to join-selected; bind both g& and & to join-selected - [loaders pandas] add error message for unpickling non-dataframes - [join] fail if no key columns on any sheet (thanks @geekscrapy #1061) - [loaders xlsx] enable access to cell metadata (thanks @hoclun-rigsep #1088) - many performance, progress bar, and UI responsiveness improvements ## Bugfixes - [cli] issue warning if +sheet-position not found (thanks @geekscrapy #1046) - [clipboard] do not copy newline for syscopy-cell (thanks @geekscrapy #1064) - [column] detect existing column by row key instead of column name (thanks @geekscrapy #1058) - [color] set `color_current_row` to the same precedence as `color_current_column` (thanks @frosenrantz #1100) - [command] do not fail/abort on unknown command - [draw] Sort indicator on top of More indicator (thanks @geekscrapy #1071) - [join] fix multiple extend (thanks @cwarden) - [join] allow extended columns to be modified (thanks @cwarden) - [join] fix for rowdefs without bool (like pandas) - [loaders dirsheet] continue after exception in copyfile - [loaders fixed] fix fixed-format saver - [loaders fixed] save uses `global options.encoding` (thanks @geekscrapy #1060) - [loaders mysql] do not stop loading on first error (thanks @SuRaMoN #1085) - [loaders pandas] fix column rename - [loaders sqlite] save based on column names, not position - [loaders sqlite] allow changing value of cells that were NULL (thanks @mattenklicker #1052) - [loaders sqlite] add message on not currently supporting WITHOUT ROWID (thanks @stephancb #1111) - [multisave] fix breaking typo - [open_txt] load new blank sheet for 0 byte files (thanks @geekscrapy #1047) - [save] do not set a default for `options.save_filetype` (thanks @frosencrantz #1072) - [split-pane mouse] activate pane on click (thanks @frosencrantz #954) - [unfurl] handle unfurling exceptions (close #1053) - [quitguard] confirm quit when set on a specific sheet even if not precious or modified - [yaml] Fix yaml loader traces on no attribute `_colnames` (thanks @frosencrantz #1104) - [visidatarc] catch all visidatarc exceptions upon load # v2.5 (2021-07-08) - [social] #visidata has moved off of freenode to libera.chat - [deps] required pandas version for the pandas loader has been bumped to at least 1.0.5 - [caa] new PR submitters required to sign CAA ## Features - [cli] when no arguments on commandline, open currentDirSheet (previously vdmenu); -f opens empty sheet of that filetype - [clipboard] bind `x` family to `cut-*` (thanks @geekscrapy #895) - [date] add specialized comparators for `datetime.date` (thanks @aborruso #975) - visidata.date now compares to datetime.date (previously raised exception) - identical dates compare equal even if intra-day times are different - this does not work for incompletely specified visidata.date; e.g. `visidata.date(2016, 10, 29, 4, 0, 0) != visidata.date(2016, 10, 29)` - [DirSheet] add y/gy to copy file(s) to given directory - [loaders vds] save non-jsonable cells as string (thanks @pacien #1011) - [loaders zstd] support loading zstd-compressed files (thanks @lxcode #971) - [movement] bind `Ctrl+Left/Right` to `go-left`/`right-page` (thanks @davidwales #1002) - [options] save to foo.visidatarc from OptionsSheet (thanks @njthomas #958) - [sqlite] RENAME and DROP tables from SqliteIndexSheet - [unfurl] add `options.unfurl_empty` to include row for empty list/dict (thanks @frosencrantz #898) - [quitguard] confirm quit/reload only if sheet modified (references #955, #844, #483; thanks @jvns, @frosencrantz) ## Improvements - [addRow] advance cursor if row inserted before cursor - [archive] add .lzma as alias for .xz - [clipboard] gzp pastes None if nothing on clipboard - [clipboard] make syspaste async - [clipboard] bind `zP` to syspaste-cells and gzP to syspaste-cells-selected (thanks @jvns and frosencrantz #983, #990) - [cliptext] better support for combining and variant chars (thanks @lxcode #758 #1034) - [colors] reduce color swatch size to remove flashing (thanks @frosencrantz #946) - [encoding] specify encoding explicitly for all Path.open_text (thanks @pacien #1016) - [error] exceptionCaught(status=False) to add to status history, but not post to status (thanks @frosencrantz #982) - [freqtbl] copy fmtstr from source col to aggcol (thanks @geekscrapy #1003) - [help] ENTER/exec-command to execute command on undersheet (thanks @geekscrapy #1011) - [help] add `all_bindings` hidden column (thanks @frosencrantz #896) - [inputs] put reused input at end of lastInputs (thanks @geekscrapy #1033) - [loaders json] streamify save to .json - [loaders npy] add `npy_allow_pickle` option, default False - [loaders tsv] increase bufsize to improve loader performance by 10% - [path] all Path.open track Progress via read/filesize (thanks @jspatz #987) - [path] add Progress for opening compressed files - [path] implement line-seek operations (thanks @pacien #1010) - [regex expand] deprecate `options.expand_col_scanrows`; standardize on `options.default_sample_size` (thanks @jsvine) - [regex] "match regex" to "capture regex" (thanks @geekscrapy #1032) - [shell] `addcol-shell` pass command to $SHELL (thanks @juston2004 #1023) - [shortcut] allow shortcut for jump-sheet to be settable - [splitwin] push sheet in empty pane iff splitwin - [stdin] use cli --encoding option for piped data (thanks @pacien #1018) - [undo] remove undo for reload (replaced with quitguard+confirm) - [quit] add Shift+Q/quit-sheet-free to quit and free associated memory (thanks @cwarden) ## Display - [canvas] add `options.disp_canvas_charset` to change displayed chars (thanks @albert-ying #963) - [canvas] use sheet specific options for draw - [disp] format list/dict as [n]/{n} only for anytype - [save] iterdispvals(format=True) convert None to empty string ## Bugfixes - [batch] ensure quitguard is off during batch mode - [canvas[ fix error on dive into cursor including y-axis - [cli] have an actual error if there is a missing argument for final option - [cli] do nothing (no error) if no sources given - [clipboard] fix zy/gzp regression (thanks @sfranky #961) - [clipboard] syscopy-cell do not include column name - [cmdlog] fix bug where customising replayable options in Options Sheet led to issues opening metasheets (thanks @jsvine #952) - [cmdlog] fix bug where cmdlog records new sheet name, instead of old sheet name for `rename-sheet` (thanks @aborruso #979) - [color] track precedence so colorizers apply over `color_current_row` - [color] determine color availability with `init_pair` - [color] do not break on nonsense color - [column] getitemdeep/setitemdeep get/set dotted item key if exists (thanks @frosencrantz #991) - [column] fix bug where hard crash occurs when cursor on cell of SheetsSheet is on cursorDisplay (thanks @frosencrantz #1029) - [curses] add default `vd.tstp_signal` for non-cli users - [execCommand] warn gracefully if bound command longname does not exist - [expr] setValuesFromExpr do not stop processing on exception - [join] fix when keys have different names (thanks @aborruso #964) - [join] fix for rowdefs without bool (like pandas) - [join] fix multiple extend (thanks @cwarden for reporting) - [loaders fixed] fix editing in final column for fixed-width load (thanks @mwayne #974) - [loaders geojson] do not abort plot if rows have errors - [loaders html] add columns even if not in first row - [loaders pandas] fix column rename - [loaders rec json] fix adding new columns for json and rec loaders (thanks @ajkerrigan #959) - [loaders postgresql] add postgresql scheme (fixes #966) (thanks @zormit #967) - [loaders sqlite] fix saving deleted cells (thanks @mattenklicker #969) - [loaders vds] save SettableColumn as Column (thanks @pacien #1012) - [loaders zip] fix extract-selected-to - [open] fix regression where opening blank sheets of type tsv, csv, txt, etc was not working - [plugins] fix stdout/error from plugins installation message (was in bytes, changed to str) - [quit] remove sheets from **Sheets Sheet** upon quit - [save-col] fix inputPath error (thanks @savulchik #962) - [shell] fix `options.dir_hidden`; also apply to dirs when `dir_recurse` - [textsheet] fix reload after `^O` sysopen ## vdplus - moved clickhouse, vsh, vgit, windows to vdplus # v2.4 (2021-04-11) - [splitwindow] stabilize sheet stack associations - `Shift+Z` pushes 'under sheet' (if any) onto other stack - `Shift+Z` does not swap panes anymore - `g Tab` swaps panes - `options.disp_splitwin_pct` is always not sheet-specific - [status] show nSelectedRows on rstatus - [color] remove `options.use_default_colors` (thanks @lxcode #939) - `options.color_default` can now have both fg and bg - other color options which do not specify fg or bg will use the missing component from `color_default` - to use terminal default colors, set `options.color_default=""` ## Bugfixes - [loaders gzip] fix progress bar when opening gzip (thanks @geekscrapy #925) - [loaders http] fix loading files from url without specifying filetype - [loaders sqlite] use `TABLE_XINFO` for hidden/virtual columns (thanks @dotcs #945) - [loaders sqlite] perf improvement: do not pre-count rows (required full table scan) - [loaders vds] save typed values instead of formatted display values (thanks @frosencrantz #885) - [loaders xlsx] stringify "header" row values for column names (thanks @davidwales #921) - [pyobj-show-hidden] grab visibility lvl from sheet specific option (thanks @frosencrantz #947) - [splitwin] prevent flickering-on-full-window - [splitwin] if top sheet quit, keep bottom sheet in bottom pane - [splitwin] full-screen/splitwin close all sheets should be part of the same stack # v2.3 (2021-04-03) ## Features - [colors] allow background colors (thanks @frosencrantz #435) - use "*fg* on *bg*" e.g. "212 yellow on 14 red" - "bg *bg* fg *fg*" (or reversed) - attributes always apply to foreground regardless of position in colorstr - as before, only the first valid color in a category (fg/bg) is used; subsequent color names (even unknown ones) are ignored - allocate colors on demand, instead of "all" 256 colors as fg - **Colors Sheet** now only includes colors actually allocated - [colors] set `use_default_colors` default to `True` (was `False`) - [delete] do not move deleted values to clipboard (thanks @geekscrapy #895) - `delete-*` commands are changed to not alter the clipboard - the previous `delete-*` commands are renamed to `cut-*` (unbound) - this affects: `delete-row`, `delete-selected`, `delete-cell`, `delete-cells` - [jump-first] bound `g^^` to cycle through sheets - [null] `zd` / `gzd` `delete-cells` set to `options.null_value` instead of `None` - [memories] add MemorySheet on `Alt+M`, `Alt+m` adds current cell to sheet (thanks @UrDub and @geekscrapy #912) - useful for storing values to reference later - both names and values can be edited on MemorySheet - [aggregator] `memo-aggregator`(z+; formerly called `show-aggregate`) adds value to memory sheet - [clipboard] clipboard stored on memory sheet; zy/zp use vd.memory.clipval; - [plugins] allow install from github url to local pip repo - [plugins] add darkdraw to plugins.jsonl - [png] save image as RGBA - [pyobj-expr] `Ctrl+X` within `Ctrl+X` input suspends directly into python REPL - [splitwin] now involves two different sheetstacks that build and quit independently (thanks @lamchau #894) - [splitwin] allows stickier panes for push/quit - [splitwin] splitwin-half (`Z`) swaps panes if already active - [splitwin] only re-split (with `zZ`) if sheets are not already split, otherwise adjust split percent - [save_filetype] if `save_ext` does not exist, or if `options.save_filetype` is different from default, use `options.save_filetype` - [vdplus] auto-import, ignore if not available ## Bugfixes - [aggregator] fix typo in deciles description (thanks @cwarden #922) - [copy] copying BasicRow (new sheets), now does not error (still blank) - [cmdlog] for `open-file` source logging in cmdlog, we want paths to physical files, so if src is a **Sheet** grabs its source - [defer] fix pasting in deferred sheets - [eval] fix **ExprColumns** on empty rows - [help] move signal config earlier in runcycle, to accommodate --help (thanks @frosencrantz #926) - [open] create blank sheet of appropriate type when path does not exist - [pandas] fix conflict between dropped index and existing column (thanks thomanq #937) - [plugins] only check for plugins.jsonl once daily (previously: every start-up) - [pivot] fix `openRow` - [pivot] fix bug with sheet name - [png] fix saving directly from canvas - [sort] fix sorting of visidata.Path objects (thanks @frosencrantz #897) - [splitwin] fix cursor behaviour on both panes when active - cursor movement on inactive panes is blocked - [SuspendCurses] workaround for bug in curses.wrapper (thanks @frosencrantz #899) - [undo] do not set undo for a `commit-sheet` ## Api - [addRows] addRows(rows, index, undo) adds rows at index, sets undo if True - set undo to False, if using addRows within an addUndo function - [deleteBy] add an undo flag to deleteBy - [clipboard] change `cliprows` to be a simple list of rows - new **DrawablePane** super-base class - [json] rowdef now **AttrDict** for massive convenience # v2.2.1 (2021-02-07) ## Bugfixes - [setcol-fill] use row identity to identify selected rows (thanks @frosencrantz, #884) - for jsonl, empty rows are identical ({}), and if ones is selected, previously it would result in all of them being filled. - also, fill with most recent *non-null* value ## man - add a manpage visidata.1 - fix typo # v2.2 (2021-01-30) ## Options - [cli options] now global by default; use `-n` to set option as sheet-specific instead - add `-n`/`--nonglobal` to make subsequent CLI options "sheet-specific" (applying only to paths specified directly on the CLI) - keep `-g`/`--global` to make subsequent CLI options "global" (applying to all sheets by default unless overridden) - invert the default: now CLI options are global by default (thus `-g` is a no-op unless preceded by `-n` on the CLI) - `-g` no longer acts as a toggle - [input] add `options.input_history` (thanks @tsibley and @ajkerrigan #468) - basename of file to store persistent input history (default of `''` means disabled) - caveat: persistent file only read if option given before first input - [options.fancy_chooser] now disabled by default--use `Ctrl+X` to open from a choose() prompt ## Types - [types] add `floatlocale` type (thanks @Guiriguanche #863) - add commands `type-floatlocale` and `type-floatlocale-selected` (unbound by default) - `floatlocale` parses based on `LC_NUMERIC` envvar (must be set before launching) - parsing is 20x slower than with standard float column - will parse commas as decimals (e.g. '1,1') if LC_NUMERIC is set to a locale like 'en_DK.UTF-8' ## Loaders - [loaders geojson] add loading and saving support for geojson files (thanks @draco #876) - [loaders vds] add loader/saver for custom .vds format (VisiData Sheet) to save column properties and data for multiple sheets in one file - [ux] autoload all subsheets by default; set `options.load_lazy` to disable - removes a minor friction with unloaded subsheets - [loaders http] add `options.http_max_next` to limit api pagination (default 0 - no pagination) (thanks @aborruso #830) ## Bugfixes and Adjustments - [cli] fail properly if path cannot be opened - [defer] only mention number of deleted rows, if some were deleted - [go-pageup go-pagedown] ensure cursor stays in the same relative positions - [loaders mysql] fix mysql loader duplicating tables for each database (thanks @SuRaMoN #868) - [loaders mysql] perform asynchronous data fetch for mysql loader (thanks @SuRaMoN #869) - [loaders pandas] fix empty subsets for dup-selected and frequency table `open-row` (thanks @ajkerrigan #881 #878) - [loaders shp] fix display (thanks @dracos #874) - [loaders shp] fix saving to geojson (thanks @dracos #876) - [replay] fix replaying of .vd with `set-option` - [slide] fix bug when sliding key columns to the left, after sliding them to the right - [types] add command `type-floatsi-selected` on **Columns Sheet** - [expand] errors and nulls can now be expanded with `expand-cols` (thanks @geekscrapy #865) - [open] openSource now uses **'global'** `options.filetype` instead of sheet-specific as previous - to set the filetype for a file locally, set through cli: `vd -f tsv sample.foo` - to set in the **CommandLog**, use sheet="global" with longname="set-option" - [loaders http] raise exception if http status is not 20x (thanks @geekscrapy #848) - [loaders shp] support more Shapefile types (thanks @dracos #875) ## API - add `create` kwarg to `openSource()`, to create the file if it does not exist already - [settings] 'global' is now 'default', and 'override' is 'global' - 'default' is the default setting within VisiData - 'global' is a user override on that default that applies globally - sheet-specific overrides global and default, for the sheet it is specific to - options set through visidatarc and cli are 'global' unless otherwise specified - [save] grab `save_foo` from **SheetType** first - allows overrides of sheet-specific saving # v2.1.1 (2021-01-03) - [macros] allow macro interfaces to be longnames (thanks @frosencrantz #787) - [save] better default save filename for url sheets (thanks @geekscrapy #824) ## Bugfixes - [cmdlog] record column, sheet, and row info for open-cell - [cmdlog] catch case of 'override' sheet for set-option - [expr-col] `curcol` now works for multiple invocations (thanks @geekscrapy #659) - [loaders postgres] account for postgres_schema when rendering Postgres tables (thanks @jdormit for PR #852) - [loaders url] fail unknown URL scheme (thanks @geekscrapy for PR #84) - [pyobj] fix Pyobj Sheets for lists (thanks @brookskindle #843) - [pipe] handle broken pipes gracefully (thanks @robdmc #851) - [scroll] fix issue with jagged scrolling down (thanks @uoee #832) - [sort] fix bug where total progress in sorting is (100 * # of columns to sort) (thanks @cwarden) ## api - format_field formats int(0) and float(0.0) as "0" (thanks @geekscrapy for PR #821) - add TypedWrapper.__len__ (thanks @geekscrapy) # v2.1 (2020-12-06) - [add] add bulk rows and cols leave cursor on first added (like add singles) - [add] add colname input to `addcol-new` - [aggregators] add mode and stdev to aggregator options (thanks @jsvine for PR #754) - [api] add options.unset() - [columns] add hidden 'keycol' to **ColumnsSheet** (thanks @geekscrapy for feature request #768) - [cli] support running as `python -m visidata` (thanks @abitrolly for PR #785) - [cli] add `#!vd -p` as first line of `.vdj` for executable vd script - [cli] allow `=` in `.vd` replay parameters - [clipboard] clipboard commands now require some selected rows #681 - [commands] add unset-option command bound to `d` on OptionsSheet #733 - [config] `--config=''` now ignores visidatarc (thanks @rswgnu for feature request #777) - [defer] commit changes, even if no deferred changes - [deprecated] add traceback warnings for deprecated calls (thanks @ajkerrigan for PR #724) - [display] add sort indication #582 - [display] show ellipsis on left side with non-zero hoffset (thanks @frosencrantz for feature request #751) - [expr] allow column attributes as variables (thanks @frosencrantz for feature request #659) - [freq] change `numeric_binning` back to False by default - [input] Shift+Arrow within `edit-cell` to move cursor and re-enter edit mode - [loaders http] have automatic API pagination (thanks @geekscrapy for feature request #480) - [loaders json] improve loading speedup 50% (thanks @lxcode for investigating and pointing this out #765) - this makes JSON saving non-deterministic in Python 3.6, as the order of fields output is dependent on the order within the dict - (this is the default behaviour for dicts in Python 3.7+) - [loaders json] try loading as jsonl before json (inverted) - jsonl is a streamable format, so this way it doesn't have to wait for the entire contents to be loaded before failing to parse as json and then trying to parse as jsonl - fixes api loading with http so that contents of each response are added as they happen - unfurl toplevel lists - functionally now jsonl and json are identical - [loaders json] try parsing `options.json_indent` as int (thanks @frosencrantz for the bug report #753) this means json output can't be indented with a number. this seems like an uncommon use case - [loaders json] skip lines starting with `#` - [loaders pdf] `options.pdf_tables` to parse tables from pdf with tabular - [loaders sqlite] use rowid to update and delete rows - note that this will not work with WITHOUT ROWID sqlite tables - [loaders xlsx] add active column (thanks @kbd for feature request #726) - [loaders zip] add extract-file, extract-selected, extract-file-to, extract-selected-to commands - [macros] add improved macro system (thanks @bob-u for feature request #755) - `m` (`macro-record`) begins recording macro; `m` prompts for keystroke, and completes recording - macro can then be executed every time provided keystroke is used, will override existing keybinding - `gm` opens an index of all existing macros, can be directly viewed with `Enter` and then modified with `Ctrl+S` - macros will run command on current row, column sheet - remove deprecated `z Ctrl+D` older iteration of macro system - [regex] use capture names for column names, if available, in `capture-col` (thanks @tsibley for PR #808) - allows for pre-determining friendlier column names, saving a renaming step later - [save] `g Ctrl+S` is `save-sheets-selected` on **IndexSheet** - new command allows some or all sheets on an **IndexSheet** to be saved (and not the sheets on the sheet stack) - [saver] add fixed-width saver (uses col.width) - [saver sqlite] ensureLoaded when saving sheets to sqlite db - [search] `search-next` and `searchr-next` are now bound to n and N (was `next-search` and `search-prev`) - [select] differentiate select-equal- and select-exact- (thanks @geekscrapy for feature request #734) - previous select-equal- matched type value - now select-equal- matches display value - add `z,` and `gz,` bindings for select-exact-cell/-row - [sheets] sorting on **SheetsSheet** now does not sort **SheetsSheet** itself. (thanks @klartext and @geekscrapy for bug reports #761 #518) - [status] use `color_working` for progress indicator (thanks @geekscrapy for feature request #804) - [types] add floatsi parser (sponsored feature by @anjakefala #661) - floatsi type now parses SI strings (like 2.3M) - use `z%` to set column type to floatsi ## Bugfixes - [api] expose visidata.view (thanks @alekibango for bug report #732) - [color] use `color_column_sep` for sep chars (thanks @geekscrapy for bug report) - [defer] frozen columns should not be deferred (thanks @frosencrantz for bug report #786) - [dir] fix commit-sheet and delete-row on DirSheet - [draw] fix display for off-screen cursor with multiline rows - [expr] remove duplicate tabbing suggestions (thanks @geekscrapy for bug report #747) - [expr] never include computing column (thanks @geekscrapy for bug report #756) - only checks for self-reference; 2+ cycles still raises RecursionException - caches are now for each cell, instead of for each row - [freeze] freeze-sheet with errors should replace with null - [loaders frictionless] assume JSON if no format (thanks scls19fr for bug report #803) - from https://specs.frictionlessdata.io/data-resource/#data-location): - a consumer of resource object MAY assume if no format or mediatype property is provided that the data is JSON and attempt to process it as such. - [loaders hdf5] misc bugfixes to hdf5 dataset loading (thanks @amotl for PR #728) - [loaders jsonl] fix copy-rows - [loaders pandas] support loading Python objects directly (thanks @ajkerrigan for PR #816 and scls19fr for bug report #798) - [loaders pandas] ensure all column names are strings (thanks @ajkerrigan for PR #816 and scls19fr for bug report #800) - [loaders pandas] build frequency table using a copy of the source (thanks @ajkerrigan for PR #816 and scls19fr for bug report #802) - [loaders sqlite] fix commit-sheet - [loaders sqlite] fix commit deletes - [loaders xlsx] only reload Workbook sheets to avoid error (thanks @aborruso for bug report #797) - [loaders vdj] fix add-row - [man] fix warnings with manpage (thanks @jsvine for the bug report #718) - [movement] fix scroll-cells (thanks @jsvine for bug report #762) - [numeric binning] perform degenerate binning when number of bins greater than number of values - (instead of when greater than width of bins) - [numeric binning] if width of bins is 1, fallback to degenerate binning - [numeric binning] degenerate binning should resemble non-numeric binning (thanks @setop for bug report #791) - [options] fix `confirm_overwrite` in batch mode - fix `-y` to set `confirm_overwrite` to False (means, no confirmation necessary for overwrite) - make `confirm()` always fail in batch mode - make `confirm_overwrite` a sheet-specific option - [plugins] only reload **Plugins Sheet** if not already loaded - [replay] move to replay context after getting sheet (thanks @rswgnu for bug report #796) - [replay] do not push replaying .vd on sheet stack (thanks @rswgnu for bug report #795) - [scroll] zj/zk do nothing in single-line mode (thanks @jsvine for suggestion) - [shell] empty stdin to avoid hanging process (thanks @frosencrantz for bug report #752) - [status] handle missing attributes in `disp_rstatus_fmt` (thanks @geekscrapy for bug report #764) - [tabulate] fix savers to save in their own format (thanks @frosencrantz for bug report #723) - [typing] fix indefinite hang for typing (thanks @lxcode for issue #794) - [windows] add Ctrl+M as alias for Ctrl+J #741 (thanks @bob-u for bug report #741) - [windows man] package man/vd.txt as a fallback for when man is not available on os (thanks @bob-u for bug report #745) ## Plugins - add conll loader to **PluginsSheet** (thanks @polm) - remove livesearch - add clickhouse loader ## Commands - if `options.some_selected_rows` is True, `setcol-expr`, `setcol-iter`, `setcol-subst`, `setcol-subst`, `setcol-subst-all` will return all rows, if none selected ## API - [columns] add Column.visibleWidth - [open] additionally search for `open_filetype` within the vd scope - [select] rename `someSelectedRows` to `onlySelectedRows` - [select] add new `someSelectedRows` and `options.some_selected_rows` (thanks maufdez for feature request #767) - if options is True, and no rows are selected, `someSelectedRows` will return all rows - [status] allow non-hashable status msgs by deduping based on stringified contents - [isNumeric] isNumeric is part of vdobj # v2.0.1 (2020-10-13) ## Bugfixes - Fix printing of motd to status # v2.0 (2020-10-12) ## Additions and Improvements - [aggregators] allow custom aggregators in plugins/visidatarc (thanks @geekscrapy for the feature request #651) - [loaders xlsx] automatically clean sheet name when saving; warn if sheet name changes (thanks @geekscrapy for the request #594) - [columns] unhide height attribute by default (thanks @frosencrantz for feature request #660) - add .vcf (VCard) loader - [sqlite] remove name of db from an **SqliteSheet**'s name, only tablename - [syspaste] make `syspaste-` replayable and undoable (note that `syspaste-` value will be recorded in **CommandLog**) - [savers] many text saver filetypes via tabulate library (thanks @jsvine for original vdtabulate plugin) - [calc] ExprColumn no longer cached by default - [loaders rec] add new .rec file loader and multisheet saver (recutils) - [savers] implemented multisheet saver for both json and jsonl - [loaders eml] add new .eml file loader for email files with attachments ## Options - add `options.incr_base` (thanks @chocolateboy for the suggestion #647) - (former) `options.force_valid_colnames` renamed to `options.clean_names` - applies to **Sheets** and **Columns** now (thanks @geekscrapy for the request #594) - for --X=Y, do not replace - with _ in Y (thanks @forensicdave for bug report #657) - add `options.default_height` for visibility toggle (thanks @frosencrantz for feature request #660) - add support for `--` option-ending option on CLI. - [input] default now `fancy_chooser` = True - when fancy_chooser enabled, aggregators and jointype are chosen with a ChoiceSheet. - `s` to select, `Enter` to choose current row, `g Enter` to choose selected rows, `q` to not choose any - numeric_binning is now True by default (enables numeric binning on **PivotSheet** and **FreqTable** for numeric columns ## Command changes and additions - (former) setcol-range (`gz=`) renamed to `setcol-iter` - (former) `addcol-range-step` (`i`) renamed to `addcol-incr-step` - (former) `setcol-range` (`gi`) renamed to `setcol-incr` - (former) `addcol-range-step` (`zi`) renamed to `addcol-incr-step` - (former) `setcol-range-step` (`gzi`) renamed to `setcol-incr-step` - add `scroll-cells-*` to scroll display of cells while remaining in a Column; bind to [g]z{hjkl} - (former) unbind z{hjkl} from `scroll-col` (thanks @geekscrapy for feature request #662) - add `type-floatsi` bound to `z%` (#661) - `reload-selected` now reloads all **Sheets** if none selected (thanks @geekscrapy for PR #685) - add customdate with fixed fmtstr for parsing (use `z@` and input a fmtstr compatible with strptime (thanks @suntzuisafterU for feature request #677) ## Bugfixes - [DirSheet] use changed ext as filetype when loading files (thanks @frosencrantz for bug report #645) - [slide] several major improvements to column sliding; key column sliding now works (thanks much to @geekscrapy for bug hunting #640) - [open-row] **Sheets Sheet** should be removed from stack upon `open-row` (thanks @cwarden for the bug report) - [cli] re-add --version (thanks @mlawren for bug report #674) - [open-config] fix `gO` (thanks @geekscrapy for bug report #676) - [splitwin] handle swap case for single sheet (thanks @geekscrapy for bug report #679) - [loaders xlsx] handle `None` column names for all **Sequence Sheet** loaders (thanks @jsvine for bug report #680) - [settings] retrieve from cache for top sheet if obj is None (thanks @aborruso for the bug report #675) - [settings] check if option is set on specific sheet before falling back to override - [describe] have **DescribeSheet** use source column's sheet's `options.null_value` to calculate its null column (thanks @aborruso for the bug report #675) - [undo] ensure that undos for complex commands (like `expand-cols`) are set more frequently (thanks @frosencrantz for the bug report #668) - it is still possible to find race conditions if the user presses commands fast enough, however they should happen far less frequently - [vlen] fix numeric binning for `vlen()` (thanks @frosencrantz for bug report #690) - [pivot] fix pivot case where no aggregator is set - [pyobj] fix filtering for **PyobjSheet** - [DirSheet] fix sorting for directory column of **DirSheet** (thanks @frosencrantz for bug report #691) - [json] fix bug saving cells with nested date values (thanks @ajkerrigan for PR #709) - [input] fix Ctrl+W bug when erasing word at beginning of line - [plugins] import `.visidata/plugins` by default - [pandas] use a safer `reset_index()` to avoid losing data when updating a pandas index (thanks @ajkerrigan for PR #710) - [threads] disable `add-row` on **ThreadsSheet** (thanks @geekscrapy for bug report #713) ## deprecated - complete removal of `status` and `statuses` from deprecated (thanks @frosencrantz for bug report #621) - longnames are now `open-status` and `show-status` - remove `cursorColIndex` ## API and Interface - `Sheet(*names, **kwargs)` autojoins list of name parts - `openSource()`, `aggregator()`, and `aggregators` are now part of vdobj - `set_option` is now `setOption` - move `isError` to `Column.isError` - deprecate `load_pyobj`, now **PyobjSheet** - add `.getall('foo_')` which returns all options prefixed with `'foo_'`; deprecated `options('foo_')` - `nSelected` is now `nSelectedRows` - make `Column.width` property, so setting is same as `Column.setWidth` - `evalexpr` is now `evalExpr` - `format` is now `formatValue` - `SettableColumn.cache` is now `._store` - `vdtype()` is now `vd.addType()` - add `addColumnAtCursor` (thanks @geekscrapy for bug report #714) ## Plugins - update sparkline (thanks @layertwo #696) - plugin dependencies now install into `plugins-deps` (former plugin-deps) ## Dev niceties - Fully automate dev setup with Gitpod.io (thanks @ajkerrigan for PR #673) # v2.-4 (2020-07-27) ## Additions and Improvements - [cmdlog] allow sheet-specific set-option for replay - [columns] add default uppercase names for created columns (like VisiCalc) - these names are global; no default name is ever reused - [cosmetic] a column with a width 1 will now display (thanks @frosencrantz for the bug report #512) - [defer] move defermods and vls back into vdcore - configure sqlite and DirSheet to use it - [dir] allow explicit filetype when loading a directory (thanks @geekscrapy for the bug report #546) - [errors] ErrorsSheet on `g Ctrl+E` lists errors, instead of concatenating - [expand-cols] account for all visible rows when expanding a column (thanks @ajkerrigan for PR #497) - [loaders csv] use `options.safe_error` for cell exceptions on save - [loaders http] use file format in path if loader available (thanks @jsvine for PR #576 and bug report #531) - if not, fail back to MIME type (prev behaviour) - [loaders imap] add loader for imap:// - [loaders json] handle non-dict rows in json data (thanks @ajkerrigan for PR #541 and @jsvine for bug report #529) - [loaders jsonl] show parse errors in every column - [loaders MySQL] add support for MySQL loader (thanks @p3k for PR #617) - [loaders pandas] upgrade pandas to 1.0.3 (thanks @ajkerrigan for PR #563) - [loaders pandas] add auto-loaders for feather, gbq, orc, parquet, pickle, sas, stata (thanks @khughitt for bug report #460) - [loaders pdf] add simple pdf loader - [loaders postgres] add support for connecting directly to rds (thanks @danielcynerio for PR #536) - the url has the following format: `rds://db_user@hostname:port/region/dbname` - it assumes that the AWS IAM for the user is configured properly - [loaders xls/xlsx] add save_xls and save_xlsx (thanks @geekscrapy for PR #574) - [loaders yaml] allow diving into YAML rows (thanks @ajkerrigan for PR #533) - [loaders yaml] use the default safe YAML loader (thanks @tsibley for the PR #600 ) - the full loader is unsafe because serialized files can be constructed which run arbitrary code during their deserialization - the safe loader supports a very large subset of YAML and supports the most common uses of YAML - [loaders yaml] support files containing multiple documents (thanks @tsibley for PR #601) - [options] set visidata_dir and config from `$VD_DIR` and `$VD_CONFIG` (thanks @tsibley for bug report #448) - [type fmtstr] thousands separator (thanks @dimonf for bug report #575) - default for int/float is string.format for roundtripping accurately in data text files like csv - if fmtstr starts with '%', use locale.format_string (with grouping) - otherwise, use python string.format - currency uses locale, and is grouped. - [quitguard] if set on specific sheet, only confirm quit on that sheet (thanks @jsvine for bug report #538) - [undo] add undo for `rename-col-x` family, mouse slide, and `reload-sheet` (thanks @jsvine for feature request #528) ## Command changes - [add-sheet] renamed to open-new; new sheet always has a single column - [config] bind `g Shift+O` back to open-config (#553) - [dive] convert many dive- commands to open- (#557) - add open-row bound to `ENTER` on Sheet itself - add `open-source` unbound on BaseSheet - deprecate `dive-*` longname - [options] options-global now `Shift+O`; options-sheet now `z Shift+O` - [multi-line] have visibility toggle Multi-Line Row on TextSheets (Closes #513) - used to toggle `wrap` ## Command additions - [canvas] add resize-x/y-input commands to set x/y axis dimensions (thanks @pigmonkey for feature request #403) - [errors] add select-error-col and select-error (thanks @pigmonkey for feature request #402) - [input] `Ctrl+Y` paste from cell clipboard - [input] Ctrl+Left/Right move cursor to prev/next word - [iota] add `i` family of commands (iota/increment) - (former) setcol-range (`gz=`) renamed to `setcol-iter` - `addcol-range-step` (`i`): add column with incremental value - `secol-range` (`gi`): set current column for selected rows to incremental values - `addcol-range-step` (`zi`): add column with incremental values times given step - `setcol-range` (`gzi`): set current column for selected rows to incremental values times given step - [mouse] add unbound `mouse-enable` and `mouse-disable` commands - [quitguard add unbound `guard-sheet` command to set quitguard on current sheet (thanks jsvine for feature request #538) - [unfurl-col] add command, bound to `zM`, which does row-wise expansion of iterables in a column (thanks @frosencrantz for feature request and jsvine for initial code sample #623) - thanks @jsvine for name and initial implementation ## Options - [cli] custom cli option parsing (thanks @tsibley for the behaviour request #573) - `--options` apply as sheet-specific option overrides to the sources following them - the last setting for a given option is the cli-given override setting (applies to all cli sources, unless they have the option already set) - this allows both - `vd -f csv foo.txt` - `vd foo.txt -f csv` - `--help` opens the manpage - `-g` prefix sets option globally for all sheets - [cli] add --imports (default "plugins") (thanks @tsibley for feature request #448) - space-separated list of modules to import into globals before loading .visidatarc - plugins can be installed by VisiData without modifying .visidatarc - [chooser] experimental `options.fancy_chooser` - when fancy_chooser enabled, aggregators and jointype are chosen with a ChoiceSheet. - press `ENTER` on any row to choose a single option, or select some rows, and press `ENTER` to choose the selectedrows - warning: the mechanism to do this effectively launches another instance of visidata, and so it is possible to get into an embedded state (if you jump around sheets, for example, instead of selecting). 'gq' should still work (thought `CTRL+Q` may need to be pressed several times). - [dir] add `-r` alias for `--dir-recurse` - [join-cols] add `options.value_joiner` to combine cell values for join-col (thanks @aborruso for feature request #550) - [join-cols] add `options.name_joiner` to combine column names for join-col, and sheet names for dive-row (thanks @aborruso for feature request #550) - sheet names for join-sheets are still joined with '+' or '&' for the time being - [loaders html] add `options.html_title` to exclude the sheetname when saving sheet as html table (thanks @geekscrapy for PR #566) - [loaders postgres] add support for custom postgres schema (Thanks @p3k for PR #615) - schema defaults to `public` but can be overridden using the `--postgres-schema` flag: - `vd --postgres-schema=foo postgres://user:pw@localhost/foobar` - [loaders zip] -f filetype now applies to inner files - [mouse] add options.mouse_interval to control the max time between press/release for click (ms) - set to 0 to disable completely - [pyobj] add `options.expand_col_scanrows` to set the number of rows to check when expanding columns (0 = all) - [type fmtstr] add fmtstr options for numerical types - add options.disp_currency_fmt - add options.disp_int_fmt - add options.disp_date_fmt ## Plugins - [dependencies] install plugin dependencies into vd dir (thanks @tsibley for feature request #448) - [diff] diff is now a plugin - `--diff` is not available as a cmdline argument anymore - [vds3] bumped to 0.4 (@ajkerrigan) - [marks] initial release 0.1; marks selected rows with a keystroke; utils for selecting + viewing marked rows (@saulpw) - [genericSQL] initial release (1.0); basic loader for MySQL (Oracle, MySQL) (@aswanson) - [diff] is now a plugin (@saulpw) ## Bugfixes - [cmdlog] fix case where CommandLog `open-` entries would not be replayable - [cmdlog] record keystrokes for command - [cmdlog] global cmdlog behaviour is now consistent with VisiData v1.5.2 cmdlog - [dirsheet] check if directory before grabbing filetype from ext (thanks @frosencrantz for bug report #629) - handles case where `.` in directory name - [helpsheet] do not include deprecated longnames (thanks @frosencrantz for bug report #621) - [input] flush input buffer upon newline in input; prevent pastes with accidental newlines from becoming keystrokes (thanks @geekscrapy for bug report #585) - [loaders csv] PEP 479 fix for csv loader (thanks @ajkerrigan for PR #499) - This avoids the following error when opening CSV files in Python 3.8: `RuntimeError: generator raised StopIteration`, but maintains the behaviour of gracefully handling malformed CSV files. - References: - https://www.python.org/dev/peps/pep-0479/#examples-of-breakage - https://github.com/python/cpython/pull/6381/files - [loaders html] cast to str before writing (thanks @geekscrapy for bug report #501) - [loaders html md] preserve formatting of display values when saving - [loaders html] fix string formatting issue for the html table name when saving (thanks @geekscrapy for PR #566) - [loaders pandas] bugfixes for sort (thanks @ajkerrigan for PR #496) - [loaders pandas] fix row deletion + its undo (thanks @ajkerrigan for PR #496) - [loaders pandas] improve regex select/unselect logic (thanks @ajkerrigan for PR #496) - [loaders pandas] fix row selection/deselection (thanks @ajkerrigan for PR #496) - [loaders postgres] load an estimate of row numbers for improved performance (thanks @danielcynerio for PR #549) - [loaders postgres] fix expand column to work on a json column in postgres (thanks @danielcynerio for PR #552) - [loaders sqlite] save display value if not supported sqlite type (thanks @jtf621 for bug report #570) - [loaders xml] correctly copy columns; fix path (#504) - [numeric-binning] fix numeric-binning bug with currency type column - [dir] fix dup-rows-deep on DirSheet (thanks @geekscrapy for bug report #489) - [rstatus] fix rstatus when repeating a command with no keystrokes (Thanks @ajkerrigan for bug report #577) - [save-sheets] fix saving multi-sheets as individual files to directory - [settings] remove internal option defaults from cmdlog - [sheets_all] make opened .vd/.vdj precious - [transpose] handle case where columns are numeric (thanks @frosencrantz for bug report #631) - [undo] fix undo with duplicate-named sheets (thanks @jsvine for bug report #527) - [utils] Fix namedlist bug with column named after VisiData attrs (particularly 'length') (thanks @tsibley for bug report #543) ## Infrastructure / API - [asyncsingle] ensure that unfinished threads decorated with @asyncsingle do not block upon sync() - used so that domotd() and PluginsSheet().reload() do not block replay progression - [open-] switch from vd.filetype to open_ext; deprecate vd.filetype - [warnings] output Python warnings to status # v2.-3 (2020-03-09) ## Major changes - [cosmetic] change default column separators - [json] make json load/save key order same as column order (ensures round-trip #429) - [commands.tsv] remove commands.tsv; move helpstr into code ## Major features - add Split Window - options.disp_splitwin_pct (default: 0) controls height of second sheet on screen - add .vdj for cmdlog in jsonl format - add plugins/bazaar.jsonl for PluginsSheet in jsonl format ### new commands - `splitwin-half` (`Shift+Z`) -- split screen, show sheet under top sheet - `splitwin-close` (`g Shift+Z`) -- closes split screen, current sheet full screens - `splitwin-swap` (`TAB`) -- swap to other pane - `splitwin-input` (`z Shift+Z`) -- queries for height of split window - `repeat-last` (unbound) -- run the previous cmd longname with any previous input (thanks #visidata for feature request! #441) - `repeat-input` (unbound) -- run the last command longname with empty, queried input (thanks #visidata for feature request! #441) - `resize-cols-input` (`gz_`) -- resize all visible columns to given input width - thanks @sfranky for feature request #414 - `save-col-keys` (unbound) -- save current column and key columns - fixes #415; thanks @sfranky for feature request ### new options - options.disp_float_fmt; default fmtstr to format for float values (default: %0.2f) - thanks khughitt for PR! #410 ## Additions and Improvements - add merge jointype (thanks @sfranky for feature request #405) - like "outer" join, except combines columns by name and each cell returns the first non-null/non-error value - use color_diff to merge join diffs - on edit, set values on *all* sheets which have the given row - adjust `save-cmdlog` input message for clarity - all sheets have a name (thanks @ajkerrigan for helping iron out the kinks with PR #472) - add args re-parsing to handle plugin options (helps with #443; thanks tkossak for bug report) - vdmenu should only get pushed outside of replay and batch mode - move cursor to row/col of undone command (thanks @jsvine for request) - move urlcache into async reload (affects PluginsSheet and motd) - add 'type' column to `SheetsSheet` ### Command changes - `HOME`/`END` now bound to `go-leftmost`/`go-rightmost` - thanks [@gerard_sanroma](https://twitter.com/gerard_sanroma/status/1222128370567327746) for request - `z Ctrl+HOME`/`z Ctrl+END` now bound to `go-top`/`go-bottom` - `Ctrl+N` now bound to `replay-advance` ### longname renamings - `search-next` (was `next-search`) - `search-prev` (was `prev-search`) - `jump-prev` (was `prev-sheet`) - `go-prev-value` (was `prev-value`) - `go-next-value` (was `next-value`) - `go-prev-selected` (was `prev-selected`) - `go-next-selected` (was `next-selected`) - `go-prev-null` (was `prev-null`) - `go-next-null` (was `next-null`) - `go-right-page` (was `page-right`) - `go-left-page` (was `page-left`) ## Plugins - add usd plugin - provide USD(s) function to convert strings with currencies to equivalent US$ as float - uses data from fixer.io - add vds3 by @ajkerrigan - initial support for browsing S3 paths and read-only access to object - add "provides" column for plugins (helps with #449; thanks @tsibley for feature request) - standardize author in bazaar.jsonl - "Firstname Lastname @githbhandle" ## Bugfixes - [cmdlog] fix issue with `append_tsv_row`, that occurred with `options.cmdlog_histfile` set - [replay] fix replaying of rowkeys - [replay] fix race condition which required the `--replay-wait` workaround - [plugins] ensure that `options.confirm_overwrite` applies to plugin installation - [slide] fix slide-leftmost - had inconsistent behaviour when a sheet had key columns - [slide] use visibleCol variants, such that slide works as expected with hidden cols - [options min_memory_mb] disable (set to 0) if "free" command not available - [core] auto-add raw default column only if options.debug (fixes #424; thanks @frosencrantz for bug report) - [cli] fix --config (thanks @osunderdog for bug report! #427) - [draw] fix status flickering that occurred with certain terminals (thanks @vapniks for bug report #412) - [txt save] save all visibleCols instead of only first one - [json] avoid adding columns twice when loading JSON dicts (thanks @ajkerrigan for bug report (#444) and PR (#447) - [fixed] fixed error that occurs when there are no headerlines (thanks @frosencrantz for bug report #439) - [pcap] update loader with modern api - [csv] catch rows with csv.Errors and yield error msg - [curses] keypad(1) needs to be set on all newwin (fixes #458) - [save-sheets] address two bugs with `g Ctrl+S` - [batch api] override editline() in batch mode (addresses #464; thanks @Geoffrey42 for bug report) - [replay] better handling of failed confirm (addresses #464; thanks @Geoffrey42 for bug report) - [asyncthread] with changed decorators, asyncthread should be the closest decorator to the function - if it is not, the act of decorating becomes spawned off, instead of calls to the function being decorated - [canvas] update Canvas delete- commands with current API (fixes #334) ## Infrastructure / API - rename `Sheet` to `TableSheet` - deprecate `Sheet` but keep it around as a synonym probably forever - use HTTPS protocol for git submodules (thanks @tombh for PR #419) - this allows installation of VisiData in automated environments such as Dockerfiles where the git user is not logged into Github - unit tests have been migrated to pytest - use counter to keep track of frequency of column names - for joins, we want un-ambiguous sheets of origin when more than one sheet has a c.name - all sheets use addColumn api instead of manually appending columns - set terminal height/width via LINES/COLUMNS via curses.use_env (thanks halloleo for feature request #372) - update pip command to pull development branch of vsh (thanks @khughitt for PR #457) - change longnames *-replay to replay-* - rename vd.run() to vd.mainloop() - `vd.save_foo(p, *sheets)` throughout - standardize on vd.exceptionCaught - Sheet.addRows renamed to Sheet.addNewRows - option overrides can be done with SubSheet.options - options set with Sheet.options - extend status() varargs to error/fail/warning - add @BaseSheet.command decorator - rename tidydata.py to melt.py - deprecate globalCommand; use BaseSheet.addCommand - remove vd.addCommand - deprecate theme(); use option() instead - deprecate global bindkey/unbindkey - move commands, bindkeys, `_options` globals to vd object - DisplayWrapper compares with its value - this allows sensible colorizers like `lambda s,c,r,v: v==3` - Sheet.addColorizer now apply to single sheet itself (fixes #433; thanks @frosencrantz for bug report) - add Sheet.removeColorizer (thanks @frosencrantz for feature request #434) # v2.-2 (2019-12-03) ## Major changes - [cmdlog] every sheet now has its own cmdlog - change `Shift+D` to `cmdlog-sheet`, with commands from source sheets recursively - `gShift+D` now `cmdlog-all` - `zShift+D` `cmdlog-sheet-only` - [dirsheet] VisiData's DirSheet is readonly; move write-mode for DirSheet to `vls` (see plugins) - [options] `options-global` bound to `gO`and `options-sheet` to `O` - `open-config` is now unbound (previously `gO`) - [defermods] has been moved to an opt-in plugin - [vdmenu] launching `vd` without a source file, opens menu of core sheets - press `Enter` to open sheet described in current row ## Major Features - [IndexSheet] index into sub-sheets from command line (thanks @aborruso for suggestion #214) - currently works for html and hdf5 loaders - `+:subsheet:col:row` in cli - `subsheet` the topsheet upon load, with cursor located in cell at `row` and `col` - `+:subsheet::` to ignore row/col - can name toplevel source index if more than one: `+toplevel:subsheet::` ## Additions and improvements - [add-rows] now undo-able - [aggregators] show-aggregate with quantiles (thanks @wesleyac for feature request #395) - [cli] `-P ` on commandline executes command on startup - [cmdlog] jump commands are not logged - [config] set VisiData height/width via LINES/COLUMNS envvars (thanks @halloleo for suggestion #372) - [csv] add `csv_lineterminator` option (default: '\r\n') (thanks @dbandstra for bug report #387) - retain csv writer default DOS line endings - [describe] add `options.describe_aggrs` (thanks @unhammer for suggestion #273) - space-separated list of statistics to calculate for numeric columns - default to existing 'mean stdev' - add this to .visidatarc for e.g. a harmonic mean to be added automatically to the describe sheet: ``` from statistics import harmonic_mean options.describe_aggrs += ' harmonic_mean' # note the leading space ``` - [describe] add hidden "type" col (thanks aborruso for suggestion #356) - [dirsheet] add `open-dir-current` command to open the DirSheet for the current directory - [help] add `help-commands-all` on `gz^H` (thanks @frosencrantz for suggestion #393) - [help] add `help-search` command (thanks @paulklemm for suggestion #247) - opens a commands sheet filtered by the input regex. - [loaders] add --header and --skip universal handling to all sheets that inherit from `SequenceSheet` (currently tsv/csv/fixed/xlsx/xls) - [menu] if no arguments, open VisiData Main Menu instead of DirSheet - [plugins] update PluginsSheet to add sha256 and vdpluginsdeps - [plugins] PluginsSheet now loads plugins in `~/.visidata/plugins/__init__.py` instead of in `~/.visidatarc` - to use this feature, add `from plugins import *` to `~/.visidatarc` - [pyobj] for security reasons, `.py` loader moved out of VisiData core and into snippets - Note that the PyObj loader auto-imports `.py` modules upon loading them - [ttf] use `Enter` to plot instead of `.` ## Plugins - add hello world minimal plugin - update viewtsv example (thanks @suhrig for --skip improvement suggestions #347) - add vmailcap with `^V` to view by mimetype (thanks @cwarden for suggestion) - add basic frictionless loader (thanks @aborruso for suggestion #237) - `-f frictionless` with .json either http[s] or local file - .zip may not work yet - add fdir filetype; opens a DirSheet for a .txt with a list of paths - move trackmod and defermod out of VisiData core and into module defermods.py - defermods defers saving to source until commit-sheet - deleted rows are colored red and visible until commit - trackmods tracks changes in source sheet until save-sheet - deletes are removed upon delete-row(s) - defermods and trackmods are not on by default, `import visidata.defermods` must be added to visidatarc - plugin/loader authors: by default, all sheets that inherit from BaseSheet have .defermods=False and .trackmods set to True when defermods is imported - create package `vsh`; add to it `vls`, `vping`, `vtop` - `vls` contains write-mode for DirSheet - add vmutagen for audio tags on DirSheet - `Alt+m` to add the mutagen columns on the DirSheet - add geocoding using nettoolkit.com API - add `addcol-geocode` command to add lat/long columns from location/address column - new commands in rownum plugin - `addcol-rownum` adds column with original row ordering - `addcol-delta` adds column with delta of current column - vtask is now a discrete plugin ## Bugfixes - [bindkey] move global bindkey after BaseSheet bindkey (thanks @sfranky for bug report #379) - [cmdlog] now will check for `confirm-overwrite` - [dirsheet] commit/restat/filesize interactions (thanks @Mikee-3000 for bug report #340) - [dirsheet] pass filetype to openSource - if filetype is not passed, options.filetype would overload file ext - [expr] catch recursive expression columns (columns that calculate their cells using themselves) (thanks @chocolateboy for bug report #350) - [fixed] various improvements to fixed-width sheet loader (thanks @frosencrantz for thorough bughunting #331) - [http] use options.encoding when no encoding is provided by responses headers (thanks @tsibley for the PR #370) - [join] joining columns in the ColumnSheet resulted in exception (thanks @frosencrantz for bug report #336) - [load] fix replay sync bug (required wait previously) - however, look out for `vd *` with lots of big datasets, they will now all load simultaneously - [longname] fix getCommand() error reporting - [mbtiles] now works again - [metasheets] created VisiDataMetaSheet which sets system TsvSheet options - now changes in tsv options for source files will not affect HelpSheet, CmdLog or PluginsSheet - thanks frosencrantz for bug report #323 - [options] no error on unset if option not already set - [path] filesize of url is 0 - [path] fix piping bug (vd failed to read stdin) (thanks @ajkerrigan for bug report #354) - [plugins] ensure consistent Python exe for plugin installs (thanks @ajkerrigan for fix) - [plugins] make plugin removal more predictable (thanks @ajkerrigan for fix) - [prev-sheet] would stack trace if more than one sheet loaded and no other sheet visited (thanks @frosencrantz for bug report #342) - [regex] will not silently fail if some example rows are not matches - [save] convert savers to use itervalues - itervalues(format=False) now yields OrderedDict of col -> value - value is typed value if format=False, display string if True - options.safety_first will convert newlines and tabs to options.tsv_safe_newline and options.tsv_safe_tab (thanks @mesibov for bug report #76) - [sheets] colorizer exceptions are now caught - [sheets] keycols now keep order they are keyed - [sysedit] trim all trailing newlines from external edits (thanks @sfranky for bug report #378) - [tsv] column name "length" prevented loading (thanks @suhrig for bug report #344) - [undo] redo with cmd on first row did not move cursor (thanks @Mikee-3000 for bug report #339) - now row/col context are set as strings, even when they are numeric indices ## Infrastructure / API - [add-row] create a default newRow for Sheet (thanks @for-coursera for bug report #363) - [calc] add INPROGRESS sentinel - sentinel that looks like an exception for calcs that have not completed yet - [extensible] add new cached_property, which caches until clear_all_caches, which clears all cached_property - [Fanout] add Fanout - fan out attribute changes to every element in a list; tracks undo for list - [lazy_property] newSheet and cmdlog are now lazy_property - this enables the overwriting and extending of them by plugins - [loaders] add sheet.iterload() - will use sheet.source to populate and then yield each row - [loaders] vd.filetype(ext, ExtSheet) to register a constructor - [loaders] add Sheet.iterrows() to yield row objects - grouping use iterrows() for streaming input - __iter__() yields LazyComputeRows ``` for row in vd.openSource('foo.csv'): print(row.date, row.name) ``` - [IndexSheet] refactor SheetsSheet parent to IndexSheet - HtmlTablesSheet now inherits from IndexSheet - excel index changed to standard IndexSheet model - VisiDataSheet changed into IndexSheet - move join-sheets to IndexSheet - [options] add unset() to unset options (thanks @khughitt for suggestion #343) - [path] consolidate PathFd, UrlPath, and HttpPath into Path - [SequenceSheet] refactor tsv, csv, xls(x), fixed_width to inherit from SequenceSheet - [sheets] vd.sheetsSheet is sheetstack, vd.allSheetsSheet is sheetpile - [sheets] rename LazyMap to LazyChainMap and LazyMapRow to LazyComputeRow - [shortcut] BaseSheet.shortcut now property - [status] make right status more configurable (thanks @layertwo #375 and khugitt #343 for filing issues) - BaseSheet.progressPct now returns string instead of int - BaseSheet.rightStatus() now returns string only (not color) - by default uses `options.disp_rstatus_fmt`, configured like `disp_status_fmt` - progress indicator (% and gerund) moved out of rightStatus and into drawRightStatus - [undo] use undofuncs to associate command with its undo - [undo/redo] moved to undo.py - [vd] add sheet properties for errors and statuses - [vd] vd.quit() now takes `*sheets` - [vd] rename main() to main_vd() # v2.-1 (2019-08-18) ## Major changes - Minimum Python requirement bumped to 3.6 - Several interface changes (see below) ## Major features - add Alt/Esc as prefix; Alt+# to go to that sheet - Alt+ layer not otherwise used; bind with `^[x` for Alt+X - undo/redo - [new command] `options.undo` (default: True) to enable infinite linear undo/redo - provisionally bound to `Shift+U` and `Shift+R` - will undo most recent modification on current sheet - `undoEditCells` assumes commands modified only selectedRows - multi-line rows - toggle by pressing `v` on any sheets with truncated values - range binning for numeric columns - `options.numeric_binning` (default: False) is the feature flag - [feature freqtbl] numeric binning for frequency/pivot table - `options.histogram_bins` to set number of bins (0 to choose a reasonable default) - (thanks @paulklemm for the issue #244) - stdout pipe/redirect - `ls|vd|lpr` to interactively select a list of filenames to send to the printer - `q`/`gq` to output nothing - `Ctrl+Q` to output current sheet (like at end of -b) - `vd -o-` to send directly to the terminal (not necessary if already redirected) - plugin framework - plugins are optional Python modules that extend or modify base VisiData's functionality - this release establishes a structure for creating plugins, and provides an interface within VisiData for installing them - `open-plugins` opens the **PluginsSheet** - to download and install a plugin, move the cursor to its row and press `a` (add) - to turn off a plugin, move the cursor to its row and press `d` (delete). - for more information see (https://visidata.org/docs/plugins) - deferred changes - modifications are now highlighted with yellow, until committed to with `^S` (`save-sheet`) ## interface changes - `setcol-*`, `dive-selected`, `dup-selected-*`, `columns-selected`, `describe-selected` use only selectedRows (do not use all rows if none selected) #265 (thanks @cwarden) - `edit-cells` renamed to `setcol-input` - `fill-nulls` renamed to `setcol-fill` - `paste-cells` renamed to `setcol-clipboard` - `dup-cell`/`dup-row` on SheetFreqTable and DescribeSheet renamed to `dive-cell`/`dive-row` - `next-page`/`prev-page` renamed to `go-pagedown`/`go-pageup` - `save-col` always saves all rows in current column (instead of selectedRows or rows) - `copy-*` use only selectedRows, warning if none selected (cmdlog safe) - `syscopy-*` use only selectedRows, fail if none selected (not cmdlog safe) - all `plot-selected` are now `plot-numerics`; `plot-numerics` uses all rows - Shift+S pushes `sheets-stack`; gS pushes `sheets-all`. removed graveyard sheet. - `random-rows` is no longer bound to any key by default (was Shift+R). - `freq-summary` was `freq-rows`; adds summary for selected rows - cmdlog is now based on longname instead of keystrokes - cmdlog does not log resize commands - exit with error code on error during replay (suggested by @cwarden #240) - split `Ctrl+V` (check-version) into `Ctrl+V` (show-version) and `z Ctrl+V` (require-version) - `show-expr` now unbound from `z=` - add `options.row_delimiter` (default to `\n`) ## plugins - vfake: anonymizes columns - livesearch: filter rows as you search - rownum: add column of original row ordering - sparkline: add a sparkline column to visualise trends of numeric cells in a row (thanks @layertwo #297) ## Bugfixes - [addcol-new] addcol-new now works in batch mode (thanks @cwarden for the bug report #251) - [canvas] clipstr xname to prevent overlap with 1st element in xaxis - [color] column separator color applies to regular rows (thanks @mightymiff for bug report #321) - [DirSheet] delete-selected now deletes all of the selected files upon save-sheet (thanks @cwarden for the bug report #261) - [display] fix resizing issue with wide chars (thanks @polm for the bug report #279 and for the fix #284 ) - [freqtbl] unselect-rows now updates source rows (thanks @cwarden for bug report #318) - [go-col-regex] nextColRegex sheet is implicit parameter - [help] use tab as sep for system sheets (thanks @frosencrantz for bug report #323) - [plot] graphing currency values now works - [pyobj] SheetDict nested editing (thanks @egwynn for the bug report #245) - [txt] TextSheets now save as .txt - [yaml] handle sources that do not load as lists (thanks @frosencrantz for bug report #327) - [vdtui] make Sheet sortable (related to an issue found by @jsvine #241) ## Additions and improvements - [addcol-new] does not ask for column name - [aggr] add `list` aggregator (thanks @chocolateboy #263) - [canvas] add legend width to fit max key (thanks @nicwaller for request) - [chooseMany] error() on invalid choice #169 - [command join] add join-sheets-top2 (`&`) / join-sheets-all (`g&`) to Sheet to join top 2/all sheets in sheets-stack - [command sort] `sort-*-add` bound to z[] and gz[] to add additional sort columns - [command syspaste-cells] add `syspaste-cells` to paste into vd from system clipboard (thanks kovasap for PR #258) - [describe] add `sum` (thanks @pigmonkey for suggestion #315) - [DirSheet] include folders and hidden files - [exec-longname] enable history - [freeze-sheet] only freeze visibleCols - [html] add links column where hrefs available (suggested by @am-zed #278) - [license] remove MIT license from vdtui; all code now licensed under GPL3 - [loader fixed] provide a way to limit the max number of columns created (thanks @frosencrantz for suggestion #313) - added `options.fixed_maxcols` (default: no limit) - [loader fixed] loaders override putValue, not setValue (thanks @aborruso for bug report #298) - [loader jira] add support for jira filetype, a markdown derivative compatible with Atlassian JIRA (thanks @layertwo #301) - [loader Pyobj] `py` filetype to import and explore a python module: `vd -f py curses` - [loader pyxlsb] add .xlsb loader (suggested by @woutervdijke #246) - [loader ndjson ldjson] add as aliases for jsonl - [loader npy] add .npy loader, including type detection - [loader npz] add support for .npz index - [loader usv] add .usv loader - [macros] is now deprecated - [motd] domotd is asyncsingle and thus not sync-able - [mouse] bind Ctrl+scrollwheel to scroll-left/right; change to move cursor by `options.scroll_incr` (like scroll-up/down) - [mouse] slide columns/rows with left-click and drag - [openSource] create new blank sheet if file does not exist - [option json] add `options.json_sort_keys` (default True) to sort keys when saving to JSON (thanks @chocolateboy for PR #262) - [option regex+] `options.default_sample_size` (default 100) to set number of example rows for regex split/capture (now async). use None for all rows. (thanks @aborruso #219) - [option vd] `--config` option to specify visidatarc file (suggested by @jsvine #236) - [option vdtui] remove `curses_timeout` option (fix to 100ms) - [pandas] support multi-line column names (suggested by @jtrakk #223) - [pandas] implement sort() for pandas DataFrame (suggested by @migueldvb #257) - [pandas] use value_counts() for PandasSheetFreqTable (thanks @azjps for PR #267) - [pandas] selection support for PandasSheet (thanks @azjps for PR #267) - [pandas] reset index (thanks @danlat #277) - [pandas] if the df contains an index column, hide it - [pcap] adds saver for .pcap to json (thanks @layertwo for PR #272) - [perf] expr columns are now set to cache automatically - [perf] drawing performance improvements - [perf] minor improvements to cliptext - [perf] several minor optimisations to color - [precious] describe-sheet is now precious; error-sheet and threads-sheet are not - [replay] show comments as status (suggested by @cwarden) - [save] make all `save_` callers async - [sqlite] add save (CREATE/INSERT only; for wholesale saving, not updates) - [sqlite] `Ctrl+S` to commit add/edit/deletes - [sqlite] add support for .sqlite3 extension - [tar] add support for opening tar files (thanks @layertwo #302) - [vdmenu] `Shift+V` opens menu of core sheets - press `Enter` to open sheet described in current row - [win] several changes made for increased windows-compatibility (thanks @scholer!) - [yaml] bump min required version (thanks @frosencrantz for suggestion #326) ## API - VisiData, BaseSheet, Column inherit from Extensible base class - internal modules and plugins can be self-contained - `@X.property @X.lazy_property`, `X.init()`, `@X.api` - remove Sheet.vd; 'vd' attrs now available in execstr - remove hooks - add @deprecated(ver) decorator; put deprecations in deprecated.py - `vd.sync(*threads)` waits on specific threads (returned by calls to `@asyncthread` functions) - add Sheet.num for left status prompt - pivot and frequency table have been consolidated for numeric binning - add Sheet.nFooterRows property - Sheet.column() takes colname instead of regex; add Sheet.colsByName cached property - use addRow to rows.append in reload() - Selection API is overloadable for subclasses of Sheet whose rows don't have a stable id() (like pandas) - use locale.format_string and .currency - uses user default locale settings at startup - changes fmtstr back to %fmt (from {:fmt}) - vdtui broken apart into separate modules: editline, textsheet, cliptext, color, column, sheet - much code reorganization throughout - convert all `vd()` to `vd` - remove ArrayColumns, NamedArrayColumns - urlcache now takes days=n - Sheet.rowid - add windowWidth and windowHeight - Sheets use their own .scr, in preparation for split-screen - add VisiData.finalInit() stage - call vd.finalInit() at end of module imports to initialise VisiData.init() members - so that e.g. cmdlog is not created until all internal sheet-specific options has been set - remove replayableOption() (now replay an argument within option()) - CursesAttr is now ColorAttr; ColorAttr now a named tuple - variables that contain a ColorAttr have been renamed from attr to cattr for readability - improvements to scrolling API - rename most cases of Sheet*/Column* to *Sheet/*Column - use pathlib.Path in visidata.Path - remove BaseSheet.loaded; add BaseSheet.rows = UNLOADED - vd.push no longer returns sheet - add @asyncsingle for asyncthread singleton ## Deps - add submodule fork of pyxlsb for VisiData integration - add amoffat/sh as submodule for vgit and vsh - [postgres] swap for binary version of dep # v1.5.2 (2019-01-12) ## Bugfixes - [regex] fix `g*` #239 (thanks to @jsvine for bug hunting) - [editline] suspend during editline will resume in editline - [editline] `Ctrl+W` on an empty value in editline now works ## Docs - [manpage] update the manpage to be more accurate for boolean command line options # v1.5.1 (2018-12-17) ## Bugfixes - [canvas] fix mouse right-click and cursor movement on canvas - [idle performance] fix regression - [columns] fix editing of "value" column on ColumnsSheet - [describe] fix colorizer inheritance - [csv] always create at least one column - [pandas] fix pandas eval (`=`, etc) #208 (thanks to @nickray for suggesting) - [pandas] preserve columns types from DataFrame #208 (thanks to @nickray for suggesting) - [pandas] remove data autodetect #208 (thanks to @nickray for suggesting) ## Additions and changes - [selection] `options.bulk_select_clear` per #229 (thanks to @aborruso for suggesting) - [setcol-subst-all] add `gz*` to substitute over all visible cols (thanks to @aborruso for suggesting) - [options] Shift+O now global options (was sheet options); `zO` now sheet options; `gO` now opens .visidatarc which can be edited (was global options) - [sort] orderBy now asynchronous #207 (thanks to @apnewberry for suggesting) - [fill] fill now async; uses previous non-null regardless of selectedness #217 (thanks to @aborruso for suggesting) - [pandas] `options.pandas_filetype_*` passed to `pandas.read_` (like `csv_*` to Python `csv` module) # 210 (thanks to @pigmonkey for suggesting) - [rename-col-selected] `z^` now renames the current column to contents of selected rows (previously `gz^`); `gz^` now renames all visible columns to contents of selected rows #220 (thanks to @aborruso for suggesting) - [vdtui null] show null display note in cells which match `options.null_value` (was only for None) # 213 (thanksto @aborruso for suggesting) - [vdtui] visidata.loadConfigFile("~/.visidatarc") for use in REPL #211 (thanks to @apnewberry for suggesting) - [progress] include thread name on right status during async - [progress] add gerund to display (instead of threadname) - [http] user specified filetype overrieds mime type - e.g. `vd https://url.com/data -f html` - [clipboard] use `options.save_filetype` for default format # v1.5 (2018-11-02) ## Bugfixes - [clipboard] fix broken `gzY` (syscopy-cells) - [cmdlog] always encode .vd files in utf-8, regardless of options.encoding - [tsv] major `save_tsv` performance improvement - [tsv] make short rows missing entries editable - [shp] reset columns on reload - [graph] shift rightmost x-axis label to be visible - [http] allow CLI urls to have `=` in them - [fixed width] truncate cell edits on fixed width sheets - [aggregators] ignore unknown aggregators - `visidata.view(obj)`: obj no longer required to have a `__name__` ## Additions and changes - [save tsv json] errors are saved as `options.safe_error` (default `#ERR`) - if empty, error message is saved instead - [plugins] `~/.visidata` added to sys.path on startup - put plugin in `~/.visidata/vdfoo.py` - put `import vdfoo` in `.visidatarc` to activate - [aggregators] show-aggregate (`z+`) now aggregates selectedRows - [tsv] add unnamed columns if extra cells in rows - [diff] now based on display value (more intuitive) - [mouse] move to column also - [mouse] right-click to rename-col, rename-sheet, or edit-cell - [cosmetic] addcol-new (`za`) input new column name on top of new column - [cosmetic] include file iteration in progress meter - [xls xlsx] use options.header to determine column names # v1.4 (2018-09-23) ## Bugfixes - batch mode with no script should use implicit stdin only if no other files given (Closed #182) - [pivot] pivot keycolumn copy was yielding strange nulls - [join] fix extend join - [csv] include first row in file even if `options.header` == 0 - [sysclip] fix bug where `gzY` did not copy selected rows (Closed #186) - [motd] fix bug with disabling `options.motd_url` (Closed #190) ## Additions and changes - various improvements in performance and in CPU usage (Closed #184, #153) - [pyobj] `visidata.view(obj)` and `visidata.view_pandas(df)` - [pandas] `-f pandas` loads file with `pandas.read_` - [TextSheet] wrap made consistent with new options - [date] date minus date now gives float number of days instead of seconds - [pcap] add support for reading pcapng (thanks @layertwo!) - [setcol] limit `gz=` range parameters to the number of rows selected to be filled (thanks @ssiegel!) - [anytype] format anytype with simple str() # v1.3.1 (2018-08-19) - [http] add `tab-seperated-values` to content_filetypes mapping - [join] add `extend` join type to use keep all rows and retain **SheetType** from first selected sheet - `rename-sheet` renames current sheet to input - [json] add options.json_indent for pretty-printing - [tsv json txt] add options.save_errors (default True) to include errors when saving - remove all options.foo_is_null and fix according to 178-nulls.md - add `z^C` and `gz^C` to cancel threads in current/selected row(s) - [bugfix] `^R` (reload) on a filtered sheet (`"`) now reloads only the filtered rows - [aggregators] fix summation with exceptions - [DirSheet] add `gz^R` (reload-rows) to undo modifications on selected rows # v1.3 (2018-08-11) - commands overhaul; see `commands.tsv` (command longnames should now be largely stable) - add quantile aggregators (q3/q4/q5/q10) - add `z;` to add new column from bash *expr*, with `$`columnNames as variables - keyboard layout (thanks to @deinspanjer for the inspiration) - `O` launches sheet-specific options (see design/169.md); `gO` launches global OptionsSheet - options.wrap now defaults to False - options.quitguard enables confirmation before quitting last sheet - options.safety_first makes loading/saving more robust, at the cost of performance - currently only removing NULs from csv input - dedup, sort, color status messages by "priority" (thanks to @jsvine for suggestion) - remove menu system - can now edit source values from FreqSheet - Command changes - `^H` is now main command to open the manpage! `z^H` opens a list of all commands for this sheet. - `R` (`random-sheet`) pushes sheet instead of selecting (reverting to former behavior) - `za` (`addcol-empty`) asks for column name - `zd` (`delete-cell`) moves value to clipboard ("cut", like other delete commands) - add `gI` (`describe-all`) like `gC` (`columns-all`) - add `gS` (`sheets-graveyard`) - add `g(`, `z(`, `gz(` variants of `(` 'expand-column' - add `z|` and `z\` to un/select by python expr (thanks to @jsvine for suggestion) - add `z#` to set type of current column to `len` - add `z;` to get the stdout/stderr from running a cmdline program with $colname args - `Space` is now bound to exec-longname (was `menu`; `^A` was exec-longname previously) - Loaders: - add pandas adapter - add xml loader - add pcap loader (thanks to @vbrown608 and @TemperedNetworks) - add yaml loader (thanks to @robcarrington, @JKiely, @anjakefala at PyCon Sprints for making this happen) - add jsonl saver - remove `tsv_safe_char` and split into `tsv_safe_newline` and `tsv_safe_tab` - initial commit of a task warrior app (vtask) ## minor changes - more portable system clipboard handling (thanks @chocolateboy for PR) - [json] no more incremental display during loading (need better json parser than stdlib) - `date` supports adding a number of days (or `6*hours`, `9*months`, etc) - hidden columns are darkened on columns sheet - exception rollup - dev/commands.tsv table of commands - motd default url uses https - improve ProfileSheet - [DirSheet] editable `mode` (set to octal like `0o0644`) # v1.2.1 (2018-07-05) - python 3.7 - Change `async` decorator to `asyncthread` and rename `async.py` to avoid using Python 3.7 keyword # v1.2 (2018-04-30) - macro system - `gD` goes to directory browser of `options.visidata_dir` (default to `~/.visidata/`) which contains saved commandlogs and macros - `z^S` on CommandLog saves selected rows to macro for given keystroke, saving to `.visidata/macro/command-longname.vd` - macro list saved at `.visidata/macros.vd` (keystroke, filename) - `options.cmdlog_histfile` for auto-appended (default: empty means disabled) - [DirSheet] edits make deferred changes to any field - add `directory` and `filetype` columns - note: only 256 changes maintained per column (same as column cache size) - `^S` saves all deferred changes - `z^S` saves changes for the current file only - `^R` clears all changes (reload) - `z^R` clears changes on the current file only - `d`/`gd` marks the current/selected file for deletion - if `directory` is edited, on `^S` (save) file is moved (if directory not existing, a new directory is created) - [New conda package](https://github.com/conda-forge/visidata-feedstock) - add .visidatarc [snippets](https://github.com/saulpw/visidata/tree/stable/snippets) with examples of extra functionality - add replayable options [#97](https://github.com/saulpw/visidata/issues/97) - `g^S` for multisave to single file (`.html`, `.md` and `.txt` are currently supported) or directory - `z^S` to save selected rows of current column only (along with key columns) - `T` to transpose rows and columns [#129](https://github.com/saulpw/visidata/issues/129) - `^A` to specify a command longname to execute - `^O`/`g^O` to open current/selected files in external editor - `g^R` on SheetsSheet to reload all [selected] sheets - `options.error_is_null` to treat errors as nulls when applicable - `g,` fixed to compare by visible column values, not by row objects - `gv` to unhide all columns - `gM` open melted sheet (unpivot) with key columns retained and *regex* capture groups determining how the non-key columns will be reduced to Variable-Value rows - `g*` replace selected row cells in current column with regex transform - Shift-Up/Down aliases for mac [#135](https://github.com/saulpw/visidata/issues/135) - options.wrap now true by default on TextSheet (`v` to toggle) - `save_txt` with single column concatenates all values to single file - `+` can add multiple aggregators - ^X bugfix: use evalexpr over cursorRow - `z`/`gz` `s`/`t`/`u` to select to/from cursorRow - `z<` and `z>` to move up/down to next null cell - `"` no longer reselects all rows - `sheet-set-diff` command to act like `--diff` - math functions (like sin/cos) now at toplevel - bugfix: freeze - all `csv_` options sent to csv.reader/writer - `options.tsv_safe_char` to replace \t and \n in tsv files; set to empty for speedup during tsv save - loaders and savers - support bz2 and xz (LZMA) compression (thanks @jpgrayson) - add loaders for: - sas7bda (SAS; requires `sas7bdat`) - xpt (SAS; requires `xport`) - sav (SPSS; requires `savReaderWriter`) - dta (Stata; requires `pandas`) - .shp can save as .geojson - add htm as alias for html filetype - json bugfix: fix [#133](https://github.com/saulpw/visidata/issues/133) json loader column deduction - [experimental] bin/vsh initial commit # v1.1 (2018-03-05) - VisiData will be included in the [next debian repository release](https://tracker.debian.org/pkg/visidata)! - remove all install dependencies - additional libraries must be installed manually for certain loaders; see requirements.txt - experimental hierarchical menu system with SPACE to explore commands - use standard movement keys (`hjkl`/`arrows`) to navigate within a command level - Use `Enter`/`q` to navigate down/up a command tree - abort with `gq` or `^C` - existing chooseOne selections (aggregators/joins) still use simple input() for now - most longnames changed - let me know if anyone is using any longnames at all, and we will stabilize the names - if you do end up playing with it, please let me know what did and didn't work for you - randomized message/announcement/tip on startup; disable with `options.motd_url = None` - cache messages in `$HOME/.visidata/` Command additions/changes: - add `za` and `gza` to add 1/N new blanks column - add `(` and `)` commands to expand/collapse list/dict columns (e.g. in nested json) - add `Backspace` command to drop sheet like `q` and also scrub its history from the cmdlog - [canvas] add `d` and `gd` to delete points from source sheet - remove `!@#$%-_` special actions on columns sheet - alias Shift+Arrows to `HJKL` (may not work in all environments) - alias `ENTER` to modify-edit-cell by default - add `Y`/`gY`/`zY` to copy row/selected/cell to system clipboard (with options.clipboard_copy_cmd) - filename `-` works to specify stdin/stdout (`-b -o -` will dump final sheet to stdout) - search/select uses most recent when not given any (as in vim/etc) - annotate None with disp_note_none ('∅'); previously was not visually distinguishable from empty string - save to .md org-mode compatible table format - load/view/edit/save png, edit pixels in data form - load/view ttf/otf font files - [canvas] draw quadratic curves with qcurve([(x,y)...]) - improvements/bugfixes: pivot, describe, melt, sqlite, shp, html # v1.0 (2018-01-24) - date.__sub__ returns timedelta object (was int days) - pivot table bugfixes - many cosmetic fixes - disable default profiling for perf improvements - remove .visidatarc support in PWD or XDG; only $HOME/.visidatarc supported now - website and docs complete overhaul - do not execute .py files - apt/brew packages submitted # v0.99 (2017-12-22) - tab completion for filename and python expr - `v` now 'visibility toggle' (moved from `w`) - `^W` to erase a word in the line editor - `gC` - `--version` (thanks to @jsvine) - `options.use_default_colors` (thanks to @wavexx) - `median` aggregator - .html loads tables (requires lxml) - simple http works (requires requests) - json save - json incremental load - [cmdlog] use rowkey if available instead of row number; options.rowkey_prefix - [cmdlog] only set row/col when relevant - [vdtui] task renamed to thread - /howto/dev/loader - /design/graphics # v0.98.1 (2017-12-04) - [packaging] - make non Python standard library loader dependencies optional - provide method for full installation via `pip3 install "visidata[full]"` - [visidata.org](http://visidata.org) change copyright in footer - [docs] add csv dialects to manpage (closes issue #88) - [bugfix] - fix for `^Z` in builtin line editor - fixed-width loader needs source kwarg # v0.98 (2017-11-23) - [visidata.org](http://visidata.org) revamp - [canvas] graphs and maps! - `.` or `g.` to push a graph or a map from the current sheet (dot=plot) - supports .shp and vector .mbtiles - mouse left-click/drag to set cursor - mouse right-click/drag to scroll canvas - scrollwheel to zoom in/out on a canvas - `s`/`u` to select/unselect rows at canvas cursor - `ENTER` to push source sheet with only rows at canvas cursor - 1-9 to toggle display of 'layers' (colors) - `_` to zoom out to full width - `disp_pixel_random` option chooses pixel attrs at random (weighted), instead of most common - `+`/`-` to zoom in/out via keyboard - Updates to commands - Remove ` (backtick) command - Remove most zscroll commands (`zs`/`ze`) - `zz` moves cursor to center, uncertain about the future of `zt` due to conflict with `t` for toggle - `ga` adds N new rows - `gz=` sets value for selected/all rows to a Python sequence in this column - `z_` sets column width to given value - `z-` cuts column width in half - `P` is now "paste before" (like vim); `R` now pushes a random sample - `^Z` now sends SIGSTOP; `^O` "opens" the external $EDITOR (from builtin line editor) - [ColumnsSheet] Added `~!@#$` commands back, to set type of source columns - `w` is becoming a more universal "visibility toggle" - [TextSheet] `w` toggles wordwrap - [canvas] `w` toggles display of the labels - [pyobj] `w` toggles hidden properties and methods - Updates to command line args and options - set initial row/col with `+:` (numeric only) - `--delimiter`/`-d ` option (separate from `--csv-delimiter`) sets delimiter for tsv filetype - `--replay-wait`/`-w` renamed from `--delay`/`-d` - `disp_date_fmt` option for date display format string (default is date-only) - `zero_is_null`/`empty_is_null`/`none_is_null`/`false_is_null` set which values are considered null (previously was `aggr_null_filter`) - `--skiplines` option renamed to `--skip`, and `--headerlines` to `--header` - Design improvements - Add specific rowtype for each sheet (see right status) - dates are a kind of numeric type (useful for graphing as the x-axis) - `use_default_colors` (at behest of @wavexx) - more robust Progress indicator - populate DescribeSheet in async thread - remove default names for unnamed columns - history up/down in edit widget now feels right - API changes - change main Column API to getter(col, row) and setter(col, row, val) - move Path and subclasses out of vdtui - TextSheet source is any iterable of strings - Sheet.filetype provides default save filename extension ## 0.97.1 (2017-10-29) - Fix postgres lazy import - BugFix: issue #83 - `z?` works on OSX - BugFix: on SheetsSheets itself now does nothing - Move from readthedocs to visidata.org ## 0.97 (2017-10-05) - Features - [replay] - move vdplay into vd --play - -p --play now replays scripts live - --delay interspaces replay by delay seconds - --batch to replay without interface - --output to save at end of replay - --replay-movement=True has --play move the cursor cell-by-cell - -y --confirm-overwrite=False - replay scripts can be strformatted with field=value - add ^U command to pause/resume playback - add ^K to cancel replay - add Space command to go to next step of replay while paused - [global] - remap toggle to 't' (was Space) - remap ^Y to push sheet of cursorRow - 'A' creates new sheet with N empty columns - remap 'r' to regex search of row key - add zr/zc to go to row/col number - F1/z? now launches man page - gF1/gz? now launches commands sheet - add `f` command to fill empty cells with the content of a non-empty cell up the current column - add Del/gDel to set value(s) to None - remove TAB/Shift-TAB sheet cycling - add z^ command to set current column name to current cell value - add gz^ to set current column name to cell values in selected rows - add 'z=' to show computed expression over current row - z' adds cache to current column (gz' for all columns) - `gh` moves cursor to leftmost column (instead of leftmost non-key column) - [aggregators] - allow multiple aggregators - 'g+ adds an aggregator to selected columns on columns sheets - sets the exact set of aggregators on the column sheet with 'e'/'ge' - 'z+' displays result of aggregation over selected rows for current column on status - rework aggregators so multiple aggregators can be set - [sheets sheet] - '&' on Sheets sheet is now sole join sheet command; jointype is input directly - add sheet concat - [columns sheet] - remap ~!@#$%^ on Columns sheet to behave like they do on other sheets - add g prefix to ~!@#$%^ to operate on all 'selected rows' on Columns sheet (thus modifying column parameters on source sheet) - [textsheet] - add 'w' command on TextSheets to toggle wrap - [cmdlog] - editlog renamed to cmdlog - cmdlog has a new format which minimises recordings of movement commands - '^D' now saves cmdlog sheet - [pivot] - zEnter pushes this cell; Enter pushes whole row - [describe] - add DescribeSheet with 'I' command for viewing descriptive statistics - add zs/zu/zt/zEnter commands to engage with rows on source sheet which are being described in current cell of describe sheet - [frequency] - 'zF' provides summary aggregation - [metasheets] - add hidden source column to metasheets - ^P view status history - [loaders] - add 'postgres' schema for simple loader from postgres:// url - add gEnter for .zip file mass open - add 'fixed' filetype to use fixed column detector - [clipboard] - remove `B` clipboard sheet - rework all d/y/p commands for only one buffer - remove g^Z and gp - [options] - remove -d debug option - add --diff to add colorizer against base sheet - diffs a pair of tsvs cell-by-cell - theme options removed as CLI arguments (still available for .visidatarc or apps) - `'` appends frozen column - rename and reorder options - Community - [docs] - replace .rst userguide with VisiData [man page](http://visidata.org/man) - [visidata.org] - update index.html - automate creation of tour pages from tours.vd - tours will be played and recorded using asciinema - then compiled into a .html with mkdemo.py for http://visidata.org/tour - upload html version of manpage - Internals - renamed toplevel command() to globalCommand(); removed Sheet.command(); sheet commands now specified in Sheet.commands list of Command() objects at class level - setter API now (sheet,col,row,value) - move `visidata/addons/*.py` into toplevel package ## 0.96 (2017-08-21) - data can be piped through stdin - remap: `N` is now previous match (instead of `p`) - `:` now regex split - add `bin/viewtsv` example tsv viewer as an example of a small vdtui application - add `options.cmd_after_edit` for automove after edit - add clipboard functionality - `y` yanks row at cursor to clipboard; `gy` copies all selected rows - `d` deletes row and move to clipboard; `gd` moves all selected rows - `p` now pastes the row most recently added to the clipboard after current row; `gp` pastes all rows from clipboard after current row - `Shift-B` opens clipboard sheet - `Ctrl+z` now undoes the most recent delete; `gCtrl+z` undoes all deletes - Fix cursor row highlighting of identical rows ## v0.95.2 - move some functionality out of vdtui into separate python files - add Ctrl+z command to launch external $EDITOR - add ``options.force_valid_names`` ## v0.94 (2017-08-02) - add options.textwrap for TextSheet - add vd.remove(sheet) - Sheet.sources now modifiable ## v0.93 (2017-07-30) - fix display/feel bugs in editText - remove BACKSPACE for editlog undo - fix colorizer API - add `ctrl-u` command to toggle profiling of main thread - fix `C`olumn statistics (`options.col_stats` still disabled by default) ## v0.92 (2017-07-11) - `F`requency sheet groups numeric data into intervals - added `histogram_bins` and `histogram_even_interval` options - added `w` command on the sheet that toggles `histogram_even_interval` - change key for 'eval Python expression as new pyobj sheet' from Ctrl+O to Ctrl+X ## v0.91 (2017-06-28) - make options automatically typed based on default - documentation cleanups - remove R command (set filetype on CLI) ## v0.80 - tour of screenshot.gif - regex transform now `*` (';' is still regex split) - Make regex search/select to work more like vim - Move several non-essential commands out of vd.py - change license of vd.py to MIT - vdtutor start - currency type with `$`; str type moved to `~`; remove type autodetect - www/ for landing page - move from .md to .rst for documentation ## v0.61 (2017-06-12) - colorizers - `g[` and `g]` to sort by all key columns - `;` and `.` experimental regex commands ## v0.59 (2017-05-31) - pivot sheets with `W` - undo with `BACKSPACE` and replay with `ga` - dev guide and user guide - `ge` mass edit - freeze with `g'` ## v0.44 - creating sustainable dev process at RC - `z` scrolling prefix ## v0.42 - async select/unselect - aggregator functions on columns - .xls ## v0.41 (2017-01-18) - asynchronous commands (each in its own thread) with - `^T` sheet of long-running commands - `^C` cancel - `ENTER` to see the final performance profile - `P` random population of current sheet - headerlines default now 1 ## v0.40 - options settable with command-line arguments (`--encoding=cp437`) - input() histories with UP/DOWN (and viewable with `I`) - unicode input now works - editText clears value on first typing - `"` duplicates sheet with only selected rows; `g"` duplicates entire sheet verbatim ## v0.38 - sortable date - open_zip comes back ## v0.37 - `g~` (autodetect all columns) - `"` copies row to immediately following - nulls, uniques on columns sheet ## v0.36 - right column - regex subst - unreverse [/] sort keys ([ = ascending) ## v0.35 (2016-12-04) - reverse [/] sort keys - goto `r`ow by number or `c`olumn by name ## v0.33 - type detection with `~` - date type - fix outer join ## v0.32 - expose col.type in column header - push value conversion to time of usage/display ## v0.31 - F1 help sheet - ^O directly exposes eval result as sheet - custom editText with initial value, ESC that raises VEscape, and readline edit keys ## v0.30 (2016-11-27) - make all sheets subclasses of VSheet - remove .zip opening and url fetching - added options ColumnStats and csv_header ## v0.29 - pin key columns to left - join sheets on exact key match - -r/--readonly mode ## v0.28 (2016-11-22) - inputs: .csv, .tsv, .json, .hdf5, .xlsx, .zip - outputs: .csv, .tsv - hjkl cursor movement, t/m/b scroll to position screen cursor - skip up/down columns by value - row/column reordering and deleting - resize column to fix max width of onscreen row - filter/search by regex in column - sort asc/desc by one column - `g`lobal prefix supersizes many commands - `e`dit cell contents - convert column to int/str/float - reload sheet with different format options - add new column by Python expression - `s`elect/`u`nselect rows, bulk delete with `gd` - `F`requency table for current column with histogram - `S`heets metasheet to manage/navigate multiple sheets, - `C`olumns metasheet - `O`ptions sheet to change the style or behavior - `E`rror metasheet - `g^P` status history sheet ## v0.14 (2016-11-13) ================================================ FILE: CLAUDE.md ================================================ # VisiData Development Guide Quick reference for VisiData development. For detailed coding patterns, conventions, and best practices, see **[dev/STYLE.md](dev/STYLE.md)**. `CLAUDE.md` and `AGENTS.md` are complementary: use this file for primary contributor workflow and architecture context, and use `AGENTS.md` for concise agent-oriented repository guidance. ## Important Note About AI Usage VisiData (created in 2016) is 99% written by humans and is NOT a vibe-coded AI project. This file is meant to allow AI-assisted development of features and bugfixes. **All code must be reviewed and approved and tested by a human before being merged into the codebase or submitted as a PR.** ## Repository Structure ``` visidata/ ├── visidata/ # Main package │ ├── *.py # Core modules (sheet.py, column.py, etc.) │ ├── features/ # Auto-loaded feature plugins │ ├── loaders/ # File format loaders │ ├── apps/ # Standalone applications │ └── experimental/ # Experimental features (load/install with 'import visidata.experimental.foo') ├── tests/ # Test files ├── docs/ # Documentation └── dev/ # Development utilities and docs ``` ## Features Directory (`visidata/features/`) - All `.py` files in this directory are **automatically imported** when VisiData starts - Each feature file should be self-contained - Features extend VisiData functionality without modifying core files ## Quick Reference ### Core Classes - `BaseSheet` - Minimal sheet functionality - `Sheet` / `TableSheet` - Sheet with columns and rows (most common) - `Column` - Column definition with getter/setter ### Adding Commands ```python BaseSheet.addCommand('', 'command-name', 'code', 'help text') ``` ### Adding to Global Namespace ```python vd.addGlobals(MyClass=MyClass) # Use keyword args, not dict ``` ### Adding Menu Items ```python vd.addMenuItems(''' Menu > Submenu > Item Name > command-name ''') ``` ### Example Feature Structure ```python from visidata import vd, Sheet, Column # rowdef: description of what a row represents class MySheet(Sheet): rowtype = 'items' columns = [ Column('name', getter=lambda c,r: r.attribute), ] def reload(self): self.rows = [...] BaseSheet.addCommand('', 'my-command', 'code', 'help') vd.addGlobals(MySheet=MySheet) ``` ## Development Workflow 1. Add `.py` file to `visidata/features/` 2. Run `vd` and test interactively 3. Iterate and refine 4. Document with docstrings and comments ## Make Targets - `make test` — run all tests - `make help` — list all targets ## Documentation For comprehensive development documentation, see the `dev/` directory: ### [dev/STYLE.md](dev/STYLE.md) - Coding Style and Patterns Use this when writing code, creating features, or defining sheets and columns. - Naming conventions (camelCaps, under_score, etc.) - Feature file structure and patterns - Sheet and Column class patterns - Command and menu integration - API decorators - Best practices and examples ### [dev/GIT.md](dev/GIT.md) - Version Control Practices Use this when making commits or preparing pull requests. - Commit message format and conventions - Issue tracking in code - Branch and merge workflow - Patch-safe commit marking ### [dev/DOCS.md](dev/DOCS.md) - Documentation Writing Use this when writing user-facing documentation, help text, or in-app guides. - VisiData's markdown syntax - Display attribute syntax (colors, clickable links) - Option and command reference format - Technical writing guidelines ### [dev/PERFORMANCE.md](dev/PERFORMANCE.md) - Performance Analysis Use this when investigating or optimizing performance issues. - Finding reproducible performance issues - Profiling techniques and tools - Analyzing profiling results - Optimization workflow ### [dev/OPTIONS.md](dev/OPTIONS.md) - Options System Use this when working with options, adding new options, or understanding how configuration resolves. - Resolution chain (instance → class → global → default) - How sheets and paths participate in options - Setting and reading options at different levels ## Updating Documentation When making **user-facing changes** (new commands, changed behavior, new options, new/changed loaders, UI changes), check [docs/README.md](docs/README.md) to identify which documentation files need to be updated. ================================================ FILE: CODE_OF_CONDUCT.md ================================================ Please don't be a dick ♥ ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing ## Spread the Word The single best way you can contribute, is to share your enthusiasm about VisiData with other people. A vibrant community is essential to its sustainable development. However, direct and forceful promotion is probably not the most effective approach for a tool like VisiData. People generally need to be exposed several times and from several sources before they will try some terminal utility they've never heard of before. Some people are interested, but are daunted by the installation process or the interface; you can [help them get it installed](/install), and provide a few pointers to get started. Don't make it too complicated or overload them with too many features. Stick to the basics: arrow keys, quit, help, search, sort, freq table. We also need people to mention VisiData in their forums and communities that relate to data and terminal programs. Don't spam or do a drive-by promotion; these are largely ineffective and will often be received negatively. Endorsements have more weight from people who actively post about other relevant topics; we don't want to become the "VisiData Brigade". Finally, if you are on "Web 2.social", you can post a [tweet](https://twitter.com/visidata) or a [tutorial]() or a [demo](https://www.youtube.com/watch?v=N1CBDTgGtOU) or [host a workshop](https://www.meetup.com/pt-BR/Journocoders/events/258035880/), or anything else you think might make people interested in exploring the wonderful world of VisiData. ## Support on Patreon If VisiData saves you time on a regular basis, and especially if VisiData makes your paid work easier, please contribute to [my Patreon](https://www.patreon.com/saulpw). ## Start a Project Using VisiData If you know Python and want to augment it to suit your own workflow, you can create a loader or a plugin. In support of this, I have written [a detailed api guide for VisiData](https://www.visidata.org/docs/api/). Here are some great examples: - [jsvine's custom visidata plugins](https://github.com/jsvine/visidata-plugins) - [layertwo's pcap loader](https://github.com/saulpw/visidata/blob/develop/visidata/loaders/pcap.py) Without fail, these projects lead to discovering bugs and help flesh out the API, which result in design improvements in VisiData. Importantly, each issue found this way comes with real world motivations, so it is easy to explain your reasoning behind proposals and core feature requests. ## Feature Requests VisiData is designed to be extensible, and most feature requests can be implemented as a one line command, or a tiny snippet of code to include in a `.visidatarc`. If this would require changes to the VisiData core, and a reasonable design is approved, then the issue can stay open until the core changes have been made. Otherwise, in the spirit of Marie Kondo, the issue will be closed without prejudice. Feature requests with some amount of working Python code are more likely to get attention. Design proposals with concrete use cases are very welcome. ## Writing a well constructed bug report If you encounter any bugs or have any problems, please [create an issue on GitHub](https://github.com/saulpw/visidata/issues). A great bug report will include: - a stacktrace, if there is an unexpected error; the most recent full stack traces can be viewed with `Ctrl+E` (then saved with `Ctrl+S`) - a [.vd](http://visidata.org/docs/save-restore/) and sample dataset that reproduces the issue - a .png/.gif (esp. for user interface changes) Some examples of great bug reports: - [#350 by @chocolateboy](https://github.com/saulpw/visidata/issues/350) - [#340 by @Mikee-3000](https://github.com/saulpw/visidata/issues/340) ## Setting Up Git Hooks VisiData includes git hooks in `dev/hooks/` that run unit tests and cmdlog tests before pushing. To enable them: ``` git config core.hooksPath dev/hooks ``` ## Submitting Source Code Check out the [Plugin Authors Guide](https://visidata.org/docs/api) for an overview of the API. Code in `visidata/features/` or `visidata/loaders/` is generally welcome, as long as it is useful to someone and safe for everyone. Updates or additions to the core code should be proposed via an [Github Issue](https://github.com/saulpw/visidata/issues/new/choose) before submitting a PR. VisiData has two main branches: - [stable](https://github.com/saulpw/visidata/tree/stable) has the last known good version of VisiData (what is in pypi/brew/apt). - [develop](https://github.com/saulpw/visidata/tree/develop) has the most up-to-date version of VisiData (which will eventually be merged to stable). All pull requests should be submitted against `develop`. Submitters will need to e-sign a [Copyright Assignment Agreement (CAA)](https://visidata.org/caa) before a pull request will be accepted. # Open Source License and Copyright VisiData is an open-source utility that can be installed and used for free (under the terms of the [GPL3](https://www.gnu.org/licenses/gpl-3.0.en.html)). The core VisiData utility and rendering library will always be both free and libre. As the copyright holder, Saul Pwanson has the authority to negotiate other license terms. **By submitting changes to this repository, you acknowledge that you assign copyright to the owner of the repository ([Saul Pwanson ](mailto:vd@saul.pw)).** ================================================ FILE: Dockerfile.alpine ================================================ FROM python:3.8-alpine RUN pip install requests python-dateutil wcwidth RUN mkdir -p /opt/visidata WORKDIR /opt/visidata COPY . ./ RUN sh -c 'yes | pip install -vvv .' ENV TERM="xterm-256color" ENTRYPOINT bin/vd ================================================ FILE: Dockerfile.darkdraw.alpine ================================================ FROM visidata RUN apk add git RUN pip install git+https://github.com/devottys/darkdraw.git@master RUN sh -c "echo >>~/.visidatarc import darkdraw" ENV TERM="xterm-256color" ENTRYPOINT ["/opt/visidata/bin/vd", "-f", "ddw"] ================================================ FILE: LICENSE.gpl3 ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: MANIFEST.in ================================================ include README.md include LICENSE.gpl3 include CHANGELOG.md include CONTRIBUTING.md include CODE_OF_CONDUCT.md include requirements.txt include requirements.scm include visidata/man/vd.1 include visidata/man/vd.txt include visidata/man/visidata.1 include visidata/ddw/input.ddw include visidata/ddw/regex.ddw include visidata/tests/sample.tsv include visidata/tests/benchmark.csv include visidata/desktop/visidata.desktop include visidata/desktop/org.visidata.VisiData.metainfo.xml include visidata/desktop/icons/48x48/visidata.png include visidata/desktop/icons/32x32/visidata.png include visidata/experimental/noahs_tapestry/*.json include visidata/experimental/noahs_tapestry/*.md include visidata/experimental/noahs_tapestry/*.ddw include visidata/experimental/noahs_tapestry/*.sqlite include visidata/guides/*.md ================================================ FILE: Makefile ================================================ .PHONY: help \ install install-dev install-test install-all \ test test-all test-vgit test-vdsql \ build man zsh-completion docker \ setup-hooks setup-vscode lint \ diff-test clean help: @echo "Install:" @echo " make install pip install visidata" @echo " make install-dev editable install with dev deps" @echo " make install-test install with test deps" @echo " make install-all install with all optional deps" @echo "" @echo "Test:" @echo " make test run all tests (same as test-all)" @echo "" @echo "Build:" @echo " make man generate man pages (requires soelim, preconv, aha)" @echo " make zsh-completion generate zsh completion script" @echo " make docker build docker images" @echo "" @echo "Setup:" @echo " make setup-hooks configure git to use dev/hooks" @echo " make setup-vscode copy devcontainer configs to .vscode/" @echo "" @echo "Utility:" @echo " make lint run ruff linter" @echo " make diff-test show diffs from last test run" @echo " make clean remove generated files" install: pip3 install . install-dev: pip3 install -r dev/requirements-dev.txt pip3 install -e . install-test: pip3 install . pip3 install ".[test]" install-all: pip3 install ".[all]" test: test-all test-all: dev/test-all.sh test-vgit: vd -p visidata/apps/vgit/tests/*.vdx --batch test-vdsql: cd visidata/apps/vdsql && ./test.sh build: man zsh-completion man: dev/mkman.sh zsh-completion: python3 dev/zsh-completion.py _visidata docker: dev/build-container # Setup setup-hooks: git config core.hooksPath dev/hooks setup-vscode: mkdir -p .vscode cp .devcontainer/launch.json .vscode/launch.json cp .devcontainer/settings.json .vscode/settings.json # Utility lint: ruff check . diff-test: dev/diff-test.sh clean: rm -f visidata/man/vd.1 visidata/man/visidata.1 visidata/man/vd.txt rm -f docs/man.md ================================================ FILE: README.md ================================================ # VisiData v3.3 [![Tests](https://github.com/saulpw/visidata/workflows/visidata-ci-build/badge.svg)](https://github.com/saulpw/visidata/actions/workflows/main.yml) [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/saulpw/visidata) [![discord](https://img.shields.io/discord/880915750007750737?label=discord)](https://visidata.org/chat) [![Mastodon](https://img.shields.io/mastodon/follow/110136431814047095?domain=https%3A%2F%2Ffosstodon.org)](https://fosstodon.org/@saulpw) A terminal interface for exploring and arranging tabular data. ![Frequency table](http://visidata.org/videos/freq-move-row.gif) VisiData supports tsv, csv, sqlite, json, xlsx (Excel), hdf5, and [many other formats](https://visidata.org/formats). ## Platform requirements - Linux, OS/X, or Windows (with WSL) - Python 3.8+ - additional Python modules are required for certain formats and sources ## Install To install the latest release from PyPi: pip3 install visidata To try VisiData without installing, use [pipx](https://pipx.pypa.io/) or [uv](https://docs.astral.sh/uv/): pipx run visidata # or: uvx visidata To install permanently (adds `vd` to your PATH): pipx install visidata # or: uv tool install visidata Additional Python packages are needed for some formats: pipx install visidata --preinstall openpyxl --preinstall lxml # or: uv tool install visidata --with openpyxl --with lxml To add format packages to an existing pipx install: pipx inject visidata openpyxl lxml To install the cutting edge `develop` branch (no warranty expressed or implied): pip3 install git+https://github.com/saulpw/visidata.git@develop See [visidata.org/install](https://visidata.org/install) for detailed instructions for all available platforms and package managers. ### Usage $ vd $ | vd Press `Ctrl+Q` to quit at any time. Hundreds of other commands and options are also available; see the documentation. ### Documentation * [VisiData documentation](https://visidata.org/docs) * [Plugin Author's Guide and API Reference](https://visidata.org/docs/api) * [Quick reference](https://visidata.org/man) (available within `vd` with `Ctrl+H`), which has a list of commands and options. * [Intro to VisiData Tutorial](https://jsvine.github.io/intro-to-visidata/) by [Jeremy Singer-Vine](https://www.jsvine.com/) ### Help and Support If you have a question, issue, or suggestion regarding VisiData, please [create an issue on Github](https://github.com/saulpw/visidata/issues) or chat with us at #visidata on [irc.libera.chat](https://libera.chat/). If you use VisiData regularly, please [support me on Patreon](https://www.patreon.com/saulpw)! ## License Code in the `stable` branch of this repository, including the main `vd` application, loaders, and plugins, is available for use and redistribution under GPLv3. ## Credits VisiData is conceived and developed by Saul Pwanson ``. Anja Kefala `` maintains the documentation and packages for all platforms. Many thanks to numerous other [contributors](https://visidata.org/credits/), and to those wonderful users who provide feedback, for helping to make VisiData the awesome tool that it is. ================================================ FILE: bin/filter-doc.py ================================================ #!/usr/bin/python3 import fileinput import inspect import visidata tmpl=''' ~~~ {name}{sign} [ [{sourcepy}:{sourceline}](https://github.com/saulpw/visidata/visidata/blob/develop/visidata/{sourcepy}#{sourceline})] ~~~ {doc} ''' for line in fileinput.input(): if line.startswith(':#'): objname, funcname = line[2:].strip().split('.') func = getattr(getattr(visidata, objname), funcname) src = visidata.Path(inspect.getsourcefile(func)).parts[-1] print(tmpl.format( name=objname+'.'+func.__name__, doc=inspect.getdoc(func) or 'XXX', sourcepy=src, sourceline=inspect.getsourcelines(func)[1], sign=inspect.signature(func))) else: print(line, end='') ================================================ FILE: bin/vd ================================================ #!/usr/bin/env python3 import visidata.main if __name__ == '__main__': visidata.main.vd_cli() ================================================ FILE: bin/vd2to3.vdx ================================================ #!/usr/bin/env -S vd -p # VisiData v3.0dev open-file ~/.visidata/macros.tsv col command rename-col binding col filename rename-col source save-sheet ~/.visidata/macros.jsonl quit-all ================================================ FILE: bin/viewtsv.py ================================================ #!/usr/bin/env python3 # as plugin: `from viewtsv import open_tsv` in .visidatarc # standalone: `viewtsv.py ' from visidata import VisiData, Sheet, ColumnItem, asyncthread, options @VisiData.api def open_tsv(vd, p): return MinimalTsvSheet(p.base_stem, source=p) class MinimalTsvSheet(Sheet): rowtype = 'rows' @asyncthread def reload(self): self.rows = [] delim = options.delimiter header = True with open(self.source, encoding=options.encoding) as fp: for line in fp: line = line[:-1] # strip trailing newline if header: if delim in line: header = False self.columns = [] for i, colname in enumerate(line.split()): self.addColumn(ColumnItem(colname, i)) continue self.addRow(line.split(delim)) # a minimal main() for standalone apps if __name__ == '__main__': import sys from visidata import run, Path, vd run(*(vd.open_tsv(Path(fn)) for fn in sys.argv[1:])) ================================================ FILE: dev/DOCS.md ================================================ # VisiData Documentation Style Guide `docs/man.md` is generated from the manpage source (`visidata/man/vd.inc`) by `dev/mkman.sh`. Edit `vd.inc`, not `man.md`. VisiData supports basic markdown like # Headings, **bold**, *italics*, `code snippets`, and _underscore_. VisiData has its own display attribute syntax. For e.g.: [:onclick ][/] formats into a clickable url that will open in $BROWSER. [:red on black][/] changes the colour of to be red text on black background. Any color option can be used after :, like [:warning], [:error], [:menu]. VisiData replaces `{vd.options.disp_selected_note}` with `+`, the value that `vd.options.disp_selected_note` is set to. Reference any option value with `{vd.options.optname}`. This is a great way to ensure that the appropriate option is displayed, even if the user changed the option value. - Use `{help.commands.longname}` to put the properly formatted string (below) into the GuideSheet. It’s much preferred to change the command helpstring itself, in order to make this pattern work, than to write it out manually. It will look like this: - `` (``) to . The keystroke immediately follows the bullet. Do not say “Press” or “Use” within VisiData docs and helpstrings. - List relevant options with the following pattern. - [:onclick options-sheet