Skip to content

Commit

Permalink
[clipdraw] stack inline format; [/] to pop, [:] to clear
Browse files Browse the repository at this point in the history
- [:] still reset to original attr
  • Loading branch information
saulpw committed Oct 19, 2023
1 parent 769eecd commit 9cd4230
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 29 deletions.
2 changes: 1 addition & 1 deletion visidata/apps/vgit/grep.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def iterload(self):
tmp = (self.topRowIndex, self.cursorRowIndex)
for line in self.git_lines('grep', '--no-color', '-z', '--line-number', '--ignore-case', self.regex):
# line = line.replace(ESC+'[1;31m', '[:green]')
# line = line.replace(ESC+'[m', '[:]')
# line = line.replace(ESC+'[m', '[/]')
yield list(line.split('\0'))
self.topRowIndex, self.cursorRowIndex = tmp

Expand Down
58 changes: 39 additions & 19 deletions visidata/cliptext.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from visidata import options, drawcache, vd, update_attr, colors, ColorAttr

disp_column_fill = ' '
internal_markup_re = r'(\[:[^\]]*?\])' # [:whatever until the closing bracket] or [:]
internal_markup_re = r'(\[[:/][^\]]*?\])' # [:whatever until the closing bracket] or [/whatever] or [:]

### Curses helpers

Expand Down Expand Up @@ -53,15 +53,41 @@ def wcwidth(cc, ambig=1):
return 0


def is_vdcode(s:str) -> bool:
return (s.startswith('[:') and s.endswith(']')) or \
(s.startswith('[/') and s.endswith(']'))


def iterchunks(s, literal=False):
attrstack = [dict(link='', cattr=ColorAttr())]
legitopens = 0
chunks = re.split(internal_markup_re, s)
for chunk in chunks:
if not chunk:
continue
if not literal and chunk.startswith('[:') and chunk.endswith(']'):
yield chunk[2:-1] or ':', '' # color/attr change
else:
yield '', chunk

if not literal and is_vdcode(chunk):
cattr = attrstack[-1]['cattr']
link = attrstack[-1]['link']

if chunk.startswith(':onclick'):
attrstack.append(dict(link=chunk[9:], cattr=cattr.update(colors.clickable)))
elif chunk == '[:]': # clear stack, keep origattr
if len(attrstack) > 1:
del attrstack[1:]
continue
elif chunk.startswith('[/'): # pop last attr off stack
if len(attrstack) > 1:
attrstack.pop()
continue
else: # push updated color on stack
newcolor = colors.get_color(chunk[2:-1])
if newcolor:
cattr = update_attr(cattr, newcolor, len(attrstack))
attrstack.append(dict(link=link, cattr=cattr))
continue

yield attrstack[-1], chunk


@functools.lru_cache(maxsize=100000)
Expand Down Expand Up @@ -170,7 +196,7 @@ def clipdraw(scr, y, x, s, attr, w=None, clear=True, literal=False, **kwargs):
if not literal:
chunks = iterchunks(s, literal=literal)
else:
chunks = [('', s)]
chunks = [(dict(link='', cattr=ColorAttr()), s)]
return clipdraw_chunks(scr, y, x, chunks, attr, w=w, clear=clear, **kwargs)


Expand All @@ -197,18 +223,12 @@ def clipdraw_chunks(scr, y, x, chunks, cattr:ColorAttr=ColorAttr(), w=None, clea
scr.addstr(y, x, disp_column_fill*actualw, cattr.attr) # clear whole area before displaying

try:
for colorname, chunk in chunks:
if colorname.startswith('onclick'):
link = colorname
colorname = 'clickable'

if colorname == ':':
link = ''
cattr = origattr
continue

if colorname:
cattr = update_attr(cattr, colors.get_color(colorname), 8)
for colorstate, chunk in chunks:
if isinstance(colorstate, str):
cattr = cattr.update(colors.get_color(colorstate))
else:
cattr = origattr.update(colorstate['cattr'])
link = colorstate['link']

if not chunk:
continue
Expand Down Expand Up @@ -268,7 +288,7 @@ def wraptext(text, width=80, indent=''):

line = _markdown_to_internal(line)
chunks = re.split(internal_markup_re, line)
textchunks = [x for x in chunks if not (x.startswith('[:') and x.endswith(']'))]
textchunks = [x for x in chunks if not is_vdcode(x)]
for linenum, textline in enumerate(textwrap.wrap(''.join(textchunks), width=width, drop_whitespace=False)):
txt = textline
r = ''
Expand Down
9 changes: 7 additions & 2 deletions visidata/color.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ def _split_colorstr(self, colorstr):
if not fgbgattrs[i]: # keep first known color
if self._get_colornum(x) is not None: # only set known colors
fgbgattrs[i] = x
else:
fgbgattrs[i] = None

return fgbgattrs

Expand Down Expand Up @@ -171,9 +173,12 @@ def _attrnames_to_num(self, attrnames:'list[str]') -> int:
@drawcache
def _colornames_to_cattr(self, colorname:str, precedence=0) -> ColorAttr:
fg, bg, attrlist = self._split_colorstr(colorname)
if fg is None or bg is None:
return None

return ColorAttr(self._get_colornum(fg),
self._get_colornum(bg),
fg = self._get_colornum(fg)
bg = self._get_colornum(bg)
return ColorAttr(fg, bg,
self._attrnames_to_num(attrlist),
precedence, colorname)

Expand Down
11 changes: 4 additions & 7 deletions visidata/statusbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,7 @@ def recentStatusMessages(vd):
elif pri == 1: msgattr = '[:warning]'
else: msgattr = ''

if msgattr:
msg = ' ' + msg + ' '

r += f'\n{msgattr}{msg}[:]'
r += f'\n{msgattr}{msg}[/]'

if r:
return '# statuses' + r
Expand All @@ -197,7 +194,7 @@ def rightStatus(vd, sheet):
@BaseSheet.property
def keystrokeStatus(vs):
if vs is vd.activeSheet:
return f'[:keystrokes]{vd.keystrokes}[:]'
return f'[:keystrokes]{vd.keystrokes}[/]'

return ''

Expand All @@ -207,7 +204,7 @@ def threadStatus(vs) -> str:
if vs.currentThreads:
ret = str(vd.checkMemoryUsage())
gerunds = [p.gerund for p in vs.progresses if p.gerund] or ['processing']
ret += f' [:working]{vs.progressPct} {gerunds[0]}…[:]'
ret += f' [:working]{vs.progressPct} {gerunds[0]}…[/]'
return ret
return ''

Expand All @@ -220,7 +217,7 @@ def modifiedStatus(sheet):
@Sheet.property
def selectedStatus(sheet):
if sheet.nSelectedRows:
return f' [:selected_row]{sheet.options.disp_selected_note}{sheet.nSelectedRows}[:]'
return f' [:selected_row]{sheet.options.disp_selected_note}{sheet.nSelectedRows}[/]'


@VisiData.api
Expand Down
6 changes: 6 additions & 0 deletions visidata/tests/test_cliptext.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ def test_clipdraw_chunks(self):
call(0, 0, 'x', 0),
call(0, 1, 'jso…', 0),
], any_order=True)

@pytest.mark.parametrize('s, chunked', [
('[:b]bold[/]', [(':b', ''), ('', 'bold'), ('/', '')]),
])
def test_iterchunks(self, s, chunked):
assert list(visidata.iterchunks(s)) == chunked

0 comments on commit 9cd4230

Please sign in to comment.