visidata 3.1__py3-none-any.whl → 3.2__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 +70 -36
  3. visidata/_open.py +9 -6
  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 -1
  8. visidata/canvas.py +11 -7
  9. visidata/clipboard.py +11 -2
  10. visidata/cliptext.py +65 -23
  11. visidata/cmdlog.py +5 -1
  12. visidata/column.py +6 -2
  13. visidata/ddwplay.py +2 -2
  14. visidata/deprecated.py +91 -63
  15. visidata/errors.py +41 -5
  16. visidata/{features → experimental}/helloworld.py +1 -1
  17. visidata/expr.py +1 -0
  18. visidata/extensible.py +4 -0
  19. visidata/features/cmdpalette.py +3 -3
  20. visidata/features/describe.py +2 -2
  21. visidata/features/expand_cols.py +8 -5
  22. visidata/features/freeze.py +14 -2
  23. visidata/features/go_col.py +2 -1
  24. visidata/features/graph_zoom_y.py +47 -0
  25. visidata/features/incr.py +7 -3
  26. visidata/features/join.py +23 -12
  27. visidata/features/layout.py +8 -3
  28. visidata/features/melt.py +1 -0
  29. visidata/features/rank.py +103 -0
  30. visidata/features/reload_every.py +9 -6
  31. visidata/features/sysedit.py +14 -4
  32. visidata/features/transpose.py +1 -0
  33. visidata/features/window.py +12 -0
  34. visidata/form.py +4 -4
  35. visidata/freqtbl.py +47 -3
  36. visidata/fuzzymatch.py +8 -5
  37. visidata/graph.py +5 -3
  38. visidata/guides/AggregatorsSheet.md +84 -0
  39. visidata/guides/MacrosSheet.md +1 -1
  40. visidata/guides/RankGuide.md +51 -0
  41. visidata/guides/TypesSheet.md +1 -1
  42. visidata/guides/WindowFunctionGuide.md +49 -0
  43. visidata/help.py +3 -4
  44. visidata/indexsheet.py +1 -1
  45. visidata/loaders/_pandas.py +3 -1
  46. visidata/loaders/archive.py +6 -3
  47. visidata/loaders/csv.py +5 -1
  48. visidata/loaders/eml.py +2 -0
  49. visidata/loaders/f5log.py +2 -2
  50. visidata/loaders/fec.py +6 -9
  51. visidata/loaders/fixed_width.py +2 -0
  52. visidata/loaders/hdf5.py +34 -10
  53. visidata/loaders/npy.py +54 -23
  54. visidata/loaders/orgmode.py +3 -2
  55. visidata/loaders/pandas_freqtbl.py +4 -0
  56. visidata/loaders/psv.py +13 -0
  57. visidata/loaders/sqlite.py +1 -1
  58. visidata/loaders/vds.py +3 -4
  59. visidata/macros.py +4 -3
  60. visidata/main.py +11 -5
  61. visidata/mainloop.py +7 -4
  62. visidata/man/parse_options.py +3 -2
  63. visidata/man/vd.1 +26 -14
  64. visidata/man/vd.txt +25 -14
  65. visidata/menu.py +9 -9
  66. visidata/metasheets.py +3 -3
  67. visidata/mouse.py +1 -0
  68. visidata/pyobj.py +17 -9
  69. visidata/save.py +5 -1
  70. visidata/selection.py +29 -18
  71. visidata/settings.py +2 -2
  72. visidata/sheets.py +52 -24
  73. visidata/shell.py +2 -2
  74. visidata/sidebar.py +4 -2
  75. visidata/sort.py +89 -11
  76. visidata/statusbar.py +10 -9
  77. visidata/tests/test_cliptext.py +151 -0
  78. visidata/tests/test_commands.py +5 -2
  79. visidata/tests/test_menu.py +1 -1
  80. visidata/textsheet.py +34 -8
  81. visidata/themes/ascii8.py +2 -2
  82. visidata/themes/light.py +5 -0
  83. visidata/threads.py +16 -8
  84. visidata/undo.py +1 -1
  85. {visidata-3.1.data → visidata-3.2.data}/data/share/man/man1/vd.1 +26 -14
  86. {visidata-3.1.data → visidata-3.2.data}/data/share/man/man1/visidata.1 +26 -14
  87. {visidata-3.1.dist-info → visidata-3.2.dist-info}/METADATA +62 -15
  88. {visidata-3.1.dist-info → visidata-3.2.dist-info}/RECORD +95 -93
  89. {visidata-3.1.dist-info → visidata-3.2.dist-info}/WHEEL +1 -1
  90. {visidata-3.1.dist-info → visidata-3.2.dist-info}/entry_points.txt +1 -0
  91. visidata/features/errors_guide.py +0 -26
  92. visidata/loaders/api_bitio.py +0 -102
  93. visidata/stored_prop.py +0 -38
  94. visidata-3.1.data/scripts/vd +0 -6
  95. /visidata/{guides/SortGuide.md → vendor/__init__.py} +0 -0
  96. {visidata-3.1.data → visidata-3.2.data}/data/share/applications/visidata.desktop +0 -0
  97. {visidata-3.1.data → visidata-3.2.data}/scripts/vd2to3.vdx +0 -0
  98. {visidata-3.1.dist-info → visidata-3.2.dist-info}/LICENSE.gpl3 +0 -0
  99. {visidata-3.1.dist-info → visidata-3.2.dist-info}/top_level.txt +0 -0
@@ -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
@@ -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'
5
+ __version__ = '3.2'
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()
@@ -344,6 +344,8 @@ def main_vd():
344
344
  run(vd.sheets[0])
345
345
  else:
346
346
  if args.play == '-':
347
+ if vd.stdinSource.fptext.isatty():
348
+ vd.fail('replay commands must come by pipe, not by terminal')
347
349
  vdfile = vd.stdinSource
348
350
  else:
349
351
  vdfile = Path(args.play)
@@ -357,6 +359,7 @@ def main_vd():
357
359
  return 1
358
360
 
359
361
  if vd.options.interactive:
362
+ vd.options.batch = False #2639
360
363
  vd.execAsync = lambda *args, vd=vd, **kwargs: visidata.VisiData.execAsync(vd, *args, **kwargs)
361
364
  run()
362
365
  else:
@@ -369,7 +372,7 @@ def main_vd():
369
372
 
370
373
  saver_threads = [t for t in vd.unfinishedThreads if t.name.startswith('save_')]
371
374
  if saver_threads:
372
- vd.printout('finishing %d savers' % len(saver_threads))
375
+ vd.printerr('finishing %d savers' % len(saver_threads))
373
376
  vd.sync(*saver_threads)
374
377
 
375
378
  vd._stdout.flush()
@@ -386,9 +389,12 @@ def vd_cli():
386
389
  if vd.options.debug:
387
390
  raise
388
391
  except FileNotFoundError as e:
389
- print(e)
392
+ print(e, file=sys.stderr)
390
393
  if options.debug:
391
394
  raise
395
+ except Exception as e:
396
+ for l in stacktrace(): #show the stack trace without carets
397
+ print(l, file=sys.stderr)
392
398
 
393
399
  sys.stderr.flush()
394
400
  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
 
@@ -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
@@ -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.2"
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
visidata/man/vd.txt CHANGED
@@ -108,6 +108,8 @@ DESCRIPTION
108
108
  gz_ number adjust widths of all visible columns to Ar number
109
109
 
110
110
  - (hyphen) hide current column
111
+ g- (hyphen) hide any column that has multiple rows but only one dis‐
112
+ tinct value
111
113
  z- reduce width of current column by half
112
114
  gv unhide all columns
113
115
 
@@ -152,11 +154,12 @@ DESCRIPTION
152
154
  requires example row)
153
155
  z; expr create new column from bash expr, with $columnNames as
154
156
  variables
155
- * regex/subst add column derived from current column, replacing regex
156
- with subst (may include \1 backrefs)
157
- g* gz* regex/subst
157
+ * search Tab replace
158
+ add column derived from current column, replacing search
159
+ regex with replace (may include \1 backrefs)
160
+ g* gz* search Tab replace
158
161
  modify selected rows in current/all visible column(s),
159
- replacing regex with subst (may include \1 backrefs)
162
+ replacing search with replace (may include \1 backrefs)
160
163
 
161
164
  ( g( expand current/all visible column(s) of lists (e.g. [3])
162
165
  or dicts (e.g. {3}) one level
@@ -191,8 +194,8 @@ DESCRIPTION
191
194
  existing sort criteria
192
195
  g[ g] sort ascending/descending by all key columns; replace
193
196
  any existing sort criteria
194
- z[ z] sort ascending/descending by current column; add to ex‐
195
- isting sort criteria
197
+ z[ z] sort ascending/descending by current column; keep higher
198
+ priority sort criteria
196
199
  gz[ gz] sort ascending/descending by all key columns; add to ex‐
197
200
  isting sort criteria
198
201
  " open duplicate sheet with only selected rows
@@ -202,7 +205,8 @@ DESCRIPTION
202
205
  The rows in these duplicated sheets (except deepcopy) are references to
203
206
  rows on the original source sheets, and so edits to the filtered rows
204
207
  will naturally be reflected in the original rows. Use g' to freeze sheet
205
- contents in a deliberate copy.
208
+ contents in a deliberate copy. z' replace current column with a frozen
209
+ copy, with all cells evaluated
206
210
 
207
211
  Editing Rows and Cells
208
212
  a za append blank row/column; appended columns cannot be
@@ -232,6 +236,7 @@ DESCRIPTION
232
236
  f fill null cells in current column with contents of non-
233
237
  null cells up the current column
234
238
  e text edit contents of current cell
239
+ ^O edit contents of current cell in external EDITOR
235
240
  ge text set contents of current column for selected rows to text
236
241
 
237
242
  Commands While Editing Input
@@ -292,6 +297,7 @@ DESCRIPTION
292
297
  + - increase/decrease zoom level, centered on cursor
293
298
  _ (underbar) zoom to fit full extent
294
299
  z_ (underbar) set aspect ratio
300
+ g_ (underbar) Zoom y-axis to fit all visible data points
295
301
  x xmin xmax set xmin/xmax on graph
296
302
  y ymin ymax set ymin/ymax on graph
297
303
  s t u select/toggle/unselect rows on source sheet con‐
@@ -582,7 +588,8 @@ COMMANDLINE OPTIONS
582
588
  files
583
589
  -N, --nothing=T False disable loading
584
590
  .visidatarc and plugin addons
585
- --visidata-dir=str ~/.visidata/ directory to load and
591
+ --visidata-dir=str /home/anja/.config/visidata
592
+ directory to load and
586
593
  store additional files
587
594
  --debug False exit on error and display
588
595
  stacktrace
@@ -739,7 +746,7 @@ COMMANDLINE OPTIONS
739
746
  --reddit-client-id=str client_id for reddit api
740
747
  --reddit-client-secret=str client_secret for reddit
741
748
  api
742
- --reddit-user-agent=str 3.1dev user_agent for reddit api
749
+ --reddit-user-agent=str 3.2 user_agent for reddit api
743
750
  --zulip-batch-size=int -100 number of messages to
744
751
  fetch per call (<0 to
745
752
  fetch before anchor)
@@ -799,6 +806,8 @@ COMMANDLINE OPTIONS
799
806
  --grep-base-dir=NoneType None base directory for rela‐
800
807
  tive paths opened with
801
808
  sysopen-row
809
+ --hdf5-matrix-enumerate False enumerate matrix rows and
810
+ columns
802
811
  --html-title=str <h2>{sheet.name}</h2>
803
812
  table header when saving
804
813
  to html
@@ -810,6 +819,8 @@ COMMANDLINE OPTIONS
810
819
  cates for https
811
820
  --npy-allow-pickle False numpy allow unpickling
812
821
  objects (unsafe)
822
+ --npy-matrix-enumerate False enumerate matrix rows and
823
+ columns
813
824
  --pcap-internet=str n (y/s/n) if save_dot in‐
814
825
  cludes all internet hosts
815
826
  separately (y), combined
@@ -851,8 +862,6 @@ COMMANDLINE OPTIONS
851
862
  --describe-aggrs=str mean stdev numeric aggregators to
852
863
  calculate on Describe
853
864
  sheet
854
- --hello-world=str ¡Hola mundo! shown by the hello-world
855
- command
856
865
  --incr-base=float 1.0 start value for column
857
866
  increments
858
867
  --ping-count=int 3 send this many pings to
@@ -897,7 +906,7 @@ COMMANDLINE OPTIONS
897
906
  onto sheet stack
898
907
  disp_menu_input … indicator if input required for
899
908
  command
900
- disp_menu_fmt | VisiData {vd.version} | {vd.hintStatus}
909
+ disp_menu_fmt | VisiData {vd.version} | {vd.motd}
901
910
  right-side menu format string
902
911
  disp_float_fmt {:.02f} default fmtstr to format float
903
912
  values
@@ -984,6 +993,8 @@ COMMANDLINE OPTIONS
984
993
  disp_wrap_placeholder … multiline string to indicate
985
994
  truncation
986
995
  disp_multiline_focus True only multiline cursor row
996
+ color_multiline_bottom color of bottom line of multiline
997
+ rows
987
998
  color_aggregator bold 255 white on 234 black
988
999
  color of aggregator summary on
989
1000
  bottom row
@@ -1033,7 +1044,7 @@ COMMANDLINE OPTIONS
1033
1044
  ⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿
1034
1045
  charset to render 2x4 blocks on
1035
1046
  canvas
1036
- disp_pixel_random False randomly choose attr from set of
1047
+ disp_graph_pixel_random False randomly choose attr from set of
1037
1048
  pixels instead of most common
1038
1049
  disp_zoom_incr 2.0 amount to multiply current zoom‐
1039
1050
  level when zooming
@@ -1189,4 +1200,4 @@ SUPPORTED SOURCES
1189
1200
  AUTHOR
1190
1201
  VisiData was made by Saul Pwanson <vd@saul.pw>.
1191
1202
 
1192
- Linux/MacOS October 13, 2024 Linux/MacOS
1203
+ Linux/MacOS June 13, 2025 Linux/MacOS
visidata/menu.py CHANGED
@@ -18,7 +18,7 @@ vd.theme_option('disp_menu_boxchars', '││──┌┐└┘├┤', 'box cha
18
18
  vd.theme_option('disp_menu_more', '»', 'command submenu indicator')
19
19
  vd.theme_option('disp_menu_push', '⎘', 'indicator if command pushes sheet onto sheet stack')
20
20
  vd.theme_option('disp_menu_input', '…', 'indicator if input required for command')
21
- vd.option('disp_menu_fmt', '| VisiData {vd.version} | {vd.hintStatus}', 'right-side menu format string')
21
+ vd.option('disp_menu_fmt', '| VisiData {vd.version} | {vd.motd}', 'right-side menu format string')
22
22
 
23
23
  BaseSheet.init('activeMenuItems', list)
24
24
  vd.menuRunning = False
@@ -178,9 +178,9 @@ def drawSubmenu(vd, scr, sheet, y, x, menus, level, disp_menu_boxchars=''):
178
178
 
179
179
  maxbinding = 0
180
180
  if vd.options.disp_menu_keys:
181
- maxbinding = max(len(item.binding or '') for item in menus)+1
181
+ maxbinding = max(dispwidth(item.binding or '') for item in menus)+1
182
182
 
183
- w = max(len(item.title) for item in menus)+maxbinding+2
183
+ w = max(dispwidth(item.title) for item in menus)+maxbinding+2
184
184
 
185
185
  # draw borders before/under submenus
186
186
  if level > 1:
@@ -225,11 +225,11 @@ def drawSubmenu(vd, scr, sheet, y, x, menus, level, disp_menu_boxchars=''):
225
225
  mainbinding = vd.prettykeys(revbinds[0])
226
226
 
227
227
  # actually display the menu item
228
- title += ' '*(w-len(pretitle)-len(item.title)+1) # padding
228
+ title += ' '*(w-dispwidth(pretitle)-dispwidth(item.title)+1) # padding
229
229
 
230
230
  menudraw(scr, y+i, x+1, pretitle+title, attr)
231
231
  if maxbinding and mainbinding:
232
- menudraw(scr, y+i, x+1+w-len(mainbinding), mainbinding, attr.update(colors.keystrokes))
232
+ menudraw(scr, y+i, x+1+w-dispwidth(mainbinding), mainbinding, attr.update(colors.keystrokes))
233
233
  menudraw(scr, y+i, x+2+w, titlenote, attr)
234
234
  menudraw(scr, y+i, x+3+w, ls, colors.color_menu)
235
235
 
@@ -317,7 +317,7 @@ def drawMenu(vd, scr, sheet):
317
317
  BUTTON1_RELEASED=vd.nop,
318
318
  BUTTON2_RELEASED=vd.nop,
319
319
  BUTTON3_RELEASED=vd.nop)
320
- x += len(item.title)+2
320
+ x += dispwidth(item.title)+2
321
321
 
322
322
  rightdisp = sheet.options.disp_menu_fmt.format(sheet=sheet, vd=vd)
323
323
  menudraw(scr, 0, x+4, rightdisp, colors.color_menu)
@@ -355,13 +355,13 @@ def drawMenu(vd, scr, sheet):
355
355
 
356
356
  # cmd.helpstr text
357
357
  for i, line in enumerate(helplines):
358
- menudraw(scr, y+i, helpx, ls+' '+line+' '*(helpw-len(line)-3)+rs, helpattr)
358
+ menudraw(scr, y+i, helpx, ls+' '+line+' '*(helpw-dispwidth(line)-3)+rs, helpattr)
359
359
  y += len(helplines)
360
360
 
361
361
  if sidelines:
362
362
  menudraw(scr, y, helpx, ls+' '*(helpw-2)+rs, helpattr)
363
363
  for i, line in enumerate(sidelines):
364
- menudraw(scr, y+i+1, helpx, ls+' '+line+' '*(helpw-len(line)-6)+rs, helpattr)
364
+ menudraw(scr, y+i+1, helpx, ls+' '+line+' '*(helpw-dispwidth(line)-6)+rs, helpattr)
365
365
  y += len(sidelines)+1
366
366
 
367
367
  menudraw(scr, y, helpx, bl+bs*(helpw-2)+br, helpattr)
@@ -371,7 +371,7 @@ def drawMenu(vd, scr, sheet):
371
371
  menudraw(scr, menuy, helpx+2, rsl, helpattr)
372
372
  ks = vd.prettykeys(mainbinding or '(unbound)')
373
373
  menudraw(scr, menuy, helpx+3, ' '+ks+' ', colors.color_menu_active)
374
- menudraw(scr, menuy, helpx+2+len(ks)+3, lsr, helpattr)
374
+ menudraw(scr, menuy, helpx+2+dispwidth(ks)+3, lsr, helpattr)
375
375
  menudraw(scr, menuy, helpx+19, ' '+cmd.longname+' ', helpattr)
376
376
 
377
377
  vd.onMouse(scr, helpx, menuy, helpw, y-menuy+1,
visidata/metasheets.py CHANGED
@@ -38,8 +38,8 @@ Other commands (not specific to Columns Sheet):
38
38
  'passthrough to the value on the source cursorRow'
39
39
  def calcValue(self, srcCol):
40
40
  return srcCol.getDisplayValue(srcCol.sheet.cursorRow)
41
- def setValue(self, srcCol, val):
42
- srcCol.setValue(srcCol.sheet.cursorRow, val)
41
+ def setValue(self, srcCol, val, setModified=True):
42
+ srcCol.setValue(srcCol.sheet.cursorRow, val, setModified=setModified)
43
43
 
44
44
  columns = [
45
45
  ColumnAttr('sheet', type=str),
@@ -134,7 +134,7 @@ globalCommand('gC', 'columns-all', 'vd.push(vd.allColumnsSheet)', 'open Columns
134
134
  Sheet.addCommand('C', 'columns-sheet', 'vd.push(ColumnsSheet(name+"_columns", source=[sheet]))', 'open Columns Sheet: edit column properties for current sheet')
135
135
 
136
136
  # used ColumnsSheet, affecting the 'row' (source column)
137
- ColumnsSheet.addCommand('g!', 'key-selected', 'for c in onlySelectedRows: c.sheet.setKeys([c])', 'toggle selected source columns as key columns')
137
+ ColumnsSheet.addCommand('g!', 'key-selected', 'for c in onlySelectedRows: c.sheet.setKeys([c])', 'set selected source columns as key columns')
138
138
  ColumnsSheet.addCommand('gz!', 'key-off-selected', 'for c in onlySelectedRows: c.sheet.unsetKeys([c])', 'unset selected source columns as key columns')
139
139
 
140
140
  ColumnsSheet.addCommand('g-', 'hide-selected', 'onlySelectedRows.hide()', 'hide selected source columns')
visidata/mouse.py CHANGED
@@ -15,6 +15,7 @@ BaseSheet.init('mouseY', int)
15
15
  def initCurses(vd):
16
16
  curses.MOUSE_ALL = 0xffffffff
17
17
  curses.mousemask(curses.MOUSE_ALL if vd.options.mouse_interval else 0)
18
+ curses.def_prog_mode()
18
19
  curses.mouseinterval(vd.options.mouse_interval)
19
20
  curses.mouseEvents = {}
20
21
 
visidata/pyobj.py CHANGED
@@ -3,7 +3,7 @@ import inspect
3
3
  import math
4
4
  import numbers
5
5
 
6
- from visidata import vd, asyncthread, ENTER, deduceType
6
+ from visidata import vd, asyncthread, ENTER, deduceType, anytype
7
7
  from visidata import Sheet, Column, VisiData, ColumnItem, TableSheet, BaseSheet, Progress, ColumnAttr, SuspendCurses, TextSheet, setitem
8
8
  import visidata
9
9
 
@@ -46,14 +46,19 @@ def view(vd, obj):
46
46
  vd.run(PyobjSheet(getattr(obj, '__name__', ''), source=obj))
47
47
 
48
48
 
49
-
50
- def getPublicAttrs(obj):
51
- 'Return all public attributes (not methods or `_`-prefixed) on object.'
52
- return [k for k in dir(obj) if not k.startswith('_') and not callable(getattr(obj, k))]
53
-
54
49
  def PyobjColumns(obj):
55
50
  'Return columns for each public attribute on an object.'
56
- return [ColumnAttr(k, type=deduceType(getattr(obj, k))) for k in getPublicAttrs(obj)]
51
+ cols = []
52
+ for k in dir(obj):
53
+ coltype = anytype
54
+ try:
55
+ if k.startswith('_') or callable(getattr(obj, k)):
56
+ continue
57
+ coltype = deduceType(getattr(obj, k))
58
+ except AttributeError: #2631 attributes like formatted_help can raise AttributeError
59
+ pass
60
+ cols.append(ColumnAttr(k, type=coltype))
61
+ return cols
57
62
 
58
63
  def AttrColumns(attrnames):
59
64
  'Return column names for all elements of list `attrnames`.'
@@ -151,8 +156,11 @@ class ColumnSourceAttr(Column):
151
156
  'Use row as attribute name on sheet source'
152
157
  def calcValue(self, attrname):
153
158
  return getattr(self.sheet.source, attrname)
154
- def setValue(self, attrname, value):
155
- return setattr(self.sheet.source, attrname, value)
159
+ def setValue(self, attrname, value, setModified=True):
160
+ ret = setattr(self.sheet.source, attrname, value)
161
+ if setModified:
162
+ self.sheet.setModified()
163
+ return ret
156
164
 
157
165
  def docstring(obj, attr):
158
166
  v = getattr(obj, attr)
visidata/save.py CHANGED
@@ -114,6 +114,10 @@ def saveSheets(vd, givenpath, *vsheets, confirm_overwrite=True):
114
114
  if not vsheets: # blank tuple
115
115
  vd.warning('no sheets to save')
116
116
  return
117
+ if not givenpath.name:
118
+ vd.warning('no save path given')
119
+ return
120
+
117
121
  unloaded = [ vs for vs in vsheets if vs.rows is UNLOADED ]
118
122
  vd.sync(*vd.ensureLoaded(unloaded))
119
123
 
@@ -128,7 +132,7 @@ def saveSheets(vd, givenpath, *vsheets, confirm_overwrite=True):
128
132
  break
129
133
 
130
134
  if savefunc is None:
131
- vd.fail(f'no function to save as {filetype}')
135
+ vd.fail(f'no function to save as {", ".join(filetypes)}')
132
136
 
133
137
  if confirm_overwrite:
134
138
  vd.confirmOverwrite(givenpath)