visidata 3.1.1__py3-none-any.whl → 3.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. visidata/__init__.py +2 -2
  2. visidata/_input.py +106 -58
  3. visidata/_open.py +10 -7
  4. visidata/_types.py +2 -2
  5. visidata/aggregators.py +125 -16
  6. visidata/apps/vdsql/_ibis.py +8 -13
  7. visidata/basesheet.py +4 -3
  8. visidata/canvas.py +11 -7
  9. visidata/clipboard.py +11 -2
  10. visidata/cliptext.py +68 -23
  11. visidata/cmdlog.py +5 -1
  12. visidata/column.py +48 -33
  13. visidata/ddwplay.py +2 -2
  14. visidata/deprecated.py +96 -63
  15. visidata/errors.py +41 -5
  16. visidata/{features → experimental}/helloworld.py +1 -1
  17. visidata/experimental/liveupdate.py +1 -1
  18. visidata/expr.py +1 -0
  19. visidata/extensible.py +4 -0
  20. visidata/features/cmdpalette.py +64 -25
  21. visidata/features/describe.py +2 -2
  22. visidata/features/expand_cols.py +7 -5
  23. visidata/features/freeze.py +14 -2
  24. visidata/features/go_col.py +3 -3
  25. visidata/features/graph_zoom_y.py +47 -0
  26. visidata/features/incr.py +7 -3
  27. visidata/features/join.py +23 -12
  28. visidata/features/layout.py +8 -4
  29. visidata/features/melt.py +1 -0
  30. visidata/features/rank.py +103 -0
  31. visidata/features/reload_every.py +11 -8
  32. visidata/features/sysedit.py +14 -4
  33. visidata/features/transpose.py +1 -0
  34. visidata/features/window.py +12 -0
  35. visidata/form.py +10 -9
  36. visidata/freqtbl.py +47 -3
  37. visidata/fuzzymatch.py +11 -7
  38. visidata/graph.py +5 -3
  39. visidata/guides/AggregatorsSheet.md +84 -0
  40. visidata/guides/CommandsSheet.md +1 -0
  41. visidata/guides/MacrosSheet.md +1 -1
  42. visidata/guides/RankGuide.md +51 -0
  43. visidata/guides/TypesSheet.md +1 -1
  44. visidata/guides/WindowFunctionGuide.md +49 -0
  45. visidata/help.py +23 -6
  46. visidata/indexsheet.py +1 -1
  47. visidata/loaders/_pandas.py +3 -1
  48. visidata/loaders/archive.py +33 -6
  49. visidata/loaders/csv.py +12 -1
  50. visidata/loaders/eml.py +2 -0
  51. visidata/loaders/f5log.py +2 -2
  52. visidata/loaders/fec.py +6 -9
  53. visidata/loaders/fixed_width.py +2 -0
  54. visidata/loaders/hdf5.py +34 -10
  55. visidata/loaders/npy.py +54 -23
  56. visidata/loaders/orgmode.py +3 -2
  57. visidata/loaders/pandas_freqtbl.py +4 -0
  58. visidata/loaders/psv.py +13 -0
  59. visidata/loaders/sqlite.py +1 -1
  60. visidata/loaders/vds.py +3 -4
  61. visidata/macros.py +5 -4
  62. visidata/main.py +21 -11
  63. visidata/mainloop.py +8 -5
  64. visidata/man/parse_options.py +3 -2
  65. visidata/man/vd.1 +38 -17
  66. visidata/man/vd.txt +47 -17
  67. visidata/menu.py +10 -10
  68. visidata/metasheets.py +3 -3
  69. visidata/mouse.py +3 -0
  70. visidata/movement.py +6 -3
  71. visidata/pyobj.py +17 -9
  72. visidata/save.py +10 -2
  73. visidata/selection.py +29 -18
  74. visidata/settings.py +9 -5
  75. visidata/sheets.py +124 -48
  76. visidata/shell.py +2 -2
  77. visidata/sidebar.py +11 -8
  78. visidata/sort.py +89 -11
  79. visidata/statusbar.py +10 -9
  80. visidata/tests/test_cliptext.py +164 -0
  81. visidata/tests/test_commands.py +6 -2
  82. visidata/tests/test_menu.py +1 -1
  83. visidata/textsheet.py +34 -8
  84. visidata/themes/ascii8.py +2 -2
  85. visidata/themes/light.py +5 -0
  86. visidata/threads.py +38 -8
  87. visidata/utils.py +15 -1
  88. visidata/vendor/__init__.py +0 -0
  89. {visidata-3.1.1.data → visidata-3.3.data}/data/share/man/man1/vd.1 +38 -17
  90. {visidata-3.1.1.data → visidata-3.3.data}/data/share/man/man1/visidata.1 +38 -17
  91. {visidata-3.1.1.dist-info → visidata-3.3.dist-info}/METADATA +62 -15
  92. {visidata-3.1.1.dist-info → visidata-3.3.dist-info}/RECORD +98 -92
  93. {visidata-3.1.1.dist-info → visidata-3.3.dist-info}/WHEEL +1 -1
  94. {visidata-3.1.1.dist-info → visidata-3.3.dist-info}/entry_points.txt +1 -0
  95. visidata-3.1.1.data/scripts/vd +0 -6
  96. {visidata-3.1.1.data → visidata-3.3.data}/data/share/applications/visidata.desktop +0 -0
  97. {visidata-3.1.1.data → visidata-3.3.data}/scripts/vd2to3.vdx +0 -0
  98. {visidata-3.1.1.dist-info → visidata-3.3.dist-info}/LICENSE.gpl3 +0 -0
  99. {visidata-3.1.1.dist-info → visidata-3.3.dist-info}/top_level.txt +0 -0
visidata/loaders/npy.py CHANGED
@@ -1,4 +1,5 @@
1
- from visidata import VisiData, vd, Sheet, date, anytype, options, Column, Progress, ColumnItem, vlen, PyobjSheet, TypedWrapper
1
+ from visidata import VisiData, vd, Sheet, date, anytype, options, Column, ItemColumn, Progress, vlen, PyobjSheet, TypedWrapper
2
+ from itertools import chain
2
3
 
3
4
  'Loaders for .npy and .npz. Save to .npy. Depends on the zip loader.'
4
5
 
@@ -11,44 +12,74 @@ def open_npz(vd, p):
11
12
  return NpzSheet(p.base_stem, source=p)
12
13
 
13
14
  vd.option('npy_allow_pickle', False, 'numpy allow unpickling objects (unsafe)')
15
+ vd.option('npy_matrix_enumerate', False, 'enumerate matrix rows and columns')
14
16
 
15
17
  class NpySheet(Sheet):
16
18
  def iterload(self):
17
19
  numpy = vd.importExternal('numpy')
18
20
  if not hasattr(self, 'npy'):
19
- self.npy = numpy.load(str(self.source), encoding='bytes', **self.options.getall('npy_'))
21
+ self.npy = numpy.load(str(self.source), encoding='bytes', allow_pickle=bool(self.options.npy_allow_pickle))
20
22
  self.reloadCols()
21
- yield from Progress(self.npy, total=len(self.npy))
23
+ transpose = len(self.npy.shape)==1 and not bool(self.npy.dtype.names)
24
+ if transpose:
25
+ source = self.npy[:,None]
26
+ else:
27
+ source = self.npy
28
+
29
+ nrows = len(self.npy)
30
+
31
+ if self.options.npy_matrix_enumerate:
32
+ source = list(list((chain((i,), row))) for i, row in enumerate(source))
33
+
34
+ yield from Progress(source, nrows)
35
+
22
36
 
23
37
  def reloadCols(self):
24
38
  self.columns = []
25
- for i, (name, fmt, *shape) in enumerate(self.npy.dtype.descr):
26
- if not name:
27
- continue
28
- if shape:
29
- t = anytype
30
- elif 'M' in fmt:
31
- self.addColumn(Column(name, type=date, getter=lambda c,r,i=i: str(r[i])))
32
- continue
33
- elif 'i' in fmt:
34
- t = int
35
- elif 'f' in fmt:
36
- t = float
39
+ if len(self.npy.shape)==1:
40
+ for i, (colname, fmt, *shape) in enumerate(self.npy.dtype.descr):
41
+ if not colname:
42
+ colname = f"col{i}"
43
+ ctype = _guess_type(shape, fmt)
44
+ if ctype=="time":
45
+ self.addColumn(Column(colname, type=date, getter=lambda c,r,i=i: str(r[i])))
46
+ continue
47
+ self.addColumn(ItemColumn(colname, i, type=ctype))
48
+ elif len(self.npy.shape)==2:
49
+ ncols = self.npy.shape[1]
50
+ ctype = _guess_type(None, self.npy.dtype.descr[0][1])
51
+
52
+ if self.options.npy_matrix_enumerate:
53
+ self.addColumn(ItemColumn("row", 0, width=8, keycol=1, type=int), index=0)
54
+ for i in range(ncols):
55
+ self.addColumn(ItemColumn(f'col{i}', i+1, width=8, type=ctype), index=i+1)
37
56
  else:
38
- t = anytype
39
- self.addColumn(ColumnItem(name, i, type=t))
40
-
57
+ for i in range(ncols):
58
+ self.addColumn(ItemColumn('', i, width=8, type=ctype), index=i)
59
+ else:
60
+ vd.fail(f"too many dimensions in shape {self.npy.shape}")
61
+
62
+ def _guess_type(shape, fmt):
63
+ if shape:
64
+ return anytype
65
+ elif 'M' in fmt:
66
+ return "time"
67
+ elif 'i' in fmt or 'u' in fmt:
68
+ return int
69
+ elif 'f' in fmt:
70
+ return float
71
+ return anytype
41
72
 
42
73
  class NpzSheet(vd.ZipSheet):
43
74
  # rowdef: tuple(tablename, table)
44
75
  columns = [
45
- ColumnItem('name', 0),
46
- ColumnItem('length', 1, type=vlen),
76
+ ItemColumn('name', 0),
77
+ ItemColumn('length', 1, type=vlen),
47
78
  ]
48
79
 
49
80
  def iterload(self):
50
81
  numpy = vd.importExternal('numpy')
51
- self.npz = numpy.load(str(self.source), encoding='bytes', **self.options.getall('npy_'))
82
+ self.npz = numpy.load(str(self.source), encoding='bytes', allow_pickle=bool(self.options.npy_allow_pickle))
52
83
  yield from Progress(self.npz.items())
53
84
 
54
85
  def openRow(self, row):
@@ -74,7 +105,7 @@ def save_npy(vd, p, sheet):
74
105
  elif col.type in vd.numericTypes:
75
106
  dt = 'f8'
76
107
  else: # if col.type in (str, anytype):
77
- width = col.getMaxWidth(sheet.rows)
108
+ width = col.getMaxDataWidth(sheet.rows)
78
109
  dt = 'U'+str(width)
79
110
  dtype.append((col.name, dt))
80
111
 
@@ -94,4 +125,4 @@ def save_npy(vd, p, sheet):
94
125
 
95
126
  arr = np.array(data, dtype=dtype)
96
127
  with p.open_bytes(mode='w') as outf:
97
- np.save(outf, arr, **sheet.options.getall('npy_'))
128
+ np.save(outf, arr, allow_pickle=bool(sheet.options.npy_allow_pickle))
@@ -55,8 +55,8 @@ def encode_date(dt=None):
55
55
 
56
56
 
57
57
  class OrgContentsColumn(Column):
58
- def setValue(self, row, v):
59
- super().setValue(row, v)
58
+ def setValue(self, row, v, setModified=True):
59
+ super().setValue(row, v, setModified=setModified)
60
60
  orgmode_parse_into(row, v)
61
61
 
62
62
  def putValue(self, row, v):
@@ -88,6 +88,7 @@ def sectionize(lines):
88
88
 
89
89
  def orgmode_parse(all_lines):
90
90
  root = parent = OrgSheet().newRow()
91
+ root.orig_contents = ''
91
92
  for linenum, lines in sectionize(all_lines):
92
93
  section = OrgSheet().newRow()
93
94
 
@@ -83,6 +83,10 @@ class PandasFreqTableSheet(PivotSheet):
83
83
  self.source._selectByILoc(row.sourcerows.mask_iloc, selected=False)
84
84
  return super().unselectRow(row)
85
85
 
86
+ def addUndoSelection(self):
87
+ self.source.addUndoSelection()
88
+ super().addUndoSelection()
89
+
86
90
  def updateLargest(self, grouprow):
87
91
  self.largest = max(self.largest, len(grouprow.sourcerows))
88
92
 
@@ -0,0 +1,13 @@
1
+ from visidata import VisiData, TsvSheet
2
+
3
+
4
+ @VisiData.api
5
+ def open_psv(vd, p):
6
+ return PsvSheet(p.name, source=p)
7
+
8
+
9
+ class PsvSheet(TsvSheet):
10
+ pass
11
+
12
+
13
+ PsvSheet.options.delimiter = '|'
@@ -20,7 +20,7 @@ def requery(url, **kwargs):
20
20
  @VisiData.api
21
21
  def guess_sqlite(vd, p):
22
22
  if p.open_bytes().read(16).startswith(b'SQLite format'):
23
- return dict(filetype='sqlite')
23
+ return dict(filetype='sqlite', _likelihood=10)
24
24
 
25
25
 
26
26
  @VisiData.api
visidata/loaders/vds.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import json
4
4
 
5
- from visidata import VisiData, JsonSheet, Progress, IndexSheet, SettableColumn, ItemColumn, ExprColumn
5
+ from visidata import vd, VisiData, JsonSheet, Progress, IndexSheet, SettableColumn, ItemColumn, ExprColumn
6
6
 
7
7
 
8
8
  NL='\n'
@@ -80,11 +80,10 @@ class VdsSheet(JsonSheet):
80
80
  classname = 'ItemColumn'
81
81
  d['expr'] = d['name']
82
82
 
83
- c = globals()[classname](d.pop('name'), sheet=self)
83
+ c = vd.getGlobals()[classname](d.pop('name'), sheet=self)
84
84
  self.addColumn(c)
85
85
  self.colnames[c.name] = c
86
- for k, v in d.items():
87
- setattr(c, k, v)
86
+ c.__setstate__(d) # must happen after addColumn sets .sheet
88
87
 
89
88
  line = fp.readline()
90
89
 
visidata/macros.py CHANGED
@@ -40,7 +40,7 @@ class MacroSheet(IndexSheet):
40
40
  def putChanges(self):
41
41
  self.commitDeletes() #1569 apply deletes early for saveSheets below
42
42
 
43
- vd.saveSheets(self.source, self, confirm_overwrite=False)
43
+ vd.sync(vd.saveSheets(self.source, self, confirm_overwrite=False))
44
44
  self._deferredDels.clear()
45
45
  self.reload()
46
46
 
@@ -107,9 +107,10 @@ def afterExecSheet(cmdlog, sheet, escaped, err):
107
107
  if not vd.activeCommand: return
108
108
  if vd.activeCommand.longname == 'macro-record': return
109
109
 
110
- cmd = copy(vd.activeCommand)
111
- cmd.sheet = ''
112
- vd.macroMode.addRow(cmd)
110
+ if vd.activeCommand.replayable:
111
+ cmd = copy(vd.activeCommand)
112
+ cmd.sheet = ''
113
+ vd.macroMode.addRow(cmd)
113
114
 
114
115
 
115
116
  @CommandLogJsonl.api
visidata/main.py CHANGED
@@ -2,7 +2,7 @@
2
2
  # Usage: $0 [<options>] [<input> ...]
3
3
  # $0 [<options>] --play <cmdlog> [--batch] [-w <waitsecs>] [-o <output>] [field=value ...]
4
4
 
5
- __version__ = '3.1.1'
5
+ __version__ = '3.3'
6
6
  __version_info__ = 'saul.pw/VisiData v' + __version__
7
7
 
8
8
  from copy import copy
@@ -16,7 +16,7 @@ import signal
16
16
  import warnings
17
17
  import builtins # to override print
18
18
 
19
- from visidata import vd, options, run, BaseSheet, AttrDict
19
+ from visidata import vd, options, run, BaseSheet, AttrDict, stacktrace
20
20
  from visidata import Path
21
21
  from visidata.settings import _get_config_file
22
22
  import visidata
@@ -189,7 +189,7 @@ def main_vd():
189
189
  vd.warning(e)
190
190
 
191
191
  warnings.showwarning = vd.warning
192
- vd.printout = builtins.print
192
+ vd.printerr = lambda *args: builtins.print(*args, file=sys.stderr)
193
193
 
194
194
  flPipedInput = not sys.stdin.isatty()
195
195
  flPipedOutput = not sys.stdout.isatty()
@@ -255,7 +255,11 @@ def main_vd():
255
255
  optval = sys.argv[i+1]
256
256
  i += 1
257
257
 
258
- current_args[optname] = optval
258
+ # batch and interactive are only meaningful when applied globally,
259
+ # so exclude them from sheet-specific options. Those would
260
+ # override any later change to vd.options.batch in global settings.
261
+ if optname not in ('batch', 'interactive'):
262
+ current_args[optname] = optval
259
263
  if flGlobal:
260
264
  global_args[optname] = optval
261
265
  elif arg.startswith('+'): # position cursor at start
@@ -285,7 +289,7 @@ def main_vd():
285
289
  # fetch motd *after* options parsing/setting
286
290
  vd.domotd()
287
291
 
288
- if args.batch:
292
+ if options.batch:
289
293
  if not vd.options.interactive:
290
294
  options.undo = False
291
295
  options.quitguard = False
@@ -316,7 +320,7 @@ def main_vd():
316
320
  for vs in reversed(sources):
317
321
  vd.push(vs, load=False) #1471, 1555
318
322
 
319
- if not vd.sheets and not args.play and not args.batch:
323
+ if not vd.sheets and not args.play and not options.batch:
320
324
  if 'filetype' in current_args:
321
325
  newfunc = getattr(vd, 'new_' + current_args['filetype'], vd.getGlobals().get('new_' + current_args['filetype']))
322
326
  datestr = datetime.date.today().strftime('%Y-%m-%d')
@@ -333,23 +337,25 @@ def main_vd():
333
337
  vd.cmdlog.openHook(vd.currentDirSheet, vd.currentDirSheet.source)
334
338
 
335
339
  if not args.play:
336
- if args.batch:
340
+ if options.batch:
337
341
  if sources:
338
342
  vd.push(sources[0])
339
343
 
340
344
  for (f, *parms) in after_config:
341
345
  f(sources, *parms)
342
346
 
343
- if not args.batch:
347
+ if not options.batch:
344
348
  run(vd.sheets[0])
345
349
  else:
346
350
  if args.play == '-':
351
+ if vd.stdinSource.fptext.isatty():
352
+ vd.fail('replay commands must come by pipe, not by terminal')
347
353
  vdfile = vd.stdinSource
348
354
  else:
349
355
  vdfile = Path(args.play)
350
356
 
351
357
  vs = eval_vd(vdfile, *fmtargs, **fmtkwargs)
352
- if args.batch:
358
+ if options.batch:
353
359
  if not args.debug:
354
360
  vd.outputProgressThread = visidata.VisiData.execAsync(vd, vd.outputProgressEvery, vs, seconds=0.5, sheet=BaseSheet()) #1182
355
361
  vd.reloadMacros()
@@ -357,6 +363,7 @@ def main_vd():
357
363
  return 1
358
364
 
359
365
  if vd.options.interactive:
366
+ vd.options.batch = False #2639
360
367
  vd.execAsync = lambda *args, vd=vd, **kwargs: visidata.VisiData.execAsync(vd, *args, **kwargs)
361
368
  run()
362
369
  else:
@@ -369,7 +376,7 @@ def main_vd():
369
376
 
370
377
  saver_threads = [t for t in vd.unfinishedThreads if t.name.startswith('save_')]
371
378
  if saver_threads:
372
- vd.printout('finishing %d savers' % len(saver_threads))
379
+ vd.printerr('finishing %d savers' % len(saver_threads))
373
380
  vd.sync(*saver_threads)
374
381
 
375
382
  vd._stdout.flush()
@@ -386,9 +393,12 @@ def vd_cli():
386
393
  if vd.options.debug:
387
394
  raise
388
395
  except FileNotFoundError as e:
389
- print(e)
396
+ print(e, file=sys.stderr)
390
397
  if options.debug:
391
398
  raise
399
+ except Exception as e:
400
+ for l in stacktrace(): #show the stack trace without carets
401
+ print(l, file=sys.stderr)
392
402
 
393
403
  sys.stderr.flush()
394
404
  sys.stdout.flush()
visidata/mainloop.py CHANGED
@@ -64,6 +64,7 @@ def setWindows(vd, scr, pct=None):
64
64
  disp_menu = getattr(vd, 'menuRunning', None) or vd.options.disp_menu
65
65
  topmenulines = 1 if disp_menu else 0
66
66
  h, w = scr.getmaxyx()
67
+ if h == 1: topmenulines = 0
67
68
 
68
69
  n = 0
69
70
  if pct:
@@ -71,6 +72,7 @@ def setWindows(vd, scr, pct=None):
71
72
  n = abs(pct)*h//100
72
73
  n = min(n, h-topmenulines-3)
73
74
  n = max(3, n)
75
+ if n > h: n = 0
74
76
 
75
77
  desiredConfig = dict(pct=pct, n=n, h=h-topmenulines, w=w)
76
78
 
@@ -165,7 +167,7 @@ def mainloop(vd, scr):
165
167
  numTimeouts = 0
166
168
  prefixWaiting = False
167
169
  vd.scrFull = scr
168
- if vd.options.disp_expert >= 5:
170
+ if not vd.wantsHelp('help'):
169
171
  vd.disp_help = -1
170
172
 
171
173
  vd.keystrokes = ''
@@ -251,13 +253,14 @@ def mainloop(vd, scr):
251
253
  vd.checkForFinishedThreads()
252
254
  vd.callNoExceptions(sheet.checkCursor)
253
255
 
254
- # no idle redraw unless background threads are running
255
256
  time.sleep(0) # yield to other threads which may not have started yet
256
257
  if vd._nextCommands:
257
- if vd.options.replay_wait > 0:
258
- vd.curses_timeout = int(vd.options.replay_wait*1000)
259
- else:
258
+ if vd.unfinishedThreads: #2369 #2635
259
+ # while running a bg thread for a command, schedule infrequent redraws
260
260
  vd.curses_timeout = nonidle_timeout
261
+ else:
262
+ # otherwise, schedule the next redraw and command (immediately, for default replay_wait)
263
+ vd.curses_timeout = int(vd.options.replay_wait*1000)
261
264
  elif vd.unfinishedThreads:
262
265
  vd.curses_timeout = nonidle_timeout
263
266
  else:
@@ -4,6 +4,7 @@
4
4
 
5
5
  import sys
6
6
  import visidata
7
+ dispwidth = visidata.dispwidth
7
8
 
8
9
 
9
10
  fncli, fnopts = sys.argv[1:]
@@ -31,7 +32,7 @@ with open(fncli, 'w') as cliOut:
31
32
  optkeys = visidata.options.keys()
32
33
  optvalues = [visidata.options._opts._get(optname) for optname in optkeys]
33
34
 
34
- widestoptwidth, widestopt = sorted((len(opt.name)+len(str(opt.value)), opt.name) for opt in optvalues)[-1]
35
+ widestoptwidth, widestopt = sorted((dispwidth(opt.name)+dispwidth(str(opt.value)), opt.name) for opt in optvalues)[-1]
35
36
  print('widest option+default is "%s", width %d' % (widestopt, widestoptwidth))
36
37
  widestoptwidth = 35
37
38
  menuOut.write('.Bl -tag -width %s -compact\n' % ('X'*(widestoptwidth+3)))
@@ -51,7 +52,7 @@ with open(fncli, 'w') as cliOut:
51
52
  else:
52
53
  cli_optname=opt.name.replace('_', '-')
53
54
  cli_type=type(opt.value).__name__
54
- optlen = len(cli_optname)+len(cli_type)+1
55
+ optlen = dispwidth(cli_optname)+dispwidth(cli_type)+1
55
56
  if cli_type != 'bool' or visidata.options.getdefault(opt.name):
56
57
  cliOut.write(options_cli_skel.format(cli_optname=cli_optname,
57
58
  optname = opt.name,
visidata/man/vd.1 CHANGED
@@ -1,4 +1,4 @@
1
- .Dd October 13, 2024
1
+ .Dd June 13, 2025
2
2
  .Dt vd \&1 "Quick Reference Guide"
3
3
  .Os Linux/MacOS
4
4
  .
@@ -193,6 +193,8 @@ adjust widths of all visible columns to Ar number
193
193
  .Pp
194
194
  .It Ic " -" Ns " (hyphen)"
195
195
  hide current column
196
+ .It Ic "g-" Ns " (hyphen)"
197
+ hide any column that has multiple rows but only one distinct value
196
198
  .It Ic "z-" Ns
197
199
  reduce width of current column by half
198
200
  .It Ic "gv" Ns
@@ -247,10 +249,10 @@ add/reset cache for current/all visible column(s)
247
249
  .No add new columns from capture groups of Ar regex No (also requires example row)
248
250
  .It Ic "z" Ns Ic "\&;" Ar expr
249
251
  .No create new column from bash Ar expr Ns , with Sy $ Ns columnNames as variables
250
- .It Ic " *" Ar regex Ns Sy / Ns Ar subst
251
- .No add column derived from current column, replacing Ar regex No with Ar subst No (may include Sy \e1 No backrefs)
252
- .It Ic "g* gz*" Ar regex Ns Sy / Ns Ar subst
253
- .No modify selected rows in current/all visible column(s), replacing Ar regex No with Ar subst No (may include Sy \e1 No backrefs)
252
+ .It Ic " *" Ar search No Sy Tab No Ar replace
253
+ .No add column derived from current column, replacing Ar search No regex with Ar replace No (may include Sy \e1 No backrefs)
254
+ .It Ic "g* gz*" Ar search No Sy Tab No Ar replace
255
+ .No modify selected rows in current/all visible column(s), replacing Ar search No with Ar replace No (may include Sy \e1 No backrefs)
254
256
  .Pp
255
257
  .It Ic " ( g("
256
258
  .No expand current/all visible column(s) of lists (e.g. Sy [3] Ns ) or dicts (e.g. Sy {3} Ns ) one level
@@ -300,7 +302,7 @@ sort ascending/descending by current column; replace any existing sort criteria
300
302
  .It Ic " g[ g]"
301
303
  sort ascending/descending by all key columns; replace any existing sort criteria
302
304
  .It Ic " z[ z]"
303
- sort ascending/descending by current column; add to existing sort criteria
305
+ sort ascending/descending by current column; keep higher priority sort criteria
304
306
  .It Ic "gz[ gz]"
305
307
  sort ascending/descending by all key columns; add to existing sort criteria
306
308
  .It Ic " \&""
@@ -316,6 +318,8 @@ open duplicate sheet with deepcopy of selected rows
316
318
  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
317
319
  .Ic "g'"
318
320
  to freeze sheet contents in a deliberate copy.
321
+ .Ic "z'"
322
+ replace current column with a frozen copy, with all cells evaluated
319
323
  .
320
324
  .Ss Editing Rows and Cells
321
325
  .
@@ -352,6 +356,8 @@ fill null cells in current column with contents of non-null cells up the current
352
356
  .
353
357
  .It Ic " e" Ar text
354
358
  edit contents of current cell
359
+ .It Ic " ^O"
360
+ .No edit contents of current cell in external Sy EDITOR
355
361
  .It Ic " ge" Ar text
356
362
  .No set contents of current column for selected rows to Ar text
357
363
  .
@@ -443,6 +449,8 @@ increase/decrease zoom level, centered on cursor
443
449
  zoom to fit full extent
444
450
  .It Ic "z_" No (underbar)
445
451
  set aspect ratio
452
+ .It Ic "g_" No (underbar)
453
+ Zoom y-axis to fit all visible data points
446
454
  .It Ic " x" Ar xmin xmax
447
455
  .No set Ar xmin Ns / Ns Ar xmax No on graph
448
456
  .It Ic " y" Ar ymin ymax
@@ -782,7 +790,7 @@ abort replay
782
790
  .It Ic ^T
783
791
  .No open global Sy Threads Sheet No for all asynchronous threads running
784
792
  .It Ic z^T
785
- .No open current sheet's Sy Threads Sheet No
793
+ .No open current sheet's Sy Threads Sheet
786
794
  .El
787
795
  .Bl -inset -compact
788
796
  .It (sheet-specific commands)
@@ -791,7 +799,7 @@ abort replay
791
799
  .It Ic " ^C"
792
800
  abort thread at current row
793
801
  .It Ic "g^C"
794
- .No abort all threads on current Sy Threads Sheet No
802
+ .No abort all threads on current Sy Threads Sheet
795
803
  .El
796
804
  .
797
805
  .Ss DERIVED SHEETS
@@ -912,7 +920,7 @@ disable loading .visidatarc and plugin addons
912
920
  .
913
921
  .El
914
922
  .Bl -tag -width XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -compact
915
- .It Sy --visidata-dir Ns = Ns Ar "str " No "~/.visidata/"
923
+ .It Sy --visidata-dir Ns = Ns Ar "str " No "/home/anja/.config/visidata"
916
924
  directory to load and store additional files
917
925
  .It Sy --debug No " False"
918
926
  exit on error and display stacktrace
@@ -1021,7 +1029,7 @@ source of randomized startup messages
1021
1029
  folder recursion depth on DirSheet
1022
1030
  .It Sy --dir-hidden No " False"
1023
1031
  load hidden files on DirSheet
1024
- .It Sy --config Ns = Ns Ar "Path " No "/home/saul/.visidatarc"
1032
+ .It Sy --config Ns = Ns Ar "Path " No "/home/anja/.visidatarc"
1025
1033
  config file to exec in Python
1026
1034
  .It Sy --play Ns = Ns Ar "str " No ""
1027
1035
  file.vdj to replay
@@ -1055,7 +1063,7 @@ device ID associated with matrix login
1055
1063
  client_id for reddit api
1056
1064
  .It Sy --reddit-client-secret Ns = Ns Ar "str " No ""
1057
1065
  client_secret for reddit api
1058
- .It Sy --reddit-user-agent Ns = Ns Ar "str " No "3.1dev"
1066
+ .It Sy --reddit-user-agent Ns = Ns Ar "str " No "3.3"
1059
1067
  user_agent for reddit api
1060
1068
  .It Sy --zulip-batch-size Ns = Ns Ar "int " No "-100"
1061
1069
  number of messages to fetch per call (<0 to fetch before anchor)
@@ -1100,6 +1108,8 @@ max number of fixed-width columns to create (0 is no max)
1100
1108
  whether to include edge labels on graphviz diagrams
1101
1109
  .It Sy --grep-base-dir Ns = Ns Ar "NoneType " No "None"
1102
1110
  base directory for relative paths opened with sysopen-row
1111
+ .It Sy --hdf5-matrix-enumerate No " False"
1112
+ enumerate matrix rows and columns
1103
1113
  .It Sy --html-title Ns = Ns Ar "str " No "<h2>{sheet.name}</h2>"
1104
1114
  table header when saving to html
1105
1115
  .It Sy --http-max-next Ns = Ns Ar "int " No "0"
@@ -1110,6 +1120,8 @@ http headers to send to requests
1110
1120
  verify host and certificates for https
1111
1121
  .It Sy --npy-allow-pickle No " False"
1112
1122
  numpy allow unpickling objects (unsafe)
1123
+ .It Sy --npy-matrix-enumerate No " False"
1124
+ enumerate matrix rows and columns
1113
1125
  .It Sy --pcap-internet Ns = Ns Ar "str " No "n"
1114
1126
  (y/s/n) if save_dot includes all internet hosts separately (y), combined (s), or does not include the internet (n)
1115
1127
  .It Sy --pdf-tables No " False"
@@ -1144,8 +1156,6 @@ API Key for api.apilayer.com/fixer
1144
1156
  Cache days for currency conversions
1145
1157
  .It Sy --describe-aggrs Ns = Ns Ar "str " No "mean stdev"
1146
1158
  numeric aggregators to calculate on Describe sheet
1147
- .It Sy --hello-world Ns = Ns Ar "str " No "\[u00A1]Hola mundo!"
1148
- shown by the hello-world command
1149
1159
  .It Sy --incr-base Ns = Ns Ar "float " No "1.0"
1150
1160
  start value for column increments
1151
1161
  .It Sy --ping-count Ns = Ns Ar "int " No "3"
@@ -1193,7 +1203,7 @@ command submenu indicator
1193
1203
  indicator if command pushes sheet onto sheet stack
1194
1204
  .It Sy "disp_menu_input " No "\[u2026]"
1195
1205
  indicator if input required for command
1196
- .It Sy "disp_menu_fmt " No "| VisiData {vd.version} | {vd.hintStatus}"
1206
+ .It Sy "disp_menu_fmt " No "| VisiData {vd.version} | {vd.motd}"
1197
1207
  right-side menu format string
1198
1208
  .It Sy "disp_float_fmt " No "{:.02f}"
1199
1209
  default fmtstr to format float values
@@ -1305,6 +1315,8 @@ replace whitespace with spaces in multiline
1305
1315
  multiline string to indicate truncation
1306
1316
  .It Sy "disp_multiline_focus" No "True"
1307
1317
  only multiline cursor row
1318
+ .It Sy "color_multiline_bottom" No ""
1319
+ color of bottom line of multiline rows
1308
1320
  .It Sy "color_aggregator " No "bold 255 white on 234 black"
1309
1321
  color of aggregator summary on bottom row
1310
1322
  .It Sy "disp_rstatus_fmt " No "{sheet.threadStatus} {sheet.keystrokeStatus} [:longname_status]{sheet.longname}[/] {sheet.nRows:9d} {sheet.rowtype} {sheet.modifiedStatus}{sheet.selectedStatus}{vd.replayStatus}{vd.sidebarStatus}"
@@ -1365,7 +1377,7 @@ histogram element character
1365
1377
  show axes and legend on graph
1366
1378
  .It Sy "disp_canvas_charset" No "\[u2800]\[u2801]\[u2802]\[u2803]\[u2804]\[u2805]\[u2806]\[u2807]\[u2808]\[u2809]\[u280A]\[u280B]\[u280C]\[u280D]\[u280E]\[u280F]\[u2810]\[u2811]\[u2812]\[u2813]\[u2814]\[u2815]\[u2816]\[u2817]\[u2818]\[u2819]\[u281A]\[u281B]\[u281C]\[u281D]\[u281E]\[u281F]\[u2820]\[u2821]\[u2822]\[u2823]\[u2824]\[u2825]\[u2826]\[u2827]\[u2828]\[u2829]\[u282A]\[u282B]\[u282C]\[u282D]\[u282E]\[u282F]\[u2830]\[u2831]\[u2832]\[u2833]\[u2834]\[u2835]\[u2836]\[u2837]\[u2838]\[u2839]\[u283A]\[u283B]\[u283C]\[u283D]\[u283E]\[u283F]\[u2840]\[u2841]\[u2842]\[u2843]\[u2844]\[u2845]\[u2846]\[u2847]\[u2848]\[u2849]\[u284A]\[u284B]\[u284C]\[u284D]\[u284E]\[u284F]\[u2850]\[u2851]\[u2852]\[u2853]\[u2854]\[u2855]\[u2856]\[u2857]\[u2858]\[u2859]\[u285A]\[u285B]\[u285C]\[u285D]\[u285E]\[u285F]\[u2860]\[u2861]\[u2862]\[u2863]\[u2864]\[u2865]\[u2866]\[u2867]\[u2868]\[u2869]\[u286A]\[u286B]\[u286C]\[u286D]\[u286E]\[u286F]\[u2870]\[u2871]\[u2872]\[u2873]\[u2874]\[u2875]\[u2876]\[u2877]\[u2878]\[u2879]\[u287A]\[u287B]\[u287C]\[u287D]\[u287E]\[u287F]\[u2880]\[u2881]\[u2882]\[u2883]\[u2884]\[u2885]\[u2886]\[u2887]\[u2888]\[u2889]\[u288A]\[u288B]\[u288C]\[u288D]\[u288E]\[u288F]\[u2890]\[u2891]\[u2892]\[u2893]\[u2894]\[u2895]\[u2896]\[u2897]\[u2898]\[u2899]\[u289A]\[u289B]\[u289C]\[u289D]\[u289E]\[u289F]\[u28A0]\[u28A1]\[u28A2]\[u28A3]\[u28A4]\[u28A5]\[u28A6]\[u28A7]\[u28A8]\[u28A9]\[u28AA]\[u28AB]\[u28AC]\[u28AD]\[u28AE]\[u28AF]\[u28B0]\[u28B1]\[u28B2]\[u28B3]\[u28B4]\[u28B5]\[u28B6]\[u28B7]\[u28B8]\[u28B9]\[u28BA]\[u28BB]\[u28BC]\[u28BD]\[u28BE]\[u28BF]\[u28C0]\[u28C1]\[u28C2]\[u28C3]\[u28C4]\[u28C5]\[u28C6]\[u28C7]\[u28C8]\[u28C9]\[u28CA]\[u28CB]\[u28CC]\[u28CD]\[u28CE]\[u28CF]\[u28D0]\[u28D1]\[u28D2]\[u28D3]\[u28D4]\[u28D5]\[u28D6]\[u28D7]\[u28D8]\[u28D9]\[u28DA]\[u28DB]\[u28DC]\[u28DD]\[u28DE]\[u28DF]\[u28E0]\[u28E1]\[u28E2]\[u28E3]\[u28E4]\[u28E5]\[u28E6]\[u28E7]\[u28E8]\[u28E9]\[u28EA]\[u28EB]\[u28EC]\[u28ED]\[u28EE]\[u28EF]\[u28F0]\[u28F1]\[u28F2]\[u28F3]\[u28F4]\[u28F5]\[u28F6]\[u28F7]\[u28F8]\[u28F9]\[u28FA]\[u28FB]\[u28FC]\[u28FD]\[u28FE]\[u28FF]"
1367
1379
  charset to render 2x4 blocks on canvas
1368
- .It Sy "disp_pixel_random " No "False"
1380
+ .It Sy "disp_graph_pixel_random" No "False"
1369
1381
  randomly choose attr from set of pixels instead of most common
1370
1382
  .It Sy "disp_zoom_incr " No "2.0"
1371
1383
  amount to multiply current zoomlevel when zooming
@@ -1385,8 +1397,17 @@ charset to render vertical reference lines on graph
1385
1397
  charset to render horizontal reference lines on graph
1386
1398
  .It Sy "disp_graph_multiple_reflines_char" No "\[u2592]"
1387
1399
  char to render multiple parallel reflines
1388
- .It Sy "disp_expert " No "0"
1389
- max level of options and columns to include
1400
+ .It Sy "disp_help_flags " No "cmdpalette guides help hints inputfield inputkeys nometacols sidebar"
1401
+ list of helper features to enable (space-separated):
1402
+ - "cmdpalette": exec-longname suggestions
1403
+ - "guides": guides in sidebar
1404
+ - "help": help sidebar collapsed by default
1405
+ - "hints": context-sensitive hints on menu line
1406
+ - "inputfield": context-sensitive help for each input field
1407
+ - "inputkeys": input quick reference in sidebar
1408
+ - "nometacols": hide expert columns on metasheets
1409
+ - "sidebar": context-sensitive sheet help in sidebar
1410
+ - "all": enable all helper features
1390
1411
  .It Sy "color_add_pending " No "green"
1391
1412
  color for rows pending add
1392
1413
  .It Sy "color_change_pending" No "reverse yellow"