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/stored_list.py
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
import json
|
2
|
+
|
3
|
+
from visidata import vd, VisiData, Path, AttrDict
|
4
|
+
|
5
|
+
|
6
|
+
@VisiData.api
|
7
|
+
class StoredList(list):
|
8
|
+
'Read existing persisted list from filesystem, and append new elements to .jsonl in .visidata'
|
9
|
+
def __init__(self, *args, name:str='', **kwargs):
|
10
|
+
super().__init__(*args, **kwargs)
|
11
|
+
self.name = name
|
12
|
+
|
13
|
+
@property
|
14
|
+
def path(self):
|
15
|
+
vdpath = Path(vd.options.visidata_dir)
|
16
|
+
if vdpath.exists():
|
17
|
+
return vdpath/(self.name + '.jsonl')
|
18
|
+
|
19
|
+
def reload(self):
|
20
|
+
p = self.path
|
21
|
+
if not p or not p.exists():
|
22
|
+
return
|
23
|
+
|
24
|
+
ret = []
|
25
|
+
with p.open(encoding='utf-8-sig') as fp:
|
26
|
+
for line in fp:
|
27
|
+
value = vd.callNoExceptions(json.loads, line)
|
28
|
+
if value is not None:
|
29
|
+
if isinstance(value, dict):
|
30
|
+
value = AttrDict(value)
|
31
|
+
ret.append(value)
|
32
|
+
|
33
|
+
self[:] = ret # replace without using .append
|
34
|
+
|
35
|
+
def append(self, v):
|
36
|
+
super().append(v)
|
37
|
+
|
38
|
+
p = self.path
|
39
|
+
if p is None:
|
40
|
+
return
|
41
|
+
|
42
|
+
with p.open(encoding='utf-8', mode='a') as fp:
|
43
|
+
fp.write(json.dumps(v) + '\n')
|
visidata/stored_prop.py
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
from functools import wraps
|
2
|
+
import json
|
3
|
+
import atexit
|
4
|
+
|
5
|
+
from visidata import vd, VisiData, Path
|
6
|
+
|
7
|
+
vd.stored_properties = {}
|
8
|
+
|
9
|
+
@VisiData.class_api
|
10
|
+
@classmethod
|
11
|
+
def stored_property(vdcls, f):
|
12
|
+
def _save_on_exit():
|
13
|
+
if vd.stored_properties.get(f, None):
|
14
|
+
p = Path(vd.options.visidata_dir)/(f.__name__ + '.json')
|
15
|
+
with p.open(mode='w', encoding='utf-8') as fp:
|
16
|
+
fp.write(json.dumps(vd.stored_properties[f]))
|
17
|
+
|
18
|
+
@property
|
19
|
+
@wraps(f)
|
20
|
+
def _decorator(*args, **kwargs):
|
21
|
+
'Read persisted value from filesystem if available; otherwise call the decorated function to create a new instance.'
|
22
|
+
value = vd.stored_properties.get(f, None)
|
23
|
+
if value is not None:
|
24
|
+
return value
|
25
|
+
|
26
|
+
p = Path(vd.options.visidata_dir)/(f.__name__ + '.json')
|
27
|
+
if p.exists():
|
28
|
+
value = json.loads(p.open(encoding='utf-8-sig').read())
|
29
|
+
|
30
|
+
if value is None:
|
31
|
+
value = f(*args, **kwargs)
|
32
|
+
|
33
|
+
vd.stored_properties[f] = value
|
34
|
+
return value
|
35
|
+
|
36
|
+
atexit.register(_save_on_exit)
|
37
|
+
setattr(vdcls, f.__name__, _decorator)
|
38
|
+
return _decorator
|
@@ -0,0 +1,52 @@
|
|
1
|
+
Date,Customer,SKU,Item,Quantity,Unit,Paid
|
2
|
+
7/3/2018 1:47p,Robert Armstrong,FOOD213,BFF Oh My Gravy! Beef & Salmon 2.8oz,4,$12.95,$51.8
|
3
|
+
7/3/2018 3:32p,Kyle Kennedy,FOOD121,"Food, Adult Cat - 3.5 oz",1,$4.22,$4.22
|
4
|
+
7/5/2018 4:15p,"Douglas ""Dougie"" Powers",FOOD121,"Food, Adult Cat 3.5 oz",1,$4.22,$4.22
|
5
|
+
7/6/2018 12:15p,桜 高橋 (Sakura Takahashi),FOOD122,"Food, Senior Wet Cat - 3 oz",12,$1.29,157¥
|
6
|
+
7/10/2018 10:28a,David Attenborough,NSCT201,"Food, Salamander",30,$.05,$1.5
|
7
|
+
7/10/2018 5:23p,Susan Ashworth,CAT060,"Cat, Korat (Felis catus)",1,$720.42,$720.42
|
8
|
+
7/10/2018 5:23p,Susan Ashworth,FOOD130,"Food, Kitten 3kg",1,$14.94,$14.94
|
9
|
+
7/13/2018 10:26a,Wil Wheaton,NSCT523,"Monster, Rust (Monstrus gygaxus)",1,$39.95,$39.95
|
10
|
+
7/13/2018 3:49p,Robert Armstrong,FOOD216,BFF Oh My Gravy! Chicken & Shrimp 2.8oz,4,$12.95,$51.8
|
11
|
+
7/17/2018 9:01a,Robert Armstrong,FOOD217,BFF Oh My Gravy! Duck & Tuna 2.8oz,4,$12.95,$51.8
|
12
|
+
7/17/2018 11:30a,Helen Halestorm,LAGO342,Rabbit (Oryctolagus cuniculus),2,$32.94,$65.88
|
13
|
+
7/18/2018 12:16p,桜 高橋 (Sakura Takahashi),FOOD122,"Food, Senior Wet Cat - 3 oz",6,$1.29,157¥
|
14
|
+
7/19/2018 10:28a,Rubeus Hagrid,FOOD170,"Food, Dog - 5kg",5,$44.95,$224.75
|
15
|
+
7/20/2018 2:13p,Jon Arbuckle,FOOD167,"Food, Premium Wet Cat - 3.5 oz",50,$3.95,$197.5
|
16
|
+
7/23/2018 1:41p,Robert Armstrong,FOOD215,BFF Oh My Gravy! Lamb & Tuna 2.8oz,4,$12.95,$51.8
|
17
|
+
7/23/2018 4:23p,"Douglas ""Dougie"" Powers",TOY235,Laser Pointer,1,$16.12,$16.12
|
18
|
+
7/24/2018 12:16p,桜 高橋 (Sakura Takahashi),FOOD122,"Food, Senior Wet Cat - 3 oz",3,$1.29,157¥
|
19
|
+
7/26/2018 4:39p,"Douglas ""Dougie"" Powers",FOOD420,"Food, Shark - 10 kg",1,$15.70,$15.7
|
20
|
+
7/27/2018 12:16p,桜 高橋 (Sakura Takahashi),FOOD122,"Food, Senior Wet Cat - 3 oz",3,$1.29,157¥
|
21
|
+
7/30/2018 12:17p,桜 高橋 (Sakura Takahashi),RETURN,"Food, Senior Wet Cat - 3 oz",1,$1.29,157¥
|
22
|
+
7/31/2018 5:42p,Rubeus Hagrid,CAT060,"Food, Dragon - 50kg",5,$720.42,$3602.1
|
23
|
+
8/1/2018 2:44p,David Attenborough,FOOD360,"Food, Rhinocerous - 50kg",4,$5.72,$22.88
|
24
|
+
8/2/2018 5:12p,Susan Ashworth,CAT110,"Cat, Maine Coon (Felix catus)",1,"$1,309.68",$1309.68
|
25
|
+
8/2/2018 5:12p,Susan Ashworth,FOOD130,"Food, Kitten 3kg",3,$14.94,$44.82
|
26
|
+
8/6/2018 10:21a,Robert Armstrong,FOOD212,BFF Oh My Gravy! Beef & Chicken 2.8oz,4,$12.95,$51.8
|
27
|
+
8/7/2018 4:12p,Juan Johnson,REPT082,"Kingsnake, California (Lampropeltis getula)",1,$89.95,$89.95
|
28
|
+
8/7/2018 4:12p,Juan Johnson,RDNT443,"Mouse, Pinky (Mus musculus)",1,$1.49,$1.49
|
29
|
+
8/10/2018 4:31p,Robert Armstrong,FOOD211,BFF Oh My Gravy! Chicken & Turkey 2.8oz,4,$12.95,$51.8
|
30
|
+
8/13/2018 2:07p,Monica Johnson,RDNT443,"Mouse, Pinky (Mus musculus)",1,$1.49,$1.49
|
31
|
+
8/13/2018 2:08p,María Fernández,FOOD146,Forti Diet Prohealth Mouse/Rat 3lbs,2,$2.00,$4.0
|
32
|
+
8/15/2018 11:57a,Mr. Praline,RETURN,"Parrot, Norwegian Blue (Mopsitta tanta)",1,$2300.00,-$2300.0
|
33
|
+
8/15/2018 3:48p,Kyle Kennedy,FOOD121,"Food, Adult Cat - 3.5 oz",2,$4.22,$8.44
|
34
|
+
8/16/2018 11:50a,Helen Halestorm,RETURN,Rabbit (Oryctolagus cuniculus),6,$0,$0.0
|
35
|
+
8/16/2018 4:00p,Kyle Kennedy,DOG010,"Dog, Golden Retriever (Canis lupus familiaris)",1,"$2,495.99",$2495.99
|
36
|
+
8/16/2018 5:15p,Michael Smith,BIRD160,"Parakeet, Blue (Melopsittacus undulatus)",1,29.95,$31.85
|
37
|
+
8/17/2018 9:26a,Rubeus Hagrid,NSCT201,"Food, Spider",5,$.05,$0.25
|
38
|
+
8/20/2018 9:36a,Kyle Kennedy,RETURN,"Dog, Golden Retriever (Canis lupus familiaris)",1,"$1,247.99",-$1247.99
|
39
|
+
8/20/2018 1:47p,מרוסיה ניסנהולץ אבולעפיה,GOAT224,"Goat, American Pygmy (Capra hircus)",1,₪499,$160.51
|
40
|
+
8/20/2018 3:31p,Monica Johnson,NSCT201,"Crickets, Adult Live (Gryllus assimilis)",30,$.05,$1.5
|
41
|
+
8/20/2018 5:12p,David Attenborough,NSCT084,"Food, Pangolin",30,$.17,$5.10
|
42
|
+
8/21/2018 12:13p,Robert Armstrong,FOOD214,BFF Oh My Gravy! Duck & Salmon 2.8oz,4,$12.95,$51.8
|
43
|
+
8/22/2018 9:38a,David Attenborough,BIRD160,"Food, Quoll",1,29.95,$29.95
|
44
|
+
8/22/2018 2:13p,Jon Arbuckle,FOOD170,"Food, Adult Dog - 5kg",1,$44.95,$44.95
|
45
|
+
8/22/2018 5:49p,מרוסיה ניסנהולץ,SFTY052,"Fire Extinguisher, kitchen-rated",1,$61.70,$61.70
|
46
|
+
8/24/2018 11:42a,Robert Armstrong,FOOD218,BFF Oh My Gravy! Chicken & Salmon 2.8oz,4,$12.95,$51.8
|
47
|
+
8/27/2018 3:05p,Monica Johnson,NSCT443,"Mealworms, Large (Tenebrio molitor) 100ct",1,$1.99,$1.99
|
48
|
+
8/28/2018 5:32p,Susan Ashworth,CAT020,"Cat, Scottish Fold (Felis catus)",1,"$1,964.53",$1964.53
|
49
|
+
8/28/2018 5:32p,Susan Ashworth,FOOD130,"Food, Kitten 3kg",2,$14.94,$29.88
|
50
|
+
8/29/2018 10:07a,Robert Armstrong,FOOD219,BFF Oh My Gravy! Chicken & Pumpkin 2.8oz,4,$12.95,$51.8
|
51
|
+
8/31/2018 12:00a,Robert Armstrong,FOOD219,BFF Oh My Gravy! Chicken & Pumpkin 2.8oz,144,$12.95,$1864.8
|
52
|
+
8/31/2018 5:57p,Juan Johnson,REPT217,"Lizard, Spinytail (Uromastyx ornatus)",1,$99.95,$99.95
|
visidata/tests/conftest.py
CHANGED
@@ -10,7 +10,7 @@ def curses_setup():
|
|
10
10
|
import visidata
|
11
11
|
|
12
12
|
curses.curs_set = lambda v: None
|
13
|
-
visidata.options.
|
13
|
+
visidata.options.overwrite = 'always'
|
14
14
|
|
15
15
|
|
16
16
|
@pytest.fixture(scope="function")
|
@@ -18,8 +18,8 @@ def mock_screen():
|
|
18
18
|
"""Set up and return a mock curses screen object."""
|
19
19
|
|
20
20
|
scr = Mock()
|
21
|
-
scr.addstr =
|
22
|
-
scr.move =
|
21
|
+
scr.addstr = lambda *args, **kwargs: None
|
22
|
+
scr.move = lambda *args, **kwargs: None
|
23
23
|
scr.getmaxyx = lambda: (25, 80)
|
24
24
|
|
25
25
|
return scr
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import pytest
|
2
|
+
from unittest.mock import Mock, call
|
3
|
+
|
4
|
+
import visidata
|
5
|
+
|
6
|
+
|
7
|
+
class TestClipText:
|
8
|
+
@pytest.mark.parametrize('s, dispw', [
|
9
|
+
('abcdef', 6),
|
10
|
+
('桜 高橋', 7),
|
11
|
+
('[:onclick sidebar-toggle][:reverse] b to toggle sidebar [:]', 21),
|
12
|
+
])
|
13
|
+
def test_dispwidth(self, s, dispw):
|
14
|
+
assert visidata.dispwidth(s) == dispw
|
15
|
+
|
16
|
+
@pytest.mark.parametrize('s, w, clippeds, clippedw', [
|
17
|
+
('b to', 4, 'b to', 4),
|
18
|
+
('abcde', 8, 'abcde', 5),
|
19
|
+
(' jsonl', 5, ' jso…', 5),
|
20
|
+
('abcdで', 6, 'abcdで', 6),
|
21
|
+
('abcdで', 5, 'abcd…', 5),
|
22
|
+
])
|
23
|
+
def test_clipstr(self, s, w, clippeds, clippedw):
|
24
|
+
clips, clipw = visidata.clipstr(s, w)
|
25
|
+
assert clips == clippeds
|
26
|
+
assert clipw == clippedw
|
27
|
+
|
28
|
+
def test_clipdraw_chunks(self):
|
29
|
+
prechunks = [
|
30
|
+
('', 'x'),
|
31
|
+
('', 'jsonl'),
|
32
|
+
]
|
33
|
+
scr = Mock()
|
34
|
+
scr.getmaxyx.return_value = (80,25)
|
35
|
+
visidata.clipdraw_chunks(scr, 0, 0, prechunks, visidata.ColorAttr(), w=5)
|
36
|
+
scr.addstr.assert_has_calls([
|
37
|
+
call(0, 0, 'x', 0),
|
38
|
+
call(0, 1, 'jso…', 0),
|
39
|
+
], any_order=True)
|
visidata/tests/test_commands.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
import pkg_resources
|
2
1
|
import pytest
|
3
2
|
from unittest.mock import Mock
|
4
3
|
|
5
4
|
import itertools
|
6
5
|
import visidata
|
6
|
+
from pathlib import Path
|
7
7
|
|
8
8
|
# test separately as needed
|
9
9
|
|
@@ -11,11 +11,22 @@ import visidata
|
|
11
11
|
# commands that require curses, and are not
|
12
12
|
# replayable
|
13
13
|
nonTested = (
|
14
|
+
'toggle-profile',
|
14
15
|
'syscopy',
|
15
16
|
'syspaste',
|
17
|
+
'open-syspaste',
|
16
18
|
'macro',
|
17
19
|
'mouse',
|
20
|
+
'add-subreddits',
|
21
|
+
'add-submissions',
|
22
|
+
'open-zulip',
|
18
23
|
'suspend',
|
24
|
+
'open-memstats', # TODO add testing support
|
25
|
+
'plot-column-ext',
|
26
|
+
'plot-numerics-ext',
|
27
|
+
'reload-every',
|
28
|
+
'reload-modified',
|
29
|
+
'reload-rows',
|
19
30
|
'breakpoint',
|
20
31
|
'redraw',
|
21
32
|
'menu',
|
@@ -36,38 +47,72 @@ inputLines = { 'save-sheet': 'jetsam.csv', # save to some tmp file
|
|
36
47
|
'save-col-keys': 'debris.csv',
|
37
48
|
'pyobj-expr': '2+2', # open the python object for '4'
|
38
49
|
'edit-cell': '3',
|
50
|
+
'search-keys': 'foo',
|
39
51
|
'search-col': 'foo',
|
40
52
|
'searchr-col': 'bar',
|
41
53
|
'select-col-regex': '.',
|
42
54
|
'select-cols-regex': '.',
|
43
55
|
'unselect-col-regex': '.',
|
56
|
+
'exec-python': 'import time',
|
44
57
|
'unselect-cols-regex': '.',
|
45
|
-
'edit-cell': '', # no change should not error
|
46
58
|
'go-col-regex': 'Units', # column name in sample
|
47
59
|
'go-col-number': '2',
|
48
60
|
'go-row-number': '5', # go to row 5
|
49
61
|
'addcol-bulk': '1',
|
50
62
|
'addcol-expr': 'Units', # just copy the column
|
63
|
+
'assert-expr': 'sheet.column(\"Units\")',
|
64
|
+
'show-command-info': 'select-row',
|
65
|
+
'assert-expr-row': 'Units',
|
51
66
|
'addcol-incr-step': '2',
|
52
67
|
'setcol-incr-step': '2',
|
68
|
+
'setcol-iter': 'range(1, 100)',
|
53
69
|
'setcol-format-enum': '1=cat',
|
54
|
-
'
|
70
|
+
'setcol-input': '5',
|
55
71
|
'show-expr': 'OrderDate',
|
56
72
|
'setcol-expr': 'OrderDate',
|
73
|
+
'open-ping': 'localhost',
|
57
74
|
'setcell-expr': 'OrderDate',
|
58
75
|
'setcol-range': 'range(100)',
|
59
76
|
'repeat-input-n': '1',
|
60
|
-
'
|
61
|
-
'addcol-subst': r'Units/(\w)/\1', # the first character
|
77
|
+
'addcol-regex-subst': dict(before=r'Units/(\w)', after=r'\1'), # the first character
|
62
78
|
'search-cols': 'foo',
|
63
79
|
'searchr-cols': 'bar',
|
64
80
|
'select-cols-regex': '.',
|
65
81
|
'select-expr': 'OrderDate',
|
82
|
+
'setcol-fake': 'name',
|
66
83
|
'unselect-expr': 'OrderDate',
|
67
84
|
'unselect-cols-regex': '.',
|
68
85
|
'random-rows': '3',
|
86
|
+
'select-random': '3',
|
69
87
|
'import-python': 'math',
|
70
88
|
'pyobj-expr-row': 'Units + "s"', # open the python object for '4'
|
89
|
+
'expand-col-depth': '0',
|
90
|
+
'contract-col-depth': '0',
|
91
|
+
'contract-cols-depth': '0',
|
92
|
+
'expand-cols-depth': '0',
|
93
|
+
'save-cmdlog': 'test_commands.vdj',
|
94
|
+
'aggregate-col': 'mean',
|
95
|
+
'memo-aggregate': 'mean',
|
96
|
+
'addcol-shell': '',
|
97
|
+
'theme-input': 'light',
|
98
|
+
'add-rows': '1',
|
99
|
+
'join-sheets-top2': 'append',
|
100
|
+
'join-sheets-all': 'append',
|
101
|
+
'resize-col-input': '10',
|
102
|
+
'resize-cols-input': '10',
|
103
|
+
'resize-height-input': '10',
|
104
|
+
'melt-regex': '(.*)_(.*)',
|
105
|
+
'addcol-split': '-',
|
106
|
+
'addcol-capture': '(.*)_(.*)',
|
107
|
+
'slide-left-n': '2',
|
108
|
+
'slide-right-n': '1',
|
109
|
+
'slide-down-n': '1',
|
110
|
+
'slide-up-n': '1',
|
111
|
+
'addcol-window': '0 2',
|
112
|
+
'select-around-n': '1',
|
113
|
+
'sheet': '',
|
114
|
+
'col': 'Units',
|
115
|
+
'row': '5',
|
71
116
|
}
|
72
117
|
|
73
118
|
@pytest.mark.usefixtures('curses_setup')
|
@@ -86,6 +131,9 @@ class TestCommands:
|
|
86
131
|
nerrs = 0
|
87
132
|
ntotal = 0
|
88
133
|
for longname in cmdlist.keys():
|
134
|
+
cmd = vs.getCommand(longname)
|
135
|
+
if cmd and cmd.deprecated:
|
136
|
+
continue
|
89
137
|
if not isTestableCommand(longname, cmdlist):
|
90
138
|
continue
|
91
139
|
ntotal += 1
|
@@ -102,6 +150,12 @@ class TestCommands:
|
|
102
150
|
if nerrs > 0:
|
103
151
|
assert False
|
104
152
|
|
153
|
+
# cleanup
|
154
|
+
for f in ['flotsam.csv', 'debris.csv', 'jetsam.csv', 'lagan.csv', 'test_commands.vdj']:
|
155
|
+
pf = Path(f)
|
156
|
+
if pf.exists: pf.unlink()
|
157
|
+
|
158
|
+
|
105
159
|
def runOneTest(self, mock_screen, longname):
|
106
160
|
visidata.vd.clearCaches() # we want vd to return a new VisiData object for each command
|
107
161
|
vd = visidata.vd
|
@@ -114,7 +168,7 @@ class TestCommands:
|
|
114
168
|
else:
|
115
169
|
vd.getkeystroke = Mock(side_effect=['^J'])
|
116
170
|
|
117
|
-
sample_file =
|
171
|
+
sample_file = vd.pkg_resources_files(visidata) / 'tests/sample.tsv'
|
118
172
|
vs = visidata.TsvSheet('test_commands', source=visidata.Path(sample_file))
|
119
173
|
vs.reload.__wrapped__(vs)
|
120
174
|
vs.vd = vd
|
@@ -122,4 +176,8 @@ class TestCommands:
|
|
122
176
|
vd.allSheets = [vs]
|
123
177
|
vs.mouseX, vs.mouseY = (4, 4)
|
124
178
|
vs.draw(mock_screen)
|
125
|
-
|
179
|
+
if longname in inputLines:
|
180
|
+
vd.currentReplayRow = vd.cmdlog.newRow(longname=longname, input=inputLines[longname])
|
181
|
+
else:
|
182
|
+
vd.currentReplayRow = vd.cmdlog.newRow(longname=longname)
|
183
|
+
vs.execCommand(longname, vdglobals=vd.getGlobals())
|
visidata/tests/test_edittext.py
CHANGED
@@ -48,7 +48,7 @@ class TestEditText:
|
|
48
48
|
exception = kwargs.pop('exception', None)
|
49
49
|
if exception:
|
50
50
|
with pytest.raises(exception):
|
51
|
-
visidata.vd.editline(mock_screen, 0, 0, 0, **kwargs)
|
51
|
+
visidata.vd.editline(mock_screen, 0, 0, 0, attr=visidata.ColorAttr(), **kwargs)
|
52
52
|
else:
|
53
|
-
r = visidata.vd.editline(mock_screen, 0, 0, 0, **kwargs)
|
53
|
+
r = visidata.vd.editline(mock_screen, 0, 0, 0, attr=visidata.ColorAttr(), **kwargs)
|
54
54
|
assert r == result
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import pytest
|
2
|
+
import visidata
|
3
|
+
|
4
|
+
def pytest_generate_tests(metafunc):
|
5
|
+
"""Split feature tests into separate test cases
|
6
|
+
|
7
|
+
Look up test methods in imported modules. Turn each one into a single test_feature()
|
8
|
+
case, with "module::method" as the test id.
|
9
|
+
"""
|
10
|
+
tests = [
|
11
|
+
(mod, getattr(mod, k))
|
12
|
+
for mod in visidata.vd.importedModules
|
13
|
+
for k in dir(mod)
|
14
|
+
if k.startswith("test_")
|
15
|
+
]
|
16
|
+
argvalues = [[testfunc] for _, testfunc in tests]
|
17
|
+
testids = [
|
18
|
+
f"{mod.__name__}::{testfunc.__name__}"
|
19
|
+
for mod, testfunc in tests
|
20
|
+
]
|
21
|
+
metafunc.parametrize(argnames=["testfunc"], argvalues=argvalues, ids=testids)
|
22
|
+
|
23
|
+
|
24
|
+
@pytest.mark.usefixtures("curses_setup")
|
25
|
+
def test_feature(mock_screen, testfunc):
|
26
|
+
visidata.vd.resetVisiData()
|
27
|
+
visidata.vd.scr = mock_screen
|
28
|
+
testfunc(visidata.vd)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
from visidata import vd, TableSheet
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
|
6
|
+
class TestMenu:
|
7
|
+
def test_menuitems(self):
|
8
|
+
vd.addMenuItems('''Column > Add column > foobar > hello-world''')
|
9
|
+
|
10
|
+
m = TableSheet().getMenuItem(['Column', 'Add column', 'foobar'])
|
11
|
+
assert m
|
12
|
+
|
13
|
+
with pytest.raises(AssertionError):
|
14
|
+
vd.addMenuItems('''Column > Add column > non-command''')
|
visidata/tests/test_path.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import io
|
1
2
|
import pytest
|
2
3
|
|
3
4
|
from visidata import Path
|
@@ -16,11 +17,19 @@ class TestVisidataPath:
|
|
16
17
|
assert "https://visidata.org/hello/b.tsv" == str(url_path.with_name('b.tsv')), '{} should be https://visidata.org/hello/b.tsv'.format(url_path.with_name('b.tsv'))
|
17
18
|
assert "https://visidata.org/hello/a/b.tsv" == str(url_path.with_name('a/b.tsv')), '{} should be https://visidata.org/hello/a/b.tsv'.format(url_path.with_name('a/b.tsv'))
|
18
19
|
|
19
|
-
assert Path('foo.a.b').
|
20
|
+
assert Path('foo.a.b').base_stem == 'foo.a'
|
20
21
|
assert Path('foo.a.b').ext == 'b'
|
21
22
|
assert Path('foo').ext == ''
|
22
|
-
assert Path('foo').
|
23
|
+
assert Path('foo').base_stem == 'foo'
|
23
24
|
assert Path('foo.').ext == ''
|
24
|
-
assert Path('foo.').
|
25
|
+
assert Path('foo.').base_stem == 'foo.'
|
25
26
|
assert Path('.foo').ext == ''
|
26
|
-
assert Path('.foo').
|
27
|
+
assert Path('.foo').base_stem == '.foo'
|
28
|
+
|
29
|
+
|
30
|
+
def test_opentwice(self):
|
31
|
+
'fresh iterator for each open'
|
32
|
+
p = Path('test', fptext=io.StringIO('<html>'))
|
33
|
+
a = next(p.open())
|
34
|
+
b = next(p.open())
|
35
|
+
assert a == b
|
visidata/text_source.py
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
import re
|
2
|
+
|
3
|
+
from visidata import vd, BaseSheet
|
4
|
+
|
5
|
+
vd.option('regex_skip', '', 'regex of lines to skip in text sources', help='regex')
|
6
|
+
vd.option('regex_flags', 'I', 'flags to pass to re.compile() [AILMSUX]', replay=True)
|
7
|
+
|
8
|
+
@BaseSheet.api
|
9
|
+
def regex_flags(sheet):
|
10
|
+
'Return flags to pass to regex functions from options'
|
11
|
+
return sum(getattr(re, f.upper()) for f in sheet.options.regex_flags)
|
12
|
+
|
13
|
+
|
14
|
+
class FilterFile:
|
15
|
+
def __init__(self, fp, regex:str, regex_flags:int=0):
|
16
|
+
import re
|
17
|
+
self._fp = fp
|
18
|
+
self._regex_skip = re.compile(regex, regex_flags)
|
19
|
+
|
20
|
+
def readline(self) -> str:
|
21
|
+
while True:
|
22
|
+
line = self._fp.readline()
|
23
|
+
if self._regex_skip.match(line):
|
24
|
+
continue
|
25
|
+
return line
|
26
|
+
|
27
|
+
def __getattr__(self, k):
|
28
|
+
return getattr(self._fp, k)
|
29
|
+
|
30
|
+
def __iter__(self):
|
31
|
+
return self
|
32
|
+
|
33
|
+
def __next__(self):
|
34
|
+
line = self.readline()
|
35
|
+
if not line:
|
36
|
+
raise StopIteration
|
37
|
+
return line
|
38
|
+
|
39
|
+
def __enter__(self):
|
40
|
+
return self
|
41
|
+
|
42
|
+
def __exit__(self, *args, **kwargs):
|
43
|
+
return self._fp.__exit__(*args, **kwargs)
|
44
|
+
|
45
|
+
|
46
|
+
@BaseSheet.api
|
47
|
+
def open_text_source(sheet):
|
48
|
+
'Open sheet source as text, using sheet options for encoding and regex_skip.'
|
49
|
+
fp = sheet.source.open(encoding=sheet.options.encoding, encoding_errors=sheet.options.encoding_errors)
|
50
|
+
regex_skip = sheet.options.regex_skip
|
51
|
+
if regex_skip:
|
52
|
+
return FilterFile(fp, regex_skip, sheet.regex_flags())
|
53
|
+
return fp
|
visidata/textsheet.py
CHANGED
@@ -6,7 +6,7 @@ from visidata import globalCommand, VisiData
|
|
6
6
|
import visidata
|
7
7
|
|
8
8
|
|
9
|
-
vd.option('wrap', False, 'wrap text to fit window width on TextSheet')
|
9
|
+
vd.option('wrap', False, 'wrap text to fit window width on TextSheet', max_help=0)
|
10
10
|
vd.option('save_filetype', 'tsv', 'specify default file type to save as', replay=True)
|
11
11
|
|
12
12
|
|
@@ -32,7 +32,7 @@ class TextSheet(Sheet):
|
|
32
32
|
for i, L in enumerate(textwrap.wrap(str(text), width=winWidth)):
|
33
33
|
yield [startingLine+i+1, L]
|
34
34
|
else:
|
35
|
-
yield [startingLine+1, text]
|
35
|
+
yield [startingLine+1, text.strip()]
|
36
36
|
|
37
37
|
def sysopen(sheet, linenum=0):
|
38
38
|
@asyncthread
|
@@ -44,6 +44,7 @@ class TextSheet(Sheet):
|
|
44
44
|
|
45
45
|
import tempfile
|
46
46
|
with tempfile.NamedTemporaryFile() as temp:
|
47
|
+
temp.close() #2118
|
47
48
|
writelines(sheet, temp.name)
|
48
49
|
vd.launchEditor(temp.name, '+%s' % linenum)
|
49
50
|
sheet.rows = []
|
@@ -82,7 +83,7 @@ def recentErrorsSheet(self):
|
|
82
83
|
BaseSheet.addCommand('^E', 'error-recent', 'vd.lastErrors and vd.push(recentErrorsSheet) or status("no error")', 'view traceback for most recent error')
|
83
84
|
BaseSheet.addCommand('g^E', 'errors-all', 'vd.push(vd.allErrorsSheet)', 'view traceback for most recent errors')
|
84
85
|
|
85
|
-
Sheet.addCommand(None, 'view-cell', 'vd.push(ErrorSheet("%s[%s].%s" % (name, cursorRowIndex, cursorCol.name), sourceSheet=sheet, source=cursorDisplay.splitlines()))', 'view contents of current cell in a new sheet')
|
86
|
+
Sheet.addCommand(None, 'view-cell', 'vd.push(ErrorSheet("%s[%s].%s" % (name, cursorRowIndex, cursorCol.name), sourceSheet=sheet, source=cursorDisplay.splitlines()))', 'view contents of current cell in a new sheet')
|
86
87
|
Sheet.addCommand('z^E', 'error-cell', 'vd.push(ErrorSheet(sheet.name+"_cell_error", sourceSheet=sheet, source=getattr(cursorCell, "error", None) or fail("no error this cell")))', 'view traceback for error in current cell')
|
87
88
|
|
88
89
|
TextSheet.addCommand('^O', 'sysopen-sheet', 'sheet.sysopen(sheet.cursorRowIndex)', 'open copy of text sheet in $EDITOR and reload on exit')
|
@@ -91,3 +92,9 @@ TextSheet.addCommand('^O', 'sysopen-sheet', 'sheet.sysopen(sheet.cursorRowIndex)
|
|
91
92
|
TextSheet.options.save_filetype = 'txt'
|
92
93
|
|
93
94
|
vd.addGlobals({'TextSheet': TextSheet, 'ErrorSheet': ErrorSheet})
|
95
|
+
|
96
|
+
vd.addMenuItems('''
|
97
|
+
View > Errors > recent > error-recent
|
98
|
+
View > Errors > all > errors-all
|
99
|
+
View > Errors > in cell > error-cell
|
100
|
+
''')
|
visidata/theme.py
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
'Switch between packaged themes (colors and display characters)'
|
2
|
+
|
3
|
+
from visidata import vd, VisiData, Sheet, BaseSheet
|
4
|
+
|
5
|
+
|
6
|
+
vd.option('theme', '', 'display/color theme to use')
|
7
|
+
|
8
|
+
vd.themes = {}
|
9
|
+
|
10
|
+
|
11
|
+
@VisiData.before
|
12
|
+
def run(vd, *args, **kwargs):
|
13
|
+
t = vd.options.theme
|
14
|
+
if t:
|
15
|
+
vd.set_theme(t)
|
16
|
+
|
17
|
+
|
18
|
+
@Sheet.api
|
19
|
+
@VisiData.api
|
20
|
+
def set_theme(obj, theme=''):
|
21
|
+
if theme and theme not in vd.themes:
|
22
|
+
vd.warning(f'no "{theme}" theme available')
|
23
|
+
return
|
24
|
+
|
25
|
+
# unset everything first
|
26
|
+
for k in vd.options.keys():
|
27
|
+
if k.startswith(tuple('color_ disp_ note_'.split())):
|
28
|
+
obj.options.unset(k)
|
29
|
+
|
30
|
+
if not theme:
|
31
|
+
return
|
32
|
+
|
33
|
+
if isinstance(theme, str):
|
34
|
+
theme = vd.themes[theme]
|
35
|
+
|
36
|
+
for k, v in theme.items():
|
37
|
+
obj.options[k] = v
|
38
|
+
|
39
|
+
|
40
|
+
BaseSheet.addCommand('', 'theme-input', 'vd.set_theme(chooseOne([dict(key=k) for k in themes.keys()], type="theme"))', 'choose from available themes')
|
41
|
+
BaseSheet.addCommand('', 'theme-default', 'vd.set_theme()', 'reset theme to VisiData defaults')
|
42
|
+
|
43
|
+
vd.addMenuItem('View', 'Set theme', 'choose', 'theme-input')
|
44
|
+
vd.addMenuItem('View', 'Set theme', 'default', 'theme-default')
|
File without changes
|
@@ -0,0 +1,84 @@
|
|
1
|
+
'ASCII theme using the first 8 colors'
|
2
|
+
|
3
|
+
from visidata import vd
|
4
|
+
|
5
|
+
|
6
|
+
vd.themes['ascii8'] = dict(
|
7
|
+
disp_note_none='',
|
8
|
+
disp_truncator='>',
|
9
|
+
disp_oddspace='.',
|
10
|
+
disp_more_left='<',
|
11
|
+
disp_more_right='>',
|
12
|
+
disp_error_val='',
|
13
|
+
disp_ambig_width=1,
|
14
|
+
|
15
|
+
disp_pending='',
|
16
|
+
note_pending=':',
|
17
|
+
note_format_exc='?',
|
18
|
+
note_getter_exc='!',
|
19
|
+
note_type_exc='!',
|
20
|
+
|
21
|
+
color_note_pending='bold magenta',
|
22
|
+
color_note_type='yellow',
|
23
|
+
color_note_row='yellow',
|
24
|
+
|
25
|
+
disp_column_sep='|',
|
26
|
+
disp_keycol_sep='|',
|
27
|
+
disp_rowtop_sep='|',
|
28
|
+
disp_rowmid_sep='|',
|
29
|
+
disp_rowbot_sep='|',
|
30
|
+
disp_rowend_sep='|',
|
31
|
+
disp_keytop_sep='|',
|
32
|
+
disp_keymid_sep='|',
|
33
|
+
disp_keybot_sep='|',
|
34
|
+
disp_endtop_sep='|',
|
35
|
+
disp_endmid_sep='|',
|
36
|
+
disp_endbot_sep='|',
|
37
|
+
disp_selected_note='+',
|
38
|
+
disp_sort_asc='^^^^^^',
|
39
|
+
disp_sort_desc='vvvvvv',
|
40
|
+
color_default='white on black',
|
41
|
+
color_default_hdr='bold',
|
42
|
+
color_bottom_hdr='underline',
|
43
|
+
color_current_row='reverse',
|
44
|
+
color_current_col='bold',
|
45
|
+
color_current_hdr='bold reverse',
|
46
|
+
color_column_sep='blue',
|
47
|
+
color_key_col='cyan',
|
48
|
+
color_hidden_col='8',
|
49
|
+
color_selected_row='yellow',
|
50
|
+
color_edit_cell='white',
|
51
|
+
color_graph_hidden='blue',
|
52
|
+
color_graph_selected='bold',
|
53
|
+
color_status_replay='green',
|
54
|
+
|
55
|
+
color_graph_axis='bold',
|
56
|
+
color_sidebar='black on blue',
|
57
|
+
color_add_pending='green',
|
58
|
+
color_change_pending='reverse yellow',
|
59
|
+
color_delete_pending='red',
|
60
|
+
disp_rstatus_fmt=' {sheet.longname} {sheet.nRows:9d} {sheet.rowtype} {sheet.modifiedStatus} {sheet.options.disp_selected_note}{sheet.nSelectedRows}',
|
61
|
+
disp_status_fmt='{sheet.shortcut}> {sheet.name}| ',
|
62
|
+
disp_lstatus_max=0,
|
63
|
+
disp_status_sep=' | ',
|
64
|
+
color_keystrokes='bold black on cyan',
|
65
|
+
color_status='bold black on cyan',
|
66
|
+
color_error='red',
|
67
|
+
color_warning='yellow',
|
68
|
+
color_top_status='underline',
|
69
|
+
color_active_status='black on cyan',
|
70
|
+
color_inactive_status='8 on black',
|
71
|
+
color_working='green',
|
72
|
+
|
73
|
+
color_menu='black on cyan',
|
74
|
+
color_menu_active='yellow on black',
|
75
|
+
color_menu_spec='black on green',
|
76
|
+
color_menu_help='black on cyan',
|
77
|
+
disp_menu_boxchars='||-- ||',
|
78
|
+
disp_menu_more='>',
|
79
|
+
disp_menu_push='+',
|
80
|
+
disp_menu_input='_',
|
81
|
+
disp_menu_fmt='7-bit ASCII 3-bit color',
|
82
|
+
plot_colors = 'white',
|
83
|
+
disp_histogram='*'
|
84
|
+
)
|