Add options for linking different parts of ripgrep output

This commit is contained in:
Charlie Groves 2022-08-29 13:04:13 -04:00
parent 8c7968a4d6
commit db5b4da388
2 changed files with 36 additions and 11 deletions

View File

@ -75,8 +75,12 @@ 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 By default, this adds hyperlinks for several parts of ripgrep output: the
per-file header, match context lines, and match lines. Passing the per-file header, match context lines, and match lines. You can control which
`--hyperlink-only-matches` flag will only add hyperlinks to the match lines. 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

33
kittens/hyperlinked_grep/main.py Normal file → Executable file
View File

@ -20,9 +20,28 @@ def write_hyperlink(write: Callable[[bytes], None], url: bytes, line: bytes, fra
def main() -> None: def main() -> None:
write_all_hyperlinks = '--hyperlink-only-matches' not in sys.argv i = 1
if not write_all_hyperlinks: all_link_options = ['matching_lines', 'context_lines', 'file_headers']
sys.argv.remove('--hyperlink-only-matches') 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:])
@ -49,15 +68,17 @@ def main() -> None:
write(b'\n') write(b'\n')
elif in_result: elif in_result:
m = num_pat.match(clean_line) m = num_pat.match(clean_line)
if m is not None and (write_all_hyperlinks or m.group(2) == b':'): 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 write_all_hyperlinks: if link_file_headers:
write_hyperlink(write, in_result, line) write_hyperlink(write, in_result, line)
continue continue
write(line) write(line)