visidata 2.11.dev0__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 +263 -44
- visidata/_open.py +84 -29
- visidata/_types.py +22 -4
- 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
- visidata/apps/vgit/__main__.py +3 -0
- visidata/apps/vgit/abort.py +23 -0
- visidata/apps/vgit/blame.py +76 -0
- visidata/apps/vgit/branch.py +153 -0
- visidata/apps/vgit/config.py +95 -0
- visidata/apps/vgit/diff.py +169 -0
- visidata/apps/vgit/gitsheet.py +161 -0
- visidata/apps/vgit/grep.py +37 -0
- visidata/apps/vgit/log.py +81 -0
- visidata/apps/vgit/main.py +55 -0
- visidata/apps/vgit/remote.py +57 -0
- visidata/apps/vgit/repos.py +71 -0
- visidata/apps/vgit/setup.py +37 -0
- visidata/apps/vgit/stash.py +69 -0
- visidata/apps/vgit/status.py +204 -0
- visidata/apps/vgit/statusbar.py +34 -0
- visidata/basesheet.py +59 -50
- visidata/canvas.py +251 -99
- visidata/choose.py +15 -11
- visidata/clean_names.py +29 -0
- visidata/clipboard.py +84 -18
- visidata/cliptext.py +220 -46
- visidata/cmdlog.py +89 -114
- visidata/color.py +142 -56
- visidata/column.py +134 -131
- 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 +32 -6
- 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} +4 -2
- 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} +33 -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 +3 -5
- 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/macos.py +1 -1
- visidata/macros.py +130 -41
- visidata/main.py +119 -94
- visidata/mainloop.py +101 -154
- visidata/man/parse_options.py +2 -2
- visidata/man/vd.1 +302 -147
- visidata/man/vd.txt +291 -151
- visidata/memory.py +3 -3
- visidata/menu.py +104 -423
- visidata/metasheets.py +59 -141
- visidata/modify.py +79 -23
- visidata/motd.py +3 -3
- visidata/mouse.py +137 -0
- visidata/movement.py +43 -35
- visidata/optionssheet.py +99 -0
- visidata/path.py +131 -43
- visidata/pivot.py +74 -47
- visidata/plugins.py +65 -192
- visidata/pyobj.py +50 -201
- visidata/rename_col.py +20 -0
- visidata/save.py +42 -20
- visidata/search.py +54 -10
- visidata/selection.py +84 -5
- visidata/settings.py +162 -24
- 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 +18 -6
- 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.dev0.data → visidata-3.0.data}/data/share/man/man1/vd.1 +302 -147
- {visidata-2.11.dev0.data → visidata-3.0.data}/data/share/man/man1/visidata.1 +302 -147
- visidata-3.0.data/scripts/vd2to3.vdx +9 -0
- {visidata-2.11.dev0.dist-info → visidata-3.0.dist-info}/METADATA +13 -11
- visidata-3.0.dist-info/RECORD +257 -0
- {visidata-2.11.dev0.dist-info → visidata-3.0.dist-info}/WHEEL +1 -1
- {visidata-2.11.dev0.dist-info → visidata-3.0.dist-info}/entry_points.txt +0 -1
- visidata/layout.py +0 -44
- visidata/misc.py +0 -5
- visidata-2.11.dev0.dist-info/RECORD +0 -142
- /visidata/{repeat.py → features/repeat.py} +0 -0
- {visidata-2.11.dev0.data → visidata-3.0.data}/scripts/vd +0 -0
- {visidata-2.11.dev0.dist-info → visidata-3.0.dist-info}/LICENSE.gpl3 +0 -0
- {visidata-2.11.dev0.dist-info → visidata-3.0.dist-info}/top_level.txt +0 -0
visidata/mainloop.py
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
+
import builtins
|
1
2
|
import contextlib
|
2
3
|
import os
|
3
4
|
import curses
|
4
5
|
import signal
|
5
6
|
import threading
|
6
7
|
import time
|
7
|
-
from unittest import mock
|
8
8
|
|
9
|
-
from visidata import vd, VisiData, colors, ESC, options,
|
9
|
+
from visidata import vd, VisiData, colors, ESC, options, BaseSheet, AttrDict
|
10
10
|
|
11
11
|
__all__ = ['ReturnValue', 'run']
|
12
12
|
|
@@ -15,73 +15,43 @@ vd.timeouts_before_idle = 10
|
|
15
15
|
vd.min_draw_ms = 100 # draw_all at least this often, even if keystrokes are pending
|
16
16
|
vd._lastDrawTime = 0 # last time drawn (from time.time())
|
17
17
|
|
18
|
-
vd.option('disp_splitwin_pct', 0, 'height of second sheet on screen')
|
19
|
-
vd.option('mouse_interval', 1, 'max time between press/release for click (ms)', sheettype=None)
|
20
|
-
vd.option('color_sidebar', 'black on 114 blue', 'color of sidebar')
|
21
|
-
|
22
18
|
|
23
19
|
class ReturnValue(BaseException):
|
24
20
|
'raise ReturnValue(ret) to exit from an inner runresult() with its result.'
|
25
21
|
pass
|
26
22
|
|
27
23
|
|
28
|
-
|
29
24
|
@VisiData.api
|
30
|
-
def
|
31
|
-
'
|
32
|
-
|
33
|
-
sheet.ensureLoaded()
|
34
|
-
|
35
|
-
scr.erase() # clear screen before every re-draw
|
36
|
-
scr.bkgd(' ', colors.color_default)
|
37
|
-
|
38
|
-
sheet._scr = scr
|
39
|
-
|
40
|
-
self.drawLeftStatus(scr, sheet)
|
41
|
-
self.drawRightStatus(scr, sheet) # visible during this getkeystroke
|
42
|
-
|
43
|
-
try:
|
44
|
-
sheet.draw(scr)
|
45
|
-
except Exception as e:
|
46
|
-
self.exceptionCaught(e)
|
47
|
-
|
25
|
+
def callNoExceptions(vd, func, *args, **kwargs):
|
26
|
+
'Catch and log any raised exceptions. Reraise when options.debug.'
|
48
27
|
try:
|
49
|
-
|
50
|
-
sidebar_title = sheet.sidebar_title
|
28
|
+
return func(*args, **kwargs)
|
51
29
|
except Exception as e:
|
52
30
|
vd.exceptionCaught(e)
|
53
|
-
sidebar = str(e)
|
54
|
-
sidebar_title = 'error'
|
55
|
-
|
56
|
-
vd.drawSidebar(scr, sidebar, title=sidebar_title)
|
57
|
-
|
58
|
-
|
59
|
-
def iterwraplines(lines, width=80):
|
60
|
-
import textwrap
|
61
|
-
for line in lines:
|
62
|
-
yield from textwrap.wrap(line, width=width, subsequent_indent=' ')
|
63
31
|
|
64
32
|
|
65
33
|
@VisiData.api
|
66
|
-
def
|
67
|
-
|
68
|
-
return
|
34
|
+
def drawSheet(vd, scr, sheet):
|
35
|
+
'Erase *scr* and draw *sheet* on it, including status bars and sidebar.'
|
69
36
|
|
70
|
-
|
71
|
-
maxh, maxw = 0, 0
|
37
|
+
sheet.ensureLoaded()
|
72
38
|
|
73
|
-
|
39
|
+
scr.erase() # clear screen before every re-draw
|
40
|
+
scr.bkgd(' ', colors.color_default.attr)
|
74
41
|
|
75
|
-
|
76
|
-
maxw = min(w//2, max(map(len, lines))+4)
|
42
|
+
sheet._scr = scr
|
77
43
|
|
78
|
-
|
79
|
-
|
44
|
+
vd.callNoExceptions(sheet.draw, scr)
|
45
|
+
vd.callNoExceptions(vd.drawLeftStatus, scr, sheet)
|
46
|
+
vd.callNoExceptions(vd.drawRightStatus, scr, sheet) # visible during this getkeystroke
|
80
47
|
|
81
48
|
|
82
49
|
vd.windowConfig = dict(pct=0, n=0, h=0, w=0) # n=top line of bottom window; h=height of bottom window; w=width of screen
|
83
|
-
|
84
|
-
vd.
|
50
|
+
|
51
|
+
vd.winTop = None
|
52
|
+
vd.scrMenu = None
|
53
|
+
vd.scrFull = None
|
54
|
+
|
85
55
|
|
86
56
|
@VisiData.api
|
87
57
|
def setWindows(vd, scr, pct=None):
|
@@ -105,17 +75,17 @@ def setWindows(vd, scr, pct=None):
|
|
105
75
|
if not topmenulines:
|
106
76
|
vd.scrMenu = None
|
107
77
|
elif not vd.scrMenu:
|
108
|
-
vd.scrMenu =
|
78
|
+
vd.scrMenu = vd.subwindow(scr, 0, 0, w, h)
|
109
79
|
vd.scrMenu.keypad(1)
|
110
80
|
|
111
|
-
vd.winTop =
|
81
|
+
vd.winTop = vd.subwindow(scr, 0, topmenulines, w, n)
|
112
82
|
vd.winTop.keypad(1)
|
113
|
-
vd.winBottom =
|
83
|
+
vd.winBottom = vd.subwindow(scr, 0, n+topmenulines, w, h-n-topmenulines)
|
114
84
|
vd.winBottom.keypad(1)
|
115
85
|
if pct == 0 or pct >= 100: # no second pane
|
116
86
|
vd.win1 = vd.winBottom
|
117
87
|
# drawing to 0-line window causes problems
|
118
|
-
vd.win2 =
|
88
|
+
vd.win2 = None
|
119
89
|
elif pct > 0: # pane 2 from line n to bottom
|
120
90
|
vd.win1 = vd.winTop
|
121
91
|
vd.win2 = vd.winBottom
|
@@ -141,24 +111,26 @@ def draw_all(vd):
|
|
141
111
|
if ss1 and not ss2:
|
142
112
|
vd.activePane = 1
|
143
113
|
vd.setWindows(vd.scrFull)
|
144
|
-
vd.
|
114
|
+
vd.drawSheet(vd.win1, ss1[0])
|
145
115
|
if vd.win2:
|
146
116
|
vd.win2.erase()
|
147
117
|
elif not ss1 and ss2:
|
148
118
|
vd.activePane = 2
|
149
119
|
vd.setWindows(vd.scrFull)
|
150
|
-
vd.
|
120
|
+
vd.drawSheet(vd.win2, ss2[0])
|
151
121
|
if vd.win1:
|
152
122
|
vd.win1.erase()
|
153
123
|
elif ss1 and ss2 and vd.win2:
|
154
|
-
vd.
|
155
|
-
vd.
|
124
|
+
vd.drawSheet(vd.win1, ss1[0])
|
125
|
+
vd.drawSheet(vd.win2, ss2[0])
|
156
126
|
elif ss1 and ss2 and not vd.win2:
|
157
|
-
vd.
|
127
|
+
vd.drawSheet(vd.win1, vd.sheetstack(vd.activePane)[0])
|
158
128
|
vd.setWindows(vd.scrFull)
|
159
129
|
|
160
130
|
if vd.scrMenu:
|
161
|
-
vd.
|
131
|
+
vd.callNoExceptions(vd.drawMenu, vd.scrMenu, vd.activeSheet)
|
132
|
+
|
133
|
+
vd.callNoExceptions(vd.drawSidebar, vd.scrFull, vd.activeSheet)
|
162
134
|
|
163
135
|
if vd.win1:
|
164
136
|
vd.win1.refresh()
|
@@ -179,37 +151,7 @@ def runresult(vd):
|
|
179
151
|
|
180
152
|
|
181
153
|
@VisiData.api
|
182
|
-
def
|
183
|
-
'Return list of mouse interactions (clicktype, y, x, name, scr) for curses screens given in kwargs as name:scr.'
|
184
|
-
|
185
|
-
devid, x, y, z, bstate = curses.getmouse()
|
186
|
-
|
187
|
-
clicktype = ''
|
188
|
-
if bstate & curses.BUTTON_CTRL:
|
189
|
-
clicktype += "CTRL-"
|
190
|
-
bstate &= ~curses.BUTTON_CTRL
|
191
|
-
if bstate & curses.BUTTON_ALT:
|
192
|
-
clicktype += "ALT-"
|
193
|
-
bstate &= ~curses.BUTTON_ALT
|
194
|
-
if bstate & curses.BUTTON_SHIFT:
|
195
|
-
clicktype += "SHIFT-"
|
196
|
-
bstate &= ~curses.BUTTON_SHIFT
|
197
|
-
|
198
|
-
keystroke = clicktype + curses.mouseEvents.get(bstate, str(bstate))
|
199
|
-
|
200
|
-
found = []
|
201
|
-
for winname, winscr in kwargs.items():
|
202
|
-
py, px = winscr.getparyx()
|
203
|
-
mh, mw = winscr.getmaxyx()
|
204
|
-
if py <= y < py+mh and px <= x < px+mw:
|
205
|
-
found.append((keystroke, y-py, x-px, winname, winscr))
|
206
|
-
# vd.debug(f'{keystroke} at ({x-px}, {y-py}) in window {winname} {winscr}')
|
207
|
-
|
208
|
-
return found
|
209
|
-
|
210
|
-
|
211
|
-
@VisiData.api
|
212
|
-
def mainloop(self, scr):
|
154
|
+
def mainloop(vd, scr):
|
213
155
|
'Manage execution of keystrokes and subsequent redrawing of screen.'
|
214
156
|
nonidle_timeout = vd.curses_timeout
|
215
157
|
|
@@ -221,12 +163,12 @@ def mainloop(self, scr):
|
|
221
163
|
prefixWaiting = False
|
222
164
|
vd.scrFull = scr
|
223
165
|
|
224
|
-
|
166
|
+
vd.keystrokes = ''
|
225
167
|
while True:
|
226
|
-
if not
|
168
|
+
if not vd.stackedSheets and vd.currentReplay is None:
|
227
169
|
return
|
228
170
|
|
229
|
-
sheet =
|
171
|
+
sheet = vd.activeSheet
|
230
172
|
|
231
173
|
if not sheet:
|
232
174
|
continue # waiting for replay to push sheet
|
@@ -236,82 +178,76 @@ def mainloop(self, scr):
|
|
236
178
|
|
237
179
|
vd.setWindows(vd.scrFull)
|
238
180
|
|
239
|
-
if not
|
240
|
-
|
241
|
-
|
181
|
+
if not vd.drainPendingKeys(scr) or time.time() - vd._lastDrawTime > vd.min_draw_ms/1000: #1459
|
182
|
+
vd.draw_all()
|
183
|
+
vd._lastDrawTime = time.time()
|
242
184
|
|
243
|
-
|
244
|
-
sheet.execCommand(vd._nextCommands.pop(0), keystrokes=self.keystrokes)
|
245
|
-
continue
|
246
|
-
|
247
|
-
keystroke = self.getkeystroke(scr, sheet)
|
185
|
+
keystroke = vd.getkeystroke(scr, sheet)
|
248
186
|
|
249
|
-
if not keystroke and prefixWaiting and "Alt+" in
|
250
|
-
|
187
|
+
if not keystroke and prefixWaiting and "Alt+" in vd.keystrokes: # timeout ESC
|
188
|
+
vd.keystrokes = ''
|
251
189
|
|
252
190
|
if keystroke: # wait until next keystroke to clear statuses and previous keystrokes
|
253
191
|
numTimeouts = 0
|
254
192
|
if not prefixWaiting:
|
255
|
-
|
193
|
+
vd.keystrokes = ''
|
256
194
|
|
257
|
-
|
195
|
+
vd.statuses.clear()
|
258
196
|
|
259
197
|
if keystroke == 'KEY_MOUSE':
|
260
198
|
try:
|
261
|
-
|
262
|
-
pct = vd.windowConfig['pct']
|
263
|
-
topPaneActive = ((vd.activePane == 2 and pct < 0) or (vd.activePane == 1 and pct > 0))
|
264
|
-
bottomPaneActive = ((vd.activePane == 1 and pct < 0) or (vd.activePane == 2 and pct > 0))
|
265
|
-
|
266
|
-
if (bottomPaneActive and winname == 'top') or (topPaneActive and winname == 'bot'):
|
267
|
-
self.activePane = 1 if self.activePane == 2 else 2
|
268
|
-
sheet = self.activeSheet
|
269
|
-
|
270
|
-
for keystroke, y, x, winname, winscr in vd.parseMouse(top=vd.winTop, bot=vd.winBottom, menu=vd.scrMenu):
|
271
|
-
f = self.getMouse(winscr, x, y, keystroke)
|
272
|
-
sheet.mouseX, sheet.mouseY = x, y
|
273
|
-
if f:
|
274
|
-
if isinstance(f, str):
|
275
|
-
for cmd in f.split():
|
276
|
-
sheet.execCommand(cmd)
|
277
|
-
else:
|
278
|
-
f(y, x, keystroke)
|
279
|
-
|
280
|
-
self.keystrokes = self.prettykeys(keystroke)
|
281
|
-
keystroke = '' # already handled
|
282
|
-
break # first successful command stops checking
|
283
|
-
except curses.error:
|
284
|
-
pass
|
199
|
+
keystroke = vd.handleMouse(sheet) # if it was handled, don't handle again as a regular keystroke
|
285
200
|
except Exception as e:
|
286
|
-
|
201
|
+
vd.exceptionCaught(e)
|
287
202
|
|
288
|
-
if keystroke and keystroke in
|
203
|
+
if keystroke and keystroke in vd.allPrefixes and keystroke in vd.keystrokes[:-1]:
|
289
204
|
vd.warning('duplicate prefix: ' + keystroke)
|
290
|
-
|
205
|
+
vd.keystrokes = ''
|
291
206
|
else:
|
292
|
-
|
207
|
+
keystroke = vd.prettykeys(keystroke)
|
208
|
+
vd.keystrokes += keystroke
|
293
209
|
|
294
|
-
|
210
|
+
vd.drawRightStatus(sheet._scr, sheet) # visible for commands that wait for input
|
295
211
|
|
296
212
|
if not keystroke: # timeout instead of keypress
|
297
213
|
pass
|
298
|
-
elif keystroke == '
|
299
|
-
return
|
300
|
-
elif vd.bindkeys._get(
|
301
|
-
sheet.execCommand(
|
214
|
+
elif keystroke == 'Ctrl+Q':
|
215
|
+
return vd.lastErrors and '\n'.join(vd.lastErrors[-1])
|
216
|
+
elif vd.bindkeys._get(vd.keystrokes):
|
217
|
+
sheet.execCommand(vd.keystrokes, keystrokes=vd.keystrokes)
|
302
218
|
prefixWaiting = False
|
303
|
-
elif keystroke in
|
219
|
+
elif keystroke in vd.allPrefixes:
|
304
220
|
prefixWaiting = True
|
305
221
|
else:
|
306
|
-
vd.status('no command for "%s"' % (
|
222
|
+
vd.status('no command for "%s"' % (vd.keystrokes))
|
307
223
|
prefixWaiting = False
|
308
224
|
|
309
|
-
|
310
|
-
|
225
|
+
# play next queued command
|
226
|
+
if vd._nextCommands and not vd.unfinishedThreads:
|
227
|
+
cmd = vd._nextCommands.pop(0)
|
228
|
+
if isinstance(cmd, (dict, list)): # .vd cmdlog rows are NamedListTemplate
|
229
|
+
try:
|
230
|
+
if vd.replayOne(cmd):
|
231
|
+
vd.replay_cancel()
|
232
|
+
except Exception as e:
|
233
|
+
vd.exceptionCaught(e)
|
234
|
+
vd.replay_cancel()
|
235
|
+
else:
|
236
|
+
sheet.execCommand(cmd, keystrokes=vd.keystrokes)
|
237
|
+
|
238
|
+
if not vd._nextCommands:
|
239
|
+
if vd.currentReplay:
|
240
|
+
vd.currentReplayRow = None
|
241
|
+
vd.currentReplay = None
|
242
|
+
|
243
|
+
vd.checkForFinishedThreads()
|
244
|
+
vd.callNoExceptions(sheet.checkCursor)
|
311
245
|
|
312
246
|
# no idle redraw unless background threads are running
|
313
247
|
time.sleep(0) # yield to other threads which may not have started yet
|
314
|
-
if vd.
|
248
|
+
if vd._nextCommands:
|
249
|
+
vd.curses_timeout = int(vd.options.replay_wait*1000)
|
250
|
+
elif vd.unfinishedThreads:
|
315
251
|
vd.curses_timeout = nonidle_timeout
|
316
252
|
else:
|
317
253
|
numTimeouts += 1
|
@@ -323,7 +259,8 @@ def mainloop(self, scr):
|
|
323
259
|
scr.timeout(vd.curses_timeout)
|
324
260
|
|
325
261
|
|
326
|
-
|
262
|
+
@VisiData.api
|
263
|
+
def initCurses(vd):
|
327
264
|
# reduce ESC timeout to 25ms. http://en.chys.info/2009/09/esdelay-ncurses/
|
328
265
|
os.putenv('ESCDELAY', '25')
|
329
266
|
curses.use_env(True)
|
@@ -338,25 +275,23 @@ def initCurses():
|
|
338
275
|
|
339
276
|
curses.raw() # get control keys instead of signals
|
340
277
|
curses.meta(1) # allow "8-bit chars"
|
341
|
-
curses.MOUSE_ALL = 0xffffffff
|
342
|
-
curses.mousemask(curses.MOUSE_ALL if options.mouse_interval else 0)
|
343
|
-
curses.mouseinterval(options.mouse_interval)
|
344
|
-
curses.mouseEvents = {}
|
345
278
|
|
346
279
|
scr.keypad(1)
|
347
280
|
|
348
281
|
curses.def_prog_mode()
|
349
282
|
|
350
|
-
|
351
|
-
|
352
|
-
|
283
|
+
vd.drainPendingKeys(scr)
|
284
|
+
if '\x1b' in vd.pendingKeys: #1993
|
285
|
+
# if start of an ANSI escape sequence, might be mangled, discard remaining keystrokes
|
286
|
+
vd.pendingKeys.clear()
|
287
|
+
curses.flushinp()
|
353
288
|
|
354
289
|
return scr
|
355
290
|
|
356
291
|
|
357
292
|
def wrapper(f, *args, **kwargs):
|
358
293
|
try:
|
359
|
-
scr = initCurses()
|
294
|
+
scr = vd.initCurses()
|
360
295
|
return f(scr, *args, **kwargs)
|
361
296
|
finally:
|
362
297
|
curses.endwin()
|
@@ -372,9 +307,11 @@ def run(vd, *sheetlist):
|
|
372
307
|
for vs in sheetlist:
|
373
308
|
vd.push(vs, load=False)
|
374
309
|
|
375
|
-
scr = initCurses()
|
310
|
+
scr = vd.initCurses()
|
376
311
|
ret = vd.mainloop(scr)
|
377
312
|
except curses.error as e:
|
313
|
+
if vd.options.debug:
|
314
|
+
raise
|
378
315
|
vd.fail(str(e))
|
379
316
|
finally:
|
380
317
|
if scr:
|
@@ -383,4 +320,14 @@ def run(vd, *sheetlist):
|
|
383
320
|
vd.cancelThread(*[t for t in vd.unfinishedThreads if not t.name.startswith('save_')])
|
384
321
|
|
385
322
|
if ret:
|
386
|
-
|
323
|
+
builtins.print(ret)
|
324
|
+
|
325
|
+
return ret
|
326
|
+
|
327
|
+
@VisiData.api
|
328
|
+
def addCommand(vd, *args, **kwargs):
|
329
|
+
return BaseSheet.addCommand(*args, **kwargs)
|
330
|
+
|
331
|
+
|
332
|
+
import sys
|
333
|
+
vd.addGlobals({k:getattr(sys.modules[__name__], k) for k in __all__})
|
visidata/man/parse_options.py
CHANGED
@@ -23,8 +23,8 @@ options_menu_skel = '''.It Sy "{optname:<19}" No "{default}"
|
|
23
23
|
{description}
|
24
24
|
'''
|
25
25
|
|
26
|
-
visidata.options.setdefault('plot_colors', '', visidata.options._opts._get('plot_colors', 'default').helpstr)
|
27
|
-
visidata.options.setdefault('motd_url', '', visidata.options._opts._get('motd_url', 'default').helpstr)
|
26
|
+
visidata.options.setdefault('plot_colors', '', visidata.options._opts._get('plot_colors', 'default').helpstr, visidata.options._opts._get('plot_colors', 'default').module)
|
27
|
+
visidata.options.setdefault('motd_url', '', visidata.options._opts._get('motd_url', 'default').helpstr, visidata.options._opts._get('motd_url', 'default').module)
|
28
28
|
|
29
29
|
with open(fncli, 'w') as cliOut:
|
30
30
|
with open(fnopts, 'w') as menuOut:
|