Merge branch 'hyperlinked-grep-only-matches' of https://github.com/groves/kitty
This commit is contained in:
commit
49f8c0eae6
@ -74,6 +74,14 @@ to :program:`rg`. How to do that varies based on the shell:
|
|||||||
To learn more about kitty's powerful framework for customizing URL click
|
To learn more about kitty's powerful framework for customizing URL click
|
||||||
actions, see :doc:`here </open_actions>`.
|
actions, see :doc:`here </open_actions>`.
|
||||||
|
|
||||||
|
By default, this adds hyperlinks for several parts of ripgrep output: the
|
||||||
|
per-file header, match context lines, and match lines. You can control which
|
||||||
|
items are linked with a :command:`--kitten hyperlink` flag. For example,
|
||||||
|
:command:`--kitten hyperlink=matching_lines` will only add hyperlinks to the
|
||||||
|
match lines. :command:`--kitten hyperlink=file_headers,context_lines` will
|
||||||
|
link file headers and context lines but not match lines.
|
||||||
|
:command:`--kitten hyperlink` may be specified multiple times.
|
||||||
|
|
||||||
Hopefully, someday this functionality will make it into some `upstream grep
|
Hopefully, someday this functionality will make it into some `upstream grep
|
||||||
<https://github.com/BurntSushi/ripgrep/issues/665>`__ program directly removing
|
<https://github.com/BurntSushi/ripgrep/issues/665>`__ program directly removing
|
||||||
the need for this kitten.
|
the need for this kitten.
|
||||||
|
|||||||
35
kittens/hyperlinked_grep/main.py
Normal file → Executable file
35
kittens/hyperlinked_grep/main.py
Normal file → Executable file
@ -20,6 +20,29 @@ def write_hyperlink(write: Callable[[bytes], None], url: bytes, line: bytes, fra
|
|||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
i = 1
|
||||||
|
all_link_options = ['matching_lines', 'context_lines', 'file_headers']
|
||||||
|
link_options = set()
|
||||||
|
while i < len(sys.argv):
|
||||||
|
if sys.argv[i] == '--kitten':
|
||||||
|
if len(sys.argv) < i + 2 or not sys.argv[i + 1].startswith("hyperlink="):
|
||||||
|
raise SystemExit("--kitten argument must be followed by hyperlink=(all|matching_lines|context_lines|file_headers)")
|
||||||
|
for option in sys.argv[i + 1].split('=')[1].split(','):
|
||||||
|
if option == 'all':
|
||||||
|
link_options.update(all_link_options)
|
||||||
|
elif option not in all_link_options:
|
||||||
|
raise SystemExit(f"hyperlink option must be one of all, matching_lines, context_lines, or file_headers, not '{option}'")
|
||||||
|
else:
|
||||||
|
link_options.add(option)
|
||||||
|
del sys.argv[i:i+2]
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
if len(link_options) == 0: # Default to linking everything if no options given
|
||||||
|
link_options.update(all_link_options)
|
||||||
|
link_file_headers = 'file_headers' in link_options
|
||||||
|
link_context_lines = 'context_lines' in link_options
|
||||||
|
link_matching_lines = 'matching_lines' in link_options
|
||||||
|
|
||||||
if not sys.stdout.isatty() and '--pretty' not in sys.argv and '-p' not in sys.argv:
|
if not sys.stdout.isatty() and '--pretty' not in sys.argv and '-p' not in sys.argv:
|
||||||
os.execlp('rg', 'rg', *sys.argv[1:])
|
os.execlp('rg', 'rg', *sys.argv[1:])
|
||||||
cmdline = ['rg', '--pretty', '--with-filename'] + sys.argv[1:]
|
cmdline = ['rg', '--pretty', '--with-filename'] + sys.argv[1:]
|
||||||
@ -31,7 +54,7 @@ def main() -> None:
|
|||||||
write: Callable[[bytes], None] = cast(Callable[[bytes], None], sys.stdout.buffer.write)
|
write: Callable[[bytes], None] = cast(Callable[[bytes], None], sys.stdout.buffer.write)
|
||||||
sgr_pat = re.compile(br'\x1b\[.*?m')
|
sgr_pat = re.compile(br'\x1b\[.*?m')
|
||||||
osc_pat = re.compile(b'\x1b\\].*?\x1b\\\\')
|
osc_pat = re.compile(b'\x1b\\].*?\x1b\\\\')
|
||||||
num_pat = re.compile(br'^(\d+)[:-]')
|
num_pat = re.compile(br'^(\d+)([:-])')
|
||||||
|
|
||||||
in_result: bytes = b''
|
in_result: bytes = b''
|
||||||
hostname = socket.gethostname().encode('utf-8')
|
hostname = socket.gethostname().encode('utf-8')
|
||||||
@ -43,19 +66,21 @@ def main() -> None:
|
|||||||
if not clean_line:
|
if not clean_line:
|
||||||
in_result = b''
|
in_result = b''
|
||||||
write(b'\n')
|
write(b'\n')
|
||||||
continue
|
elif in_result:
|
||||||
if in_result:
|
|
||||||
m = num_pat.match(clean_line)
|
m = num_pat.match(clean_line)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
|
is_match_line = m.group(2) == b':'
|
||||||
|
if (is_match_line and link_matching_lines) or (not is_match_line and link_context_lines):
|
||||||
write_hyperlink(write, in_result, line, frag=m.group(1))
|
write_hyperlink(write, in_result, line, frag=m.group(1))
|
||||||
else:
|
continue
|
||||||
write(line)
|
write(line)
|
||||||
else:
|
else:
|
||||||
if line.strip():
|
if line.strip():
|
||||||
path = quote_from_bytes(os.path.abspath(clean_line)).encode('utf-8')
|
path = quote_from_bytes(os.path.abspath(clean_line)).encode('utf-8')
|
||||||
in_result = b'file://' + hostname + path
|
in_result = b'file://' + hostname + path
|
||||||
|
if link_file_headers:
|
||||||
write_hyperlink(write, in_result, line)
|
write_hyperlink(write, in_result, line)
|
||||||
else:
|
continue
|
||||||
write(line)
|
write(line)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
p.send_signal(signal.SIGINT)
|
p.send_signal(signal.SIGINT)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user