Compare commits

..

3 Commits

Author SHA1 Message Date
e26e40413f Change download url to branch
Backport from 065ef47b2
2023-03-06 11:04:49 -05:00
5e2943624a Use shlex to split custom vim command
This allows to include spaces in vim command
Add example to change default diff algorithm
Move to first line on each file

Backport from da5e24260
2023-03-06 11:01:40 -05:00
32e186695a Keep new changes on right
Saves and restores splitright option
Backported from 512df2948
2023-03-06 10:53:14 -05:00
2 changed files with 37 additions and 68 deletions

View File

@ -24,34 +24,20 @@ You may need to add `~/bin` to your PATH variable if not already done. See [here
# Usage # Usage
```help ```help
usage: vimtabdiff.py [-h] [--vim VIM] [--onlydiffs] pathA pathB usage: vimtabdiff.py [-h] [--vim VIM] pathA pathB
Show diff of files from two directories in vim tabs Show diff of files from two directories in vim tabs
positional arguments: positional arguments:
pathA pathA
pathB pathB
options: options:
-h, --help show this help message and exit -h, --help show this help message and exit
--vim VIM vim command to run --vim VIM vim command to run
--onlydiffs only open files where there is a diff
``` ```
## Relevant vim tips # Git difftool
* `gt` → Go to next tab
* `gT` → Go to previous tab
* `:tabr` → Go to first tab
* `:drop filenam<Tab>` → Go to the tab with filename
* `g<Tab>` → Go to last used tab (Works in vim version > 8.2.1401)
* `:set mouse=a` → Now clicking on a tab works
* `]c` → Go to next diff hunk
* `[c` → Go to previous diff hunk
* `do`, `dp` → Diff obtain, Diff put
* `zo`, `zc`, `zi` → Fold open, Fold close, toggle all folds
# See Git diffs
## Setup ## Setup
@ -79,7 +65,7 @@ Using clean vim without reading `vimrc`
Git config file (`~/.gitconfig`) should look like this Git config file (`~/.gitconfig`) should look like this
```TOML ```toml
[alias] [alias]
... ...
dt = difftool --tool vimtabdiff --dir-diff dt = difftool --tool vimtabdiff --dir-diff
@ -97,7 +83,4 @@ Using better diff algorithm
# Similar # Similar
* https://gist.github.com/Osse/4709787 is very similar, written as a `zsh` script. https://gist.github.com/Osse/4709787
* https://github.com/will133/vim-dirdiff is a Vim plugin that uses an interactive list of files instead of tabs.
* https://github.com/Soares/tabdiff.vim is a Vim plugin takes a list of files as aguments.
* [`:Git difftool -y`](https://github.com/tpope/vim-fugitive/blob/d507d00bd04794119beeb41da118774a96815b65/doc/fugitive.txt#L92) is a command from vim-fugitive which is a vim git plugin.

View File

@ -1,45 +1,34 @@
#!/usr/bin/python3 #!/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/.
import os import os
import argparse import argparse
import pathlib
import itertools import itertools
import tempfile import tempfile
import subprocess import subprocess
import shlex import shlex
from pathlib import Path
from typing import TypeVar
from collections.abc import Iterator, Callable
R = TypeVar('R') def star(f):
def star(f: Callable[..., R]) -> Callable[[tuple], R]:
""" see https://stackoverflow.com/q/21892989 """ """ see https://stackoverflow.com/q/21892989 """
return lambda args: f(*args) return lambda args: f(*args)
def parse_args() -> argparse.Namespace: def parse_args():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Show diff of files from two directories in vim tabs", description="Show diff of files from two directories in vim tabs",
epilog="See https://github.com/balki/vimtabdiff for more info") epilog="See https://github.com/balki/vimtabdiff for more info")
parser.add_argument("pathA", type=Path) parser.add_argument("pathA")
parser.add_argument("pathB", type=Path) parser.add_argument("pathB")
parser.add_argument("--vim", help="vim command to run", default="vim") 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"
)
return parser.parse_args() return parser.parse_args()
def get_dir_info(dirpath: Path | None) -> tuple[list[Path], list[Path]]: def get_dir_info(dirname):
if not dirpath: if not dirname:
return [], [] return [], []
dirs, files = [], [] dirs, files = [], []
for p in dirpath.iterdir(): dirp = pathlib.Path(dirname)
for p in dirp.iterdir():
if p.is_dir(): if p.is_dir():
dirs.append(p) dirs.append(p)
else: else:
@ -47,26 +36,27 @@ def get_dir_info(dirpath: Path | None) -> tuple[list[Path], list[Path]]:
return dirs, files return dirs, files
def get_pairs(aPaths: list[Path], def get_pairs(aItems, bItems):
bPaths: list[Path]) -> Iterator[tuple[Path | None, Path | None]]: aItems = [(item, 'A') for item in aItems]
aItems = [(item, 'A') for item in aPaths] bItems = [(item, 'B') for item in bItems]
bItems = [(item, 'B') for item in bPaths]
abItems = aItems + bItems abItems = aItems + bItems
abItems.sort(key=star(lambda item, tag: (item.name, tag))) abItems.sort(key=star(lambda item, tag: (item.name, tag)))
for _, items in itertools.groupby(abItems, for _, items in itertools.groupby(abItems,
key=star(lambda item, _: item.name)): key=star(lambda item, _: item.name)):
match list(items): items = list(items)
case [(aItem, _), (bItem, _)]: # NOTE: python 3.10's match expression can make this better
if len(items) == 2:
(aItem, _), (bItem, _) = items
yield aItem, bItem yield aItem, bItem
case [(item, 'A'),]: else:
(item, tag), = items
if tag == 'A':
yield item, None yield item, None
case [(item, 'B'),]: else:
yield None, item yield None, item
def get_file_pairs( def get_file_pairs(a, b):
a: Path | None,
b: Path | None) -> Iterator[tuple[Path | None, Path | None]]:
aDirs, aFiles = get_dir_info(a) aDirs, aFiles = get_dir_info(a)
bDirs, bFiles = get_dir_info(b) bDirs, bFiles = get_dir_info(b)
yield from get_pairs(aFiles, bFiles) yield from get_pairs(aFiles, bFiles)
@ -74,7 +64,7 @@ def get_file_pairs(
yield from get_file_pairs(aDir, bDir) yield from get_file_pairs(aDir, bDir)
def main() -> None: def main():
args = parse_args() args = parse_args()
vimCmdFile = tempfile.NamedTemporaryFile(mode='w', delete=False) vimCmdFile = tempfile.NamedTemporaryFile(mode='w', delete=False)
with vimCmdFile: with vimCmdFile:
@ -86,13 +76,9 @@ def main() -> None:
for a, b in get_file_pairs(args.pathA, args.pathB): for a, b in get_file_pairs(args.pathA, args.pathB):
aPath = a.resolve() if a else os.devnull aPath = a.resolve() if a else os.devnull
bPath = b.resolve() if b else os.devnull bPath = b.resolve() if b else os.devnull
if ( print(
args.onlydiffs f"tabedit {aPath} | vsp {bPath}",
and a and b file=vimCmdFile)
and open(aPath, mode="rb").read() == open(bPath, mode="rb").read()
):
continue
print(f"tabedit {aPath} | vsp {bPath}", file=vimCmdFile)
cmds = f""" cmds = f"""
let &splitright = s:spr let &splitright = s:spr
tabdo windo :1 tabdo windo :1