Skip to content

Commit

Permalink
[help] readd input.ddw help, move to sidebar #2085
Browse files Browse the repository at this point in the history
  • Loading branch information
saulpw committed Oct 27, 2023
1 parent 77c0512 commit 41e92d1
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 56 deletions.
23 changes: 3 additions & 20 deletions visidata/_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,6 @@
from visidata import vd, options, colors, dispwidth, ColorAttr
from visidata import AttrDict

help_input = '''# Input Help
Start typing to overwrite the starting value.
(To edit the starting value, press a movement key first.)
- `Ctrl+O` to open in external $EDITOR
- `Ctrl+Y` to insert clipboard text at cursor
- `Ctrl+R` to restore the starting value
- `Tab`/`Shift+Tab` to next/prev autocomplete
- `↓`/`↑` next/prev input history
- `Ctrl+C` or `Esc` to cancel input.
- `Enter` to accept input.
- `Ctrl+G` to toggle this help sidebar
Other standard readline keybindings apply.
[:onclick https://visidata.org/help/input]🛈 for all keybindings at visidata.org[:]
'''

vd.theme_option('color_edit_unfocused', '238 on 110', 'display color for unfocused input in form')
vd.theme_option('color_edit_cell', '233 on 110', 'cell color to use when editing cell')
Expand Down Expand Up @@ -244,9 +227,9 @@ def find_nonword(s, a, b, incr):
if disp_help > 0:
sheet = vd.activeSheet
if disp_help > 1:
help = help_input
if disp_help > 0 and help:
sheet.drawSidebarText(scr, help)
help = vd.getHelpPane('input', module='visidata')
if help:
sheet.drawSidebarText(scr, help, title="Input Help")

if display:
dispval = clean_printable(v)
Expand Down
80 changes: 80 additions & 0 deletions visidata/ddw/input.ddw
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{"id": null, "type": null, "x": 6, "y": 6, "text": "\u2190", "color": "keystrokes", "tags": [], "group": "", "frame": null, "rows": null, "duration_ms": null, "ref": null, "onclick": null}
{"x": 11, "y": 6, "text": "go to prev/next char", "color": "", "tags": [], "group": ""}
{"x": 3, "y": 4, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
{"x": 11, "y": 4, "text": "cancel input (abort)", "color": "", "tags": [], "group": ""}
{"x": 45, "y": 4, "text": "delete one char at cursor", "color": "", "tags": [], "group": ""}
{"x": 45, "y": 5, "text": "delete one char before cursor", "color": "", "tags": [], "group": ""}
{"x": 0, "y": 13, "text": "Shift", "color": "keystrokes", "tags": [], "group": ""}
{"x": 4, "y": 3, "text": "Enter", "color": "keystrokes", "tags": [], "group": ""}
{"x": 11, "y": 3, "text": "accept input", "color": "", "tags": [], "group": ""}
{"x": 42, "y": 6, "text": "K", "color": "keystrokes", "tags": [], "group": ""}
{"x": 45, "y": 6, "text": "delete all before/after cursor", "color": "", "tags": [], "group": ""}
{"x": 42, "y": 12, "text": "O", "color": "keystrokes", "tags": [], "group": ""}
{"x": 45, "y": 12, "text": "open input in external editor", "color": "", "tags": [], "group": ""}
{"x": 42, "y": 13, "text": "R", "color": "keystrokes", "tags": [], "group": ""}
{"x": 45, "y": 13, "text": "restore starting value", "color": "", "tags": [], "group": ""}
{"x": 42, "y": 8, "text": "T", "color": "keystrokes", "tags": [], "group": ""}
{"x": 45, "y": 8, "text": "swap last two chars", "color": "", "tags": [], "group": ""}
{"x": 40, "y": 6, "text": "U", "color": "keystrokes", "tags": [], "group": ""}
{"x": 42, "y": 9, "text": "V", "color": "keystrokes", "tags": [], "group": ""}
{"x": 45, "y": 9, "text": "insert literal char", "color": "", "tags": [], "group": ""}
{"x": 42, "y": 7, "text": "W", "color": "keystrokes", "tags": [], "group": ""}
{"x": 45, "y": 7, "text": "delete one word before cursor", "color": "", "tags": [], "group": ""}
{"x": 42, "y": 11, "text": "Y", "color": "keystrokes", "tags": [], "group": ""}
{"x": 45, "y": 11, "text": "insert clipboard text at cursor", "color": "", "tags": [], "group": ""}
{"x": 6, "y": 7, "text": "\u2190", "color": "keystrokes", "tags": [], "group": ""}
{"x": 11, "y": 7, "text": "go to prev/next word", "color": "", "tags": [], "group": ""}
{"x": 0, "y": 0, "text": "Begin typing to overwrite the starting value.", "color": "", "tags": [], "group": ""}
{"x": 0, "y": 1, "text": "(To edit the starting value, press a movement key first.)", "color": "", "tags": [], "group": ""}
{"x": 6, "y": 10, "text": "\u2191", "color": "keystrokes", "tags": [], "group": ""}
{"x": 1, "y": 8, "text": "Home", "color": "keystrokes", "tags": [], "group": ""}
{"x": 11, "y": 8, "text": "go to start/end", "color": "", "tags": [], "group": ""}
{"x": 6, "y": 8, "text": "End", "color": "keystrokes", "tags": [], "group": ""}
{"x": 8, "y": 6, "text": "\u2192", "color": "keystrokes", "tags": [], "group": ""}
{"x": 37, "y": 4, "text": "Delete", "color": "keystrokes", "tags": [], "group": ""}
{"x": 34, "y": 5, "text": "Backspace", "color": "keystrokes", "tags": [], "group": ""}
{"x": 37, "y": 3, "text": "Insert", "color": "keystrokes", "tags": [], "group": ""}
{"x": 45, "y": 3, "text": "toggle insert mode", "color": "", "tags": [], "group": ""}
{"x": 6, "y": 12, "text": "Tab", "color": "keystrokes", "tags": [], "group": ""}
{"x": 1, "y": 7, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
{"x": 35, "y": 6, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
{"x": 37, "y": 8, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
{"x": 37, "y": 7, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
{"x": 37, "y": 9, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
{"x": 37, "y": 11, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
{"x": 37, "y": 12, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
{"x": 37, "y": 13, "text": "Ctrl", "color": "keystrokes", "tags": [], "group": ""}
{"x": 5, "y": 7, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
{"x": 39, "y": 6, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
{"x": 41, "y": 7, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
{"x": 41, "y": 8, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
{"x": 41, "y": 9, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
{"x": 41, "y": 11, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
{"x": 41, "y": 12, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
{"x": 41, "y": 13, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
{"x": 11, "y": 10, "text": "prev/next in history", "color": "", "tags": [], "group": ""}
{"x": 11, "y": 12, "text": "next autocomplete", "color": "", "tags": [], "group": ""}
{"x": 11, "y": 13, "text": "prev autocomplete", "color": "", "tags": [], "group": ""}
{"x": 7, "y": 4, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
{"x": 8, "y": 4, "text": "C", "color": "keystrokes", "tags": [], "group": ""}
{"x": 5, "y": 13, "text": "+", "color": "keystrokes", "tags": [], "group": ""}
{"x": 6, "y": 13, "text": "Tab", "color": "keystrokes", "tags": [], "group": ""}
{"x": 32, "y": 3, "text": "\u2502", "color": "", "tags": [], "group": ""}
{"x": 32, "y": 4, "text": "\u2502", "color": "", "tags": [], "group": ""}
{"x": 32, "y": 5, "text": "\u2502", "color": "", "tags": [], "group": ""}
{"x": 32, "y": 6, "text": "\u2502", "color": "", "tags": [], "group": ""}
{"x": 32, "y": 7, "text": "\u2502", "color": "", "tags": [], "group": ""}
{"x": 32, "y": 8, "text": "\u2502", "color": "", "tags": [], "group": ""}
{"x": 32, "y": 9, "text": "\u2502", "color": "", "tags": [], "group": ""}
{"x": 32, "y": 10, "text": "\u2502", "color": "", "tags": [], "group": ""}
{"x": 32, "y": 11, "text": "\u2502", "color": "", "tags": [], "group": ""}
{"x": 32, "y": 12, "text": "\u2502", "color": "", "tags": [], "group": ""}
{"x": 32, "y": 13, "text": "\u2502", "color": "", "tags": [], "group": ""}
{"x": 7, "y": 6, "text": "/", "color": "", "tags": [], "group": ""}
{"x": 5, "y": 8, "text": "/", "color": "", "tags": [], "group": ""}
{"x": 8, "y": 7, "text": "\u2192", "color": "keystrokes", "tags": [], "group": ""}
{"x": 8, "y": 10, "text": "\u2193", "color": "keystrokes", "tags": [], "group": ""}
{"x": 41, "y": 6, "text": "/", "color": "", "tags": [], "group": ""}
{"x": 7, "y": 10, "text": "/", "color": "", "tags": [], "group": ""}
{"x": 7, "y": 7, "text": "/", "color": "", "tags": [], "group": ""}
{"x": 75, "y": 0, "text": "?", "color": "bold 117 cyan", "tags": [], "group": "", "onclick": "https://visidata.org/input"}
6 changes: 3 additions & 3 deletions visidata/ddwplay.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from collections import defaultdict
import json
import time
from visidata import colors, vd, clipdraw
from visidata import colors, vd, clipdraw, ColorAttr

__all__ = ['Animation', 'AnimationMgr']

Expand Down Expand Up @@ -66,9 +66,9 @@ def load_from(self, fp):
self.width = max(self.width, x+len(r.text))
self.height = max(self.height, y)

def draw(self, scr, *, t=0, x=0, y=0, loop=False, **kwargs):
def draw(self, scr, *, t=0, x=0, y=0, loop=False, attr=ColorAttr(), **kwargs):
for r, dx, dy, _ in self.iterdeep(self.frames[''].rows):
clipdraw(scr, y+dy, x+dx, r.text, colors[r.color])
clipdraw(scr, y+dy, x+dx, r.text, attr.update(colors[r.color], 2))

if not self.total_ms:
return None
Expand Down
28 changes: 18 additions & 10 deletions visidata/help.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from visidata import VisiData, MetaSheet, ColumnAttr, Column, BaseSheet, VisiDataMetaSheet, SuspendCurses
from visidata import vd, asyncthread, ENTER

vd.option('disp_help', 1, '-1=quiet, 0=no help, 1-4=some-all help, 5-10=remove features')
vd.option('disp_help', 0, 'show help panel during input')


@VisiData.api
Expand Down Expand Up @@ -81,14 +81,22 @@ def __init__(self, name):
self.parentscr = None
self.amgr = visidata.AnimationMgr()

def draw(self, scr, x=None, y=None):
@property
def width(self):
return self.amgr.maxWidth

@property
def height(self):
return self.amgr.maxHeight

def draw(self, scr, x=None, y=None, **kwargs):
if not scr: return
if vd.options.disp_help < 2:
if self.scr:
self.scr.erase()
self.scr.refresh()
self.scr = None
return
# if vd.options.disp_help <= 0:
# if self.scr:
# self.scr.erase()
# self.scr.refresh()
# self.scr = None
# return
if y is None: y=0 # show at top of screen by default
if x is None: x=0
hneeded = self.amgr.maxHeight+3
Expand Down Expand Up @@ -118,13 +126,13 @@ def draw(self, scr, x=None, y=None):

self.scr.erase()
self.scr.box()
self.amgr.draw(self.scr, y=1, x=2)
self.amgr.draw(self.scr, y=1, x=2, **kwargs)
self.scr.refresh()


@VisiData.api
@functools.lru_cache(maxsize=None)
def getHelpPane(vd, name, module='vdplus'):
def getHelpPane(vd, name, module='visidata') -> HelpPane:
ret = HelpPane(name)
try:
ret.amgr.load(name, (vd.pkg_resources_files(module)/f'ddw/{name}.ddw').open(encoding='utf-8'))
Expand Down
58 changes: 35 additions & 23 deletions visidata/sidebar.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from typing import Optional, Union
import textwrap

from visidata import vd, VisiData, BaseSheet, colors, TextSheet, clipdraw, wraptext, dispwidth
Expand Down Expand Up @@ -42,33 +42,42 @@ def drawSidebar(vd, scr, sheet):
return sheet.drawSidebarText(scr, text=sidebar, overflowmsg=overflowmsg, bottommsg=bottommsg)

@BaseSheet.api
def drawSidebarText(sheet, scr, text:Optional[str], title:str='', overflowmsg:str='', bottommsg:str=''):
def drawSidebarText(sheet, scr, text:Union[None,str,'HelpPane'], title:str='', overflowmsg:str='', bottommsg:str=''):
scrh, scrw = scr.getmaxyx()
maxw = sheet.options.disp_sidebar_width or scrw//2
maxh = sheet.options.disp_sidebar_height or scrh-2

cattr = colors.get_color('color_sidebar')

text = text or ''
text = textwrap.dedent(text.strip('\n'))

if not text:
return
if hasattr(text, 'draw'): # like a HelpPane
maxlinew = text.width
winh = min(maxh, text.height+2)+1
else:
text = textwrap.dedent(text.strip('\n'))

if not text:
return

lines = text.splitlines()
if not title and lines and lines[0].strip().startswith('# '):
title = lines[0][1:].strip()
text = '\n'.join(lines[1:])

lines = text.splitlines()
if not title and lines and lines[0].strip().startswith('# '):
title = lines[0][1:].strip()
text = '\n'.join(lines[1:])

lines = list(wraptext(text, width=maxw-4))
maxlinew = 0
if lines:
maxlinew = max(maxlinew, max(dispwidth(textonly, maxwidth=maxw) for line, textonly in lines))
winh = min(maxh, len(lines)+2)

titlew = dispwidth(title)

cattr = colors.get_color('color_sidebar')
lines = list(wraptext(text, width=maxw-4))
maxlinew = titlew
if lines:
maxlinew = max(titlew, max(dispwidth(textonly, maxwidth=maxw) for line, textonly in lines))
maxlinew = max(maxlinew, dispwidth(overflowmsg)+4)
maxlinew = max(maxlinew, dispwidth(bottommsg)+4)
maxlinew = max(maxlinew, titlew)
winw = min(maxw, maxlinew+4)
winh = min(maxh, len(lines)+2)
x, y, w, h = scrw-winw-1, scrh-winh-1, winw, winh

sidebarscr = vd.subwindow(scr, x, y, w, h)
Expand All @@ -78,14 +87,17 @@ def drawSidebarText(sheet, scr, text:Optional[str], title:str='', overflowmsg:st
sidebarscr.border()
vd.onMouse(sidebarscr, 0, 0, w, h, BUTTON1_RELEASED='no-op', BUTTON1_PRESSED='no-op')

i = 0
for line, _ in lines:
if i >= h-2:
bottommsg = overflowmsg
break

x += clipdraw(sidebarscr, i+1, 2, line, cattr, w=w-3)
i += 1
if hasattr(text, 'draw'): # like a HelpPane
text.draw(sidebarscr, attr=cattr)
else:
i = 0
for line, _ in lines:
if i >= h-2:
bottommsg = overflowmsg
break

x += clipdraw(sidebarscr, i+1, 2, line, cattr, w=w-3)
i += 1

x = max(0, w-titlew-6)
clipdraw(sidebarscr, 0, x, f"|[:black on yellow] {title} [:]|", cattr, w=titlew+4)
Expand Down

0 comments on commit 41e92d1

Please sign in to comment.