- Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathvimtabdiff.py
More file actions
Latest commit
executable file
·113 lines (96 loc) · 3.53 KB
/
Copy pathvimtabdiff.py
File metadata and controls
executable file
·113 lines (96 loc) · 3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/usr/bin/python3
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
importos
importargparse
importitertools
importtempfile
importsubprocess
importshlex
frompathlibimportPath
fromtypingimportTypeVar
fromcollections.abcimportIterator, Callable
R=TypeVar('R')
defstar(f: Callable[..., R]) ->Callable[[tuple], R]:
""" see https://stackoverflow.com/q/21892989 """
returnlambdaargs: f(*args)
defparse_args() ->argparse.Namespace:
parser=argparse.ArgumentParser(
description="Show diff of files from two directories in vim tabs",
epilog="See https://github.com/balki/vimtabdiff for more info")
parser.add_argument("pathA", type=Path)
parser.add_argument("pathB", type=Path)
parser.add_argument("--vim", help="vim command to run", default="vim")
parser.add_argument(
"--onlydiffs", help="only open files where there is a diff", action="store_true"
)
parser.add_argument(
"--skipmissing", help="skip non-existent files", action="store_true"
)
returnparser.parse_args()
defget_dir_info(dirpath: Path|None) ->tuple[list[Path], list[Path]]:
ifnotdirpath:
return [], []
dirs, files= [], []
forpindirpath.iterdir():
ifp.is_dir():
dirs.append(p)
else:
files.append(p)
returndirs, files
defget_pairs(aPaths: list[Path],
bPaths: list[Path]) ->Iterator[tuple[Path|None, Path|None]]:
aItems= [(item, 'A') foriteminaPaths]
bItems= [(item, 'B') foriteminbPaths]
abItems=aItems+bItems
abItems.sort(key=star(lambdaitem, tag: (item.name, tag)))
for_, itemsinitertools.groupby(abItems,
key=star(lambdaitem, _: item.name)):
matchlist(items):
case [(aItem, _), (bItem, _)]:
yieldaItem, bItem
case [(item, 'A'),]:
yielditem, None
case [(item, 'B'),]:
yieldNone, item
defget_file_pairs(
a: Path|None,
b: Path|None) ->Iterator[tuple[Path|None, Path|None]]:
aDirs, aFiles=get_dir_info(a)
bDirs, bFiles=get_dir_info(b)
yieldfromget_pairs(aFiles, bFiles)
foraDir, bDiringet_pairs(aDirs, bDirs):
yieldfromget_file_pairs(aDir, bDir)
defmain() ->None:
args=parse_args()
vimCmdFile=tempfile.NamedTemporaryFile(mode='w', delete=False)
withvimCmdFile:
cmds=f"""
let s:spr = &splitright
set splitright
"""
print(cmds, file=vimCmdFile)
fora, binget_file_pairs(args.pathA, args.pathB):
aPath=a.resolve() ifaelseos.devnull
bPath=b.resolve() ifbelseos.devnull
if (
(args.skipmissingand (notaornotb)) or
(args.onlydiffs
andaandb
andopen(aPath, mode="rb").read() ==open(bPath, mode="rb").read())
):
continue
print(f"tabedit {aPath} | vsp {bPath}", file=vimCmdFile)
cmds=f"""
let &splitright = s:spr
tabdo windo :1
tabdo windo diffthis
tabdo windo diffupdate
tabfirst | tabclose
call delete("{vimCmdFile.name}")
"""
print(cmds, file=vimCmdFile)
subprocess.run(shlex.split(args.vim) + ["-S", vimCmdFile.name])
if__name__=='__main__':
main()