visidata 2.11.1__py3-none-any.whl → 3.0.1__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.
- visidata/__init__.py +72 -91
- visidata/_input.py +259 -42
- visidata/_open.py +84 -29
- visidata/_types.py +21 -3
- visidata/_urlcache.py +17 -4
- visidata/aggregators.py +78 -25
- visidata/apps/__init__.py +0 -0
- visidata/apps/vdsql/__about__.py +8 -0
- visidata/apps/vdsql/__init__.py +5 -0
- visidata/apps/vdsql/__main__.py +27 -0
- visidata/apps/vdsql/_ibis.py +748 -0
- visidata/apps/vdsql/bigquery.py +61 -0
- visidata/apps/vdsql/clickhouse.py +53 -0
- visidata/apps/vdsql/setup.py +40 -0
- visidata/apps/vdsql/snowflake.py +67 -0
- visidata/apps/vgit/__init__.py +13 -0
- {vgit → visidata/apps/vgit}/blame.py +5 -2
- {vgit → visidata/apps/vgit}/branch.py +31 -16
- {vgit → visidata/apps/vgit}/config.py +3 -3
- visidata/apps/vgit/diff.py +169 -0
- visidata/apps/vgit/gitsheet.py +161 -0
- {vgit → visidata/apps/vgit}/grep.py +6 -5
- visidata/apps/vgit/log.py +81 -0
- {vgit → visidata/apps/vgit}/main.py +18 -5
- {vgit → visidata/apps/vgit}/remote.py +8 -4
- visidata/apps/vgit/repos.py +71 -0
- {vgit → visidata/apps/vgit}/setup.py +6 -4
- visidata/apps/vgit/stash.py +69 -0
- visidata/apps/vgit/status.py +204 -0
- {vgit → visidata/apps/vgit}/statusbar.py +2 -0
- visidata/basesheet.py +63 -51
- visidata/canvas.py +208 -93
- visidata/choose.py +6 -6
- visidata/clean_names.py +29 -0
- visidata/clipboard.py +73 -17
- visidata/cliptext.py +220 -46
- visidata/cmdlog.py +88 -114
- visidata/color.py +142 -56
- visidata/column.py +121 -129
- visidata/ddw/input.ddw +74 -79
- visidata/ddw/regex.ddw +57 -0
- visidata/ddwplay.py +33 -14
- visidata/deprecated.py +77 -3
- visidata/desktop/visidata.desktop +7 -0
- visidata/editor.py +12 -6
- visidata/errors.py +6 -2
- visidata/experimental/__init__.py +0 -0
- visidata/experimental/diff_sheet.py +29 -0
- visidata/experimental/digit_autoedit.py +6 -0
- visidata/experimental/gdrive.py +89 -0
- visidata/experimental/google.py +37 -0
- visidata/experimental/gsheets.py +79 -0
- visidata/experimental/live_search.py +37 -0
- visidata/experimental/liveupdate.py +45 -0
- visidata/experimental/mark.py +133 -0
- visidata/experimental/noahs_tapestry/__init__.py +1 -0
- visidata/experimental/noahs_tapestry/tapestry.py +147 -0
- visidata/experimental/rownum.py +73 -0
- visidata/experimental/slide_cells.py +26 -0
- visidata/expr.py +8 -4
- visidata/extensible.py +22 -4
- visidata/features/__init__.py +0 -0
- visidata/features/addcol_audiometadata.py +42 -0
- visidata/features/addcol_histogram.py +34 -0
- visidata/features/canvas_save_svg.py +69 -0
- visidata/features/change_precision.py +46 -0
- visidata/features/cmdpalette.py +197 -0
- visidata/features/colorbrewer.py +363 -0
- visidata/{colorsheet.py → features/colorsheet.py} +17 -16
- visidata/features/command_server.py +105 -0
- visidata/features/currency_to_usd.py +70 -0
- visidata/{customdate.py → features/customdate.py} +2 -0
- visidata/features/dedupe.py +132 -0
- visidata/{describe.py → features/describe.py} +17 -15
- visidata/features/errors_guide.py +26 -0
- visidata/features/expand_cols.py +202 -0
- visidata/{fill.py → features/fill.py} +3 -1
- visidata/{freeze.py → features/freeze.py} +11 -6
- visidata/features/graph_seaborn.py +79 -0
- visidata/features/helloworld.py +10 -0
- visidata/features/hint_types.py +17 -0
- visidata/{incr.py → features/incr.py} +5 -0
- visidata/{join.py → features/join.py} +107 -53
- visidata/features/known_cols.py +21 -0
- visidata/features/layout.py +62 -0
- visidata/{melt.py → features/melt.py} +32 -21
- visidata/features/normcol.py +118 -0
- visidata/features/open_config.py +7 -0
- visidata/features/open_syspaste.py +18 -0
- visidata/features/ping.py +157 -0
- visidata/features/procmgr.py +208 -0
- visidata/features/random_sample.py +6 -0
- visidata/{regex.py → features/regex.py} +47 -31
- visidata/features/reload_every.py +55 -0
- visidata/features/rename_col_cascade.py +30 -0
- visidata/features/scroll_context.py +60 -0
- visidata/features/select_equal_selected.py +11 -0
- visidata/features/setcol_fake.py +65 -0
- visidata/{slide.py → features/slide.py} +77 -21
- visidata/features/sparkline.py +48 -0
- visidata/features/status_source.py +20 -0
- visidata/{sysedit.py → features/sysedit.py} +2 -1
- visidata/features/sysopen_mailcap.py +46 -0
- visidata/features/term_extras.py +13 -0
- visidata/{transpose.py → features/transpose.py} +5 -4
- visidata/features/type_ipaddr.py +73 -0
- visidata/features/type_url.py +11 -0
- visidata/{unfurl.py → features/unfurl.py} +9 -9
- visidata/{window.py → features/window.py} +2 -2
- visidata/form.py +50 -21
- visidata/freqtbl.py +81 -33
- visidata/fuzzymatch.py +414 -0
- visidata/graph.py +105 -33
- visidata/guide.py +200 -0
- visidata/help.py +75 -44
- visidata/hint.py +39 -0
- visidata/indexsheet.py +109 -0
- visidata/input_history.py +55 -0
- visidata/interface.py +58 -0
- visidata/keys.py +20 -16
- visidata/loaders/__init__.py +9 -0
- visidata/loaders/_pandas.py +61 -21
- visidata/loaders/api_airtable.py +70 -0
- visidata/loaders/api_bitio.py +102 -0
- visidata/loaders/api_matrix.py +148 -0
- visidata/loaders/api_reddit.py +306 -0
- visidata/loaders/api_zulip.py +249 -0
- visidata/loaders/archive.py +41 -7
- visidata/loaders/arrow.py +7 -7
- visidata/loaders/conll.py +49 -0
- visidata/loaders/csv.py +25 -7
- visidata/loaders/eml.py +3 -4
- visidata/loaders/f5log.py +1204 -0
- visidata/loaders/fec.py +325 -0
- visidata/loaders/fixed_width.py +2 -4
- visidata/loaders/frictionless.py +3 -3
- visidata/loaders/geojson.py +8 -5
- visidata/loaders/google.py +48 -0
- visidata/loaders/graphviz.py +4 -4
- visidata/loaders/hdf5.py +4 -4
- visidata/loaders/html.py +54 -12
- visidata/loaders/http.py +84 -30
- visidata/loaders/imap.py +20 -10
- visidata/loaders/jrnl.py +52 -0
- visidata/loaders/json.py +83 -29
- visidata/loaders/jsonla.py +74 -0
- visidata/loaders/lsv.py +15 -11
- visidata/loaders/mailbox.py +40 -0
- visidata/loaders/markdown.py +1 -3
- visidata/loaders/mbtiles.py +4 -5
- visidata/loaders/mysql.py +11 -13
- visidata/loaders/npy.py +7 -7
- visidata/loaders/odf.py +4 -1
- visidata/loaders/orgmode.py +428 -0
- visidata/loaders/pandas_freqtbl.py +14 -20
- visidata/loaders/parquet.py +62 -6
- visidata/loaders/pcap.py +3 -3
- visidata/loaders/pdf.py +4 -3
- visidata/loaders/png.py +19 -13
- visidata/loaders/postgres.py +9 -8
- visidata/loaders/rec.py +7 -3
- visidata/loaders/s3.py +342 -0
- visidata/loaders/sas.py +5 -5
- visidata/loaders/scrape.py +186 -0
- visidata/loaders/shp.py +6 -5
- visidata/loaders/spss.py +5 -6
- visidata/loaders/sqlite.py +68 -28
- visidata/loaders/texttables.py +1 -1
- visidata/loaders/toml.py +60 -0
- visidata/loaders/tsv.py +61 -19
- visidata/loaders/ttf.py +19 -7
- visidata/loaders/unzip_http.py +6 -5
- visidata/loaders/usv.py +1 -1
- visidata/loaders/vcf.py +16 -16
- visidata/loaders/vds.py +10 -7
- visidata/loaders/vdx.py +30 -5
- visidata/loaders/xlsb.py +8 -1
- visidata/loaders/xlsx.py +145 -25
- visidata/loaders/xml.py +6 -3
- visidata/loaders/xword.py +4 -4
- visidata/loaders/yaml.py +15 -5
- visidata/macros.py +129 -42
- visidata/main.py +119 -94
- visidata/mainloop.py +101 -155
- visidata/man/parse_options.py +2 -2
- visidata/man/vd.1 +302 -149
- visidata/man/vd.txt +291 -154
- visidata/memory.py +3 -3
- visidata/menu.py +104 -423
- visidata/metasheets.py +59 -141
- visidata/modify.py +78 -23
- visidata/motd.py +3 -3
- visidata/mouse.py +137 -0
- visidata/movement.py +43 -35
- visidata/optionssheet.py +99 -0
- visidata/path.py +113 -32
- visidata/pivot.py +73 -47
- visidata/plugins.py +65 -192
- visidata/pyobj.py +55 -205
- visidata/rename_col.py +20 -0
- visidata/save.py +37 -20
- visidata/search.py +54 -10
- visidata/selection.py +84 -5
- visidata/settings.py +162 -25
- visidata/sheets.py +239 -260
- visidata/shell.py +51 -21
- visidata/sidebar.py +162 -0
- visidata/sort.py +11 -4
- visidata/statusbar.py +114 -104
- visidata/stored_list.py +43 -0
- visidata/stored_prop.py +38 -0
- visidata/tests/benchmark.csv +52 -0
- visidata/tests/conftest.py +3 -3
- visidata/tests/test_cliptext.py +39 -0
- visidata/tests/test_commands.py +65 -7
- visidata/tests/test_edittext.py +2 -2
- visidata/tests/test_features.py +28 -0
- visidata/tests/test_menu.py +14 -0
- visidata/tests/test_path.py +13 -4
- visidata/text_source.py +53 -0
- visidata/textsheet.py +10 -3
- visidata/theme.py +44 -0
- visidata/themes/__init__.py +0 -0
- visidata/themes/ascii8.py +84 -0
- visidata/themes/asciimono.py +84 -0
- visidata/themes/light.py +17 -0
- visidata/threads.py +89 -40
- visidata/tuiwin.py +22 -0
- visidata/type_currency.py +22 -3
- visidata/type_date.py +31 -9
- visidata/type_floatsi.py +5 -1
- visidata/undo.py +17 -5
- visidata/utils.py +106 -23
- visidata/vdobj.py +28 -17
- visidata/windows.py +10 -0
- visidata/wrappers.py +9 -3
- visidata-3.0.1.data/data/share/applications/visidata.desktop +7 -0
- {visidata-2.11.1.data → visidata-3.0.1.data}/data/share/man/man1/vd.1 +302 -149
- {visidata-2.11.1.data → visidata-3.0.1.data}/data/share/man/man1/visidata.1 +302 -149
- visidata-3.0.1.data/scripts/vd2to3.vdx +9 -0
- {visidata-2.11.1.dist-info → visidata-3.0.1.dist-info}/METADATA +12 -8
- visidata-3.0.1.dist-info/RECORD +258 -0
- {visidata-2.11.1.dist-info → visidata-3.0.1.dist-info}/WHEEL +1 -1
- vgit/__init__.py +0 -1
- vgit/gitsheet.py +0 -164
- visidata/layout.py +0 -44
- visidata/misc.py +0 -5
- visidata-2.11.1.data/scripts/vgit +0 -9
- visidata-2.11.1.dist-info/RECORD +0 -155
- {vgit → visidata/apps/vgit}/__main__.py +0 -0
- {vgit → visidata/apps/vgit}/abort.py +0 -0
- /visidata/{repeat.py → features/repeat.py} +0 -0
- {visidata-2.11.1.data → visidata-3.0.1.data}/scripts/vd +0 -0
- {visidata-2.11.1.dist-info → visidata-3.0.1.dist-info}/LICENSE.gpl3 +0 -0
- {visidata-2.11.1.dist-info → visidata-3.0.1.dist-info}/entry_points.txt +0 -0
- {visidata-2.11.1.dist-info → visidata-3.0.1.dist-info}/top_level.txt +0 -0
visidata/column.py
CHANGED
@@ -7,10 +7,11 @@ import re
|
|
7
7
|
import time
|
8
8
|
import json
|
9
9
|
|
10
|
-
from visidata import options, anytype, stacktrace, vd
|
10
|
+
from visidata import options, anytype, stacktrace, vd, drawcache
|
11
11
|
from visidata import asyncthread, dispwidth, clipstr, iterchars
|
12
12
|
from visidata import wrapply, TypedWrapper, TypedExceptionWrapper
|
13
|
-
from visidata import Extensible, AttrDict, undoAttrFunc
|
13
|
+
from visidata import Extensible, AttrDict, undoAttrFunc, ExplodingMock, MissingAttrFormatter
|
14
|
+
from visidata import getitem, setitem, getitemdef, getitemdeep, setitemdeep, getattrdeep, setattrdeep, iterchunks
|
14
15
|
|
15
16
|
class InProgress(Exception):
|
16
17
|
@property
|
@@ -19,31 +20,16 @@ class InProgress(Exception):
|
|
19
20
|
|
20
21
|
INPROGRESS = TypedExceptionWrapper(None, exception=InProgress()) # sentinel
|
21
22
|
|
22
|
-
vd.option('col_cache_size', 0, 'max number of cache entries in each cached column')
|
23
|
-
vd.option('
|
24
|
-
|
25
|
-
__all__ = [
|
26
|
-
'clean_to_id',
|
27
|
-
'Column',
|
28
|
-
'setitem',
|
29
|
-
'getattrdeep',
|
30
|
-
'setattrdeep',
|
31
|
-
'getitemdef',
|
32
|
-
'ColumnAttr', 'AttrColumn',
|
33
|
-
'ColumnItem', 'ItemColumn',
|
34
|
-
'SettableColumn',
|
35
|
-
'SubColumnFunc',
|
36
|
-
'SubColumnItem',
|
37
|
-
'SubColumnAttr',
|
38
|
-
'ColumnExpr', 'ExprColumn',
|
39
|
-
'DisplayWrapper',
|
40
|
-
]
|
23
|
+
vd.option('col_cache_size', 0, 'max number of cache entries in each cached column', max_help=-1)
|
24
|
+
vd.option('disp_formatter', 'generic', 'formatter to create the text in each cell (also used by text savers)', replay=True, max_help=0)
|
25
|
+
vd.option('disp_displayer', 'generic', 'displayer to render the text in each cell', replay=False, max_help=0)
|
41
26
|
|
42
27
|
|
43
28
|
class DisplayWrapper:
|
44
|
-
def __init__(self, value=None, *,
|
29
|
+
def __init__(self, value=None, *, typedval=None, text=None, note=None, notecolor=None, error=None):
|
45
30
|
self.value = value # actual value (any type)
|
46
|
-
self.
|
31
|
+
self.typedval = typedval # consistently typed value (or None)
|
32
|
+
self.text = text # displayed string
|
47
33
|
self.note = note # single unicode character displayed in cell far right
|
48
34
|
self.notecolor = notecolor # configurable color name (like 'color_warning')
|
49
35
|
self.error = error # list of strings for stacktrace
|
@@ -54,11 +40,6 @@ class DisplayWrapper:
|
|
54
40
|
def __eq__(self, other):
|
55
41
|
return self.value == other
|
56
42
|
|
57
|
-
|
58
|
-
def clean_to_id(s): # [Nas Banov] https://stackoverflow.com/a/3305731
|
59
|
-
return re.sub(r'\W|^(?=\d)', '_', str(s)).strip('_')
|
60
|
-
|
61
|
-
|
62
43
|
def _default_colnames():
|
63
44
|
'A B C .. Z AA AB .. ZZ AAA .. to infinity'
|
64
45
|
i=0
|
@@ -88,14 +69,14 @@ class Column(Extensible):
|
|
88
69
|
- *kwargs*: other attributes to be set on this column.
|
89
70
|
'''
|
90
71
|
def __init__(self, name=None, *, type=anytype, cache=False, **kwargs):
|
91
|
-
self.sheet =
|
72
|
+
self.sheet = ExplodingMock('use addColumn() on all columns') # owning Sheet, set in .recalc() via Sheet.addColumn
|
92
73
|
if name is None:
|
93
74
|
name = next(default_colnames)
|
94
75
|
self.name = str(name) # display visible name
|
95
76
|
self.fmtstr = '' # by default, use str()
|
96
77
|
self._type = type # anytype/str/int/float/date/func
|
97
78
|
self.getter = lambda col, row: row
|
98
|
-
self.setter =
|
79
|
+
self.setter = None
|
99
80
|
self._width = None # == 0 if hidden, None if auto-compute next time
|
100
81
|
self.hoffset = 0 # starting horizontal (char) offset of displayed column value
|
101
82
|
self.voffset = 0 # starting vertical (line) offset of displayed column value
|
@@ -103,7 +84,9 @@ class Column(Extensible):
|
|
103
84
|
self.keycol = 0 # keycol index (or 0 if not key column)
|
104
85
|
self.expr = None # Column-type-dependent parameter
|
105
86
|
self.formatter = ''
|
87
|
+
self.displayer = ''
|
106
88
|
self.defer = False
|
89
|
+
self.max_help = 10 # auto-hide above this disp_help level
|
107
90
|
|
108
91
|
self.setCache(cache)
|
109
92
|
for k, v in kwargs.items():
|
@@ -118,13 +101,17 @@ class Column(Extensible):
|
|
118
101
|
ret._cachedValues = collections.OrderedDict() # an unrelated cache for copied columns
|
119
102
|
return ret
|
120
103
|
|
104
|
+
def __str__(self):
|
105
|
+
return f'{type(self).__name__}:{self.name}'
|
106
|
+
|
107
|
+
def __repr__(self):
|
108
|
+
return f'<{type(self).__name__}: {self.name}>'
|
109
|
+
|
121
110
|
def __deepcopy__(self, memo):
|
122
111
|
return self.__copy__() # no separate deepcopy
|
123
112
|
|
124
113
|
def __getstate__(self):
|
125
|
-
|
126
|
-
d['type'] = self.type.__name__
|
127
|
-
return d
|
114
|
+
return {k:getattr(self, k) for k in 'name typestr width height expr keycol formatter displayer fmtstr voffset hoffset aggstr'.split() if hasattr(self, k)}
|
128
115
|
|
129
116
|
def __setstate__(self, d):
|
130
117
|
for attr, v in d.items():
|
@@ -145,6 +132,9 @@ class Column(Extensible):
|
|
145
132
|
|
146
133
|
@name.setter
|
147
134
|
def name(self, name):
|
135
|
+
self.setName(name)
|
136
|
+
|
137
|
+
def setName(self, name):
|
148
138
|
if name is None:
|
149
139
|
name = ''
|
150
140
|
if isinstance(name, str):
|
@@ -194,6 +184,20 @@ class Column(Extensible):
|
|
194
184
|
vd.addUndo(setattr, self, '_width', self.width)
|
195
185
|
self._width = w
|
196
186
|
|
187
|
+
@property
|
188
|
+
def formatted_help(self):
|
189
|
+
return MissingAttrFormatter().format(self.help, sheet=self.sheet, col=self, vd=vd)
|
190
|
+
|
191
|
+
@property
|
192
|
+
def help_formatters(self):
|
193
|
+
formatters = [k[10:] for k in dir(self) if k.startswith('formatter_')]
|
194
|
+
return ' '.join(formatters)
|
195
|
+
|
196
|
+
@property
|
197
|
+
def help_displayers(self):
|
198
|
+
displayers = [k[10:] for k in dir(self) if k.startswith('displayer_')]
|
199
|
+
return ' '.join(displayers)
|
200
|
+
|
197
201
|
@property
|
198
202
|
def _formatdict(col):
|
199
203
|
if '=' in col.fmtstr:
|
@@ -229,6 +233,7 @@ class Column(Extensible):
|
|
229
233
|
def formatter_python(self, fmtstr):
|
230
234
|
return lambda v,*args,**kwargs: str(v)
|
231
235
|
|
236
|
+
@drawcache
|
232
237
|
def make_formatter(self):
|
233
238
|
'Return function for format(v) from the current formatter and fmtstr'
|
234
239
|
_formatMaker = getattr(self, 'formatter_'+(self.formatter or self.sheet.options.disp_formatter))
|
@@ -250,7 +255,34 @@ class Column(Extensible):
|
|
250
255
|
if isinstance(typedval, bytes):
|
251
256
|
typedval = typedval.decode(options.encoding, options.encoding_errors)
|
252
257
|
|
253
|
-
|
258
|
+
gt = vd.getType(self._type)
|
259
|
+
return gt.formatter(self._fmtstr or gt.fmtstr, typedval)
|
260
|
+
|
261
|
+
def displayer_generic(self, dw:DisplayWrapper, width=None):
|
262
|
+
'''Fit *dw.text* into *width* charcells.
|
263
|
+
Generate list of (attr:str, text:str) suitable for clipdraw_chunks.
|
264
|
+
|
265
|
+
The 'generic' displayer does not do any formatting.
|
266
|
+
'''
|
267
|
+
if width is not None and width > 1 and vd.isNumeric(self):
|
268
|
+
yield ('', dw.text.rjust(width-2))
|
269
|
+
else:
|
270
|
+
yield ('', dw.text)
|
271
|
+
|
272
|
+
def displayer_full(self, dw:DisplayWrapper, width=None):
|
273
|
+
'''Fit *dw.text* into *width* charcells.
|
274
|
+
Generate list of (attr:str, text:str) suitable for clipdraw_chunks.
|
275
|
+
|
276
|
+
The 'full' displayer allows formatting like [:color].
|
277
|
+
'''
|
278
|
+
if width is not None and width > 1 and vd.isNumeric(self):
|
279
|
+
yield from iterchunks(text.rjust(width-2))
|
280
|
+
else:
|
281
|
+
yield from iterchunks(dw.text)
|
282
|
+
|
283
|
+
def display(self, *args, **kwargs):
|
284
|
+
f = getattr(self, 'displayer_'+(self.displayer or self.sheet.options.disp_displayer), self.displayer_generic)
|
285
|
+
return f(*args, **kwargs)
|
254
286
|
|
255
287
|
def hide(self, hide=True):
|
256
288
|
if hide:
|
@@ -284,7 +316,7 @@ class Column(Extensible):
|
|
284
316
|
|
285
317
|
@asyncthread
|
286
318
|
def _calcIntoCacheAsync(self, row):
|
287
|
-
# causes
|
319
|
+
# causes issues when moved into _calcIntoCache gen case
|
288
320
|
self._cachedValues[self.sheet.rowid(row)] = INPROGRESS
|
289
321
|
self._calcIntoCache(row)
|
290
322
|
|
@@ -335,34 +367,35 @@ class Column(Extensible):
|
|
335
367
|
else:
|
336
368
|
dispval = options.disp_error_val
|
337
369
|
return DisplayWrapper(cellval.val, error=exc.stacktrace,
|
338
|
-
|
370
|
+
text=dispval,
|
339
371
|
note=options.note_getter_exc,
|
340
372
|
notecolor='color_error')
|
341
373
|
elif typedval.val is None: # early out for strict None
|
342
|
-
return DisplayWrapper(None,
|
374
|
+
return DisplayWrapper(None, text='', # force empty display for None
|
343
375
|
note=options.disp_note_none,
|
344
376
|
notecolor='color_note_type')
|
345
377
|
elif isinstance(typedval, TypedExceptionWrapper): # calc succeeded, type failed
|
346
|
-
return DisplayWrapper(typedval.val,
|
378
|
+
return DisplayWrapper(typedval.val, text=str(cellval),
|
347
379
|
error=typedval.stacktrace,
|
348
380
|
note=options.note_type_exc,
|
349
381
|
notecolor='color_warning')
|
350
382
|
else:
|
351
|
-
return DisplayWrapper(typedval.val,
|
383
|
+
return DisplayWrapper(typedval.val, text=str(typedval.val),
|
352
384
|
error='unknown',
|
353
385
|
note=options.note_type_exc,
|
354
386
|
notecolor='color_warning')
|
355
387
|
|
356
388
|
elif isinstance(typedval, threading.Thread):
|
357
389
|
return DisplayWrapper(None,
|
358
|
-
|
390
|
+
text=options.disp_pending,
|
359
391
|
note=options.note_pending,
|
360
392
|
notecolor='color_note_pending')
|
361
393
|
|
362
394
|
dw = DisplayWrapper(cellval)
|
395
|
+
dw.typedval = typedval
|
363
396
|
|
364
397
|
try:
|
365
|
-
dw.
|
398
|
+
dw.text = self.format(typedval, width=(self.width or 0)*2) or ''
|
366
399
|
|
367
400
|
# annotate cells with raw value type in anytype columns, except for strings
|
368
401
|
if self.type is anytype and type(cellval) is not str:
|
@@ -375,21 +408,23 @@ class Column(Extensible):
|
|
375
408
|
e.stacktrace = stacktrace()
|
376
409
|
dw.error = e.stacktrace
|
377
410
|
try:
|
378
|
-
dw.
|
411
|
+
dw.text = str(cellval)
|
379
412
|
except Exception as e:
|
380
|
-
dw.
|
413
|
+
dw.text = str(e)
|
381
414
|
dw.note = options.note_format_exc
|
382
415
|
dw.notecolor = 'color_warning'
|
383
416
|
|
417
|
+
# dw.display = self.display(dw) # set during draw() when colwidth is known
|
384
418
|
return dw
|
385
419
|
|
386
420
|
def getDisplayValue(self, row):
|
387
421
|
'Return string displayed in this column for given *row*.'
|
388
|
-
return self.getCell(row).
|
422
|
+
return self.getCell(row).text
|
389
423
|
|
390
424
|
def putValue(self, row, val):
|
391
425
|
'Change value for *row* in this column to *val* immediately. Does not check the type. Overridable; by default calls ``.setter(row, val)``.'
|
392
|
-
|
426
|
+
if self.setter:
|
427
|
+
return self.setter(self, row, val)
|
393
428
|
|
394
429
|
def setValue(self, row, val, setModified=True):
|
395
430
|
'Change value for *row* in this column to *val*. Call ``putValue`` immediately if not a deferred column (added to deferred parent at load-time); otherwise cache until later ``putChanges``. Caller must add undo function.'
|
@@ -400,19 +435,14 @@ class Column(Extensible):
|
|
400
435
|
if setModified: #1800
|
401
436
|
self.sheet.setModified()
|
402
437
|
|
403
|
-
def setValueSafe(self, row, value):
|
404
|
-
'setValue and ignore exceptions.'
|
405
|
-
try:
|
406
|
-
return self.setValue(row, value)
|
407
|
-
except Exception as e:
|
408
|
-
vd.exceptionCaught(e)
|
409
|
-
|
410
438
|
@asyncthread
|
411
439
|
def setValues(self, rows, *values):
|
412
440
|
'Set values in this column for *rows* to *values*, recycling values as needed to fill *rows*.'
|
413
441
|
vd.addUndoSetValues([self], rows)
|
442
|
+
|
414
443
|
for r, v in zip(rows, itertools.cycle(values)):
|
415
|
-
self.
|
444
|
+
vd.callNoExceptions(self.setValue, r, v)
|
445
|
+
|
416
446
|
self.recalc()
|
417
447
|
return vd.status('set %d cells to %d values' % (len(rows), len(values)))
|
418
448
|
|
@@ -420,7 +450,7 @@ class Column(Extensible):
|
|
420
450
|
'Set values on this column for *rows* to *values*, coerced to column type, recycling values as needed to fill *rows*. Abort on type exception.'
|
421
451
|
vd.addUndoSetValues([self], rows)
|
422
452
|
for r, v in zip(rows, itertools.cycle(self.type(val) for val in values)):
|
423
|
-
self.
|
453
|
+
vd.callNoExceptions(self.setValue, r, v)
|
424
454
|
|
425
455
|
self.recalc()
|
426
456
|
|
@@ -437,7 +467,7 @@ class Column(Extensible):
|
|
437
467
|
if w_max < row_w:
|
438
468
|
w_max = row_w
|
439
469
|
if w_max >= self.sheet.windowWidth:
|
440
|
-
break
|
470
|
+
break #1747 early out to speed up wide columns
|
441
471
|
w = w_max
|
442
472
|
w = max(w, nlen)+2
|
443
473
|
w = min(w, self.sheet.windowWidth)
|
@@ -445,88 +475,33 @@ class Column(Extensible):
|
|
445
475
|
|
446
476
|
|
447
477
|
|
448
|
-
# ----
|
478
|
+
# ---- basic Columns
|
449
479
|
|
450
|
-
|
451
|
-
r[i] = v
|
452
|
-
return True
|
453
|
-
|
454
|
-
|
455
|
-
def getattrdeep(obj, attr, *default, getter=getattr):
|
456
|
-
try:
|
457
|
-
'Return dotted attr (like "a.b.c") from obj, or default if any of the components are missing.'
|
458
|
-
if not isinstance(attr, str):
|
459
|
-
return getter(obj, attr, *default)
|
460
|
-
|
461
|
-
try: # if attribute exists, return toplevel value, even if dotted
|
462
|
-
if attr in obj:
|
463
|
-
return getter(obj, attr)
|
464
|
-
except Exception as e:
|
465
|
-
pass
|
466
|
-
|
467
|
-
attrs = attr.split('.')
|
468
|
-
for a in attrs[:-1]:
|
469
|
-
obj = getter(obj, a)
|
470
|
-
|
471
|
-
return getter(obj, attrs[-1])
|
472
|
-
except Exception as e:
|
473
|
-
if not default: raise
|
474
|
-
return default[0]
|
475
|
-
|
476
|
-
|
477
|
-
def setattrdeep(obj, attr, val, getter=getattr, setter=setattr):
|
478
|
-
'Set dotted attr (like "a.b.c") on obj to val.'
|
479
|
-
if not isinstance(attr, str):
|
480
|
-
return setter(obj, attr, val)
|
481
|
-
|
482
|
-
try: # if attribute exists, overwrite toplevel value, even if dotted
|
483
|
-
getter(obj, attr)
|
484
|
-
return setter(obj, attr, val)
|
485
|
-
except Exception as e:
|
486
|
-
pass
|
487
|
-
|
488
|
-
attrs = attr.split('.')
|
489
|
-
for a in attrs[:-1]:
|
490
|
-
try:
|
491
|
-
obj = getter(obj, a)
|
492
|
-
except Exception as e:
|
493
|
-
obj = obj[a] = type(obj)() # assume homogeneous nesting
|
494
|
-
|
495
|
-
setter(obj, attrs[-1], val)
|
496
|
-
|
497
|
-
|
498
|
-
def getitemdeep(obj, k, *default):
|
499
|
-
return getattrdeep(obj, k, *default, getter=getitem)
|
500
|
-
|
501
|
-
def setitemdeep(obj, k, val):
|
502
|
-
return setattrdeep(obj, k, val, getter=getitemdef, setter=setitem)
|
503
|
-
|
504
|
-
def AttrColumn(name='', attr=None, **kwargs):
|
480
|
+
class AttrColumn(Column):
|
505
481
|
'Column using getattr/setattr with *attr*.'
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
482
|
+
def __init__(self, name=None, expr=None, **kwargs):
|
483
|
+
super().__init__(name,
|
484
|
+
expr=expr if expr is not None else name,
|
485
|
+
getter=lambda col,row: getattrdeep(row, col.expr, None),
|
486
|
+
**kwargs)
|
511
487
|
|
512
|
-
def
|
513
|
-
|
488
|
+
def putValue(self, row, val):
|
489
|
+
super().putValue(row, val)
|
490
|
+
setattrdeep(row, self.expr, val)
|
514
491
|
|
515
|
-
def getitemdef(o, k, default=None):
|
516
|
-
try:
|
517
|
-
return default if o is None else o[k]
|
518
|
-
except Exception:
|
519
|
-
return default
|
520
492
|
|
521
493
|
class ItemColumn(Column):
|
522
|
-
'Column using getitem/setitem with *
|
494
|
+
'Column using getitem/setitem with *expr*.'
|
523
495
|
def __init__(self, name=None, expr=None, **kwargs):
|
524
496
|
super().__init__(name,
|
525
497
|
expr=expr if expr is not None else name,
|
526
498
|
getter=lambda col,row: getitemdeep(row, col.expr, None),
|
527
|
-
setter=lambda col,row,val: setitemdeep(row, col.expr, val),
|
528
499
|
**kwargs)
|
529
500
|
|
501
|
+
def putValue(self, row, val):
|
502
|
+
super().putValue(row, val)
|
503
|
+
setitemdeep(row, self.expr, val)
|
504
|
+
|
530
505
|
|
531
506
|
class SubColumnFunc(Column):
|
532
507
|
'Column compositor; preprocess row with *subfunc*(row, *expr*) before passing to *origcol*.getValue and *origcol*.setValue.'
|
@@ -584,7 +559,7 @@ class ExprColumn(Column):
|
|
584
559
|
a = self.getDisplayValue(row)
|
585
560
|
b = self.format(self.type(val))
|
586
561
|
if a != b:
|
587
|
-
vd.warning(
|
562
|
+
vd.warning("Cannot change value of calculated column. Use `'` to freeze column.")
|
588
563
|
|
589
564
|
@property
|
590
565
|
def expr(self):
|
@@ -608,7 +583,24 @@ class SettableColumn(Column):
|
|
608
583
|
SettableColumn.init('_store', dict, copy=True)
|
609
584
|
|
610
585
|
|
586
|
+
vd.addGlobals(
|
587
|
+
INPROGRESS=INPROGRESS,
|
588
|
+
Column=Column,
|
589
|
+
setitem=setitem,
|
590
|
+
getattrdeep=getattrdeep,
|
591
|
+
setattrdeep=setattrdeep,
|
592
|
+
getitemdef=getitemdef,
|
593
|
+
AttrColumn=AttrColumn,
|
594
|
+
ItemColumn=ItemColumn,
|
595
|
+
ExprColumn=ExprColumn,
|
596
|
+
SettableColumn=SettableColumn,
|
597
|
+
SubColumnFunc=SubColumnFunc,
|
598
|
+
SubColumnItem=SubColumnItem,
|
599
|
+
SubColumnAttr=SubColumnAttr,
|
600
|
+
|
611
601
|
# synonyms
|
612
|
-
ColumnItem
|
613
|
-
ColumnAttr
|
614
|
-
ColumnExpr
|
602
|
+
ColumnItem=ItemColumn,
|
603
|
+
ColumnAttr=AttrColumn,
|
604
|
+
ColumnExpr=ExprColumn,
|
605
|
+
DisplayWrapper=DisplayWrapper
|
606
|
+
)
|
visidata/ddw/input.ddw
CHANGED
@@ -1,79 +1,67 @@
|
|
1
|
-
{"x":
|
2
|
-
{"x":
|
3
|
-
{"x":
|
4
|
-
{"x": 11, "y":
|
5
|
-
{"x":
|
6
|
-
{"x":
|
7
|
-
{"x":
|
8
|
-
{"x":
|
9
|
-
{"x":
|
10
|
-
{"x":
|
11
|
-
{"x":
|
12
|
-
{"x":
|
13
|
-
{"x": 45, "y":
|
14
|
-
{"x":
|
15
|
-
{"x": 45, "y":
|
16
|
-
{"x":
|
17
|
-
{"x": 45, "y":
|
18
|
-
{"x":
|
19
|
-
{"x":
|
20
|
-
{"x":
|
21
|
-
{"x":
|
22
|
-
{"x":
|
23
|
-
{"x":
|
24
|
-
{"x":
|
25
|
-
{"x":
|
26
|
-
{"x":
|
27
|
-
{"x":
|
28
|
-
{"x":
|
29
|
-
{"x":
|
30
|
-
{"x":
|
31
|
-
{"x":
|
32
|
-
{"x":
|
33
|
-
{"x":
|
34
|
-
{"x":
|
35
|
-
{"x":
|
36
|
-
{"x":
|
37
|
-
{"x":
|
38
|
-
{"x":
|
39
|
-
{"x":
|
40
|
-
{"x":
|
41
|
-
{"x":
|
42
|
-
{"x":
|
43
|
-
{"x":
|
44
|
-
{"x":
|
45
|
-
{"x":
|
46
|
-
{"x":
|
47
|
-
{"x":
|
48
|
-
{"x":
|
49
|
-
{"x":
|
50
|
-
{"x":
|
51
|
-
{"x":
|
52
|
-
{"x":
|
53
|
-
{"x":
|
54
|
-
{"x":
|
55
|
-
{"x":
|
56
|
-
{"x":
|
57
|
-
{"x":
|
58
|
-
{"x":
|
59
|
-
{"x":
|
60
|
-
{"x":
|
61
|
-
{"x":
|
62
|
-
{"x":
|
63
|
-
{"x":
|
64
|
-
{"x":
|
65
|
-
{"x": 5, "y": 11, "text": "\u2192", "color": "bold white on 237", "tags": [], "group": ""}
|
66
|
-
{"x": 11, "y": 11, "text": "go to next word", "color": "", "tags": [], "group": ""}
|
67
|
-
{"x": 11, "y": 9, "text": "go to end of input", "color": "", "tags": [], "group": ""}
|
68
|
-
{"x": 11, "y": 7, "text": "go to next char", "color": "", "tags": [], "group": ""}
|
69
|
-
{"x": 11, "y": 13, "text": "next input history", "color": "", "tags": [], "group": ""}
|
70
|
-
{"x": 11, "y": 14, "text": "prev input history", "color": "", "tags": [], "group": ""}
|
71
|
-
{"x": 11, "y": 15, "text": "next autocomplete", "color": "", "tags": [], "group": ""}
|
72
|
-
{"x": 11, "y": 16, "text": "prev autocomplete", "color": "", "tags": [], "group": ""}
|
73
|
-
{"x": 4, "y": 4, "text": "+", "color": "", "tags": [], "group": ""}
|
74
|
-
{"x": 5, "y": 4, "text": "C", "color": "bold white on 237", "tags": [], "group": ""}
|
75
|
-
{"x": 5, "y": 16, "text": "+", "color": "", "tags": [], "group": ""}
|
76
|
-
{"x": 6, "y": 16, "text": "Tab", "color": "bold white on 237", "tags": [], "group": ""}
|
1
|
+
{"id": null, "type": null, "x": 6, "y": 7, "text": "\u2190", "color": "keystrokes", "tags": [], "group": "", "frame": null, "rows": null, "duration_ms": null, "ref": null, "onclick": null}
|
2
|
+
{"x": 11, "y": 7, "text": "go to prev/next char", "color": "", "tags": [], "group": ""}
|
3
|
+
{"x": 3, "y": 4, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
|
4
|
+
{"x": 11, "y": 4, "text": "cancel input (abort)", "color": "", "tags": [], "group": ""}
|
5
|
+
{"x": 45, "y": 4, "text": "delete one char at cursor", "color": "", "tags": [], "group": ""}
|
6
|
+
{"x": 45, "y": 5, "text": "delete one char before cursor", "color": "", "tags": [], "group": ""}
|
7
|
+
{"x": 0, "y": 13, "text": "Shift", "color": "keystrokes", "tags": [], "group": ""}
|
8
|
+
{"x": 4, "y": 3, "text": "Enter", "color": "keystrokes", "tags": [], "group": ""}
|
9
|
+
{"x": 11, "y": 3, "text": "accept input", "color": "", "tags": [], "group": ""}
|
10
|
+
{"x": 42, "y": 6, "text": "K", "color": "keystrokes", "tags": [], "group": ""}
|
11
|
+
{"x": 45, "y": 6, "text": "delete all before/after cursor", "color": "", "tags": [], "group": ""}
|
12
|
+
{"x": 42, "y": 12, "text": "O", "color": "keystrokes", "tags": [], "group": ""}
|
13
|
+
{"x": 45, "y": 12, "text": "open input in external editor", "color": "", "tags": [], "group": ""}
|
14
|
+
{"x": 42, "y": 13, "text": "R", "color": "keystrokes", "tags": [], "group": ""}
|
15
|
+
{"x": 45, "y": 13, "text": "restore starting value", "color": "", "tags": [], "group": ""}
|
16
|
+
{"x": 42, "y": 8, "text": "T", "color": "keystrokes", "tags": [], "group": ""}
|
17
|
+
{"x": 45, "y": 8, "text": "swap last two chars", "color": "", "tags": [], "group": ""}
|
18
|
+
{"x": 40, "y": 6, "text": "U", "color": "keystrokes", "tags": [], "group": ""}
|
19
|
+
{"x": 42, "y": 9, "text": "V", "color": "keystrokes", "tags": [], "group": ""}
|
20
|
+
{"x": 45, "y": 9, "text": "insert literal char", "color": "", "tags": [], "group": ""}
|
21
|
+
{"x": 42, "y": 7, "text": "W", "color": "keystrokes", "tags": [], "group": ""}
|
22
|
+
{"x": 45, "y": 7, "text": "delete one word before cursor", "color": "", "tags": [], "group": ""}
|
23
|
+
{"x": 42, "y": 11, "text": "Y", "color": "keystrokes", "tags": [], "group": ""}
|
24
|
+
{"x": 45, "y": 11, "text": "insert clipboard text at cursor", "color": "", "tags": [], "group": ""}
|
25
|
+
{"x": 6, "y": 8, "text": "\u2190", "color": "keystrokes", "tags": [], "group": ""}
|
26
|
+
{"x": 11, "y": 8, "text": "go to prev/next word", "color": "", "tags": [], "group": ""}
|
27
|
+
{"x": 0, "y": 0, "text": "Begin typing to overwrite the starting value.", "color": "", "tags": [], "group": ""}
|
28
|
+
{"x": 0, "y": 1, "text": "(To edit the starting value, press a movement key first.)", "color": "", "tags": [], "group": ""}
|
29
|
+
{"x": 6, "y": 11, "text": "\u2191", "color": "keystrokes", "tags": [], "group": ""}
|
30
|
+
{"x": 1, "y": 9, "text": "Home", "color": "keystrokes", "tags": [], "group": ""}
|
31
|
+
{"x": 11, "y": 9, "text": "go to start/end", "color": "", "tags": [], "group": ""}
|
32
|
+
{"x": 6, "y": 9, "text": "End", "color": "keystrokes", "tags": [], "group": ""}
|
33
|
+
{"x": 8, "y": 7, "text": "\u2192", "color": "keystrokes", "tags": [], "group": ""}
|
34
|
+
{"x": 37, "y": 4, "text": "Delete", "color": "keystrokes", "tags": [], "group": ""}
|
35
|
+
{"x": 34, "y": 5, "text": "Backspace", "color": "keystrokes", "tags": [], "group": ""}
|
36
|
+
{"x": 37, "y": 3, "text": "Insert", "color": "keystrokes", "tags": [], "group": ""}
|
37
|
+
{"x": 45, "y": 3, "text": "toggle insert mode", "color": "", "tags": [], "group": ""}
|
38
|
+
{"x": 6, "y": 12, "text": "Tab", "color": "keystrokes", "tags": [], "group": ""}
|
39
|
+
{"x": 1, "y": 8, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
|
40
|
+
{"x": 35, "y": 6, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
|
41
|
+
{"x": 37, "y": 8, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
|
42
|
+
{"x": 37, "y": 7, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
|
43
|
+
{"x": 37, "y": 9, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
|
44
|
+
{"x": 37, "y": 11, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
|
45
|
+
{"x": 37, "y": 12, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
|
46
|
+
{"x": 37, "y": 13, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
|
47
|
+
{"x": 5, "y": 8, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
|
48
|
+
{"x": 39, "y": 6, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
|
49
|
+
{"x": 41, "y": 7, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
|
50
|
+
{"x": 41, "y": 8, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
|
51
|
+
{"x": 41, "y": 9, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
|
52
|
+
{"x": 41, "y": 11, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
|
53
|
+
{"x": 41, "y": 12, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
|
54
|
+
{"x": 41, "y": 13, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
|
55
|
+
{"x": 11, "y": 11, "text": "prev/next in history", "color": "", "tags": [], "group": ""}
|
56
|
+
{"x": 11, "y": 12, "text": "next autocomplete", "color": "", "tags": [], "group": ""}
|
57
|
+
{"x": 11, "y": 13, "text": "prev autocomplete", "color": "", "tags": [], "group": ""}
|
58
|
+
{"x": 7, "y": 4, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
|
59
|
+
{"x": 8, "y": 4, "text": "C", "color": "keystrokes", "tags": [], "group": ""}
|
60
|
+
{"x": 5, "y": 13, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
|
61
|
+
{"x": 6, "y": 13, "text": "Tab", "color": "keystrokes", "tags": [], "group": ""}
|
62
|
+
{"x": 32, "y": 3, "text": "\u2502", "color": "", "tags": [], "group": ""}
|
63
|
+
{"x": 32, "y": 4, "text": "\u2502", "color": "", "tags": [], "group": ""}
|
64
|
+
{"x": 32, "y": 5, "text": "\u2502", "color": "", "tags": [], "group": ""}
|
77
65
|
{"x": 32, "y": 6, "text": "\u2502", "color": "", "tags": [], "group": ""}
|
78
66
|
{"x": 32, "y": 7, "text": "\u2502", "color": "", "tags": [], "group": ""}
|
79
67
|
{"x": 32, "y": 8, "text": "\u2502", "color": "", "tags": [], "group": ""}
|
@@ -82,6 +70,13 @@
|
|
82
70
|
{"x": 32, "y": 11, "text": "\u2502", "color": "", "tags": [], "group": ""}
|
83
71
|
{"x": 32, "y": 12, "text": "\u2502", "color": "", "tags": [], "group": ""}
|
84
72
|
{"x": 32, "y": 13, "text": "\u2502", "color": "", "tags": [], "group": ""}
|
85
|
-
{"x":
|
86
|
-
{"x":
|
87
|
-
{"x":
|
73
|
+
{"x": 7, "y": 7, "text": "/", "color": "", "tags": [], "group": ""}
|
74
|
+
{"x": 5, "y": 9, "text": "/", "color": "", "tags": [], "group": ""}
|
75
|
+
{"x": 8, "y": 8, "text": "\u2192", "color": "keystrokes", "tags": [], "group": ""}
|
76
|
+
{"x": 8, "y": 11, "text": "\u2193", "color": "keystrokes", "tags": [], "group": ""}
|
77
|
+
{"x": 41, "y": 6, "text": "/", "color": "", "tags": [], "group": ""}
|
78
|
+
{"x": 7, "y": 11, "text": "/", "color": "", "tags": [], "group": ""}
|
79
|
+
{"x": 7, "y": 8, "text": "/", "color": "", "tags": [], "group": ""}
|
80
|
+
{"x": 75, "y": 0, "text": "?", "color": "bold 117 cyan", "tags": [], "group": "", "onclick": "https://visidata.org/input"}
|
81
|
+
{"x": 3, "y": 5, "text": "Ctrl+G", "color": "keystrokes", "tags": [], "group": ""}
|
82
|
+
{"x": 11, "y": 5, "text": "cycle help sidebar", "color": "", "tags": [], "group": ""}
|