Merge branch 'master' of https://github.com/suvayu/kitty
This commit is contained in:
commit
fc217dafba
29
kittens/diff/collect.py
Normal file → Executable file
29
kittens/diff/collect.py
Normal file → Executable file
@ -4,8 +4,10 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
from fnmatch import fnmatch
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
|
from itertools import product
|
||||||
from kitty.guess_mime_type import guess_type
|
from kitty.guess_mime_type import guess_type
|
||||||
from typing import TYPE_CHECKING, Dict, List, Set, Optional, Iterator, Tuple, Union
|
from typing import TYPE_CHECKING, Dict, List, Set, Optional, Iterator, Tuple, Union
|
||||||
|
|
||||||
@ -37,6 +39,8 @@ class Segment:
|
|||||||
|
|
||||||
class Collection:
|
class Collection:
|
||||||
|
|
||||||
|
ignore_paths: Tuple[str, ...] = ()
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.changes: Dict[str, str] = {}
|
self.changes: Dict[str, str] = {}
|
||||||
self.renames: Dict[str, str] = {}
|
self.renames: Dict[str, str] = {}
|
||||||
@ -105,22 +109,29 @@ def resolve_remote_name(path: str, default: str) -> str:
|
|||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def walk(base: str, names: Set[str], pmap: Dict[str, str], ignore_paths: Tuple[str, ...]) -> None:
|
||||||
|
for dirpath, dirnames, filenames in os.walk(base):
|
||||||
|
ignored = [_dir for _dir, pat in product(dirnames, ignore_paths) if fnmatch(_dir, pat)]
|
||||||
|
for _dir in ignored:
|
||||||
|
dirnames.pop(dirnames.index(_dir))
|
||||||
|
for filename in filenames:
|
||||||
|
if any(fnmatch(filename, pat) for pat in ignore_paths if pat):
|
||||||
|
continue
|
||||||
|
path = os.path.abspath(os.path.join(dirpath, filename))
|
||||||
|
path_name_map[path] = name = os.path.relpath(path, base)
|
||||||
|
names.add(name)
|
||||||
|
pmap[name] = path
|
||||||
|
|
||||||
|
|
||||||
def collect_files(collection: Collection, left: str, right: str) -> None:
|
def collect_files(collection: Collection, left: str, right: str) -> None:
|
||||||
left_names: Set[str] = set()
|
left_names: Set[str] = set()
|
||||||
right_names: Set[str] = set()
|
right_names: Set[str] = set()
|
||||||
left_path_map: Dict[str, str] = {}
|
left_path_map: Dict[str, str] = {}
|
||||||
right_path_map: Dict[str, str] = {}
|
right_path_map: Dict[str, str] = {}
|
||||||
|
|
||||||
def walk(base: str, names: Set[str], pmap: Dict[str, str]) -> None:
|
walk(left, left_names, left_path_map, collection.ignore_paths)
|
||||||
for dirpath, dirnames, filenames in os.walk(base):
|
walk(right, right_names, right_path_map, collection.ignore_paths)
|
||||||
for filename in filenames:
|
|
||||||
path = os.path.abspath(os.path.join(dirpath, filename))
|
|
||||||
path_name_map[path] = name = os.path.relpath(path, base)
|
|
||||||
names.add(name)
|
|
||||||
pmap[name] = path
|
|
||||||
|
|
||||||
walk(left, left_names, left_path_map)
|
|
||||||
walk(right, right_names, right_path_map)
|
|
||||||
common_names = left_names & right_names
|
common_names = left_names & right_names
|
||||||
changed_names = {n for n in common_names if data_for_path(left_path_map[n]) != data_for_path(right_path_map[n])}
|
changed_names = {n for n in common_names if data_for_path(left_path_map[n]) != data_for_path(right_path_map[n])}
|
||||||
for n in changed_names:
|
for n in changed_names:
|
||||||
|
|||||||
1
kittens/diff/main.py
Normal file → Executable file
1
kittens/diff/main.py
Normal file → Executable file
@ -655,6 +655,7 @@ def main(args: List[str]) -> None:
|
|||||||
opts = init_config(cli_opts)
|
opts = init_config(cli_opts)
|
||||||
set_diff_command(opts.diff_cmd)
|
set_diff_command(opts.diff_cmd)
|
||||||
lines_for_path.replace_tab_by = opts.replace_tab_by
|
lines_for_path.replace_tab_by = opts.replace_tab_by
|
||||||
|
Collection.ignore_paths = opts.ignore_paths
|
||||||
left, right = map(get_remote_file, (left, right))
|
left, right = map(get_remote_file, (left, right))
|
||||||
if os.path.isdir(left) != os.path.isdir(right):
|
if os.path.isdir(left) != os.path.isdir(right):
|
||||||
raise SystemExit('The items to be diffed should both be either directories or files. Comparing a directory to a file is not valid.')
|
raise SystemExit('The items to be diffed should both be either directories or files. Comparing a directory to a file is not valid.')
|
||||||
|
|||||||
8
kittens/diff/options/definition.py
Normal file → Executable file
8
kittens/diff/options/definition.py
Normal file → Executable file
@ -47,6 +47,14 @@ opt('replace_tab_by', '\\x20\\x20\\x20\\x20',
|
|||||||
option_type='python_string',
|
option_type='python_string',
|
||||||
long_text='The string to replace tabs with. Default is to use four spaces.'
|
long_text='The string to replace tabs with. Default is to use four spaces.'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
opt('ignore_paths', '',
|
||||||
|
option_type='pattern_list',
|
||||||
|
long_text='''List of patterns that are matched against directory and file
|
||||||
|
names and ignored when directories are compared.
|
||||||
|
''',
|
||||||
|
)
|
||||||
|
|
||||||
egr() # }}}
|
egr() # }}}
|
||||||
|
|
||||||
# colors {{{
|
# colors {{{
|
||||||
|
|||||||
5
kittens/diff/options/parse.py
generated
5
kittens/diff/options/parse.py
generated
@ -1,7 +1,7 @@
|
|||||||
# generated by gen-config.py DO NOT edit
|
# generated by gen-config.py DO NOT edit
|
||||||
|
|
||||||
import typing
|
import typing
|
||||||
from kittens.diff.options.utils import parse_map, syntax_aliases
|
from kittens.diff.options.utils import parse_map, pattern_list, syntax_aliases
|
||||||
from kitty.conf.utils import merge_dicts, positive_int, python_string, to_color, to_color_or_none
|
from kitty.conf.utils import merge_dicts, positive_int, python_string, to_color, to_color_or_none
|
||||||
|
|
||||||
|
|
||||||
@ -86,6 +86,9 @@ class Parser:
|
|||||||
for k in parse_map(val):
|
for k in parse_map(val):
|
||||||
ans['map'].append(k)
|
ans['map'].append(k)
|
||||||
|
|
||||||
|
def ignore_paths(self, val: str, ans: typing.Dict[str, typing.Any]):
|
||||||
|
ans['ignore_paths'] = pattern_list(val)
|
||||||
|
|
||||||
|
|
||||||
def create_result_dict() -> typing.Dict[str, typing.Any]:
|
def create_result_dict() -> typing.Dict[str, typing.Any]:
|
||||||
return {
|
return {
|
||||||
|
|||||||
2
kittens/diff/options/types.py
generated
2
kittens/diff/options/types.py
generated
@ -20,6 +20,7 @@ option_names = ( # {{{
|
|||||||
'highlight_removed_bg',
|
'highlight_removed_bg',
|
||||||
'hunk_bg',
|
'hunk_bg',
|
||||||
'hunk_margin_bg',
|
'hunk_margin_bg',
|
||||||
|
'ignore_paths',
|
||||||
'map',
|
'map',
|
||||||
'margin_bg',
|
'margin_bg',
|
||||||
'margin_fg',
|
'margin_fg',
|
||||||
@ -49,6 +50,7 @@ class Options:
|
|||||||
highlight_removed_bg: Color = Color(253, 184, 192)
|
highlight_removed_bg: Color = Color(253, 184, 192)
|
||||||
hunk_bg: Color = Color(241, 248, 255)
|
hunk_bg: Color = Color(241, 248, 255)
|
||||||
hunk_margin_bg: Color = Color(219, 237, 255)
|
hunk_margin_bg: Color = Color(219, 237, 255)
|
||||||
|
ignore_paths: typing.Tuple[str, ...] = ()
|
||||||
margin_bg: Color = Color(250, 251, 252)
|
margin_bg: Color = Color(250, 251, 252)
|
||||||
margin_fg: Color = Color(170, 170, 170)
|
margin_fg: Color = Color(170, 170, 170)
|
||||||
margin_filler_bg: typing.Optional[kitty.fast_data_types.Color] = None
|
margin_filler_bg: typing.Optional[kitty.fast_data_types.Color] = None
|
||||||
|
|||||||
7
kittens/diff/options/utils.py
Normal file → Executable file
7
kittens/diff/options/utils.py
Normal file → Executable file
@ -3,7 +3,8 @@
|
|||||||
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
|
||||||
from typing import Any, Dict, Iterable, Tuple, Union
|
import shlex
|
||||||
|
from typing import Any, Dict, Iterable, List, Tuple, Union
|
||||||
|
|
||||||
from kitty.conf.utils import (
|
from kitty.conf.utils import (
|
||||||
KeyFuncWrapper, KittensKeyDefinition, parse_kittens_key
|
KeyFuncWrapper, KittensKeyDefinition, parse_kittens_key
|
||||||
@ -58,6 +59,10 @@ def syntax_aliases(raw: str) -> Dict[str, str]:
|
|||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
def pattern_list(raw: str) -> Tuple[str, ...]:
|
||||||
|
return tuple(shlex.split(raw, comments=True))
|
||||||
|
|
||||||
|
|
||||||
def parse_map(val: str) -> Iterable[KittensKeyDefinition]:
|
def parse_map(val: str) -> Iterable[KittensKeyDefinition]:
|
||||||
x = parse_kittens_key(val, func_with_args.args_funcs)
|
x = parse_kittens_key(val, func_with_args.args_funcs)
|
||||||
if x is not None:
|
if x is not None:
|
||||||
|
|||||||
@ -43,3 +43,43 @@ class TestDiff(BaseTest):
|
|||||||
|
|
||||||
highlights = [h(0, 1, 1), h(1, 3, 2)]
|
highlights = [h(0, 1, 1), h(1, 3, 2)]
|
||||||
self.ae(['S1SaE1ES2SbcE2Ed'], split_with_highlights('abcd', 10, highlights))
|
self.ae(['S1SaE1ES2SbcE2Ed'], split_with_highlights('abcd', 10, highlights))
|
||||||
|
|
||||||
|
def test_walk(self):
|
||||||
|
from pathlib import Path
|
||||||
|
import tempfile
|
||||||
|
from kittens.diff.collect import walk
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
# /tmp/test/
|
||||||
|
# ├── a
|
||||||
|
# │ └── b
|
||||||
|
# │ └── c
|
||||||
|
# ├── d
|
||||||
|
# ├── #d#
|
||||||
|
# ├── e
|
||||||
|
# ├── e~
|
||||||
|
# └── f
|
||||||
|
# │ └── g
|
||||||
|
# └── h space
|
||||||
|
Path(tmpdir, "a/b").mkdir(parents=True)
|
||||||
|
Path(tmpdir, "a/b/c").touch()
|
||||||
|
Path(tmpdir, "b").touch()
|
||||||
|
Path(tmpdir, "d").touch()
|
||||||
|
Path(tmpdir, "#d#").touch()
|
||||||
|
Path(tmpdir, "e").touch()
|
||||||
|
Path(tmpdir, "e~").touch()
|
||||||
|
Path(tmpdir, "f").mkdir()
|
||||||
|
Path(tmpdir, "f/g").touch()
|
||||||
|
Path(tmpdir, "h space").touch()
|
||||||
|
expected_names = {"d", "e", "f/g", "h space"}
|
||||||
|
expected_pmap = {
|
||||||
|
"d": f"{tmpdir}/d",
|
||||||
|
"e": f"{tmpdir}/e",
|
||||||
|
"f/g": f"{tmpdir}/f/g",
|
||||||
|
"h space": f"{tmpdir}/h space"
|
||||||
|
}
|
||||||
|
names = set()
|
||||||
|
pmap = {}
|
||||||
|
walk(tmpdir, names, pmap, ("*~", "#*#", "b"))
|
||||||
|
self.ae(expected_names, names)
|
||||||
|
self.ae(expected_pmap, pmap)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user