visidata 2.11.1__py3-none-any.whl → 3.0__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 +65 -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 +59 -50
- 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 +5 -1
- 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 +30 -5
- 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 +163 -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} +75 -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 +180 -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 +17 -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 +48 -10
- 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 +301 -148
- visidata/man/vd.txt +290 -153
- 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 +50 -201
- 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 +229 -257
- visidata/shell.py +51 -21
- visidata/sidebar.py +162 -0
- visidata/sort.py +11 -4
- visidata/statusbar.py +113 -104
- visidata/stored_list.py +43 -0
- visidata/stored_prop.py +38 -0
- visidata/tests/conftest.py +3 -3
- visidata/tests/test_cliptext.py +39 -0
- visidata/tests/test_commands.py +62 -7
- visidata/tests/test_edittext.py +2 -2
- visidata/tests/test_features.py +17 -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 +87 -39
- 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.data/data/share/applications/visidata.desktop +7 -0
- {visidata-2.11.1.data → visidata-3.0.data}/data/share/man/man1/vd.1 +301 -148
- {visidata-2.11.1.data → visidata-3.0.data}/data/share/man/man1/visidata.1 +301 -148
- visidata-3.0.data/scripts/vd2to3.vdx +9 -0
- {visidata-2.11.1.dist-info → visidata-3.0.dist-info}/METADATA +12 -8
- visidata-3.0.dist-info/RECORD +257 -0
- {visidata-2.11.1.dist-info → visidata-3.0.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.data}/scripts/vd +0 -0
- {visidata-2.11.1.dist-info → visidata-3.0.dist-info}/LICENSE.gpl3 +0 -0
- {visidata-2.11.1.dist-info → visidata-3.0.dist-info}/entry_points.txt +0 -0
- {visidata-2.11.1.dist-info → visidata-3.0.dist-info}/top_level.txt +0 -0
visidata/guide.py
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
'''
|
2
|
+
# A Guide to VisiData Guides
|
3
|
+
Each guide shows you how to use a particular feature in VisiData. Gray guides have not been written yet. We love contributions: [:onclick https://visidata.org/docs/api/guides]https://visidata.org/docs/api/guides[/].
|
4
|
+
|
5
|
+
- [:keystrokes]Up/Down[/] to move the row cursor
|
6
|
+
- [:keystrokes]Enter[/] to view a topic
|
7
|
+
'''
|
8
|
+
import re
|
9
|
+
|
10
|
+
from visidata import vd, BaseSheet, Sheet, ItemColumn, Column, VisiData, ENTER, RowColorizer, AttrDict, MissingAttrFormatter
|
11
|
+
from visidata import wraptext
|
12
|
+
|
13
|
+
guides_list = '''
|
14
|
+
GuideIndex ("A Guide to VisiData Guides (you are here)")
|
15
|
+
HelpGuide ("Where to Start and How to Quit") # manpage; ask for patreon
|
16
|
+
MenuGuide ("The VisiData Menu System")
|
17
|
+
CommandsSheet ("How to find the command you want run")
|
18
|
+
|
19
|
+
# real barebones basics
|
20
|
+
MovementGuide ("Movement and Search")
|
21
|
+
SortGuide ("Sorting")
|
22
|
+
TypesSheet ("The basic type system")
|
23
|
+
CommandLog ("Undo and Replay")
|
24
|
+
|
25
|
+
# rev this thing up
|
26
|
+
|
27
|
+
SelectionGuide ("Selecting and filtering") # stu|, and variants; filtering with dup-sheet; g prefix often refers to selected rowset
|
28
|
+
SheetsSheet ("The Sheet Stack")
|
29
|
+
ColumnsSheet ("Columns: the only way to fly")
|
30
|
+
StatusesSheet ("Revisit old status messages")
|
31
|
+
SidebarSheet ("Dive into the sidebar")
|
32
|
+
SaversGuide ("Saving Data") # talk about options.overwrite + ro here
|
33
|
+
|
34
|
+
ErrorsSheet ("What was that error?")
|
35
|
+
ModifyGuide ("Adding, Editing, Deleting Rows")
|
36
|
+
|
37
|
+
# the varieties of data experience
|
38
|
+
|
39
|
+
SlideGuide ("Sliding rows and columns around")
|
40
|
+
ExprGuide ("Compute Python over every row")
|
41
|
+
JoinGuide ("Joining multiple sheets together")
|
42
|
+
DescribeSheet ("Basic Statistics (min/max/mode/median/mean)")
|
43
|
+
AggregatorsSheet ("Aggregations like sum, mean, and distinct")
|
44
|
+
FrequencyTable ("Frequency Tables are how you GROUP BY")
|
45
|
+
PivotGuide ("Pivot Tables are just Frequency Tables with more columns")
|
46
|
+
MeltGuide ("Melt is just Unpivot")
|
47
|
+
JsonGuide ("Some special features for JSON") # with expand/contract, unfurl
|
48
|
+
RegexGuide ("Matching and Transforming Strings with Regex")
|
49
|
+
GraphSheet ("Basic scatterplots and other graphs")
|
50
|
+
WindowFunctionGuide ("Perform operations on groups of rows")
|
51
|
+
|
52
|
+
# for the frequent user
|
53
|
+
OptionsSheet ("Options and Settings")
|
54
|
+
ClipboardGuide ("Copy and Paste Data via the Clipboard")
|
55
|
+
DirSheet ("Browsing the local filesystem")
|
56
|
+
FormatsSheet ("What can you open with VisiData?")
|
57
|
+
SplitpaneGuide ("Split VisiData into two panes")
|
58
|
+
ThemesSheet ("Change Interface Theme")
|
59
|
+
ColorSheet ("See available colors")
|
60
|
+
MacrosSheet ("Recording macros")
|
61
|
+
MemorySheet ("Making note of certain values")
|
62
|
+
|
63
|
+
# advanced usage and developers
|
64
|
+
|
65
|
+
ThreadsSheet ("Threads past and present")
|
66
|
+
PyobjSheet ("Inspecting internal Python objects")
|
67
|
+
|
68
|
+
# appendices
|
69
|
+
|
70
|
+
InputEditorGuide ("Using the builtin line editor")
|
71
|
+
'''
|
72
|
+
|
73
|
+
vd.guides = {} # name -> guidecls
|
74
|
+
|
75
|
+
@VisiData.api
|
76
|
+
def addGuide(vd, name, guidecls):
|
77
|
+
vd.guides[name] = guidecls
|
78
|
+
|
79
|
+
@VisiData.api
|
80
|
+
class GuideIndex(Sheet):
|
81
|
+
guide = __doc__
|
82
|
+
|
83
|
+
rowtype = 'guides' # rowdef: list(guide number, guide name, topic description, points, max_points)
|
84
|
+
columns = [
|
85
|
+
ItemColumn('n', 0, type=int),
|
86
|
+
ItemColumn('name', 1, width=0),
|
87
|
+
ItemColumn('topic', 2, width=60),
|
88
|
+
]
|
89
|
+
colorizers = [
|
90
|
+
RowColorizer(7, 'color_guide_unwritten', lambda s,c,r,v: r and r[1] not in vd.guides)
|
91
|
+
]
|
92
|
+
def iterload(self):
|
93
|
+
i = 0
|
94
|
+
for line in guides_list.splitlines():
|
95
|
+
m = re.search(r'(\w+?) \("(.*)"\)', line)
|
96
|
+
if m:
|
97
|
+
yield [i] + list(m.groups())
|
98
|
+
i += 1
|
99
|
+
|
100
|
+
def openRow(self, row):
|
101
|
+
name = row[1]
|
102
|
+
return vd.getGuide(name)
|
103
|
+
|
104
|
+
class OptionHelpGetter:
|
105
|
+
'For easy and consistent formatting in sidebars and helpstrings, use {vd.options.help.opt_name}.'
|
106
|
+
def __getattr__(self, optname):
|
107
|
+
opt = vd.options._get(optname, 'default')
|
108
|
+
return f'[:onclick options-sheet {optname}]`{optname}`[/]: to {opt.helpstr} (default: {opt.value})'
|
109
|
+
|
110
|
+
|
111
|
+
class CommandHelpGetter:
|
112
|
+
'For easy and consistent formatting in sidebars and helpstrings, use {vd.commands.help.long_name}.'
|
113
|
+
def __init__(self, cls):
|
114
|
+
self.cls = cls
|
115
|
+
self.helpsheet = vd.HelpSheet()
|
116
|
+
self.helpsheet.ensureLoaded()
|
117
|
+
|
118
|
+
def __getattr__(self, k):
|
119
|
+
longname = k.replace('_', '-')
|
120
|
+
binding = self.helpsheet.revbinds.get(longname, [None])[0]
|
121
|
+
# cmddict has a SheetClass associated with each command
|
122
|
+
# go through all the parents of the Sheet type, to look for the command
|
123
|
+
for cls in self.cls.superclasses():
|
124
|
+
cmd = self.helpsheet.cmddict.get((cls.__name__, longname), None)
|
125
|
+
if cmd:
|
126
|
+
break
|
127
|
+
if not cmd:
|
128
|
+
return ''
|
129
|
+
if 'input' in cmd.execstr.lower():
|
130
|
+
inputtype = 'input'
|
131
|
+
m = re.search(r'type="(\w*)"', cmd.execstr, re.IGNORECASE)
|
132
|
+
if not m:
|
133
|
+
m = re.search(r'input(\w*)\("', cmd.execstr, re.IGNORECASE)
|
134
|
+
if m:
|
135
|
+
inputtype = m.groups()[0].lower()
|
136
|
+
binding += f'[:45] {inputtype}[/]'
|
137
|
+
|
138
|
+
helpstr = cmd.helpstr
|
139
|
+
return f'`{binding}` (`{longname}`) to {helpstr}'
|
140
|
+
|
141
|
+
|
142
|
+
class GuideSheet(Sheet):
|
143
|
+
rowtype = 'lines'
|
144
|
+
filetype = 'guide'
|
145
|
+
columns = [
|
146
|
+
ItemColumn('linenum', 0, type=int, width=0),
|
147
|
+
ItemColumn('guide', 1, width=80, displayer='full'),
|
148
|
+
]
|
149
|
+
precious = False
|
150
|
+
guide_text = ''
|
151
|
+
sheettype = Sheet
|
152
|
+
|
153
|
+
def iterload(self):
|
154
|
+
winWidth = 78
|
155
|
+
helper = AttrDict(commands=CommandHelpGetter(self.sheettype),
|
156
|
+
options=OptionHelpGetter())
|
157
|
+
guidetext = MissingAttrFormatter().format(self.guide_text, help=helper, vd=vd)
|
158
|
+
for startingLine, text in enumerate(guidetext.splitlines()):
|
159
|
+
text = text.strip()
|
160
|
+
if text:
|
161
|
+
for i, (L, _) in enumerate(wraptext(str(text), width=winWidth)):
|
162
|
+
yield [startingLine+i+1, L]
|
163
|
+
else:
|
164
|
+
yield [startingLine+1, text]
|
165
|
+
|
166
|
+
|
167
|
+
|
168
|
+
@VisiData.api
|
169
|
+
def getGuide(vd, name): # -> GuideSheet()
|
170
|
+
if name in vd.guides:
|
171
|
+
return vd.guides[name]()
|
172
|
+
vd.warning(f'no guide named {name}')
|
173
|
+
|
174
|
+
BaseSheet.addCommand('', 'open-guide-index', 'vd.push(GuideIndex("VisiData_Guide"))', 'open VisiData guides table of contents')
|
175
|
+
|
176
|
+
vd.addMenuItems('''
|
177
|
+
Help > VisiData Feature Guides > open-guide-index
|
178
|
+
''')
|
179
|
+
|
180
|
+
vd.addGlobals({'GuideSheet':GuideSheet, "CommandHelpGetter": CommandHelpGetter, "OptionHelpGetter": OptionHelpGetter})
|
visidata/help.py
CHANGED
@@ -1,10 +1,35 @@
|
|
1
1
|
import functools
|
2
2
|
import collections
|
3
|
-
from pkg_resources import resource_filename
|
4
3
|
|
5
|
-
from visidata import
|
4
|
+
from visidata import VisiData, MetaSheet, ColumnAttr, Column, BaseSheet, VisiDataMetaSheet, SuspendCurses
|
5
|
+
from visidata import vd, asyncthread, ENTER, drawcache, AttrDict
|
6
6
|
|
7
|
-
vd.
|
7
|
+
vd.option('disp_help', 2, 'show help panel during input')
|
8
|
+
|
9
|
+
@BaseSheet.api
|
10
|
+
def hint_basichelp(sheet):
|
11
|
+
return 0, '`Alt+[:underline]H[/]` to open the [:underline]H[/]elp menu'
|
12
|
+
|
13
|
+
|
14
|
+
@VisiData.api
|
15
|
+
def iterMenuPaths(vd, item=None, menupath=[]):
|
16
|
+
'Generate (longname, menupath).'
|
17
|
+
if item is None:
|
18
|
+
item = vd.menus
|
19
|
+
|
20
|
+
if isinstance(item, (list, tuple)):
|
21
|
+
for m in item:
|
22
|
+
yield from vd.iterMenuPaths(m, menupath)
|
23
|
+
elif item.longname:
|
24
|
+
yield item.longname, ' > '.join(menupath+[item.title])
|
25
|
+
else:
|
26
|
+
yield from vd.iterMenuPaths(item.menus, menupath+[item.title])
|
27
|
+
|
28
|
+
|
29
|
+
@VisiData.property
|
30
|
+
@drawcache
|
31
|
+
def menuPathsByLongname(vd):
|
32
|
+
return dict(vd.iterMenuPaths())
|
8
33
|
|
9
34
|
|
10
35
|
@VisiData.api
|
@@ -16,10 +41,12 @@ class HelpSheet(MetaSheet):
|
|
16
41
|
|
17
42
|
columns = [
|
18
43
|
ColumnAttr('sheet'),
|
44
|
+
ColumnAttr('module'),
|
19
45
|
ColumnAttr('longname'),
|
46
|
+
Column('menupath', width=0, cache=True, getter=lambda col,row: vd.menuPathsByLongname[row.longname]),
|
20
47
|
Column('keystrokes', getter=lambda col,row: col.sheet.revbinds.get(row.longname, [None])[0]),
|
21
|
-
Column('all_bindings', width=0, getter=lambda col,row: list(set(col.sheet.revbinds.get(row.longname, [])))),
|
22
|
-
Column('description', getter=lambda col,row: col.sheet.cmddict[(row.sheet, row.longname)].helpstr),
|
48
|
+
Column('all_bindings', width=0, cache=True, getter=lambda col,row: list(set(col.sheet.revbinds.get(row.longname, [])))),
|
49
|
+
Column('description', width=40, getter=lambda col,row: col.sheet.cmddict[(row.sheet, row.longname)].helpstr),
|
23
50
|
ColumnAttr('execstr', width=0),
|
24
51
|
Column('logged', width=0, getter=lambda col,row: vd.isLoggableCommand(row.longname)),
|
25
52
|
]
|
@@ -54,73 +81,69 @@ class HelpSheet(MetaSheet):
|
|
54
81
|
return revbinds
|
55
82
|
|
56
83
|
|
57
|
-
@VisiData.api
|
58
|
-
@asyncthread
|
59
|
-
def help_search(vd, sheet, regex):
|
60
|
-
vs = HelpSheet(source=None)
|
61
|
-
vs.rows = [] # do not trigger push reload
|
62
|
-
vd.push(vs) # push first, then reload
|
63
|
-
vd.sync(vs.reload())
|
64
|
-
|
65
|
-
# find rows matching regex on original HelpSheet
|
66
|
-
rowidxs = list(vd.searchRegex(vs, regex=regex, columns="visibleCols"))
|
67
|
-
|
68
|
-
# add only matching rows
|
69
|
-
allrows = vs.rows
|
70
|
-
vs.rows = []
|
71
|
-
for rowidx in rowidxs:
|
72
|
-
vs.addRow(allrows[rowidx])
|
73
|
-
|
74
|
-
|
75
84
|
class HelpPane:
|
76
85
|
def __init__(self, name):
|
86
|
+
import visidata
|
77
87
|
self.name = name
|
78
88
|
self.scr = None
|
79
89
|
self.parentscr = None
|
80
90
|
self.amgr = visidata.AnimationMgr()
|
81
91
|
|
82
|
-
|
92
|
+
@property
|
93
|
+
def width(self):
|
94
|
+
return self.amgr.maxWidth
|
95
|
+
|
96
|
+
@property
|
97
|
+
def height(self):
|
98
|
+
return self.amgr.maxHeight
|
99
|
+
|
100
|
+
def draw(self, scr, x=None, y=None, **kwargs):
|
83
101
|
if not scr: return
|
84
|
-
if
|
85
|
-
if self.scr:
|
86
|
-
self.scr.erase()
|
87
|
-
self.scr.refresh()
|
88
|
-
self.scr = None
|
89
|
-
return
|
102
|
+
# if vd.options.disp_help <= 0:
|
103
|
+
# if self.scr:
|
104
|
+
# self.scr.erase()
|
105
|
+
# self.scr.refresh()
|
106
|
+
# self.scr = None
|
107
|
+
# return
|
90
108
|
if y is None: y=0 # show at top of screen by default
|
91
109
|
if x is None: x=0
|
110
|
+
hneeded = self.amgr.maxHeight+3
|
111
|
+
wneeded = self.amgr.maxWidth+4
|
112
|
+
scrh, scrw = scr.getmaxyx()
|
92
113
|
if not self.scr or scr is not self.parentscr: # (re)allocate help pane scr
|
93
114
|
if y >= 0:
|
94
|
-
if y+
|
115
|
+
if y+hneeded < scrh:
|
95
116
|
yhelp = y+1
|
96
117
|
else:
|
97
|
-
|
118
|
+
hneeded = max(0, min(hneeded, y-1))
|
119
|
+
yhelp = y-hneeded
|
98
120
|
else: # y<0
|
99
|
-
yhelp =
|
121
|
+
yhelp = max(0, scrh-hneeded-1)
|
100
122
|
|
101
123
|
if x >= 0:
|
102
|
-
if x+
|
124
|
+
if x+wneeded < scrw:
|
103
125
|
xhelp = x+1
|
104
126
|
else:
|
105
|
-
|
127
|
+
wneeded = max(0, min(wneeded, x-1))
|
128
|
+
xhelp = x-wneeded
|
106
129
|
else: # x<0
|
107
|
-
xhelp =
|
130
|
+
xhelp = max(0, scrh-wneeded-1)
|
108
131
|
|
109
|
-
self.scr =
|
132
|
+
self.scr = vd.subwindow(scr, xhelp, yhelp, wneeded, hneeded)
|
110
133
|
self.parentscr = scr
|
111
134
|
|
112
135
|
self.scr.erase()
|
113
136
|
self.scr.box()
|
114
|
-
self.amgr.draw(self.scr, y=1, x=2)
|
137
|
+
self.amgr.draw(self.scr, y=1, x=2, **kwargs)
|
115
138
|
self.scr.refresh()
|
116
139
|
|
117
140
|
|
118
141
|
@VisiData.api
|
119
142
|
@functools.lru_cache(maxsize=None)
|
120
|
-
def getHelpPane(vd, name, module='
|
143
|
+
def getHelpPane(vd, name, module='visidata') -> HelpPane:
|
121
144
|
ret = HelpPane(name)
|
122
145
|
try:
|
123
|
-
ret.amgr.load(name,
|
146
|
+
ret.amgr.load(name, (vd.pkg_resources_files(module)/f'ddw/{name}.ddw').open(encoding='utf-8'))
|
124
147
|
ret.amgr.trigger(name, loop=True)
|
125
148
|
except FileNotFoundError as e:
|
126
149
|
vd.debug(str(e))
|
@@ -135,23 +158,31 @@ def getHelpPane(vd, name, module='vdplus'):
|
|
135
158
|
def openManPage(vd):
|
136
159
|
import os
|
137
160
|
with SuspendCurses():
|
138
|
-
|
139
|
-
|
161
|
+
module_path = vd.pkg_resources_files(__name__.split('.')[0])
|
162
|
+
if os.system(' '.join(['man', str(module_path/'man/vd.1')])) != 0:
|
163
|
+
vd.push(TextSheet('man_vd', source=module_path/'man/vd.txt'))
|
140
164
|
|
141
165
|
|
142
166
|
# in VisiData, g^H refers to the man page
|
143
167
|
BaseSheet.addCommand('g^H', 'sysopen-help', 'openManPage()', 'Show the UNIX man page for VisiData')
|
144
168
|
BaseSheet.addCommand('z^H', 'help-commands', 'vd.push(HelpSheet(name + "_commands", source=sheet, revbinds={}))', 'list commands and keybindings available on current sheet')
|
145
169
|
BaseSheet.addCommand('gz^H', 'help-commands-all', 'vd.push(HelpSheet("all_commands", source=None, revbinds={}))', 'list commands and keybindings for all sheet types')
|
146
|
-
BaseSheet.addCommand(None, 'help-search', 'help_search(sheet, input("help: "))', 'search through command longnames with search terms')
|
147
170
|
|
148
171
|
BaseSheet.bindkey('KEY_F(1)', 'sysopen-help')
|
149
172
|
BaseSheet.bindkey('zKEY_F(1)', 'help-commands')
|
150
173
|
BaseSheet.bindkey('zKEY_BACKSPACE', 'help-commands')
|
174
|
+
BaseSheet.bindkey('gKEY_BACKSPACE', 'sysopen-help')
|
151
175
|
|
152
|
-
HelpSheet.addCommand(
|
176
|
+
HelpSheet.addCommand(None, 'exec-command', 'quit(sheet); draw_all(); activeStack[0].execCommand(cursorRow.longname)', 'execute command on undersheet')
|
153
177
|
BaseSheet.addCommand(None, 'open-tutorial-visidata', 'launchBrowser("https://jsvine.github.io/intro-to-visidata/")', 'open https://jsvine.github.io/intro-to-visidata/')
|
154
178
|
|
155
179
|
vd.addMenuItem("Help", "VisiData tutorial", 'open-tutorial-visidata')
|
156
180
|
vd.addMenuItem("Help", 'Sheet commands', 'help-commands')
|
157
181
|
vd.addMenuItem("Help", 'All commands', 'help-commands-all')
|
182
|
+
|
183
|
+
vd.addGlobals(HelpSheet=HelpSheet)
|
184
|
+
|
185
|
+
vd.addMenuItems('''
|
186
|
+
Help > Quick reference > sysopen-help
|
187
|
+
Help > Command list > help-commands
|
188
|
+
''')
|
visidata/hint.py
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
import collections
|
2
|
+
|
3
|
+
from visidata import vd, BaseSheet
|
4
|
+
|
5
|
+
|
6
|
+
@BaseSheet.lazy_property
|
7
|
+
def prevHints(sheet):
|
8
|
+
return collections.defaultdict(int)
|
9
|
+
|
10
|
+
|
11
|
+
@BaseSheet.api
|
12
|
+
def getHint(sheet, *args, **kwargs) -> str:
|
13
|
+
funcs = [getattr(sheet, x) for x in dir(sheet) if x.startswith('hint_')]
|
14
|
+
results = []
|
15
|
+
hints = sheet.prevHints
|
16
|
+
for f in funcs:
|
17
|
+
try:
|
18
|
+
r = f(*args, **kwargs)
|
19
|
+
if r:
|
20
|
+
if isinstance(r, dict):
|
21
|
+
n = r.get('_relevance', 1)
|
22
|
+
v = r
|
23
|
+
elif isinstance(r, tuple):
|
24
|
+
n, v = r
|
25
|
+
else:
|
26
|
+
n = 1
|
27
|
+
v = r
|
28
|
+
|
29
|
+
if v not in sheet.prevHints:
|
30
|
+
results.append((n, v))
|
31
|
+
sheet.prevHints[v] += 1
|
32
|
+
except Exception as e:
|
33
|
+
vd.debug(f'{f.__name__}: {e}')
|
34
|
+
|
35
|
+
if results:
|
36
|
+
return sorted(results, reverse=True)[0][1]
|
37
|
+
|
38
|
+
|
39
|
+
vd.addCommand('', 'help-hint', 'status(getHint() or pressMenu("Help"))', 'get context-dependent hint on what to do next')
|
visidata/indexsheet.py
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
from visidata import vd, VisiData, BaseSheet, Sheet, Column, AttrColumn, ItemColumn, setitem, asyncthread
|
2
|
+
|
3
|
+
|
4
|
+
class IndexSheet(Sheet):
|
5
|
+
'Base class for tabular sheets with rows that are Sheets.'
|
6
|
+
guide = '''
|
7
|
+
# Index Sheet
|
8
|
+
This is a list of sheets from `{sheet.source}`.
|
9
|
+
|
10
|
+
- `Enter` to open {sheet.cursorRow}
|
11
|
+
- `g Enter` to open all selected sheets
|
12
|
+
'''
|
13
|
+
rowtype = 'sheets' # rowdef: Sheet
|
14
|
+
|
15
|
+
columns = [
|
16
|
+
Column('name', getter=lambda c,r: r.names[-1], setter=lambda c,r,v: setitem(r.names, -1, v)),
|
17
|
+
AttrColumn('rows', 'nRows', type=int, width=9),
|
18
|
+
AttrColumn('cols', 'nCols', type=int),
|
19
|
+
AttrColumn('keys', 'keyColNames'),
|
20
|
+
AttrColumn('source'),
|
21
|
+
]
|
22
|
+
nKeys = 1
|
23
|
+
|
24
|
+
def newRow(self):
|
25
|
+
return Sheet('', columns=[ItemColumn('', 0)], rows=[])
|
26
|
+
|
27
|
+
def openRow(self, row):
|
28
|
+
return row # rowdef is Sheet
|
29
|
+
|
30
|
+
def getSheet(self, k):
|
31
|
+
for vs in self.rows:
|
32
|
+
if vs.name == k:
|
33
|
+
return vs
|
34
|
+
|
35
|
+
def addRow(self, sheet, **kwargs):
|
36
|
+
super().addRow(sheet, **kwargs)
|
37
|
+
if not self.options.load_lazy and not sheet.options.load_lazy:
|
38
|
+
sheet.ensureLoaded()
|
39
|
+
|
40
|
+
@asyncthread
|
41
|
+
def reloadSheets(self, sheets):
|
42
|
+
for vs in vd.Progress(sheets):
|
43
|
+
vs.reload()
|
44
|
+
|
45
|
+
|
46
|
+
class SheetsSheet(IndexSheet):
|
47
|
+
columns = [
|
48
|
+
AttrColumn('name'),
|
49
|
+
AttrColumn('type', '__class__.__name__'),
|
50
|
+
AttrColumn('pane', type=int),
|
51
|
+
Column('shortcut', getter=lambda c,r: getattr(r, 'shortcut'), setter=lambda c,r,v: setattr(r, '_shortcut', v)),
|
52
|
+
AttrColumn('nRows', type=int),
|
53
|
+
AttrColumn('nCols', type=int),
|
54
|
+
AttrColumn('nVisibleCols', type=int),
|
55
|
+
AttrColumn('cursorDisplay'),
|
56
|
+
AttrColumn('keyColNames'),
|
57
|
+
AttrColumn('source'),
|
58
|
+
AttrColumn('progressPct'),
|
59
|
+
# AttrColumn('threads', 'currentThreads', type=vlen),
|
60
|
+
]
|
61
|
+
precious = False
|
62
|
+
nKeys = 1
|
63
|
+
def reload(self):
|
64
|
+
self.rows = self.source
|
65
|
+
|
66
|
+
def sort(self):
|
67
|
+
self.rows[1:] = sorted(self.rows[1:], key=self.sortkey)
|
68
|
+
|
69
|
+
|
70
|
+
class GlobalSheetsSheet(SheetsSheet): #1620
|
71
|
+
def sort(self):
|
72
|
+
IndexSheet.sort(self)
|
73
|
+
|
74
|
+
|
75
|
+
@VisiData.lazy_property
|
76
|
+
def sheetsSheet(vd):
|
77
|
+
return SheetsSheet("sheets", source=vd.sheets)
|
78
|
+
|
79
|
+
|
80
|
+
@VisiData.lazy_property
|
81
|
+
def allSheetsSheet(vd):
|
82
|
+
return GlobalSheetsSheet("sheets_all", source=vd.allSheets)
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
@Sheet.api
|
87
|
+
def nextRow(sheet, n=1):
|
88
|
+
sheet.cursorRowIndex += n
|
89
|
+
sheet.checkCursor()
|
90
|
+
return sheet.rows[sheet.cursorRowIndex] # cursorRow itself might be cached
|
91
|
+
|
92
|
+
|
93
|
+
vd.addCommand('S', 'sheets-stack', 'vd.push(vd.sheetsSheet)', 'open Sheets Stack: join or jump between the active sheets on the current stack')
|
94
|
+
vd.addCommand('gS', 'sheets-all', 'vd.push(vd.allSheetsSheet)', 'open Sheets Sheet: join or jump between all sheets from current session')
|
95
|
+
|
96
|
+
BaseSheet.addCommand('g>', 'open-source-next', 'vd.replace(openSource(source.nextRow())) if isinstance(source, IndexSheet) else fail("parent sheet must be Index Sheet")', 'open next sheet on parent index sheet')
|
97
|
+
BaseSheet.addCommand('g<', 'open-source-prev', 'vd.replace(openSource(source.nextRow(-1))) if isinstance(source, IndexSheet) else fail("parent sheet must be Index Sheet")', 'open prev sheet on parent index sheet')
|
98
|
+
|
99
|
+
IndexSheet.addCommand('g^R', 'reload-selected', 'reloadSheets(selectedRows or rows)', 'reload all selected sheets')
|
100
|
+
|
101
|
+
# when diving into a sheet, remove the index unless it is precious
|
102
|
+
SheetsSheet.addCommand('gC', 'columns-selected', 'vd.push(ColumnsSheet("all_columns", source=selectedRows))', 'open Columns Sheet with all visible columns from selected sheets')
|
103
|
+
SheetsSheet.addCommand('z^C', 'cancel-row', 'cancelThread(*cursorRow.currentThreads)', 'abort async thread for current sheet')
|
104
|
+
SheetsSheet.addCommand('gz^C', 'cancel-rows', 'for vs in selectedRows: cancelThread(*vs.currentThreads)', 'abort async threads for selected sheets')
|
105
|
+
SheetsSheet.addCommand('Enter', 'open-row', 'dest=cursorRow; vd.sheets.remove(sheet) if not sheet.precious else None; vd.push(openRow(dest))', 'open sheet referenced in current row')
|
106
|
+
|
107
|
+
vd.addGlobals(IndexSheet=IndexSheet,
|
108
|
+
SheetsSheet=SheetsSheet,
|
109
|
+
GlobalSheetsSheet=GlobalSheetsSheet)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
from visidata import vd, VisiData, Sheet, ItemColumn, asyncthread
|
2
|
+
|
3
|
+
|
4
|
+
vd._inputHistoryList = vd.StoredList(name='input_history')
|
5
|
+
vd.inputHistory = {} # [input_type][input] -> anything
|
6
|
+
|
7
|
+
|
8
|
+
@VisiData.api
|
9
|
+
def addInputHistory(vd, input:str, type:str=''):
|
10
|
+
r = vd.processInputHistory(input, type)
|
11
|
+
if r:
|
12
|
+
vd._inputHistoryList.append(r)
|
13
|
+
|
14
|
+
|
15
|
+
@VisiData.api
|
16
|
+
def processInputHistory(vd, input:str, type:str=''):
|
17
|
+
hist = list(vd.inputHistory.setdefault(type, {}).keys())
|
18
|
+
if hist and hist[-1] == input:
|
19
|
+
return
|
20
|
+
if input in vd.inputHistory[type]:
|
21
|
+
n = vd.inputHistory[type][input].get('n', 0)
|
22
|
+
del vd.inputHistory[type][input] # make it the most recent entry
|
23
|
+
else:
|
24
|
+
n = 0
|
25
|
+
|
26
|
+
r = dict(type=type, input=input, n=n+1)
|
27
|
+
vd.inputHistory[type][input] = r
|
28
|
+
return r
|
29
|
+
|
30
|
+
|
31
|
+
class InputHistorySheet(Sheet):
|
32
|
+
# rowdef: dict(type=, input=, n=)
|
33
|
+
# .source=vd.inputHistory
|
34
|
+
columns = [
|
35
|
+
ItemColumn('type'),
|
36
|
+
ItemColumn('input'),
|
37
|
+
]
|
38
|
+
def iterload(self):
|
39
|
+
yield from vd._inputHistoryList
|
40
|
+
|
41
|
+
|
42
|
+
@VisiData.before
|
43
|
+
@asyncthread
|
44
|
+
def run(vd, *args, **kwargs):
|
45
|
+
vd._inputHistoryList.reload()
|
46
|
+
for x in vd._inputHistoryList:
|
47
|
+
vd.processInputHistory(x.input, x.type)
|
48
|
+
|
49
|
+
|
50
|
+
@VisiData.property
|
51
|
+
def inputHistorySheet(vd):
|
52
|
+
return InputHistorySheet('input_history', source=vd._inputHistoryList.path)
|
53
|
+
|
54
|
+
|
55
|
+
vd.addCommand(None, 'open-input-history', 'vd.push(inputHistorySheet)', 'open sheet with previous inputs')
|
visidata/interface.py
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
from visidata import VisiData, vd
|
2
|
+
|
3
|
+
vd.theme_option('disp_splitwin_pct', 0, 'height of second sheet on screen')
|
4
|
+
vd.theme_option('disp_note_none', '⌀', 'visible contents of a cell whose value is None')
|
5
|
+
vd.theme_option('disp_truncator', '…', 'indicator that the contents are only partially visible')
|
6
|
+
vd.theme_option('disp_oddspace', '\u00b7', 'displayable character for odd whitespace')
|
7
|
+
vd.theme_option('disp_more_left', '<', 'header note indicating more columns to the left')
|
8
|
+
vd.theme_option('disp_more_right', '>', 'header note indicating more columns to the right')
|
9
|
+
vd.theme_option('disp_error_val', '', 'displayed contents for computation exception')
|
10
|
+
vd.theme_option('disp_ambig_width', 1, 'width to use for unicode chars marked ambiguous')
|
11
|
+
|
12
|
+
vd.theme_option('disp_pending', '', 'string to display in pending cells')
|
13
|
+
vd.theme_option('note_pending', '⌛', 'note to display for pending cells')
|
14
|
+
vd.theme_option('note_format_exc', '?', 'cell note for an exception during formatting')
|
15
|
+
vd.theme_option('note_getter_exc', '!', 'cell note for an exception during computation')
|
16
|
+
vd.theme_option('note_type_exc', '!', 'cell note for an exception during type conversion')
|
17
|
+
|
18
|
+
vd.theme_option('color_note_pending', 'bold magenta', 'color of note in pending cells')
|
19
|
+
vd.theme_option('color_note_type', '226 yellow', 'color of cell note for non-str types in anytype columns')
|
20
|
+
vd.theme_option('color_note_row', '220 yellow', 'color of row note on left edge')
|
21
|
+
vd.option('scroll_incr', -3, 'amount to scroll with scrollwheel')
|
22
|
+
vd.theme_option('disp_column_sep', '│', 'separator between columns')
|
23
|
+
vd.theme_option('disp_keycol_sep', '║', 'separator between key columns and rest of columns')
|
24
|
+
vd.theme_option('disp_rowtop_sep', '│', '') # ╷│┬╽⌜⌐▇
|
25
|
+
vd.theme_option('disp_rowmid_sep', '⁝', '') # ┃┊│█
|
26
|
+
vd.theme_option('disp_rowbot_sep', '⁝', '') # ┊┴╿⌞█⍿╵⎢┴⌊ ⋮⁝
|
27
|
+
vd.theme_option('disp_rowend_sep', '║', '') # ┊┴╿⌞█⍿╵⎢┴⌊
|
28
|
+
vd.theme_option('disp_keytop_sep', '║', '') # ╽╿┃╖╟
|
29
|
+
vd.theme_option('disp_keymid_sep', '║', '') # ╽╿┃
|
30
|
+
vd.theme_option('disp_keybot_sep', '║', '') # ╽╿┃╜‖
|
31
|
+
vd.theme_option('disp_endtop_sep', '║', '') # ╽╿┃╖╢
|
32
|
+
vd.theme_option('disp_endmid_sep', '║', '') # ╽╿┃
|
33
|
+
vd.theme_option('disp_endbot_sep', '║', '') # ╽╿┃╜‖
|
34
|
+
vd.theme_option('disp_selected_note', '•', '') #
|
35
|
+
vd.theme_option('disp_sort_asc', '↑↟⇞⇡⇧⇑', 'characters for ascending sort') # ↑▲↟↥↾↿⇞⇡⇧⇈⤉⤒⥔⥘⥜⥠⍏˄ˆ
|
36
|
+
vd.theme_option('disp_sort_desc', '↓↡⇟⇣⇩⇓', 'characters for descending sort') # ↓▼↡↧⇂⇃⇟⇣⇩⇊⤈⤓⥕⥙⥝⥡⍖˅ˇ
|
37
|
+
vd.theme_option('color_default', 'white on black', 'the default fg and bg colors')
|
38
|
+
vd.theme_option('color_default_hdr', 'bold', 'color of the column headers')
|
39
|
+
vd.theme_option('color_bottom_hdr', 'underline', 'color of the bottom header row')
|
40
|
+
vd.theme_option('color_current_row', 'reverse', 'color of the cursor row')
|
41
|
+
vd.theme_option('color_current_col', 'bold', 'color of the cursor column')
|
42
|
+
vd.theme_option('color_current_cell', '', 'color of current cell, if different from color_current_row+color_current_col')
|
43
|
+
vd.theme_option('color_current_hdr', 'bold reverse', 'color of the header for the cursor column')
|
44
|
+
vd.theme_option('color_column_sep', '246 blue', 'color of column separators')
|
45
|
+
vd.theme_option('color_key_col', '81 cyan', 'color of key columns')
|
46
|
+
vd.theme_option('color_hidden_col', '8', 'color of hidden columns on metasheets')
|
47
|
+
vd.theme_option('color_selected_row', '215 yellow', 'color of selected rows')
|
48
|
+
vd.theme_option('color_clickable', 'underline', 'color of internally clickable item')
|
49
|
+
vd.theme_option('color_code', 'bold white on 237', 'color of code sample')
|
50
|
+
vd.theme_option('color_heading', 'bold 200', 'color of header')
|
51
|
+
vd.theme_option('color_guide_unwritten', '243 on black', 'color of unwritten guides in GuideGuide')
|
52
|
+
|
53
|
+
vd.theme_option('force_256_colors', False, 'use 256 colors even if curses reports fewer')
|
54
|
+
|
55
|
+
vd.option('quitguard', False, 'confirm before quitting modified sheet')
|
56
|
+
vd.option('default_width', 20, 'default column width', replay=True, max_help=1) # TODO: make not replay and remove from markdown saver
|
57
|
+
vd.option('default_height', 4, 'default column height', max_help=-1)
|
58
|
+
vd.option('textwrap_cells', True, 'wordwrap text for multiline rows', max_help=1)
|