diff --git a/CHANGELOG.md b/CHANGELOG.md index d22104822..f53d83b19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,37 @@ # VisiData version history +# v2.10.1 (2022-09-12) + +## 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 diff --git a/MANIFEST.in b/MANIFEST.in index 2fb0e8eb8..46f29cddb 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,3 +4,4 @@ include visidata/man/vd.1 include visidata/man/vd.txt include visidata/man/visidata.1 include visidata/ddw/input.ddw +include visidata/tests/sample.tsv diff --git a/docs/man.md b/docs/man.md index 24ce8b73f..72ca7b61a 100644 --- a/docs/man.md +++ b/docs/man.md @@ -7,662 +7,664 @@ permalink: /man/
 vd(1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        Quick Reference Guide                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        vd(1)
 
-NAME
-     VisiData — a terminal utility for exploring and arranging tabular data
+NAME
+     VisiData — a terminal utility for exploring and arranging tabular data
 
-SYNOPSIS
-     vd [options] [input ...]
-     vd [options] --play cmdlog [-w waitsecs] [--batch] [-o output] [field=value]
-     vd [options] [input ...] +toplevel:subsheet:col:row
+SYNOPSIS
+     vd [options] [input ...]
+     vd [options] --play cmdlog [-w waitsecs] [--batch] [-o output] [field=value]
+     vd [options] [input ...] +toplevel:subsheet:col:row
 
-DESCRIPTION
-     VisiData is an easy-to-use multipurpose tool to explore, clean, edit, and restructure data. Rows can be selected, filtered, and grouped; columns can be rearranged, transformed, and derived via regex or Python expressions; and workflows can be saved, documented, and replayed.
+DESCRIPTION
+     VisiData is an easy-to-use multipurpose tool to explore, clean, edit, and restructure data. Rows can be selected, filtered, and grouped; columns can be rearranged, transformed, and derived via regex or Python expressions; and workflows can be saved, documented, and replayed.
 
-   REPLAY MODE
-     -p, --play=cmdlog       replay a saved cmdlog within the interface
-     -w, --replay-wait=seconds
+   REPLAY MODE
+     -p, --play=cmdlog       replay a saved cmdlog within the interface
+     -w, --replay-wait=seconds
                              wait seconds between commands
-     -b, --batch             replay in batch mode (with no interface)
-     -o, --output=file       save final visible sheet to file as .tsv
-     --replay-movement       toggle --play to move cursor cell-by-cell
-     field=value             replace "{field}" in cmdlog contents with value
-
-   Commands During Replay
-        ^U                   pause/resume replay
-        ^N                   execute next row in replaying sheet
-        ^K                   cancel current replay
-
-   GLOBAL COMMANDS
-     All keystrokes are case sensitive. The ^ prefix is shorthand for Ctrl.
-
-   Keystrokes to start off with
-      ^Q              abort program immediately
-      ^C              cancel user input or abort all async threads on current sheet
-     g^C              abort all secondary threads
-       q              quit current sheet or menu
-       Q              quit current sheet and free associated memory
-      gq              quit all sheets (clean exit)
-
-      ^H              activate help menu (Enter/left-mouse to expand submenu or execute command)
-     g^H              view this man page
-     z^H              view sheet of command longnames and keybindings for current sheet
-     Space longname   execute command by its longname
-
-       U              undo the most recent modification (requires enabled options.undo)
-       R              redo the most recent undo (requires enabled options.undo)
-
-   Cursor Movement
-     Arrow PgUp       go as expected
-      h   j   k   l   go left/down/up/right
-     gh  gj  gk  gl   go all the way to the left/bottom/top/right of sheet
-          G  gg       go all the way to the bottom/top of sheet
+     -b, --batch             replay in batch mode (with no interface)
+     -o, --output=file       save final visible sheet to file as .tsv
+     --replay-movement       toggle --play to move cursor cell-by-cell
+     field=value             replace "{field}" in cmdlog contents with value
+
+   Commands During Replay
+        ^U                   pause/resume replay
+        ^N                   execute next row in replaying sheet
+        ^K                   cancel current replay
+
+   GLOBAL COMMANDS
+     All keystrokes are case sensitive. The ^ prefix is shorthand for Ctrl.
+
+   Keystrokes to start off with
+      ^Q              abort program immediately
+      ^C              cancel user input or abort all async threads on current sheet
+     g^C              abort all secondary threads
+       q              quit current sheet or menu
+       Q              quit current sheet and free associated memory
+      gq              quit all sheets (clean exit)
+
+      ^H              activate help menu (Enter/left-mouse to expand submenu or execute command)
+     g^H              view this man page
+     z^H              view sheet of command longnames and keybindings for current sheet
+     Space longname   execute command by its longname
+
+       U              undo the most recent modification (requires enabled options.undo)
+       R              redo the most recent undo (requires enabled options.undo)
+
+   Cursor Movement
+     Arrow PgUp       go as expected
+      h   j   k   l   go left/down/up/right
+     gh  gj  gk  gl   go all the way to the left/bottom/top/right of sheet
+          G  gg       go all the way to the bottom/top of sheet
      Ic. End  Home    go all the way to the bottom/top of sheet
-     ^B  ^F           scroll one page back/forward
-     ^Left ^Right     scroll one page left/right
-     zz               scroll current row to center of screen
+     ^B  ^F           scroll one page back/forward
+     ^Left ^Right     scroll one page left/right
+     zz               scroll current row to center of screen
 
-     ^^ (Ctrl+^)      jump to previous sheet (swaps with current sheet)
+     ^^ (Ctrl+^)      jump to previous sheet (swaps with current sheet)
 
-      /   ? regex     search for regex forward/backward in current column
-     g/  g? regex     search for regex forward/backward over all visible columns
-     z/  z? expr      search by Python expr forward/backward in current column (with column names as variables)
-      n   N           go to next/previous match from last regex search
+      /   ? regex     search for regex forward/backward in current column
+     g/  g? regex     search for regex forward/backward over all visible columns
+     z/  z? expr      search by Python expr forward/backward in current column (with column names as variables)
+      n   N           go to next/previous match from last regex search
 
-      <   >           go up/down current column to next value
-     z<  z>           go up/down current column to next null value
-      {   }           go up/down current column to next selected row
+      <   >           go up/down current column to next value
+     z<  z>           go up/down current column to next null value
+      {   }           go up/down current column to next selected row
 
-      c regex         go to next column with name matching regex
-      r regex         go to next row with key matching regex
-     zc  zr number    go to column/row number (0-based)
+      c regex         go to next column with name matching regex
+      r regex         go to next row with key matching regex
+     zc  zr number    go to column/row number (0-based)
 
-      H   J   K   L   slide current row/column left/down/up/right
-     gH  gJ  gK  gL   slide current row/column all the way to the left/bottom/top/right of sheet
-     zH  zJ  zK  zK number
+      H   J   K   L   slide current row/column left/down/up/right
+     gH  gJ  gK  gL   slide current row/column all the way to the left/bottom/top/right of sheet
+     zH  zJ  zK  zK number
                       slide current row/column number positions to the left/down/up/right
 
-     zh  zj  zk  zl   scroll one left/down/up/right
+     zh  zj  zk  zl   scroll one left/down/up/right
 
-   Column Manipulation
+   Column Manipulation
        _ (underbar)   toggle width of current column between full and default width
-      g_              toggle widths of all visible columns between full and default width
-      z_ number       adjust width of current column to number
-     gz_ number       adjust widths of all visible columns to Ar number
+      g_              toggle widths of all visible columns between full and default width
+      z_ number       adjust width of current column to number
+     gz_ number       adjust widths of all visible columns to Ar number
 
-      - (hyphen)      hide current column
-     z-               reduce width of current column by half
-     gv               unhide all columns
+      - (hyphen)      hide current column
+     z-               reduce width of current column by half
+     gv               unhide all columns
 
-     ! z!             toggle/unset current column as a key column
-     ~  #  %  $  @  z#
+     ! z!             toggle/unset current column as a key column
+     ~  #  %  $  @  z#
                       set type of current column to str/int/float/currency/date/len
-       ^              edit name of current column
-      g^              set names of all unnamed visible columns to contents of selected rows (or current row)
-      z^              set name of current column to combined contents of current cell in selected rows (or current row)
-     gz^              set name of all visible columns to combined contents of current column for selected rows (or current row)
+       ^              rename current column
+      g^              rename all unnamed visible columns to contents of selected rows (or current row)
+      z^              rename current column to combined contents of current cell in selected rows (or current row)
+     gz^              rename all visible columns to combined contents of current column for selected rows (or current row)
 
-       = expr         create new column from Python expr, with column names, and attributes, as variables
-      g= expr         set current column for selected rows to result of Python expr
-     gz= expr         set current column for selected rows to the items in result of Python sequence expr
-      z= expr         evaluate Python expression on current row and set current cell with result of Python expr
+       = expr         create new column from Python expr, with column names, and attributes, as variables
+      g= expr         set current column for selected rows to result of Python expr
+     gz= expr         set current column for selected rows to the items in result of Python sequence expr
+      z= expr         evaluate Python expression on current row and set current cell with result of Python expr
 
        i              add column with incremental values
       gi              set current column for selected rows to incremental values
       zi step         add column with values at increment step
      gzi step         set current column for selected rows at increment step
 
-      ' (tick)        add a frozen copy of current column with all cells evaluated
-     g'               open a frozen copy of current sheet with all visible columns evaluated
-     z'  gz'          add/reset cache for current/all visible column(s)
-
-      : regex         add new columns from regex split; number of columns determined by example row at cursor
-      ; regex         add new columns from capture groups of regex (also requires example row)
-     z; expr          create new column from bash expr, with $columnNames as variables
-      * regex/subst   add column derived from current column, replacing regex with subst (may include \1 backrefs)
-     g*  gz* regex/subst
-                      modify selected rows in current/all visible column(s), replacing regex with subst (may include \1 backrefs)
-
-      (   g(          expand current/all visible column(s) of lists (e.g. [3]) or dicts (e.g. {3}) one level
-     z(  gz( depth    expand current/all visible column(s) of lists (e.g. [3]) or dicts (e.g. {3}) to given depth (0= fully)
-      )               unexpand current column; restore original column and remove other columns at this level
-     zM               row-wise expand current column of lists (e.g. [3]) or dicts (e.g. {3}) within that column
-
-   Row Selection
-       s   t   u      select/toggle/unselect current row
-      gs  gt  gu      select/toggle/unselect all rows
-      zs  zt  zu      select/toggle/unselect all rows from top to cursor
-     gzs gzt gzu      select/toggle/unselect all rows from cursor to bottom
-      |   \ regex     select/unselect rows matching regex in current column
-     g|  g\ regex     select/unselect rows matching regex in any visible column
-     z|  z\ expr      select/unselect rows matching Python expr in any visible column
-      , (comma)       select rows matching display value of current cell in current column
-     g,               select rows matching display value of current row in all visible columns
-     z, gz,           select rows matching typed value of current cell/row in current column/all visible columns
-
-   Row Sorting/Filtering
-       [    ]         sort ascending/descending by current column; replace any existing sort criteria
-      g[   g]         sort ascending/descending by all key columns; replace any existing sort criteria
-      z[   z]         sort ascending/descending by current column; add to existing sort criteria
-     gz[  gz]         sort ascending/descending by all key columns; add to existing sort criteria
-      "               open duplicate sheet with only selected rows
-     g"               open duplicate sheet with all rows
-     gz"              open duplicate sheet with deepcopy of selected rows
-
-     The rows in these duplicated sheets (except deepcopy) are references to rows on the original source sheets, and so edits to the filtered rows will naturally be reflected in the original rows.  Use g' to freeze sheet contents in a deliberate copy.
-
-   Editing Rows and Cells
-       a   za         append blank row/column; appended columns cannot be copied to clipboard
-      ga  gza number  append number blank rows/columns
-       d   gd         delete current/selected row(s)
-       y   gy         yank (copy) current/all selected row(s) to clipboard in Memory Sheet
-       x   gx         cut (copy and delete) current/all selected row(s) to clipboard in Memory Sheet
-      zy  gzy         yank (copy) contents of current column for current/selected row(s) to clipboard in Memory Sheet
-      zd  gzd         set contents of current column for current/selected row(s) to options.null_value
-      zx  gzx         cut (copy and delete) contents of current column for current/selected row(s) to clipboard in Memory Sheet
-       p    P         paste clipboard rows after/before current row
-      zp  gzp         set cells of current column for current/selected row(s) to last clipboard value
-      zP  gzP         paste to cells of current column for current/selected row(s) using the system clipboard
-       Y   gY         yank (copy) current/all selected row(s) to system clipboard (using options.clipboard_copy_cmd)
-      zY  gzY         yank (copy) contents of current column for current/selected row(s) to system clipboard (using options.clipboard_copy_cmd)
-       f              fill null cells in current column with contents of non-null cells up the current column
-       e text         edit contents of current cell
-      ge text         set contents of current column for selected rows to text
-
-     Commands While Editing Input
-        Enter  ^C        accept/abort input
-        ^O               open external $EDITOR to edit contents
-        ^R               reload initial value
-        ^A  ^E           go to beginning/end of line
-        ^B  ^F           go back/forward one character
-        ^←  ^→ (arrow)   go back/forward one word
-        ^H  ^D           delete previous/current character
-        ^T               transpose previous and current characters
-        ^U  ^K           clear from cursor to beginning/end of line
-        ^Y               paste from cell clipboard
-        Backspace  Del   delete previous/current character
-        Insert           toggle insert mode
-        Up  Down         set contents to previous/next in history
-        Tab  Shift+Tab   autocomplete input (when available)
-        Shift+Arrow      move cursor in direction of Arrow and re-enter edit mode
-
-   Data Toolkit
-      o input         open input in VisiData
-     ^S g^S filename  save current/all sheet(s) to filename in format determined by extension (default .tsv)
-                      Note: if the format does not support multisave, or the filename ends in a /, a directory will be created.
-     z^S filename     save current column only to filename in format determined by extension (default .tsv)
-     ^D filename.vdj  save CommandLog to filename.vdj file
-     A                open new blank sheet with one column
-     T                open new sheet that has rows and columns of current sheet transposed
-
-      + aggregator    add aggregator to current column (see Frequency Table)
-     z+ aggregator    display result of aggregator over values in selected rows for current column; store result in Memory Sheet
-      &               concatenate top two sheets in Sheets Stack
-     g&               concatenate all sheets in Sheets Stack
-
-      w nBefore nAfter
+      ' (tick)        add a frozen copy of current column with all cells evaluated
+     g'               open a frozen copy of current sheet with all visible columns evaluated
+     z'  gz'          add/reset cache for current/all visible column(s)
+
+      : regex         add new columns from regex split; number of columns determined by example row at cursor
+      ; regex         add new columns from capture groups of regex (also requires example row)
+     z; expr          create new column from bash expr, with $columnNames as variables
+      * regex/subst   add column derived from current column, replacing regex with subst (may include \1 backrefs)
+     g*  gz* regex/subst
+                      modify selected rows in current/all visible column(s), replacing regex with subst (may include \1 backrefs)
+
+      (   g(          expand current/all visible column(s) of lists (e.g. [3]) or dicts (e.g. {3}) one level
+     z(  gz( depth    expand current/all visible column(s) of lists (e.g. [3]) or dicts (e.g. {3}) to given depth (0= fully)
+      )               unexpand current column; restore original column and remove other columns at this level
+     zM               row-wise expand current column of lists (e.g. [3]) or dicts (e.g. {3}) within that column
+
+   Row Selection
+       s   t   u      select/toggle/unselect current row
+      gs  gt  gu      select/toggle/unselect all rows
+      zs  zt  zu      select/toggle/unselect all rows from top to cursor
+     gzs gzt gzu      select/toggle/unselect all rows from cursor to bottom
+      |   \ regex     select/unselect rows matching regex in current column
+     g|  g\ regex     select/unselect rows matching regex in any visible column
+     z|  z\ expr      select/unselect rows matching Python expr in any visible column
+      , (comma)       select rows matching display value of current cell in current column
+     g,               select rows matching display value of current row in all visible columns
+     z, gz,           select rows matching typed value of current cell/row in current column/all visible columns
+
+   Row Sorting/Filtering
+       [    ]         sort ascending/descending by current column; replace any existing sort criteria
+      g[   g]         sort ascending/descending by all key columns; replace any existing sort criteria
+      z[   z]         sort ascending/descending by current column; add to existing sort criteria
+     gz[  gz]         sort ascending/descending by all key columns; add to existing sort criteria
+      "               open duplicate sheet with only selected rows
+     g"               open duplicate sheet with all rows
+     gz"              open duplicate sheet with deepcopy of selected rows
+
+     The rows in these duplicated sheets (except deepcopy) are references to rows on the original source sheets, and so edits to the filtered rows will naturally be reflected in the original rows.  Use g' to freeze sheet contents in a deliberate copy.
+
+   Editing Rows and Cells
+       a   za         append blank row/column; appended columns cannot be copied to clipboard
+      ga  gza number  append number blank rows/columns
+       d   gd         delete current/selected row(s)
+       y   gy         yank (copy) current/all selected row(s) to clipboard in Memory Sheet
+       x   gx         cut (copy and delete) current/all selected row(s) to clipboard in Memory Sheet
+      zy  gzy         yank (copy) contents of current column for current/selected row(s) to clipboard in Memory Sheet
+      zd  gzd         set contents of current column for current/selected row(s) to options.null_value
+      zx  gzx         cut (copy and delete) contents of current column for current/selected row(s) to clipboard in Memory Sheet
+       p    P         paste clipboard rows after/before current row
+      zp  gzp         set cells of current column for current/selected row(s) to last clipboard value
+      zP  gzP         paste to cells of current column for current/selected row(s) using the system clipboard
+       Y   gY         yank (copy) current/all selected row(s) to system clipboard (using options.clipboard_copy_cmd)
+      zY  gzY         yank (copy) contents of current column for current/selected row(s) to system clipboard (using options.clipboard_copy_cmd)
+       f              fill null cells in current column with contents of non-null cells up the current column
+       e text         edit contents of current cell
+      ge text         set contents of current column for selected rows to text
+
+     Commands While Editing Input
+        Enter  ^C        accept/abort input
+        ^O               open external $EDITOR to edit contents
+        ^R               reload initial value
+        ^A  ^E           go to beginning/end of line
+        ^B  ^F           go back/forward one character
+        ^←  ^→ (arrow)   go back/forward one word
+        ^H  ^D           delete previous/current character
+        ^T               transpose previous and current characters
+        ^U  ^K           clear from cursor to beginning/end of line
+        ^Y               paste from cell clipboard
+        Backspace  Del   delete previous/current character
+        Insert           toggle insert mode
+        Up  Down         set contents to previous/next in history
+        Tab  Shift+Tab   autocomplete input (when available)
+        Shift+Arrow      move cursor in direction of Arrow and re-enter edit mode
+
+   Data Toolkit
+      o input         open input in VisiData
+     zo               open file or url from path in current cell
+     ^S g^S filename  save current/all sheet(s) to filename in format determined by extension (default .tsv)
+                      Note: if the format does not support multisave, or the filename ends in a /, a directory will be created.
+     z^S filename     save current column only to filename in format determined by extension (default .tsv)
+     ^D filename.vdj  save CommandLog to filename.vdj file
+     A                open new blank sheet with one column
+     T                open new sheet that has rows and columns of current sheet transposed
+
+      + aggregator    add aggregator to current column (see Frequency Table)
+     z+ aggregator    display result of aggregator over values in selected rows for current column; store result in Memory Sheet
+      &               concatenate top two sheets in Sheets Stack
+     g&               concatenate all sheets in Sheets Stack
+
+      w nBefore nAfter
                       add column where each row contains a list of that row, nBefore rows, and nAfter rows
 
-   Data Visualization
-      . (dot)       plot current numeric column vs key columns. The numeric key column is used for the x-axis; categorical key column values determine color.
-     g.             plot a graph of all visible numeric columns vs key columns.
+   Data Visualization
+      . (dot)       plot current numeric column vs key columns. The numeric key column is used for the x-axis; categorical key column values determine color.
+     g.             plot a graph of all visible numeric columns vs key columns.
 
-     If rows on the current sheet represent plottable coordinates (as in .shp or vector .mbtiles sources),  . plots the current row, and g. plots all selected rows (or all rows if none selected).
+     If rows on the current sheet represent plottable coordinates (as in .shp or vector .mbtiles sources),  . plots the current row, and g. plots all selected rows (or all rows if none selected).
 
-     Canvas-specific Commands
-         +   -              increase/decrease zoom level, centered on cursor
+     Canvas-specific Commands
+         +   -              increase/decrease zoom level, centered on cursor
          _ (underbar)       zoom to fit full extent
-        z_ (underbar)       set aspect ratio
-         x xmin xmax        set xmin/xmax on graph
-         y ymin ymax        set ymin/ymax on graph
-         s   t   u          select/toggle/unselect rows on source sheet contained within canvas cursor
-        gs  gt  gu          select/toggle/unselect rows on source sheet visible on screen
-         d                  delete rows on source sheet contained within canvas cursor
-        gd                  delete rows on source sheet visible on screen
-         Enter              open sheet of source rows contained within canvas cursor
-        gEnter              open sheet of source rows visible on screen
-         1 - 9              toggle display of layers
-        ^L                  redraw all pixels on canvas
-         v                  toggle show_graph_labels option
-        mouse scrollwheel   zoom in/out of canvas
-        left click-drag     set canvas cursor
-        right click-drag    scroll canvas
-
-   Split Screen
-      Z             split screen in half, so that second sheet on the stack is visible in a second pane
-     zZ             split screen, and queries for height of second pane
-
-     Split Window specific Commands
-        gZ                  close an already split screen, current pane full screens
-         Z                  push second sheet on current pane's stack to the top of the other pane's stack
-         Tab                jump to other pane
-        gTab                swap panes
-        g Ctrl+^            cycle through sheets
-
-   Other Commands
-     Q                quit current sheet and remove it from the CommandLog
-     v                toggle sheet-specific visibility (multi-line rows on Sheet, legends/axes on Graph)
-
-      ^E  g^E         view traceback for most recent error(s)
-     z^E              view traceback for error in current cell
-
-      ^L              refresh screen
-      ^R              reload current sheet
-      ^Z              suspend VisiData process
-      ^G              show cursor position and bounds of current sheet on status line
-      ^V              show version and copyright information on status line
-      ^P              open Status History
+        z_ (underbar)       set aspect ratio
+         x xmin xmax        set xmin/xmax on graph
+         y ymin ymax        set ymin/ymax on graph
+         s   t   u          select/toggle/unselect rows on source sheet contained within canvas cursor
+        gs  gt  gu          select/toggle/unselect rows on source sheet visible on screen
+         d                  delete rows on source sheet contained within canvas cursor
+        gd                  delete rows on source sheet visible on screen
+         Enter              open sheet of source rows contained within canvas cursor
+        gEnter              open sheet of source rows visible on screen
+         1 - 9              toggle display of layers
+        ^L                  redraw all pixels on canvas
+         v                  toggle show_graph_labels option
+        mouse scrollwheel   zoom in/out of canvas
+        left click-drag     set canvas cursor
+        right click-drag    scroll canvas
+
+   Split Screen
+      Z             split screen in half, so that second sheet on the stack is visible in a second pane
+     zZ             split screen, and queries for height of second pane
+
+     Split Window specific Commands
+        gZ                  close an already split screen, current pane full screens
+         Z                  push second sheet on current pane's stack to the top of the other pane's stack
+         Tab                jump to other pane
+        gTab                swap panes
+        g Ctrl+^            cycle through sheets
+
+   Other Commands
+     Q                quit current sheet and remove it from the CommandLog
+     v                toggle sheet-specific visibility (multi-line rows on Sheet, legends/axes on Graph)
+
+      ^E  g^E         view traceback for most recent error(s)
+     z^E              view traceback for error in current cell
+
+      ^L              refresh screen
+      ^R              reload current sheet
+      ^Z              suspend VisiData process
+      ^G              show cursor position and bounds of current sheet on status line
+      ^V              show version and copyright information on status line
+      ^P              open Status History
      m keystroke      first, begin recording macro; second, prompt for keystroke , and complete recording. Macro can then be executed everytime provided keystroke is used. Will override existing keybinding. Macros will run on current row, column, sheet.
-     gm               open an index of all existing macros. Can be directly viewed with Enter, and then modified with ^S.
-
-      ^Y  z^Y  g^Y    open current row/cell/sheet as Python object
-      ^X expr         evaluate Python expr and opens result as Python object
-     z^X expr         evaluate Python expr, in context of current row, and open result as Python object
-     g^X module       import Python module in the global scope
-
-   Internal Sheets List
-      .  Directory Sheet             browse properties of files in a directory
-      .  Plugins Sheet               browse, install, and (de)activate plugins
-      .  Memory Sheet (Alt+Shift+M)        browse saved values, including clipboard
-
-     Metasheets
-      .  Columns Sheet (Shift+C)     edit column properties
-      .  Sheets Sheet (Shift+S)      jump between sheets or join them together
-      .  Options Sheet (Shift+O)     edit configuration options
-      .  Commandlog (Shift+D)        modify and save commands for replay
-      .  Error Sheet (Ctrl+E)            view last error
-      .  Status History (Ctrl+P)         view history of status messages
-      .  Threads Sheet (Ctrl+T)          view, cancel, and profile asynchronous threads
-
-     Derived Sheets
-      .  Frequency Table (Shift+F)   group rows by column value, with aggregations of other columns
-      .  Describe Sheet (Shift+I)    view summary statistics for each column
-      .  Pivot Table (Shift+W)       group rows by key and summarize current column
-      .  Melted Sheet (Shift+M)      unpivot non-key columns into variable/value columns
-      .  Transposed Sheet (Shift+T)   open new sheet with rows and columns transposed
-
-   INTERNAL SHEETS
-   Directory Sheet
+     gm               open an index of all existing macros. Can be directly viewed with Enter, and then modified with ^S.
+
+      ^Y  z^Y  g^Y    open current row/cell/sheet as Python object
+      ^X expr         evaluate Python expr and opens result as Python object
+     z^X expr         evaluate Python expr, in context of current row, and open result as Python object
+     g^X module       import Python module in the global scope
+
+   Internal Sheets List
+      .  Directory Sheet             browse properties of files in a directory
+      .  Plugins Sheet               browse, install, and (de)activate plugins
+      .  Memory Sheet (Alt+Shift+M)        browse saved values, including clipboard
+
+     Metasheets
+      .  Columns Sheet (Shift+C)     edit column properties
+      .  Sheets Sheet (Shift+S)      jump between sheets or join them together
+      .  Options Sheet (Shift+O)     edit configuration options
+      .  Commandlog (Shift+D)        modify and save commands for replay
+      .  Error Sheet (Ctrl+E)            view last error
+      .  Status History (Ctrl+P)         view history of status messages
+      .  Threads Sheet (Ctrl+T)          view, cancel, and profile asynchronous threads
+
+     Derived Sheets
+      .  Frequency Table (Shift+F)   group rows by column value, with aggregations of other columns
+      .  Describe Sheet (Shift+I)    view summary statistics for each column
+      .  Pivot Table (Shift+W)       group rows by key and summarize current column
+      .  Melted Sheet (Shift+M)      unpivot non-key columns into variable/value columns
+      .  Transposed Sheet (Shift+T)   open new sheet with rows and columns transposed
+
+   INTERNAL SHEETS
+   Directory Sheet
      (global commands)
-        Space open-dir-current
-                         open the Directory Sheet for the current directory
+        Space open-dir-current
+                         open the Directory Sheet for the current directory
      (sheet-specific commands)
-        Enter  gEnter    open current/selected file(s) as new sheet(s)
-         ^O  g^O         open current/selected file(s) in external $EDITOR
-         ^R  z^R  gz^R   reload information for all/current/selected file(s)
-          d   gd         delete current/selected file(s) from filesystem, upon commit
-          y   gy directory
+        Enter  gEnter    open current/selected file(s) as new sheet(s)
+         ^O  g^O         open current/selected file(s) in external $EDITOR
+         ^R  z^R  gz^R   reload information for all/current/selected file(s)
+          d   gd         delete current/selected file(s) from filesystem, upon commit
+          y   gy directory
                          copy current/selected file(s) to given directory, upon commit
-          e   ge name    rename current/selected file(s) to name
-        z^S              commit changes to file system
+          e   ge name    rename current/selected file(s) to name
+        z^S              commit changes to file system
 
-   Plugins Sheet
+   Plugins Sheet
      Browse through a list of available plugins. VisiData needs to be restarted before plugin activation takes effect. Installation may require internet access.
      (global commands)
-        Space open-plugins
-                         open the Plugins Sheet
+        Space open-plugins
+                         open the Plugins Sheet
      (sheet-specific commands)
-        a                install and activate current plugin
-        d                deactivate current plugin
+        a                install and activate current plugin
+        d                deactivate current plugin
 
-   Memory Sheet
-     Browse through a list of stored values, referanceable in expressions through their name.
+   Memory Sheet
+     Browse through a list of stored values, referanceable in expressions through their name.
      (global commands)
-        Alt+Shift+M      open the Memory Sheet
-        Alt+M name       store value in current cell in Memory Sheet under name
+        Alt+Shift+M      open the Memory Sheet
+        Alt+M name       store value in current cell in Memory Sheet under name
      (sheet-specific commands)
-        e                edit either value or name, to edit reference
+        e                edit either value or name, to edit reference
 
-   METASHEETS
-   Columns Sheet (Shift+C)
-     Properties of columns on the source sheet can be changed with standard editing commands (e ge g= Del) on the Columns Sheet. Multiple aggregators can be set by listing them (separated by spaces) in the aggregators column. The 'g' commands affect the selected rows, which are the literal columns on the source sheet.
+   METASHEETS
+   Columns Sheet (Shift+C)
+     Properties of columns on the source sheet can be changed with standard editing commands (e ge g= Del) on the Columns Sheet. Multiple aggregators can be set by listing them (separated by spaces) in the aggregators column. The 'g' commands affect the selected rows, which are the literal columns on the source sheet.
      (global commands)
-        gC               open Columns Sheet with all visible columns from all sheets
+        gC               open Columns Sheet with all visible columns from all sheets
      (sheet-specific commands)
-         &               add column from concatenating selected source columns
-        g! gz!           toggle/unset selected columns as key columns on source sheet
-        g+ aggregator    add Ar aggregator No to selected source columns
-        g- (hyphen)      hide selected columns on source sheet
-        g~ g# g% g$ g@ gz# z%
+         &               add column from concatenating selected source columns
+        g! gz!           toggle/unset selected columns as key columns on source sheet
+        g+ aggregator    add Ar aggregator No to selected source columns
+        g- (hyphen)      hide selected columns on source sheet
+        g~ g# g% g$ g@ gz# z%
                          set type of selected columns on source sheet to str/int/float/currency/date/len/floatsi
-         Enter           open a Frequency Table sheet grouped by column referenced in current row
+         Enter           open a Frequency Table sheet grouped by column referenced in current row
 
-   Sheets Sheet (Shift+S)
-     open Sheets Stack, which contains only the active sheets on the current stack
+   Sheets Sheet (Shift+S)
+     open Sheets Stack, which contains only the active sheets on the current stack
      (global commands)
-        gS               open Sheets Sheet, which contains all sheets from current session, active and inactive
-        Alt number       jump to sheet number
+        gS               open Sheets Sheet, which contains all sheets from current session, active and inactive
+        Alt number       jump to sheet number
      (sheet-specific commands)
-         Enter           jump to sheet referenced in current row
-        gEnter           push selected sheets to top of sheet stack
-         a               add row to reference a new blank sheet
-        gC  gI           open Columns Sheet/Describe Sheet with all visible columns from selected sheets
-        g^R              reload all selected sheets
-        z^C  gz^C        abort async threads for current/selected sheets(s)
-        g^S              save selected or all sheets
-         & jointype      merge selected sheets with visible columns from all, keeping rows according to jointype:
-                         .  inner  keep only rows which match keys on all sheets
-                         .  outer  keep all rows from first selected sheet
-                         .  full   keep all rows from all sheets (union)
-                         .  diff   keep only rows NOT in all sheets
-                         .  append keep all rows from all sheets (concatenation)
-                         .  extend copy first selected sheet, keeping all rows and sheet type, and extend with columns from other sheets
-                         .  merge  mostly keep all rows from first selected sheet, except prioritise cells with non-null/non-error values
-
-   Options Sheet (Shift+O)
+         Enter           jump to sheet referenced in current row
+        gEnter           push selected sheets to top of sheet stack
+         a               add row to reference a new blank sheet
+        gC  gI           open Columns Sheet/Describe Sheet with all visible columns from selected sheets
+        g^R              reload all selected sheets
+        z^C  gz^C        abort async threads for current/selected sheets(s)
+        g^S              save selected or all sheets
+         & jointype      merge selected sheets with visible columns from all, keeping rows according to jointype:
+                         .  inner  keep only rows which match keys on all sheets
+                         .  outer  keep all rows from first selected sheet
+                         .  full   keep all rows from all sheets (union)
+                         .  diff   keep only rows NOT in all sheets
+                         .  append keep all rows from all sheets (concatenation)
+                         .  extend copy first selected sheet, keeping all rows and sheet type, and extend with columns from other sheets
+                         .  merge  mostly keep all rows from first selected sheet, except prioritise cells with non-null/non-error values
+
+   Options Sheet (Shift+O)
      (global commands)
-        Shift+O          edit global options (apply to all sheets)
-        zO               edit sheet options (apply to current sheet only)
-        gO               open options.config as TextSheet
+        Shift+O          edit global options (apply to all sheets)
+        zO               edit sheet options (apply to current sheet only)
+        gO               open options.config as TextSheet
      (sheet-specific commands)
-        Enter  e         edit option at current row
-        d                remove option override for this context
-        ^S               save option configuration to foo.visidatarc
+        Enter  e         edit option at current row
+        d                remove option override for this context
+        ^S               save option configuration to foo.visidatarc
 
-   CommandLog (Shift+D)
+   CommandLog (Shift+D)
      (global commands)
-        D                open current sheet's CommandLog with all other loose ends removed; includes commands from parent sheets
-        gD               open global CommandLog for all commands executed in the current session
-        zD               open current sheet's CommandLog with the parent sheets commands' removed
+        D                open current sheet's CommandLog with all other loose ends removed; includes commands from parent sheets
+        gD               open global CommandLog for all commands executed in the current session
+        zD               open current sheet's CommandLog with the parent sheets commands' removed
      (sheet-specific commands)
-          x              replay command in current row
-         gx              replay contents of entire CommandLog
-         ^C              abort replay
+          x              replay command in current row
+         gx              replay contents of entire CommandLog
+         ^C              abort replay
 
-   Threads Sheet (Ctrl+T)
+   Threads Sheet (Ctrl+T)
      (global commands)
-        ^T               open global Threads Sheet for all asynchronous threads running
-        z^T              open current sheet's Threads Sheet
+        ^T               open global Threads Sheet for all asynchronous threads running
+        z^T              open current sheet's Threads Sheet
      (sheet-specific commands)
-         ^C              abort thread at current row
-        g^C              abort all threads on current Threads Sheet
+         ^C              abort thread at current row
+        g^C              abort all threads on current Threads Sheet
 
-   DERIVED SHEETS
-   Frequency Table (Shift+F)
-     A Frequency Table groups rows by one or more columns, and includes summary columns for those with aggregators.
+   DERIVED SHEETS
+   Frequency Table (Shift+F)
+     A Frequency Table groups rows by one or more columns, and includes summary columns for those with aggregators.
      (global commands)
-        gF               open Frequency Table, grouped by all key columns on source sheet
-        zF               open one-line summary for all rows and selected rows
+        gF               open Frequency Table, grouped by all key columns on source sheet
+        zF               open one-line summary for all rows and selected rows
      (sheet-specific commands)
-         s   t   u       select/toggle/unselect these entries in source sheet
-         Enter  gEnter   open copy of source sheet with rows that are grouped in current cell / selected rows
+         s   t   u       select/toggle/unselect these entries in source sheet
+         Enter  gEnter   open copy of source sheet with rows that are grouped in current cell / selected rows
 
-   Describe Sheet (Shift+I)
-     A Describe Sheet contains descriptive statistics for all visible columns.
+   Describe Sheet (Shift+I)
+     A Describe Sheet contains descriptive statistics for all visible columns.
      (global commands)
-        gI               open Describe Sheet for all visible columns on all sheets
+        gI               open Describe Sheet for all visible columns on all sheets
      (sheet-specific commands)
-        zs  zu           select/unselect rows on source sheet that are being described in current cell
-         !               toggle/unset current column as a key column on source sheet
-         Enter           open a Frequency Table sheet grouped on column referenced in current row
-        zEnter           open copy of source sheet with rows described in current cell
+        zs  zu           select/unselect rows on source sheet that are being described in current cell
+         !               toggle/unset current column as a key column on source sheet
+         Enter           open a Frequency Table sheet grouped on column referenced in current row
+        zEnter           open copy of source sheet with rows described in current cell
 
-   Pivot Table (Shift+W)
-     Set key column(s) and aggregators on column(s) before pressing Shift+W on the column to pivot.
+   Pivot Table (Shift+W)
+     Set key column(s) and aggregators on column(s) before pressing Shift+W on the column to pivot.
      (sheet-specific commands)
-         Enter           open sheet of source rows aggregated in current pivot row
-        zEnter           open sheet of source rows aggregated in current pivot cell
+         Enter           open sheet of source rows aggregated in current pivot row
+        zEnter           open sheet of source rows aggregated in current pivot cell
 
-   Melted Sheet (Shift+M)
+   Melted Sheet (Shift+M)
      Open Melted Sheet (unpivot), with key columns retained and all non-key columns reduced to Variable-Value rows.
      (global commands)
-        gM regex         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.
+        gM regex         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.
 
-   Python Object Sheet (^X ^Y g^Y z^Y)
+   Python Object Sheet (^X ^Y g^Y z^Y)
      (sheet-specific commands)
-         Enter           dive further into Python object
-         v               toggle show/hide for methods and hidden properties
-        gv  zv           show/hide methods and hidden properties
+         Enter           dive further into Python object
+         v               toggle show/hide for methods and hidden properties
+        gv  zv           show/hide methods and hidden properties
 
-COMMANDLINE OPTIONS
-     Add -n/--nonglobal to make subsequent CLI options sheet-specific (applying only to paths specified directly on the CLI). By default, CLI options apply to all sheets.
+COMMANDLINE OPTIONS
+     Add -n/--nonglobal to make subsequent CLI options sheet-specific (applying only to paths specified directly on the CLI). By default, CLI options apply to all sheets.
 
      Options can also be set via the Options Sheet or a .visidatarc (see FILES).
 
-     -P=longname                  preplay longname before replay or regular launch; limited to Base Sheet bound commands
-     +toplevel:subsheet:col:row   launch vd with subsheet of toplevel at top-of-stack, and cursor at col and row; all arguments are optional
-
-     -f, --filetype=filetype      tsv                set loader to use for filetype instead of file extension
-     -y, --confirm-overwrite=F    True               overwrite existing files without confirmation
-     --visidata-dir=str           ~/.visidata/       directory to load and store additional files
-     --mouse-interval=int         1                  max time between press/release for click (ms)
-     --null-value=NoneType        None               a value to be counted as null
-     --undo=bool                  True               enable undo/redo
-     --col-cache-size=int         0                  max number of cache entries in each cached column
-     --clean-names                False              clean column/sheet names to be valid Python identifiers
-     --default-width=int          20                 default column width
-     --default-height=int         4                  default column height
-     --textwrap-cells=bool        True               wordwrap text for multiline rows
-     --quitguard                  False              confirm before quitting modified sheet
-     --debug                      False              exit on error and display stacktrace
-     --skip=int                   0                  skip N rows before header
-     --header=int                 1                  parse first N rows as column names
-     --load-lazy                  False              load subsheets always (False) or lazily (True)
-     --force-256-colors           False              use 256 colors even if curses reports fewer
-     --note-pending=str           ⌛                 note to display for pending cells
-     --note-format-exc=str        ?                  cell note for an exception during formatting
-     --note-getter-exc=str        !                  cell note for an exception during computation
-     --note-type-exc=str          !                  cell note for an exception during type conversion
-     --scroll-incr=int            -3                 amount to scroll with scrollwheel
-     --name-joiner=str            _                  string to join sheet or column names
-     --value-joiner=str                              string to join display values
-     --wrap                       False              wrap text to fit window width on TextSheet
-     --save-filetype=str          tsv                specify default file type to save as
-     --profile                    False              enable profiling on threads
-     --min-memory-mb=int          0                  minimum memory to continue loading and async processing
-     --encoding=str               utf-8              encoding passed to codecs.open
-     --encoding-errors=str        surrogateescape    encoding_errors passed to codecs.open
-     --input-history=str                             basename of file to store persistent input history
-     --bulk-select-clear          False              clear selected rows before new bulk selections
-     --some-selected-rows         False              if no rows selected, if True, someSelectedRows returns all rows; if False, fails
-     --delimiter=str                                 field delimiter to use for tsv/usv filetype
-     --row-delimiter=str                             " row delimiter to use for tsv/usv filetype
-     --tsv-safe-newline=str                          replacement for newline character when saving to tsv
-     --tsv-safe-tab=str                              replacement for tab character when saving to tsv
-     --visibility=int             0                  visibility level (0=low, 1=high)
-     --default-sample-size=int    100                number of rows to sample for regex.split (0=all)
-     --fmt-expand-dict=str        %s.%s              format str to use for names of columns expanded from dict (colname, key)
-     --fmt-expand-list=str        %s[%s]             format str to use for names of columns expanded from list (colname, index)
-     --json-indent=NoneType       None               indent to use when saving json
-     --json-sort-keys             False              sort object keys when saving to json
-     --default-colname=str                           column name to use for non-dict rows
-     --filetype=str                                  specify file type
-     --confirm-overwrite=bool     True               whether to prompt for overwrite confirmation on save
-     --safe-error=str             #ERR               error string to use while saving
-     --clipboard-copy-cmd=str     xclip -selection clipboard -filter
+     -P=longname                  preplay longname before replay or regular launch; limited to Base Sheet bound commands
+     +toplevel:subsheet:col:row   launch vd with subsheet of toplevel at top-of-stack, and cursor at col and row; all arguments are optional
+
+     -f, --filetype=filetype      tsv                set loader to use for filetype instead of file extension
+     -d, --delimiter=delimiter    \t                 field delimiter to use for tsv/usv filetype
+     -y, --confirm-overwrite=F    True               overwrite existing files without confirmation
+     --visidata-dir=str           ~/.visidata/       directory to load and store additional files
+     --mouse-interval=int         1                  max time between press/release for click (ms)
+     --null-value=NoneType        None               a value to be counted as null
+     --undo=bool                  True               enable undo/redo
+     --col-cache-size=int         0                  max number of cache entries in each cached column
+     --clean-names                False              clean column/sheet names to be valid Python identifiers
+     --default-width=int          20                 default column width
+     --default-height=int         4                  default column height
+     --textwrap-cells=bool        True               wordwrap text for multiline rows
+     --quitguard                  False              confirm before quitting modified sheet
+     --debug                      False              exit on error and display stacktrace
+     --skip=int                   0                  skip N rows before header
+     --header=int                 1                  parse first N rows as column names
+     --load-lazy                  False              load subsheets always (False) or lazily (True)
+     --force-256-colors           False              use 256 colors even if curses reports fewer
+     --note-pending=str           ⌛                 note to display for pending cells
+     --note-format-exc=str        ?                  cell note for an exception during formatting
+     --note-getter-exc=str        !                  cell note for an exception during computation
+     --note-type-exc=str          !                  cell note for an exception during type conversion
+     --scroll-incr=int            -3                 amount to scroll with scrollwheel
+     --name-joiner=str            _                  string to join sheet or column names
+     --value-joiner=str                              string to join display values
+     --wrap                       False              wrap text to fit window width on TextSheet
+     --save-filetype=str          tsv                specify default file type to save as
+     --profile                    False              enable profiling on threads
+     --min-memory-mb=int          0                  minimum memory to continue loading and async processing
+     --encoding=str               utf-8              encoding passed to codecs.open
+     --encoding-errors=str        surrogateescape    encoding_errors passed to codecs.open
+     --input-history=str                             basename of file to store persistent input history
+     --bulk-select-clear          False              clear selected rows before new bulk selections
+     --some-selected-rows         False              if no rows selected, if True, someSelectedRows returns all rows; if False, fails
+     --delimiter=str                                 field delimiter to use for tsv/usv filetype
+     --row-delimiter=str                             " row delimiter to use for tsv/usv filetype
+     --tsv-safe-newline=str                          replacement for newline character when saving to tsv
+     --tsv-safe-tab=str                              replacement for tab character when saving to tsv
+     --visibility=int             0                  visibility level (0=low, 1=high)
+     --default-sample-size=int    100                number of rows to sample for regex.split (0=all)
+     --fmt-expand-dict=str        %s.%s              format str to use for names of columns expanded from dict (colname, key)
+     --fmt-expand-list=str        %s[%s]             format str to use for names of columns expanded from list (colname, index)
+     --json-indent=NoneType       None               indent to use when saving json
+     --json-sort-keys             False              sort object keys when saving to json
+     --default-colname=str                           column name to use for non-dict rows
+     --filetype=str                                  specify file type
+     --confirm-overwrite=bool     True               whether to prompt for overwrite confirmation on save
+     --safe-error=str             #ERR               error string to use while saving
+     --clipboard-copy-cmd=str     xclip -selection clipboard -filter
                                                      command to copy stdin to system clipboard
-     --clipboard-paste-cmd=str    xclip -selection clipboard -o
+     --clipboard-paste-cmd=str    xclip -selection clipboard -o
                                                      command to send contents of system clipboard to stdout
-     --fancy-chooser              False              a nicer selection interface for aggregators and jointype
-     --describe-aggrs=str         mean stdev         numeric aggregators to calculate on Describe sheet
-     --histogram-bins=int         0                  number of bins for histogram of numeric columns
-     --numeric-binning            False              bin numeric columns into ranges
-     --replay-wait=float          0.0                time to wait between replayed commands, in seconds
-     --replay-movement            False              insert movements during replay
-     --rowkey-prefix=str          キ                 string prefix for rowkey in the cmdlog
-     --cmdlog-histfile=str                           file to autorecord each cmdlog action to
-     --regex-flags=str            I                  flags to pass to re.compile() [AILMSUX]
-     --regex-maxsplit=int         0                  maxsplit to pass to regex.split
-     --show-graph-labels=bool     True               show axes and legend on graph
-     --plot-colors=str                               list of distinct colors to use for plotting distinct objects
-     --zoom-incr=float            2.0                amount to multiply current zoomlevel when zooming
-     --motd-url=str                                  source of randomized startup messages
-     --dir-recurse                False              walk source path recursively on DirSheet
-     --dir-hidden                 False              load hidden files on DirSheet
-     --config=Path                /home/anja/.visidatarc
+     --fancy-chooser              False              a nicer selection interface for aggregators and jointype
+     --describe-aggrs=str         mean stdev         numeric aggregators to calculate on Describe sheet
+     --histogram-bins=int         0                  number of bins for histogram of numeric columns
+     --numeric-binning            False              bin numeric columns into ranges
+     --replay-wait=float          0.0                time to wait between replayed commands, in seconds
+     --replay-movement            False              insert movements during replay
+     --rowkey-prefix=str          キ                 string prefix for rowkey in the cmdlog
+     --cmdlog-histfile=str                           file to autorecord each cmdlog action to
+     --regex-flags=str            I                  flags to pass to re.compile() [AILMSUX]
+     --regex-maxsplit=int         0                  maxsplit to pass to regex.split
+     --show-graph-labels=bool     True               show axes and legend on graph
+     --plot-colors=str                               list of distinct colors to use for plotting distinct objects
+     --zoom-incr=float            2.0                amount to multiply current zoomlevel when zooming
+     --motd-url=str                                  source of randomized startup messages
+     --dir-recurse                False              walk source path recursively on DirSheet
+     --dir-hidden                 False              load hidden files on DirSheet
+     --config=Path                /home/kefala/.visidatarc
                                                      config file to exec in Python
-     --play=str                                      file.vd to replay
-     --batch                      False              replay in batch mode (with no interface and all status sent to stdout)
-     --output=NoneType            None               save the final visible sheet to output at the end of replay
-     --preplay=str                                   longnames to preplay before replay
-     --imports=str                plugins            imports to preload before .visidatarc (command-line only)
-     --unfurl-empty               False              if unfurl includes rows for empty containers
-     --incr-base=float            1.0                start value for column increments
-     --csv-dialect=str            excel              dialect passed to csv.reader
-     --csv-delimiter=str          ,                  delimiter passed to csv.reader
-     --csv-quotechar=str          "                  quotechar passed to csv.reader
-     --csv-skipinitialspace=bool  True               skipinitialspace passed to csv.reader
-     --csv-escapechar=NoneType    None               escapechar passed to csv.reader
-     --csv-lineterminator=str                        " lineterminator passed to csv.writer
-     --safety-first               False              sanitize input/output to handle edge cases, with a performance cost
-     --xlsx-meta-columns          False              include columns for cell objects, font colors, and fill colors
-     --fixed-rows=int             1000               number of rows to check for fixed width columns
-     --fixed-maxcols=int          0                  max number of fixed-width columns to create (0 is no max)
-     --postgres-schema=str        public             The desired schema for the Postgres database
-     --http-max-next=int          0                  max next.url pages to follow in http response
-     --http-req-headers=dict      {}                 http headers to send to requests
-     --html-title=str             <h2>{sheet.name}</h2>
+     --play=str                                      file.vd to replay
+     --batch                      False              replay in batch mode (with no interface and all status sent to stdout)
+     --output=NoneType            None               save the final visible sheet to output at the end of replay
+     --preplay=str                                   longnames to preplay before replay
+     --imports=str                plugins            imports to preload before .visidatarc (command-line only)
+     --unfurl-empty               False              if unfurl includes rows for empty containers
+     --incr-base=float            1.0                start value for column increments
+     --csv-dialect=str            excel              dialect passed to csv.reader
+     --csv-delimiter=str          ,                  delimiter passed to csv.reader
+     --csv-quotechar=str          "                  quotechar passed to csv.reader
+     --csv-skipinitialspace=bool  True               skipinitialspace passed to csv.reader
+     --csv-escapechar=NoneType    None               escapechar passed to csv.reader
+     --csv-lineterminator=str                        " lineterminator passed to csv.writer
+     --safety-first               False              sanitize input/output to handle edge cases, with a performance cost
+     --xlsx-meta-columns          False              include columns for cell objects, font colors, and fill colors
+     --fixed-rows=int             1000               number of rows to check for fixed width columns
+     --fixed-maxcols=int          0                  max number of fixed-width columns to create (0 is no max)
+     --postgres-schema=str        public             The desired schema for the Postgres database
+     --http-max-next=int          0                  max next.url pages to follow in http response
+     --http-req-headers=dict      {}                 http headers to send to requests
+     --html-title=str             <h2>{sheet.name}</h2>
                                                      table header when saving to html
-     --pcap-internet=str          n                  (y/s/n) if save_dot includes all internet hosts separately (y), combined (s), or does not include the internet (n)
-     --graphviz-edge-labels=bool  True               whether to include edge labels on graphviz diagrams
-     --npy-allow-pickle           False              numpy allow unpickling objects (unsafe)
-     --pdf-tables                 False              parse PDF for tables instead of pages of text
-     --plugins-url=str            https://visidata.org/plugins/plugins.jsonl
+     --pcap-internet=str          n                  (y/s/n) if save_dot includes all internet hosts separately (y), combined (s), or does not include the internet (n)
+     --graphviz-edge-labels=bool  True               whether to include edge labels on graphviz diagrams
+     --npy-allow-pickle           False              numpy allow unpickling objects (unsafe)
+     --pdf-tables                 False              parse PDF for tables instead of pages of text
+     --plugins-url=str            https://visidata.org/plugins/plugins.jsonl
                                                      source of plugins sheet
-     --plugins-autoload=bool      True               do not autoload plugins if False
+     --plugins-autoload=bool      True               do not autoload plugins if False
 
-   DISPLAY OPTIONS
+   DISPLAY OPTIONS
      Display options can only be set via the Options Sheet or a .visidatarc (see FILES).
 
-     disp_splitwin_pct   0                   height of second sheet on screen
-     color_sidebar       black on 114 blue   color of sidebar
-     disp_currency_fmt   %.02f               default fmtstr to format for currency values
-     disp_float_fmt      {:.02f}             default fmtstr to format for float values
-     disp_int_fmt        {:.0f}              default fmtstr to format for int values
-     disp_date_fmt       %Y-%m-%d            default fmtstr to strftime for date values
-     disp_note_none      ⌀                   visible contents of a cell whose value is None
-     disp_truncator      …                   indicator that the contents are only partially visible
-     disp_oddspace       ·                   displayable character for odd whitespace
-     disp_more_left      <                   header note indicating more columns to the left
-     disp_more_right     >                   header note indicating more columns to the right
-     disp_error_val                          displayed contents for computation exception
-     disp_ambig_width    1                   width to use for unicode chars marked ambiguous
-     disp_pending                            string to display in pending cells
-     color_note_pending  bold magenta        color of note in pending cells
-     color_note_type     226 yellow          color of cell note for non-str types in anytype columns
-     color_note_row      220 yellow          color of row note on left edge
-     disp_column_sep     │                   separator between columns
-     disp_keycol_sep     ║                   separator between key columns and rest of columns
-     disp_rowtop_sep     │
-     disp_rowmid_sep     ⁝
-     disp_rowbot_sep     ⁝
-     disp_rowend_sep     ║
-     disp_keytop_sep     ║
-     disp_keymid_sep     ║
-     disp_keybot_sep     ║
-     disp_endtop_sep     ║
-     disp_endmid_sep     ║
-     disp_endbot_sep     ║
-     disp_selected_note  •
-     disp_sort_asc       ↑↟⇞⇡⇧⇑              characters for ascending sort
-     disp_sort_desc      ↓↡⇟⇣⇩⇓              characters for descending sort
-     color_default       white on black      the default fg and bg colors
-     color_default_hdr   bold                color of the column headers
-     color_bottom_hdr    underline           color of the bottom header row
-     color_current_row   reverse             color of the cursor row
-     color_current_col   bold                color of the cursor column
-     color_current_hdr   bold reverse        color of the header for the cursor column
-     color_column_sep    246 blue            color of column separators
-     color_key_col       81 cyan             color of key columns
-     color_hidden_col    8                   color of hidden columns on metasheets
-     color_selected_row  215 yellow          color of selected rows
-     disp_rstatus_fmt     {sheet.longname} {sheet.nRows:9d} {sheet.rowtype} {sheet.modifiedStatus} {sheet.options.disp_selected_note}{sheet.nSelectedRows}
+     disp_splitwin_pct   0                   height of second sheet on screen
+     color_sidebar       black on 114 blue   color of sidebar
+     disp_currency_fmt   %.02f               default fmtstr to format for currency values
+     disp_float_fmt      {:.02f}             default fmtstr to format for float values
+     disp_int_fmt        {:.0f}              default fmtstr to format for int values
+     disp_date_fmt       %Y-%m-%d            default fmtstr to strftime for date values
+     disp_note_none      ⌀                   visible contents of a cell whose value is None
+     disp_truncator      …                   indicator that the contents are only partially visible
+     disp_oddspace       ·                   displayable character for odd whitespace
+     disp_more_left      <                   header note indicating more columns to the left
+     disp_more_right     >                   header note indicating more columns to the right
+     disp_error_val                          displayed contents for computation exception
+     disp_ambig_width    1                   width to use for unicode chars marked ambiguous
+     disp_pending                            string to display in pending cells
+     color_note_pending  bold magenta        color of note in pending cells
+     color_note_type     226 yellow          color of cell note for non-str types in anytype columns
+     color_note_row      220 yellow          color of row note on left edge
+     disp_column_sep     │                   separator between columns
+     disp_keycol_sep     ║                   separator between key columns and rest of columns
+     disp_rowtop_sep     │
+     disp_rowmid_sep     ⁝
+     disp_rowbot_sep     ⁝
+     disp_rowend_sep     ║
+     disp_keytop_sep     ║
+     disp_keymid_sep     ║
+     disp_keybot_sep     ║
+     disp_endtop_sep     ║
+     disp_endmid_sep     ║
+     disp_endbot_sep     ║
+     disp_selected_note  •
+     disp_sort_asc       ↑↟⇞⇡⇧⇑              characters for ascending sort
+     disp_sort_desc      ↓↡⇟⇣⇩⇓              characters for descending sort
+     color_default       white on black      the default fg and bg colors
+     color_default_hdr   bold                color of the column headers
+     color_bottom_hdr    underline           color of the bottom header row
+     color_current_row   reverse             color of the cursor row
+     color_current_col   bold                color of the cursor column
+     color_current_hdr   bold reverse        color of the header for the cursor column
+     color_column_sep    246 blue            color of column separators
+     color_key_col       81 cyan             color of key columns
+     color_hidden_col    8                   color of hidden columns on metasheets
+     color_selected_row  215 yellow          color of selected rows
+     disp_rstatus_fmt     {sheet.longname} {sheet.nRows:9d} {sheet.rowtype} {sheet.modifiedStatus} {sheet.options.disp_selected_note}{sheet.nSelectedRows}
                                              right-side status format string
-     disp_status_fmt     {sheet.shortcut}› {sheet.name}|
+     disp_status_fmt     {sheet.shortcut}› {sheet.name}|
                                              status line prefix
-     disp_lstatus_max    0                   maximum length of left status line
-     disp_status_sep      │                  separator between statuses
-     color_keystrokes    bold 233 black on 110 cyan
+     disp_lstatus_max    0                   maximum length of left status line
+     disp_status_sep      │                  separator between statuses
+     color_keystrokes    bold 233 black on 110 cyan
                                              color of input keystrokes on status line
-     color_status        bold black on 110 cyan
+     color_status        bold black on 110 cyan
                                              status line color
-     color_error         red                 error message color
-     color_warning       yellow              warning message color
-     color_top_status    underline           top window status bar color
-     color_active_status black on 110 cyan    active window status bar color
-     color_inactive_status 8 on black        inactive window status bar color
-     color_working       green               color of system running smoothly
-     color_edit_cell     white               cell color to use when editing cell
-     disp_edit_fill      _                   edit field fill character
-     disp_unprintable    ·                   substitute character for unprintables
-     disp_formatter      generic             formatter to use for display and saving
-     disp_menu           True                show menu on top line when not active
-     disp_menu_keys      True                show keystrokes inline in submenus
-     color_menu          black on 110 cyan   color of menu items in general
-     color_menu_active   223 yellow on black
+     color_error         red                 error message color
+     color_warning       yellow              warning message color
+     color_top_status    underline           top window status bar color
+     color_active_status black on 110 cyan    active window status bar color
+     color_inactive_status 8 on black        inactive window status bar color
+     color_working       green               color of system running smoothly
+     color_edit_cell     white               cell color to use when editing cell
+     disp_edit_fill      _                   edit field fill character
+     disp_unprintable    ·                   substitute character for unprintables
+     disp_formatter      generic             formatter to use for display and saving
+     disp_menu           True                show menu on top line when not active
+     disp_menu_keys      True                show keystrokes inline in submenus
+     color_menu          black on 110 cyan   color of menu items in general
+     color_menu_active   223 yellow on black
                                              color of active menu items
-     color_menu_spec     black on 34 green   color of sheet-specific menu items
-     color_menu_help     black italic on 110 cyan
+     color_menu_spec     black on 34 green   color of sheet-specific menu items
+     color_menu_help     black italic on 110 cyan
                                              color of helpbox
-     disp_menu_boxchars  ││──┌┐└┘├┤          box characters to use for menus
-     disp_menu_more      »                   command submenu indicator
-     disp_menu_push      ⎘                   indicator if command pushes sheet onto sheet stack
-     disp_menu_input     …                   indicator if input required for command
-     disp_menu_fmt       Ctrl+H for help menu
+     disp_menu_boxchars  ││──┌┐└┘├┤          box characters to use for menus
+     disp_menu_more      »                   command submenu indicator
+     disp_menu_push      ⎘                   indicator if command pushes sheet onto sheet stack
+     disp_menu_input     …                   indicator if input required for command
+     disp_menu_fmt       Ctrl+H for help menu
                                              right-side menu format string
-     disp_histogram      *                   histogram element character
-     disp_histolen       50                  width of histogram column
-     disp_replay_play    ▶                   status indicator for active replay
-     disp_replay_pause   ‖                   status indicator for paused replay
-     color_status_replay green               color of replay status indicator
-     disp_canvas_charset ⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿
+     disp_histogram      *                   histogram element character
+     disp_histolen       50                  width of histogram column
+     disp_replay_play    ▶                   status indicator for active replay
+     disp_replay_pause   ‖                   status indicator for paused replay
+     color_status_replay green               color of replay status indicator
+     disp_canvas_charset ⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿
                                              charset to render 2x4 blocks on canvas
-     disp_pixel_random   False               randomly choose attr from set of pixels instead of most common
-     color_graph_hidden  238 blue            color of legend for hidden attribute
-     color_graph_selected bold               color of selected graph points
-     color_graph_axis    bold                color for graph axis labels
-     color_add_pending   green               color for rows pending add
-     color_change_pending reverse yellow     color for cells pending modification
-     color_delete_pending red                color for rows pending delete
-     color_xword_active  green               color of active clue
-
-EXAMPLES
-           vd
-     launch DirSheet for current directory
-
-           vd foo.tsv
+     disp_pixel_random   False               randomly choose attr from set of pixels instead of most common
+     color_graph_hidden  238 blue            color of legend for hidden attribute
+     color_graph_selected bold               color of selected graph points
+     color_graph_axis    bold                color for graph axis labels
+     color_add_pending   green               color for rows pending add
+     color_change_pending reverse yellow     color for cells pending modification
+     color_delete_pending red                color for rows pending delete
+     color_xword_active  green               color of active clue
+
+EXAMPLES
+           vd
+     launch DirSheet for current directory
+
+           vd foo.tsv
      open the file foo.tsv in the current directory
 
-           vd -f ddw
+           vd -f ddw
      open blank sheet of type ddw
 
-           vd new.tsv
+           vd new.tsv
      open new blank tsv sheet named new
 
-           vd -f sqlite bar.db
+           vd -f sqlite bar.db
      open the file bar.db as a sqlite database
 
-           vd foo.tsv -n -f sqlite bar.db
+           vd foo.tsv -n -f sqlite bar.db
      open foo.tsv as tsv and bar.db as a sqlite database
 
-           vd -f sqlite foo.tsv bar.db
+           vd -f sqlite foo.tsv bar.db
      open both foo.tsv and bar.db as a sqlite database
 
-           vd -b countries.fixed -o countries.tsv
+           vd -b countries.fixed -o countries.tsv
      convert countries.fixed (in fixed width format) to countries.tsv (in tsv format)
 
-           vd postgres://username:password@hostname:port/database
+           vd postgres://username:password@hostname:port/database
      open a connection to the given postgres database
 
-           vd --play tests/pivot.vd --replay-wait 1 --output tests/pivot.tsv
+           vd --play tests/pivot.vd --replay-wait 1 --output tests/pivot.tsv
      replay tests/pivot.vd, waiting 1 second between commands, and output the final sheet to test/pivot.tsv
 
-           ls -l | vd -f fixed --skip 1 --header 0
+           ls -l | vd -f fixed --skip 1 --header 0
      parse the output of ls -l into usable data
 
-           ls | vd | lpr
+           ls | vd | lpr
      interactively select a list of filenames to send to the printer
 
-           vd newfile.tsv
+           vd newfile.tsv
      open a blank sheet named newfile if file does not exist
 
-           vd sample.xlsx +:sheet1:2:3
-     launch with sheet1 at top-of-stack, and cursor at column 2 and row 3
+           vd sample.xlsx +:sheet1:2:3
+     launch with sheet1 at top-of-stack, and cursor at column 2 and row 3
 
-           vd -P open-plugins
-     preplay longname open-plugins before starting the session
+           vd -P open-plugins
+     preplay longname open-plugins before starting the session
 
-FILES
-     At the start of every session, VisiData looks for $HOME/.visidatarc, and calls Python exec() on its contents if it exists. For example:
+FILES
+     At the start of every session, VisiData looks for $HOME/.visidatarc, and calls Python exec() on its contents if it exists. For example:
 
         options.min_memory_mb=100  # stop processing without 100MB free
 
@@ -676,35 +678,35 @@ vd(1)
 
      Functions defined in .visidatarc are available in python expressions (e.g. in derived columns).
 
-SUPPORTED SOURCES
+SUPPORTED SOURCES
      Core VisiData includes these sources:
 
-        tsv (tab-separated value)
-           Plain and simple. VisiData writes tsv format by default. See the --tsv-delimiter option.
+        tsv (tab-separated value)
+           Plain and simple. VisiData writes tsv format by default. See the --tsv-delimiter option.
 
-        csv (comma-separated value)
+        csv (comma-separated value)
            .csv files are a scourge upon the earth, and still regrettably common.
-           See the --csv-dialect, --csv-delimiter, --csv-quotechar, and --csv-skipinitialspace options.
-           Accepted dialects are excel-tab, unix, and excel.
+           See the --csv-dialect, --csv-delimiter, --csv-quotechar, and --csv-skipinitialspace options.
+           Accepted dialects are excel-tab, unix, and excel.
 
-        fixed (fixed width text)
-           Columns are autodetected from the first 1000 rows (adjustable with --fixed-rows).
+        fixed (fixed width text)
+           Columns are autodetected from the first 1000 rows (adjustable with --fixed-rows).
 
-        json (single object) and jsonl/ndjson/ldjson (one object per line).
-           Cells containing lists (e.g. [3]) or dicts ({3}) can be expanded into new columns with ( and unexpanded with ).
+        json (single object) and jsonl/ndjson/ldjson (one object per line).
+           Cells containing lists (e.g. [3]) or dicts ({3}) can be expanded into new columns with ( and unexpanded with ).
 
-        sqlite
-           May include multiple tables. The initial sheet is the table directory; Enter loads the entire table into memory. z^S saves modifications to source.
+        sqlite
+           May include multiple tables. The initial sheet is the table directory; Enter loads the entire table into memory. z^S saves modifications to source.
 
      URL schemes are also supported:
-        http (requires requests); can be used as transport for with another filetype
+        http (requires requests); can be used as transport for with another filetype
 
      For a list of all remaining formats supported by VisiData, see https://visidata.org/formats.
 
-     In addition, .zip, .gz, .bz2, .xz, ,zstd, and .zst files are decompressed on the fly.
+     In addition, .zip, .gz, .bz2, .xz, ,zstd, and .zst files are decompressed on the fly.
 
-AUTHOR
-     VisiData was made by Saul Pwanson <vd@saul.pw>.
+AUTHOR
+     VisiData was made by Saul Pwanson <vd@saul.pw>.
 
 Linux/MacOS                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     August 27, 2022                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     Linux/MacOS
 
diff --git a/plugins/usd.py b/plugins/usd.py index aa75b88bb..23f614a14 100644 --- a/plugins/usd.py +++ b/plugins/usd.py @@ -7,6 +7,7 @@ import json vd.option('fixer_key', '', 'API Key for fixer.io') +vd.option('fixer_currency_cache_days', 1, 'Cache days for currency conversions') currency_symbols = { '$': 'USD', @@ -19,9 +20,25 @@ '₫': 'VND', } -def currency_rates_json(date='latest'): - url = 'http://data.fixer.io/api/%s?access_key=%s' % (date, vd.options.fixer_key) - return vd.urlcache(url).read_text() +def currency_rates_json(date='latest', base='USD'): + url = 'https://api.apilayer.com/fixer/%s?base=%s' % (date, base) + return vd.urlcache( + url, + days=vd.options.fixer_currency_cache_days, + headers={ + # First need to set some additional headers as otherwise apilayers will block it with a 403 + # See also https://stackoverflow.com/questions/13303449/urllib2-httperror-http-error-403-forbidden + 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', + 'Accept-Encoding': 'none', + 'Accept-Language': 'en-US,en;q=0.8', + 'Connection': 'keep-alive', + + # Finally set Apikey + 'apikey': vd.options.fixer_key + } + ).read_text() @functools.lru_cache() def currency_rates(): @@ -37,6 +54,7 @@ def currency_multiplier(src_currency, dest_currency): usd_mult = eur_usd_mult/eur_src_mult if dest_currency == 'USD': return usd_mult + return usd_mult/currency_rates()[dest_currency] def USD(s): diff --git a/setup.py b/setup.py index 6916b02d6..e05ae5116 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from setuptools import setup # tox can't actually run python3 setup.py: https://github.com/tox-dev/tox/issues/96 #from visidata import __version__ -__version__ = '2.10' +__version__ = '2.11dev' setup(name='visidata', version=__version__, @@ -29,7 +29,7 @@ packages=['visidata', 'visidata.loaders', 'visidata.vendor', 'visidata.tests'], include_package_data=True, data_files = [('share/man/man1', ['visidata/man/vd.1', 'visidata/man/visidata.1'])], - package_data={'visidata': ['man/vd.1', 'man/vd.txt', 'ddw/input.ddw']}, + package_data={'visidata': ['man/vd.1', 'man/vd.txt', 'ddw/input.ddw', 'tests/sample.tsv']}, license='GPLv3', classifiers=[ 'Development Status :: 5 - Production/Stable', diff --git a/tests/diff-join.vd b/tests/diff-join.vd index 5ce90add6..e62a81872 100644 --- a/tests/diff-join.vd +++ b/tests/diff-join.vd @@ -3,7 +3,7 @@ sheet col row longname input keystrokes comment open-file tests/data2.tsv o data1 Key key-col ! data1 sheets-stack S -sheets キdata2 open-row ^J +sheets キdata2 open-row-pyobj ^J data2 Key key-col ! data2 sheets-stack S sheets キdata2 select-row s diff --git a/tests/edit-joinkey-2.vd b/tests/edit-joinkey-2.vd index 8a58587f0..39d7da314 100644 --- a/tests/edit-joinkey-2.vd +++ b/tests/edit-joinkey-2.vd @@ -16,4 +16,4 @@ data2+data1 A key-col ! data2+data1 Key キ2 edit-cell 4 e data2+data1 reload-sheet ^R data2 sheets-stack S -sheets キdata1 open-row ^J +sheets キdata1 open-row-pyobj ^J diff --git a/tests/edit-joinregular-2.vd b/tests/edit-joinregular-2.vd index abc93cb86..b908118e2 100644 --- a/tests/edit-joinregular-2.vd +++ b/tests/edit-joinregular-2.vd @@ -15,4 +15,4 @@ data2+data1 sort-keys-asc g[ data2+data1 A key-col ! data2+data1 C キ2 edit-cell a3 e data2+data1 sheets-stack S -sheets キdata2 open-row ^J +sheets キdata2 open-row-pyobj ^J diff --git a/tests/invalid_unicode_sqlite.vd b/tests/invalid_unicode_sqlite.vd index 47f959bdf..effd66ef3 100644 --- a/tests/invalid_unicode_sqlite.vd +++ b/tests/invalid_unicode_sqlite.vd @@ -2,4 +2,4 @@ sheet col row longname input keystrokes comment global encoding set-option latin-1 invalid_unicode encoding set-option latin-1 open-file tests/invalid_unicode.sqlite o -invalid_unicode キTest open-row Enter open sheet with copies of rows referenced in current row +invalid_unicode キTest open-row-pyobj Enter open sheet with copies of rows referenced in current row diff --git a/tests/join-cols-single-sheet.vd b/tests/join-cols-single-sheet.vd index 88d3fc12e..f83fbde56 100644 --- a/tests/join-cols-single-sheet.vd +++ b/tests/join-cols-single-sheet.vd @@ -6,4 +6,4 @@ sample_columns キRegion select-row s select current row sample_columns キRep select-row s select current row sample_columns join-cols & add column from concatenating selected source columns sample_columns sheets-stack S open Sheets Stack: join or jump between the active sheets on the current stack -sheets キsample open-row ^J open sheet with copies of rows referenced in current row +sheets キsample open-row-pyobj ^J open sheet with copies of rows referenced in current row diff --git a/tests/join-different-types.vd b/tests/join-different-types.vd index df1733611..50f649108 100644 --- a/tests/join-different-types.vd +++ b/tests/join-different-types.vd @@ -1,16 +1,16 @@ sheet col row longname input keystrokes comment open-file tests/joining_error.xlsx o open-file tests/joining_error_interesting_records.csv o -joining_error キrecords open-row ^J open sheet with copies of rows referenced in current row +joining_error キrecords open-row-pyobj ^J open sheet with copies of rows referenced in current row joining_error_records sheets-stack S open Sheets Stack: join or jump between the active sheets on the current stack sheets キjoining_error_interesting_records slide-up K slide current row up sheets キjoining_error_interesting_records slide-up K slide current row up sheets キjoining_error_interesting_records select-row s select current row sheets キjoining_error_records select-row s select current row -sheets キjoining_error_interesting_records open-row ^J open sheet referenced in current row +sheets キjoining_error_interesting_records open-row-pyobj ^J open sheet referenced in current row joining_error_interesting_records Row key-col ! toggle current column as a key column joining_error_interesting_records sheets-stack S open Sheets Stack: join or jump between the active sheets on the current stack -sheets キjoining_error_records open-row ^J open sheet referenced in current row +sheets キjoining_error_records open-row-pyobj ^J open sheet referenced in current row joining_error_records Row key-col ! toggle current column as a key column joining_error_records sheets-stack S open Sheets Stack: join or jump between the active sheets on the current stack sheets キjoining_error_interesting_records slide-up K slide current row up diff --git a/tests/join-non-unique-cols.vd b/tests/join-non-unique-cols.vd index 5a00badea..64a2f6cf4 100644 --- a/tests/join-non-unique-cols.vd +++ b/tests/join-non-unique-cols.vd @@ -14,4 +14,4 @@ sheets join-sheets outer & benchmark+sample columns-sheet C benchmark+sample_columns name sort-desc ] benchmark+sample_columns sheets-stack S -sheets キbenchmark+sample open-row ^J +sheets キbenchmark+sample open-row-pyobj ^J diff --git a/tests/listofdictobj.vd b/tests/listofdictobj.vd index e322ea3f7..5ca963857 100644 --- a/tests/listofdictobj.vd +++ b/tests/listofdictobj.vd @@ -1,4 +1,4 @@ sheet col row longname input keystrokes comment open-file sample_data/y77d-th95.json.gz o y77d-th95 geolocation expand-col-depth 1 z( expand current column of containers to given depth (0=fully) - geolocation.coordinates 0 open-cell z^J open sheet with copies of rows referenced in current cell + geolocation.coordinates 0 open-cell-pyobj z^J open sheet with copies of rows referenced in current cell diff --git a/tests/load-ods.vd b/tests/load-ods.vd index c41baff51..6514d1008 100644 --- a/tests/load-ods.vd +++ b/tests/load-ods.vd @@ -1,3 +1,3 @@ sheet col row longname input keystrokes comment open-file sample_data/benchmark.ods o -benchmark キbenchmark open-row Enter open sheet with copies of rows referenced in current row +benchmark キbenchmark open-row-pyobj Enter open sheet with copies of rows referenced in current row diff --git a/tests/load-sqlite-view.vd b/tests/load-sqlite-view.vd index 3936e1a27..a6872f034 100644 --- a/tests/load-sqlite-view.vd +++ b/tests/load-sqlite-view.vd @@ -1,3 +1,3 @@ sheet col row longname input keystrokes comment open-file sample_data/employees.sqlite o -employees キemp_view open-row Enter open sheet with copies of rows referenced in current row +employees キemp_view open-row-pyobj Enter open sheet with copies of rows referenced in current row diff --git a/tests/load-zip.vd b/tests/load-zip.vd index e972ad937..373689340 100644 --- a/tests/load-zip.vd +++ b/tests/load-zip.vd @@ -1,3 +1,3 @@ -sheet col row longname input keystrokes comment keystrokes input longname sheet col row comment undofuncs - open-file sample_data/benchmark.zip o o sample_data/benchmark.zip open-file -benchmark キsample_data/,benchmark.csv open-row Enter open sheet with copies of rows referenced in current row Enter open-row benchmark キsample_data/,benchmark.csv open sheet with copies of rows referenced in current row [29] [3] ; [3] benchmark; _names; [1] benchmark; {0}; [3] ; [3] benchmark; _names; [1] benchmark; {0}; [3] ._undofunc at 0x7fb5c11b3f40>; [0] ; {0}; [3] ; [3] benchmark_cmdlog; _names; [1] benchmark_cmdlog; {0}; [3] ; [3] benchmark_cmdlog; _names; [1] benchmark_cmdlog; {0}; [3] ._undofunc at 0x7fb5c11b3eb0>; [0] ; {0}; [3] ; [3] benchmark_cmdlog; _names; [1] benchmark_cmdlog; {0}; [3] ; [3] benchmark_cmdlog; _names; [1] benchmark_cmdlog; {0}; [3] ._undofunc at 0x7fb5c11b3d90>; [0] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0}; [3] ; [1] ; {0} +sheet col row longname input keystrokes comment + open-file sample_data/benchmark.zip o +benchmark キsample_data/,benchmark.csv open-row-pyobj Enter open sheet with copies of rows referenced in current row diff --git a/tests/sqlite_withoutrowid.vd b/tests/sqlite_withoutrowid.vd index f9a9b0f0f..0f1b519b5 100644 --- a/tests/sqlite_withoutrowid.vd +++ b/tests/sqlite_withoutrowid.vd @@ -1,3 +1,3 @@ sheet col row longname input keystrokes comment open-file tests/without_rowid.db o -without_rowid キwithoutrowid open-row Enter open sheet with copies of rows referenced in current row +without_rowid キwithoutrowid open-row-pyobj Enter open sheet with copies of rows referenced in current row diff --git a/tests/xlsx-color-cells.vd b/tests/xlsx-color-cells.vd index eb1ab82aa..e63d9a5cf 100644 --- a/tests/xlsx-color-cells.vd +++ b/tests/xlsx-color-cells.vd @@ -1,4 +1,4 @@ sheet col row longname input keystrokes comment global xlsx_meta_columns set-option True open-file sample_data/color-merged-cells.xlsx o -color-merged-cells キSheet1 open-row Enter open sheet with copies of rows referenced in current row +color-merged-cells キSheet1 open-row-pyobj Enter open sheet with copies of rows referenced in current row diff --git a/tests/xlsx-empty-cell.vd b/tests/xlsx-empty-cell.vd index f8e01a75c..ecbbe79fe 100644 --- a/tests/xlsx-empty-cell.vd +++ b/tests/xlsx-empty-cell.vd @@ -1,3 +1,3 @@ sheet col row longname input keystrokes comment open-file sample_data/empty-cell.xlsx o -empty-cell キSheet1 open-row Enter open sheet with copies of rows referenced in current row +empty-cell キSheet1 open-row-pyobj Enter open sheet with copies of rows referenced in current row diff --git a/tests/xlsx-merged-cells.vd b/tests/xlsx-merged-cells.vd index 1bf53b7ab..80be7c545 100644 --- a/tests/xlsx-merged-cells.vd +++ b/tests/xlsx-merged-cells.vd @@ -1,3 +1,3 @@ sheet col row longname input keystrokes comment open-file sample_data/color-merged-cells.xlsx o -color-merged-cells キSheet1 open-row Enter open sheet with copies of rows referenced in current row +color-merged-cells キSheet1 open-row-pyobj Enter open sheet with copies of rows referenced in current row diff --git a/visidata/__init__.py b/visidata/__init__.py index e21c22fb8..ade7d0cc6 100644 --- a/visidata/__init__.py +++ b/visidata/__init__.py @@ -1,6 +1,6 @@ 'VisiData: a curses interface for exploring and arranging tabular data' -__version__ = '2.10' +__version__ = '2.11dev' __version_info__ = 'VisiData v' + __version__ __author__ = 'Saul Pwanson ' __status__ = 'Production/Stable' diff --git a/visidata/_open.py b/visidata/_open.py index 8c65d2d5a..f1662a6f5 100644 --- a/visidata/_open.py +++ b/visidata/_open.py @@ -132,3 +132,4 @@ def loadInternalSheet(vd, cls, p, **kwargs): BaseSheet.addCommand('o', 'open-file', 'vd.push(openSource(inputFilename("open: "), create=True))', 'Open file or URL') +TableSheet.addCommand('zo', 'open-cell', 'vd.push(openSource(cursorDisplay))', 'Open file or URL from path in current cell') diff --git a/visidata/_types.py b/visidata/_types.py index fd80a839a..d84e0f982 100644 --- a/visidata/_types.py +++ b/visidata/_types.py @@ -192,7 +192,7 @@ def __le__(self, b): return NotImplemented def __ge__(self, b): - if isinstance(b, datetime.datetime): return datetime.datetime.__le__(self, b) + if isinstance(b, datetime.datetime): return datetime.datetime.__ge__(self, b) elif isinstance(b, datetime.date): return self.date().__ge__(b) return NotImplemented diff --git a/visidata/cmdlog.py b/visidata/cmdlog.py index 31b964458..6d484cb7f 100644 --- a/visidata/cmdlog.py +++ b/visidata/cmdlog.py @@ -35,7 +35,7 @@ def open_vdj(vd, p): @VisiData.api def save_vdj(vd, p, *vsheets): with p.open_text(mode='w', encoding=vsheets[0].options.encoding) as fp: - fp.write("#!vd -p\n") + fp.write("#!/usr/bin/env vd -p\n") for vs in vsheets: vs.write_jsonl(fp) @@ -178,7 +178,7 @@ def beforeExecHook(self, sheet, cmd, args, keystrokes): self.afterExecSheet(sheet, False, '') colname, rowname, sheetname = '', '', None - if sheet and not (cmd.longname.startswith('open-') and not cmd.longname in ('open-row', 'open-cell')): + if sheet and not (cmd.longname.startswith('open-') and not cmd.longname in ('open-row-pyobj', 'open-cell-pyobj')): sheetname = sheet.name colname, rowname = sheet.commandCursor(cmd.execstr) @@ -464,14 +464,14 @@ def modifyCommand(vd): return vd.cmdlog.rows[-1] -@CommandLog.api +@CommandLogJsonl.api @asyncthread def repeat_for_n(cmdlog, r, n=1): r.sheet = r.row = r.col = "" for i in range(n): vd.replayOne(r) -@CommandLog.api +@CommandLogJsonl.api @asyncthread def repeat_for_selected(cmdlog, r): r.sheet = r.row = r.col = "" diff --git a/visidata/deprecated.py b/visidata/deprecated.py index 859ebb96c..7cca11d86 100644 --- a/visidata/deprecated.py +++ b/visidata/deprecated.py @@ -115,8 +115,9 @@ def isNumeric(col): alias('next-null', 'go-next-null') alias('page-right', 'go-right-page') alias('page-left', 'go-left-page') -alias('dive-cell', 'open-cell') -alias('dive-row', 'open-row') +alias('dive-cell', 'open-cell-pyobj') +alias('dive-row', 'open-row-pyobj') +alias('open-row', 'open-row-pyobj') alias('add-sheet', 'open-new') alias('save-sheets-selected', 'save-selected') alias('join-sheets', 'join-selected') diff --git a/visidata/extensible.py b/visidata/extensible.py index b4457c62a..1d2e807fb 100644 --- a/visidata/extensible.py +++ b/visidata/extensible.py @@ -42,6 +42,37 @@ def api(cls, func): setattr(cls, func.__name__, func) return func + @classmethod + def before(cls, beforefunc): + funcname = beforefunc.__name__ + oldfunc = getattr(cls, funcname, None) + if not oldfunc: + vd.fail('@before on non-existing func {cls.__name__}.{funcname}') + + @wraps(oldfunc) + def wrappedfunc(*args, **kwargs): + beforefunc(*args, **kwargs) + return oldfunc(*args, **kwargs) + + setattr(cls, funcname, wrappedfunc) + return wrappedfunc + + @classmethod + def after(cls, beforefunc): + funcname = beforefunc.__name__ + oldfunc = getattr(cls, funcname, None) + if not oldfunc: + vd.fail('@after on non-existing func {cls.__name__}.{funcname}') + + @wraps(oldfunc) + def wrappedfunc(*args, **kwargs): + r = oldfunc(*args, **kwargs) + beforefunc(*args, **kwargs) + return r + + setattr(cls, funcname, wrappedfunc) + return wrappedfunc + @classmethod def class_api(cls, func): name = func.__get__(None, dict).__func__.__name__ diff --git a/visidata/freqtbl.py b/visidata/freqtbl.py index 9b738fdc9..d384020c7 100644 --- a/visidata/freqtbl.py +++ b/visidata/freqtbl.py @@ -1,8 +1,7 @@ -import math -import collections +from copy import copy -from visidata import * -from visidata.pivot import PivotSheet +from visidata import vd, asyncthread, vlen, VisiData, Column, AttrColumn, Sheet, ColumnsSheet, ENTER +from visidata.pivot import PivotSheet, PivotGroupRow vd.option('disp_histogram', '*', 'histogram element character') @@ -47,10 +46,18 @@ def reload(self): # add default bonus columns for c in [ - ColumnAttr('count', 'sourcerows', type=vlen), - Column('percent', type=float, getter=lambda col,row: len(row.sourcerows)*100/col.sheet.source.nRows), - Column('histogram', type=str, getter=lambda col,row: options.disp_histogram*(options.disp_histolen*len(row.sourcerows)//col.sheet.largest), width=options.disp_histolen+2), - ]: + AttrColumn('count', 'sourcerows', type=vlen), + Column('percent', type=float, getter=lambda col,row: len(row.sourcerows)*100/col.sheet.source.nRows), + ]: + self.addColumn(c) + + if self.options.disp_histolen and self.options.disp_histogram: + def histogram(col, row): + histogram = col.sheet.options.disp_histogram + histolen = col.sheet.options.disp_histolen + return histogram*(histolen*len(row.sourcerows)//col.sheet.largest) + + c = Column('histogram', type=str, getter=histogram, width=self.options.disp_histolen+2) self.addColumn(c) # two more threads diff --git a/visidata/macros.py b/visidata/macros.py index 47a9a2741..0f2258644 100644 --- a/visidata/macros.py +++ b/visidata/macros.py @@ -1,7 +1,7 @@ from visidata import * from functools import wraps -from visidata.cmdlog import CommandLog +from visidata.cmdlog import CommandLog, CommandLogJsonl vd.macroMode = None vd.macrobindings = {} @@ -13,7 +13,14 @@ def macrosheet(vd): real_macrosheet = IndexSheet('user_macros', rows=[], source=macrosheet) for ks, fn in macrosheet.rows: - vs = vd.loadInternalSheet(CommandLog, Path(fn)) + fp = Path(fn) + if fp.ext == 'vd': + vs = vd.loadInternalSheet(CommandLog, fp) + elif fp.ext == 'vdj': + vs = vd.loadInternalSheet(CommandLogJsonl, fp) + else: + vd.warning(f'failed to load macro {fn}') + continue vd.status(f"setting {ks}") setMacro(ks, vs) real_macrosheet.addRow(vs) @@ -32,17 +39,18 @@ def setMacro(ks, vs): BaseSheet.addCommand(ks, vs.name, 'runMacro(vd.macrobindings[keystrokes])') -@CommandLog.api +@CommandLogJsonl.api def saveMacro(self, rows, ks): vs = copy(self) vs.rows = rows macropath = Path(vd.fnSuffix(options.visidata_dir+"macro")) - vd.save_vd(macropath, vs) + vd.save_vdj(macropath, vs) setMacro(ks, vs) vd.macrosheet.source.append_tsv_row((ks, macropath)) + vd.macrosheet.addRow(vd.loadInternalSheet(CommandLogJsonl, macropath)) -@CommandLog.api -@wraps(CommandLog.afterExecSheet) +@CommandLogJsonl.api +@wraps(CommandLogJsonl.afterExecSheet) def afterExecSheet(cmdlog, sheet, escaped, err): if vd.macroMode and (vd.activeCommand is not None) and (vd.activeCommand is not UNLOADED): cmd = copy(vd.activeCommand) @@ -53,7 +61,7 @@ def afterExecSheet(cmdlog, sheet, escaped, err): # once cmdlog.afterExecSheet.__wrapped__ runs, vd.activeCommand resets to None cmdlog.afterExecSheet.__wrapped__(cmdlog, sheet, escaped, err) -@CommandLog.api +@CommandLogJsonl.api def startMacro(cmdlog): if vd.macroMode: ks = vd.input('save macro for keystroke: ') @@ -61,7 +69,11 @@ def startMacro(cmdlog): vd.macroMode = None else: vd.status("recording macro") - vd.macroMode = CommandLog('current_macro', rows=[]) + vd.macroMode = CommandLogJsonl('current_macro', rows=[]) + +@VisiData.before +def run(vd, *args, **kwargs): + vd.macrosheet Sheet.addCommand('m', 'macro-record', 'vd.cmdlog.startMacro()', 'record macro') diff --git a/visidata/main.py b/visidata/main.py index 4e02ce4b5..396d421eb 100755 --- a/visidata/main.py +++ b/visidata/main.py @@ -2,7 +2,7 @@ # Usage: $0 [] [ ...] # $0 [] --play [--batch] [-w ] [-o ] [field=value ...] -__version__ = '2.10' +__version__ = '2.11dev' __version_info__ = 'saul.pw/VisiData v' + __version__ from copy import copy diff --git a/visidata/mainloop.py b/visidata/mainloop.py index 01dbfdd65..6f0f0a70a 100644 --- a/visidata/mainloop.py +++ b/visidata/mainloop.py @@ -70,7 +70,7 @@ def drawSidebar(vd, scr, text, title='sidebar'): h, w = scr.getmaxyx() maxh, maxw = 0, 0 - lines = list(iterwraplines(text.splitlines(), width=w//2)) + lines = list(iterwraplines(text.splitlines(), width=w//2-2)) maxh = min(h-2, len(lines)+2) maxw = min(w//2, max(map(len, lines))+4) @@ -230,7 +230,7 @@ def mainloop(self, scr): sheet = self.activeSheet if not sheet: - continue + continue # waiting for replay to push sheet threading.current_thread().sheet = sheet vd.drawThread = threading.current_thread() diff --git a/visidata/man/vd.1 b/visidata/man/vd.1 index c15d9396b..49ec90a90 100644 --- a/visidata/man/vd.1 +++ b/visidata/man/vd.1 @@ -187,13 +187,13 @@ toggle/unset current column as a key column .It Ic "~ # % $ @ z#" set type of current column to str/int/float/currency/date/len .It Ic " ^" -edit name of current column +rename current column .It Ic " g^" -set names of all unnamed visible columns to contents of selected rows (or current row) +rename all unnamed visible columns to contents of selected rows (or current row) .It Ic " z^" -set name of current column to combined contents of current cell in selected rows (or current row) +rename current column to combined contents of current cell in selected rows (or current row) .It Ic "gz^" -set name of all visible columns to combined contents of current column for selected rows (or current row) +rename all visible columns to combined contents of current column for selected rows (or current row) .Pp .It Ic " =" Ar expr .No create new column from Python Ar expr Ns , with column names, and attributes, as variables @@ -376,6 +376,8 @@ autocomplete input (when available) .It Ic " o" Ar input open .Ar input No in Sy VisiData +.It Ic "zo" +open file or url from path in current cell .It Ic "^S g^S" Ar filename .No save current/all sheet(s) to Ar filename No in format determined by extension (default .tsv) .It "" @@ -864,6 +866,10 @@ set loader to use for .Ar filetype instead of file extension . +.Lo d delimiter delimiter +.No "\(rst " +field delimiter to use for tsv/usv filetype +. .Lo y confirm-overwrite F .No "True " overwrite existing files without confirmation diff --git a/visidata/man/vd.inc b/visidata/man/vd.inc index 6ac7c9d35..bf0421689 100644 --- a/visidata/man/vd.inc +++ b/visidata/man/vd.inc @@ -187,13 +187,13 @@ toggle/unset current column as a key column .It Ic "~ # % $ @ z#" set type of current column to str/int/float/currency/date/len .It Ic " ^" -edit name of current column +rename current column .It Ic " g^" -set names of all unnamed visible columns to contents of selected rows (or current row) +rename all unnamed visible columns to contents of selected rows (or current row) .It Ic " z^" -set name of current column to combined contents of current cell in selected rows (or current row) +rename current column to combined contents of current cell in selected rows (or current row) .It Ic "gz^" -set name of all visible columns to combined contents of current column for selected rows (or current row) +rename all visible columns to combined contents of current column for selected rows (or current row) .Pp .It Ic " =" Ar expr .No create new column from Python Ar expr Ns , with column names, and attributes, as variables @@ -376,6 +376,8 @@ autocomplete input (when available) .It Ic " o" Ar input open .Ar input No in Sy VisiData +.It Ic "zo" +open file or url from path in current cell .It Ic "^S g^S" Ar filename .No save current/all sheet(s) to Ar filename No in format determined by extension (default .tsv) .It "" @@ -864,6 +866,10 @@ set loader to use for .Ar filetype instead of file extension . +.Lo d delimiter delimiter +.No "\(rst " +field delimiter to use for tsv/usv filetype +. .Lo y confirm-overwrite F .No "True " overwrite existing files without confirmation diff --git a/visidata/man/vd.txt b/visidata/man/vd.txt index 6a40e38c3..74ec646cf 100644 --- a/visidata/man/vd.txt +++ b/visidata/man/vd.txt @@ -105,13 +105,13 @@ DESCRIPTION ~ # % $ @ z# set type of current column to str/int/float/cur‐ rency/date/len - ^ edit name of current column - g^ set names of all unnamed visible columns to contents of - selected rows (or current row) - z^ set name of current column to combined contents of cur‐ - rent cell in selected rows (or current row) - gz^ set name of all visible columns to combined contents of - current column for selected rows (or current row) + ^ rename current column + g^ rename all unnamed visible columns to contents of se‐ + lected rows (or current row) + z^ rename current column to combined contents of current + cell in selected rows (or current row) + gz^ rename all visible columns to combined contents of cur‐ + rent column for selected rows (or current row) = expr create new column from Python expr, with column names, and attributes, as variables @@ -240,6 +240,7 @@ DESCRIPTION Data Toolkit o input open input in VisiData + zo open file or url from path in current cell ^S g^S filename save current/all sheet(s) to filename in format determined by extension (default .tsv) Note: if the format does not support multisave, or the @@ -557,6 +558,8 @@ COMMANDLINE OPTIONS -f, --filetype=filetype tsv set loader to use for filetype instead of file extension + -d, --delimiter=delimiter \t field delimiter to use + for tsv/usv filetype -y, --confirm-overwrite=F True overwrite existing files without confirmation --visidata-dir=str ~/.visidata/ directory to load and diff --git a/visidata/man/visidata.1 b/visidata/man/visidata.1 index c15d9396b..49ec90a90 100644 --- a/visidata/man/visidata.1 +++ b/visidata/man/visidata.1 @@ -187,13 +187,13 @@ toggle/unset current column as a key column .It Ic "~ # % $ @ z#" set type of current column to str/int/float/currency/date/len .It Ic " ^" -edit name of current column +rename current column .It Ic " g^" -set names of all unnamed visible columns to contents of selected rows (or current row) +rename all unnamed visible columns to contents of selected rows (or current row) .It Ic " z^" -set name of current column to combined contents of current cell in selected rows (or current row) +rename current column to combined contents of current cell in selected rows (or current row) .It Ic "gz^" -set name of all visible columns to combined contents of current column for selected rows (or current row) +rename all visible columns to combined contents of current column for selected rows (or current row) .Pp .It Ic " =" Ar expr .No create new column from Python Ar expr Ns , with column names, and attributes, as variables @@ -376,6 +376,8 @@ autocomplete input (when available) .It Ic " o" Ar input open .Ar input No in Sy VisiData +.It Ic "zo" +open file or url from path in current cell .It Ic "^S g^S" Ar filename .No save current/all sheet(s) to Ar filename No in format determined by extension (default .tsv) .It "" @@ -864,6 +866,10 @@ set loader to use for .Ar filetype instead of file extension . +.Lo d delimiter delimiter +.No "\(rst " +field delimiter to use for tsv/usv filetype +. .Lo y confirm-overwrite F .No "True " overwrite existing files without confirmation diff --git a/visidata/menu.py b/visidata/menu.py index a1ebb801a..6e3fa29f6 100644 --- a/visidata/menu.py +++ b/visidata/menu.py @@ -116,7 +116,10 @@ def _intMenuPath(obj, menupath): Menu('New', 'open-new'), Menu('Open file/url', 'open-file'), Menu('Rename', 'rename-sheet'), - Menu('Guard', 'guard-sheet'), + Menu('Guard', + Menu('on', 'guard-sheet'), + Menu('off', 'guard-sheet-off') + ), Menu('Duplicate', Menu('selected rows by ref', 'dup-selected'), Menu('all rows by ref', 'dup-rows'), @@ -557,6 +560,7 @@ def drawSubmenu(vd, scr, sheet, y, x, menus, level, disp_menu_boxchars=''): BUTTON1_PRESSED=lambda y,x,key,p=sheet.activeMenuItems[:level]+[j]: sheet.pressMenu(*p), BUTTON2_PRESSED=vd.nop, BUTTON3_PRESSED=vd.nop, + BUTTON1_CLICKED=lambda y,x,key,p=sheet.activeMenuItems[:level]+[j]: sheet.pressMenu(*p), BUTTON1_RELEASED=vd.nop, BUTTON2_RELEASED=vd.nop, BUTTON3_RELEASED=vd.nop) @@ -629,6 +633,7 @@ def drawMenu(vd, scr, sheet): BUTTON1_PRESSED=lambda y,x,key,i=i,sheet=sheet: sheet.pressMenu(i), BUTTON2_PRESSED=vd.nop, BUTTON3_PRESSED=vd.nop, + BUTTON1_CLICKED=lambda y,x,key,i=i,sheet=sheet: sheet.pressMenu(i), BUTTON1_RELEASED=vd.nop, BUTTON2_RELEASED=vd.nop, BUTTON3_RELEASED=vd.nop) diff --git a/visidata/path.py b/visidata/path.py index 2e67e779c..4c76a9bec 100644 --- a/visidata/path.py +++ b/visidata/path.py @@ -149,8 +149,8 @@ def given(self, given): self._path = pathlib.Path(given) self.ext = self.suffix[1:] - if self.suffixes: #1450 don't make this a oneliner; [:-0] doesn't work - self.name = self._path.name[:-sum(map(len, self.suffixes))] + if self.suffix: #1450 don't make this a oneliner; [:-0] doesn't work + self.name = self._path.name[:-len(self.suffix)] else: self.name = self._path.name diff --git a/visidata/pyobj.py b/visidata/pyobj.py index 063bbc531..3055d894e 100644 --- a/visidata/pyobj.py +++ b/visidata/pyobj.py @@ -405,8 +405,8 @@ def launch_repl(v, i): Sheet.addCommand(')', 'contract-col', 'closeColumn(sheet, cursorCol)', 'unexpand current column; restore original column and remove other columns at this level') -Sheet.addCommand(ENTER, 'open-row', 'vd.push(openRow(cursorRow))', 'open sheet with copies of rows referenced in current row') -Sheet.addCommand('z'+ENTER, 'open-cell', 'vd.push(openCell(cursorCol, cursorRow))', 'open sheet with copies of rows referenced in current cell') +Sheet.addCommand(ENTER, 'open-row-pyobj', 'vd.push(openRow(cursorRow))', 'open sheet with copies of rows referenced in current row') +Sheet.addCommand('z'+ENTER, 'open-cell-pyobj', 'vd.push(openCell(cursorCol, cursorRow))', 'open sheet with copies of rows referenced in current cell') Sheet.addCommand('g'+ENTER, 'dive-selected', 'for r in selectedRows: vd.push(openRow(r))', 'open sheet with copies of rows referenced in selected rows') Sheet.addCommand('gz'+ENTER, 'dive-selected-cells', 'for r in selectedRows: vd.push(openCell(cursorCol, r))', 'open sheet with copies of rows referenced in selected rows') @@ -415,6 +415,7 @@ def launch_repl(v, i): PyobjSheet.addCommand('zv', 'hide-hidden', 'sheet.options.visibility -= 1; reload()', 'hide methods and hidden properties') vd.addGlobals({ + 'ExpandedColumn': ExpandedColumn, 'PythonSheet': PythonSheet, 'expand_cols_deep': expand_cols_deep, 'deduceType': deduceType, diff --git a/visidata/regex.py b/visidata/regex.py index 1dad8076f..2d34acb43 100644 --- a/visidata/regex.py +++ b/visidata/regex.py @@ -79,14 +79,17 @@ def addRegexColumns(vs, regexMaker, origcol, regexstr): @VisiData.api def regexTransform(vd, origcol, instr): + before, after = vd.parse_sed_transform(instr) + return lambda col,row,origcol=origcol,before=before,after=after,flags=origcol.sheet.regex_flags(): re.sub(before, after, origcol.getDisplayValue(row), flags=flags) + + +@VisiData.api +def parse_sed_transform(vd, instr): i = indexWithEscape(instr, '/') if i is None: - before = instr - after = '' + return instr, '' else: - before = instr[:i] - after = instr[i+1:] - return lambda col,row,origcol=origcol,before=before,after=after,flags=origcol.sheet.regex_flags(): re.sub(before, after, origcol.getDisplayValue(row), flags=flags) + return instr[:i], instr[i+1:] def indexWithEscape(s, char, escape_char='\\'): diff --git a/visidata/sheets.py b/visidata/sheets.py index d23b71521..f793e659a 100644 --- a/visidata/sheets.py +++ b/visidata/sheets.py @@ -6,7 +6,7 @@ from visidata import VisiData, Extensible, globalCommand, ColumnAttr, ColumnItem, vd, ENTER, EscapeException, drawcache, drawcache_property, LazyChainMap, asyncthread, ExpectedException, setitem from visidata import (options, Column, namedlist, SettableColumn, TypedExceptionWrapper, BaseSheet, UNLOADED, -vd, clipdraw, ColorAttr, update_attr, colors, undoAttrFunc) +clipdraw, ColorAttr, update_attr, colors, undoAttrFunc, vlen) import visidata @@ -1200,16 +1200,17 @@ def _async_deepcopy(newlist, oldlist): BaseSheet.addCommand('^L', 'redraw', 'vd.redraw(); sheet.refresh()', 'Refresh screen') BaseSheet.addCommand(None, 'guard-sheet', 'options.set("quitguard", True, sheet); status("guarded")', 'Set quitguard on current sheet to confirm before quit') +BaseSheet.addCommand(None, 'guard-sheet-off', 'options.set("quitguard", False, sheet); status("unguarded")', 'Unset quitguard on current sheet to not confirm before quit') BaseSheet.addCommand(None, 'open-source', 'vd.push(source)', 'jump to the source of this sheet') BaseSheet.bindkey('KEY_RESIZE', 'redraw') BaseSheet.addCommand('A', 'open-new', 'vd.push(vd.newSheet("unnamed", 1))', 'Open new empty sheet') -Sheet.addCommand('^', 'rename-col', 'vd.addUndoColNames([cursorCol]); cursorCol.name = editCell(cursorVisibleColIndex, -1)', 'edit name of current column') -Sheet.addCommand('z^', 'rename-col-selected', 'updateColNames(selectedRows or [cursorRow], [sheet.cursorCol], overwrite=True)', 'set name of current column to combined contents of current cell in selected rows (or current row)') -Sheet.addCommand('g^', 'rename-cols-row', 'updateColNames(selectedRows or [cursorRow], sheet.visibleCols)', 'set names of all unnamed visible columns to contents of selected rows (or current row)') -Sheet.addCommand('gz^', 'rename-cols-selected', 'updateColNames(selectedRows or [cursorRow], sheet.visibleCols, overwrite=True)', 'set names of all visible columns to combined contents of selected rows (or current row)') +Sheet.addCommand('^', 'rename-col', 'vd.addUndoColNames([cursorCol]); cursorCol.name = editCell(cursorVisibleColIndex, -1)', 'rename current column') +Sheet.addCommand('z^', 'rename-col-selected', 'updateColNames(selectedRows or [cursorRow], [sheet.cursorCol], overwrite=True)', 'rename current column to combined contents of current cell in selected rows (or current row)') +Sheet.addCommand('g^', 'rename-cols-row', 'updateColNames(selectedRows or [cursorRow], sheet.visibleCols)', 'rename all unnamed visible columns to contents of selected rows (or current row)') +Sheet.addCommand('gz^', 'rename-cols-selected', 'updateColNames(selectedRows or [cursorRow], sheet.visibleCols, overwrite=True)', 'rename all visible columns to combined contents of selected rows (or current row)') BaseSheet.addCommand(None, 'rename-sheet', 'sheet.name = input("rename sheet to: ", value=sheet.name)', 'Rename current sheet') diff --git a/visidata/statusbar.py b/visidata/statusbar.py index f9fee0fc0..89d81f12c 100644 --- a/visidata/statusbar.py +++ b/visidata/statusbar.py @@ -195,9 +195,9 @@ def drawRightStatus(vd, scr, vs): if scr is vd.winTop: cattr = update_attr(cattr, colors.color_top_status, 0) if active: - cattr = update_attr(cattr, colors.color_active_status, 1) + cattr = update_attr(cattr, colors.color_active_status, 0) else: - cattr = update_attr(cattr, colors.color_inactive_status, 1) + cattr = update_attr(cattr, colors.color_inactive_status, 0) statuslen = clipdraw(scr, vs.windowHeight-1, rightx, rstatus, cattr.attr, w=vs.windowWidth-1, rtl=True) rightx -= statuslen ret += statuslen diff --git a/visidata/tests/sample.tsv b/visidata/tests/sample.tsv new file mode 100644 index 000000000..daf50fecd --- /dev/null +++ b/visidata/tests/sample.tsv @@ -0,0 +1,44 @@ +OrderDate Region Rep Item Units Unit_Cost Total +2016-01-06 East Jones Pencil 95 1.99 189.05 +2016-01-23 Central Kivell Binder 50 19.99 999.50 +2016-02-09 Central Jardine Pencil 36 4.99 179.64 +2016-02-26 Central Gill Pen 27 19.99 539.73 +2016-03-15 West Sorvino Pencil 56 2.99 167.44 +2016-04-01 East Jones Binder 60 4.99 299.40 +2016-04-18 Central Andrews Pencil 75 1.99 149.25 +2016-05-05 Central Jardine Pencil 90 4.99 449.10 +2016-05-22 West Thompson Pencil 32 1.99 63.68 +2016-06-08 East Jones Binder 60 8.99 539.40 +2016-06-25 Central Morgan Pencil 90 4.99 449.10 +2016-07-12 East Howard Binder 29 1.99 57.71 +2016-07-29 East Parent Binder 81 19.99 1619.19 +2016-08-15 East Jones Pencil 35 4.99 174.65 +2016-09-01 Central Smith Desk 2 125.00 250.00 +2016-09-18 East Jones Pen Set 16 15.99 255.84 +2016-10-05 Central Morgan Binder 28 8.99 251.72 +2016-10-22 East Jones Pen 64 8.99 575.36 +2016-11-08 East Parent Pen 15 19.99 299.85 +2016-11-25 Central Kivell Pen Set 96 4.99 479.04 +2016-12-12 Central Smith Pencil 67 1.29 86.43 +2016-12-29 East Parent Pen Set 74 15.99 1183.26 +2017-01-15 Central Gill Binder 46 8.99 413.54 +2017-02-01 Central Smith Binder 87 15.00 1305.00 +2017-02-18 East Jones Binder 4 4.99 19.96 +2017-03-07 West Sorvino Binder 7 19.99 139.93 +2017-03-24 Central Jardine Pen Set 50 4.99 249.50 +2017-04-10 Central Andrews Pencil 66 1.99 131.34 +2017-04-27 East Howard Pen 96 4.99 479.04 +2017-05-14 Central Gill Pencil 53 1.29 68.37 +2017-05-31 Central Gill Binder 80 8.99 719.20 +2017-06-17 Central Kivell Desk 5 125.00 625.00 +2017-07-04 East Jones Pen Set 62 4.99 309.38 +2017-07-21 Central Morgan Pen Set 55 12.49 686.95 +2017-08-07 Central Kivell Pen Set 42 23.95 1005.90 +2017-08-24 West Sorvino Desk 3 275.00 825.00 +2017-09-10 Central Gill Pencil 7 1.29 9.03 +2017-09-27 West Sorvino Pen 76 1.99 151.24 +2017-10-14 West Thompson Binder 57 19.99 1139.43 +2017-10-31 Central Andrews Pencil 14 1.29 18.06 +2017-11-17 Central Jardine Binder 11 4.99 54.89 +2017-12-04 Central Jardine Binder 94 19.99 1879.06 +2017-12-21 Central Andrews Binder 28 4.99 139.72 diff --git a/visidata/tests/test_commands.py b/visidata/tests/test_commands.py index e9ee5eb07..15d102fd0 100644 --- a/visidata/tests/test_commands.py +++ b/visidata/tests/test_commands.py @@ -29,11 +29,11 @@ def isTestableCommand(longname, cmdlist): return True -inputLines = { 'save-sheet': 'tests/jetsam.csv', # save to some tmp file - 'save-all': 'tests/lagan.csv', - 'open-file': 'tests/jetsam.csv', # reopen what was just saved ('o' must come after ^S in the commands list) - 'save-col': 'tests/flotsam.csv', - 'save-col-keys': 'tests/debris.csv', +inputLines = { 'save-sheet': 'jetsam.csv', # save to some tmp file + 'save-all': 'lagan.csv', + 'open-file': 'jetsam.csv', # reopen what was just saved ('o' must come after ^S in the commands list) + 'save-col': 'flotsam.csv', + 'save-col-keys': 'debris.csv', 'pyobj-expr': '2+2', # open the python object for '4' 'edit-cell': '3', 'search-col': 'foo', @@ -114,7 +114,7 @@ def runOneTest(self, mock_screen, longname): else: vd.getkeystroke = Mock(side_effect=['^J']) - sample_file = pkg_resources.resource_filename('visidata', '../sample_data/sample.tsv') + sample_file = pkg_resources.resource_filename('visidata', 'tests/sample.tsv') vs = visidata.TsvSheet('test_commands', source=visidata.Path(sample_file)) vs.reload.__wrapped__(vs) vs.vd = vd diff --git a/visidata/tests/test_date.py b/visidata/tests/test_date.py new file mode 100644 index 000000000..75492b459 --- /dev/null +++ b/visidata/tests/test_date.py @@ -0,0 +1,11 @@ + +import pytest + +from visidata import Sheet, date + + +class TestVisidataDate: + def test_date(self): #1507 + dt = Sheet().customdate('%d%m%Y') + assert not date(2021, 7, 1) <= dt('22092017') + assert date(2021, 7, 1) <= dt('28092021') diff --git a/visidata/tests/test_path.py b/visidata/tests/test_path.py index c3d378b60..22a5c5c21 100644 --- a/visidata/tests/test_path.py +++ b/visidata/tests/test_path.py @@ -1,17 +1,26 @@ import pytest -import visidata +from visidata import Path class TestVisidataPath: def test_withName(self): 'tests for visidata.Path().with_name' - file_path = visidata.Path('sample_data/sample.tsv') - url_path = visidata.Path('https://visidata.org/hello/sample.tsv') + file_path = Path('sample_data/sample.tsv') + url_path = Path('https://visidata.org/hello/sample.tsv') assert 'sample_data/b.tsv' == str(file_path.with_name('b.tsv')), '{} should be sample_data/b.tsv'.format(file_path.with_name('b.tsv')) assert 'sample_data/a/b.tsv' == str(file_path.with_name('a/b.tsv')), '{} should be sample_data/a/b.tsv'.format(file_path.with_name('a/b.tsv')) assert "https://visidata.org/hello/b.tsv" == str(url_path.with_name('b.tsv')), '{} should be https://visidata.org/hello/b.tsv'.format(url_path.with_name('b.tsv')) assert "https://visidata.org/hello/a/b.tsv" == str(url_path.with_name('a/b.tsv')), '{} should be https://visidata.org/hello/a/b.tsv'.format(url_path.with_name('a/b.tsv')) + + assert Path('foo.a.b').name == 'foo.a' + assert Path('foo.a.b').ext == 'b' + assert Path('foo').ext == '' + assert Path('foo').name == 'foo' + assert Path('foo.').ext == '' + assert Path('foo.').name == 'foo.' + assert Path('.foo').ext == '' + assert Path('.foo').name == '.foo' diff --git a/visidata/threads.py b/visidata/threads.py index 1a90112d5..219481558 100644 --- a/visidata/threads.py +++ b/visidata/threads.py @@ -255,10 +255,10 @@ def sync(self, *joiningThreads): threads -= deads for t in threads: try: - if not t.is_alive() or getattr(t, 'noblock', False) is True: + if not t.is_alive() or t not in threading.enumerate() or getattr(t, 'noblock', False) is True: deads.add(t) else: - t.join() + t.join(timeout=1) except RuntimeError as e: # maybe thread hasn't started yet or has already joined vd.exceptionCaught(e) pass diff --git a/visidata/vdobj.py b/visidata/vdobj.py index 87aab3b32..793a2d6a6 100644 --- a/visidata/vdobj.py +++ b/visidata/vdobj.py @@ -31,7 +31,7 @@ class VisiData(visidata.Extensible): def global_api(cls, func): 'Make global func() and identical vd.func()' def _vdfunc(*args, **kwargs): - return func(visidata.vd, *args, **kwargs) + return getattr(visidata.vd, func.__name__)(*args, **kwargs) visidata.vd.addGlobals({func.__name__: func}) setattr(cls, func.__name__, func) return wraps(func)(_vdfunc)