Allow setting markers using remote control

This commit is contained in:
Kovid Goyal 2020-01-14 15:06:52 +05:30
parent 3593189a75
commit 4dde98305e
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 99 additions and 13 deletions

View File

@ -37,7 +37,7 @@ can control the colors used for these groups in :file:`kitty.conf` with::
.. note:: .. note::
For performance reasons, matching is done per line only, and only when that line is For performance reasons, matching is done per line only, and only when that line is
altered in anyway. So you cannot match text that stretches across multiple altered in any way. So you cannot match text that stretches across multiple
lines. lines.
@ -53,6 +53,9 @@ If you want to create markers dynamically rather than pre-defining them in
Then pressing :kbd:`F1` will allow you to enter the marker definition and set Then pressing :kbd:`F1` will allow you to enter the marker definition and set
it and pressing :kbd:`F2` will remove the marker. it and pressing :kbd:`F2` will remove the marker.
You can also use the facilities for :doc:`remote-control` to dynamically
add/remove markers.
The full syntax for creating marks The full syntax for creating marks
------------------------------------- -------------------------------------

View File

@ -381,6 +381,82 @@ def set_tab_title(boss, window, payload):
# }}} # }}}
# create_marker {{{
@cmd(
'Create a marker that highlights specified text',
'Create a marker which can highlight text in the specified window. For example: '
'create_marker text 1 ERROR. For full details see: https://sw.kovidgoyal.net/kitty/marks.html',
options_spec=MATCH_WINDOW_OPTION + '''\n
--self
type=bool-set
If specified apply marker to the window this command is run in, rather than the active window.
''',
argspec='MARKER SPECIFICATION'
)
def cmd_create_marker(global_opts, opts, args):
'''
match: Which window to detach
self: Boolean indicating whether to detach the window the command is run in
marker_spec: A list or arguments that define the marker specification, for example: ['text', '1', 'ERROR']
'''
from .config import parse_marker_spec
if len(args) < 2:
raise ValueError('Invalid marker specification: {}'.format(' '.join(args)))
parse_marker_spec(args[0], args[1:])
return {'match': opts.match, 'self': opts.self, 'marker_spec': args}
def create_marker(boss, window, payload):
pg = cmd_create_marker.payload_get
match = pg(payload, 'match')
if match:
windows = tuple(boss.match_windows(match))
if not windows:
raise MatchError(match)
else:
windows = [window if window and pg(payload, 'self') else boss.active_window]
args = pg(payload, 'marker_spec')
for window in windows:
window.set_marker(args)
# }}}
# remove_marker {{{
@cmd(
'Remove the currently set marker, if any.',
options_spec=MATCH_WINDOW_OPTION + '''\n
--self
type=bool-set
If specified apply marker to the window this command is run in, rather than the active window.
''',
argspec=''
)
def cmd_remove_marker(global_opts, opts, args):
'''
match: Which window to detach
self: Boolean indicating whether to detach the window the command is run in
'''
return {'match': opts.match, 'self': opts.self}
def remove_marker(boss, window, payload):
pg = cmd_create_marker.payload_get
match = pg(payload, 'match')
if match:
windows = tuple(boss.match_windows(match))
if not windows:
raise MatchError(match)
else:
windows = [window if window and pg(payload, 'self') else boss.active_window]
for window in windows:
window.remove_marker()
# }}}
# detach_window {{{ # detach_window {{{
@cmd( @cmd(
'Detach a window and place it in a different/new tab', 'Detach a window and place it in a different/new tab',

View File

@ -241,19 +241,13 @@ def disable_ligatures_in(func, rest):
return func, [where, strategy] return func, [where, strategy]
@func_with_args('toggle_marker') def parse_marker_spec(ftype, parts):
def toggle_marker(func, rest):
parts = rest.split(maxsplit=1)
if len(parts) != 2:
raise ValueError('{} if not a valid marker specification'.format(rest))
ftype, spec = parts
flags = re.UNICODE flags = re.UNICODE
if ftype in ('text', 'itext', 'regex', 'iregex'): if ftype in ('text', 'itext', 'regex', 'iregex'):
parts = spec.split()
if ftype.startswith('i'): if ftype.startswith('i'):
flags |= re.IGNORECASE flags |= re.IGNORECASE
if not parts or len(parts) % 2 != 0: if not parts or len(parts) % 2 != 0:
raise ValueError('No color specified in marker: {}'.format(spec)) raise ValueError('No color specified in marker: {}'.format(' '.join(parts)))
ans = [] ans = []
for i in range(0, len(parts), 2): for i in range(0, len(parts), 2):
try: try:
@ -267,10 +261,20 @@ def toggle_marker(func, rest):
ftype = 'regex' ftype = 'regex'
spec = tuple(ans) spec = tuple(ans)
elif ftype == 'function': elif ftype == 'function':
pass spec = ' '.join(parts)
else: else:
raise ValueError('Unknown marker type: {}'.format(ftype)) raise ValueError('Unknown marker type: {}'.format(ftype))
return func, [ftype, spec, flags] return ftype, spec, flags
@func_with_args('toggle_marker')
def toggle_marker(func, rest):
parts = rest.split(maxsplit=1)
if len(parts) != 2:
raise ValueError('{} if not a valid marker specification'.format(rest))
ftype, spec = parts
parts = spec.split()
return func, list(parse_marker_spec(ftype, parts))
def parse_key_action(action): def parse_key_action(action):

View File

@ -617,9 +617,12 @@ class Window:
self.current_marker_spec = key self.current_marker_spec = key
def set_marker(self, spec): def set_marker(self, spec):
from .config import toggle_marker from .config import toggle_marker, parse_marker_spec
from .marks import marker_from_spec from .marks import marker_from_spec
func, (ftype, spec, flags) = toggle_marker('toggle_marker', spec) if isinstance(spec, str):
func, (ftype, spec, flags) = toggle_marker('toggle_marker', spec)
else:
ftype, spec, flags = parse_marker_spec(spec[0], spec[1:])
key = ftype, spec key = ftype, spec
self.screen.set_marker(marker_from_spec(ftype, spec, flags)) self.screen.set_marker(marker_from_spec(ftype, spec, flags))
self.current_marker_spec = key self.current_marker_spec = key