Merge branch 'master' of https://github.com/Sighery/kitty into master
This commit is contained in:
commit
fe97bbcbbf
@ -2,6 +2,7 @@
|
|||||||
# vim:fileencoding=utf-8
|
# vim:fileencoding=utf-8
|
||||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import ipaddress
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
@ -236,6 +237,11 @@ def postprocessor(func: PostprocessorFunc) -> PostprocessorFunc:
|
|||||||
return func
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidMatch(Exception):
|
||||||
|
"""Raised when a match turns out to be invalid."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@postprocessor
|
@postprocessor
|
||||||
def url(text: str, s: int, e: int) -> Tuple[int, int]:
|
def url(text: str, s: int, e: int) -> Tuple[int, int]:
|
||||||
if s > 4 and text[s - 5:s] == 'link:': # asciidoc URLs
|
if s > 4 and text[s - 5:s] == 'link:': # asciidoc URLs
|
||||||
@ -280,11 +286,28 @@ def quotes(text: str, s: int, e: int) -> Tuple[int, int]:
|
|||||||
return s, e
|
return s, e
|
||||||
|
|
||||||
|
|
||||||
|
@postprocessor
|
||||||
|
def ip(text: str, s: int, e: int) -> Tuple[int, int]:
|
||||||
|
# Check validity of IPs (or raise InvalidMatch)
|
||||||
|
ip = text[s:e]
|
||||||
|
|
||||||
|
try:
|
||||||
|
ipaddress.ip_address(ip)
|
||||||
|
except ValueError:
|
||||||
|
raise InvalidMatch("Invalid IP")
|
||||||
|
|
||||||
|
return s, e
|
||||||
|
|
||||||
|
|
||||||
def mark(pattern: str, post_processors: Iterable[PostprocessorFunc], text: str, args: HintsCLIOptions) -> Generator[Mark, None, None]:
|
def mark(pattern: str, post_processors: Iterable[PostprocessorFunc], text: str, args: HintsCLIOptions) -> Generator[Mark, None, None]:
|
||||||
pat = re.compile(pattern)
|
pat = re.compile(pattern)
|
||||||
for idx, (s, e, groupdict) in enumerate(regex_finditer(pat, args.minimum_match_length, text)):
|
for idx, (s, e, groupdict) in enumerate(regex_finditer(pat, args.minimum_match_length, text)):
|
||||||
for func in post_processors:
|
try:
|
||||||
s, e = func(text, s, e)
|
for func in post_processors:
|
||||||
|
s, e = func(text, s, e)
|
||||||
|
except InvalidMatch:
|
||||||
|
continue
|
||||||
|
|
||||||
mark_text = text[s:e].replace('\n', '').replace('\0', '')
|
mark_text = text[s:e].replace('\n', '').replace('\0', '')
|
||||||
yield Mark(idx, s, e, mark_text, groupdict)
|
yield Mark(idx, s, e, mark_text, groupdict)
|
||||||
|
|
||||||
@ -325,6 +348,15 @@ def functions_for(args: HintsCLIOptions) -> Tuple[str, List[PostprocessorFunc]]:
|
|||||||
pattern = '(?m)^\\s*(.+)[\\s\0]*$'
|
pattern = '(?m)^\\s*(.+)[\\s\0]*$'
|
||||||
elif args.type == 'hash':
|
elif args.type == 'hash':
|
||||||
pattern = '[0-9a-f]{7,128}'
|
pattern = '[0-9a-f]{7,128}'
|
||||||
|
elif args.type == 'ip':
|
||||||
|
pattern = (
|
||||||
|
# # IPv4 with no validation
|
||||||
|
r"((?:\d{1,3}\.){3}\d{1,3}"
|
||||||
|
r"|"
|
||||||
|
# # IPv6 with no validation
|
||||||
|
r"(?:[a-fA-F0-9]{0,4}:){2,7}[a-fA-F0-9]{1,4})"
|
||||||
|
)
|
||||||
|
post_processors.append(ip)
|
||||||
elif args.type == 'word':
|
elif args.type == 'word':
|
||||||
chars = args.word_characters
|
chars = args.word_characters
|
||||||
if chars is None:
|
if chars is None:
|
||||||
@ -482,7 +514,7 @@ programs.
|
|||||||
|
|
||||||
--type
|
--type
|
||||||
default=url
|
default=url
|
||||||
choices=url,regex,path,line,hash,word,linenum,hyperlink
|
choices=url,regex,path,line,hash,word,linenum,hyperlink,ip
|
||||||
The type of text to search for. A value of :code:`linenum` is special, it looks
|
The type of text to search for. A value of :code:`linenum` is special, it looks
|
||||||
for error messages using the pattern specified with :option:`--regex`, which
|
for error messages using the pattern specified with :option:`--regex`, which
|
||||||
must have the named groups, :code:`path` and :code:`line`. If not specified,
|
must have the named groups, :code:`path` and :code:`line`. If not specified,
|
||||||
|
|||||||
@ -30,3 +30,31 @@ class TestHints(BaseTest):
|
|||||||
t('link:{}[xxx]'.format(u), u)
|
t('link:{}[xxx]'.format(u), u)
|
||||||
t('`xyz <{}>`_.'.format(u), u)
|
t('`xyz <{}>`_.'.format(u), u)
|
||||||
t('<a href="{}">moo'.format(u), u)
|
t('<a href="{}">moo'.format(u), u)
|
||||||
|
|
||||||
|
def test_ip_hints(self):
|
||||||
|
from kittens.hints.main import parse_hints_args, functions_for, mark, convert_text
|
||||||
|
args = parse_hints_args(['--type', 'ip'])[0]
|
||||||
|
pattern, post_processors = functions_for(args)
|
||||||
|
|
||||||
|
def create_marks(text, cols=60):
|
||||||
|
text = convert_text(text, cols)
|
||||||
|
return tuple(mark(pattern, post_processors, text, args))
|
||||||
|
|
||||||
|
testcases = (
|
||||||
|
('100.64.0.0', ['100.64.0.0']),
|
||||||
|
('2001:0db8:0000:0000:0000:ff00:0042:8329', ['2001:0db8:0000:0000:0000:ff00:0042:8329']),
|
||||||
|
('2001:db8:0:0:0:ff00:42:8329', ['2001:db8:0:0:0:ff00:42:8329']),
|
||||||
|
('2001:db8::ff00:42:8329', ['2001:db8::ff00:42:8329']),
|
||||||
|
('2001:DB8::FF00:42:8329', ['2001:DB8::FF00:42:8329']),
|
||||||
|
('0000:0000:0000:0000:0000:0000:0000:0001', ['0000:0000:0000:0000:0000:0000:0000:0001']),
|
||||||
|
('::1', ['::1']),
|
||||||
|
# Invalid IPs won't match
|
||||||
|
('255.255.255.256', []),
|
||||||
|
(':1', []),
|
||||||
|
)
|
||||||
|
|
||||||
|
for testcase, expected in testcases:
|
||||||
|
with self.subTest(testcase=testcase, expected=expected):
|
||||||
|
marks = create_marks(testcase)
|
||||||
|
ips = [m.text for m in marks]
|
||||||
|
self.ae(ips, expected)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user