Compare commits

...

16 Commits

Author SHA1 Message Date
065ef47b2b Change download url to branch 2023-03-06 11:04:28 -05:00
702d3a6889 Add vim-fugitive command to similar section 2023-03-01 00:13:42 -05:00
512df2948e Keep new changes on right
Saves and restores splitright option
2023-03-01 00:05:35 -05:00
Balki
e81277ecb4
Merge pull request #6 from ilyagr/diffonly
Option to skip creating tabs for identical files. Useful outside git.
2023-03-01 05:04:30 +00:00
Ilya Grigoriev
4188c51081 Option to skip creating tabs for identical files 2023-02-28 18:53:16 -08:00
Ilya Grigoriev
5702bf8e27 Unindent help text in README 2023-02-28 18:41:06 -08:00
Balki
732fad0a98
Merge pull request #4 from ilyagr/patch-1
Add more similar plugins to the README
2023-03-01 01:32:29 +00:00
Ilya Grigoriev
c2809e6e0e Add more similar plugins to the README 2023-02-28 16:38:21 -08:00
731553906d update vim tips 2023-01-05 16:04:40 -05:00
c907c006db improve type annotations 2022-12-21 21:29:53 -05:00
fdae5aa6de Fix mypy errors 2022-12-21 20:50:43 -05:00
da5e24260a 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
2022-12-20 13:59:12 -05:00
bb6fa28de0 fix README link 2022-12-10 19:48:02 -05:00
e7744c8e9a update README formatting 2022-12-10 19:43:02 -05:00
da9eb32e36 update README 2022-12-10 19:40:11 -05:00
7c11878345 Add type annotations and use match statement
Now works only in python3.10 and above
2022-12-09 21:58:02 -05:00
2 changed files with 112 additions and 48 deletions

View File

@ -1,19 +1,57 @@
# Usage
```help
usage: vimtabdiff.py [-h] [--vim VIM] pathA pathB
Do you use `git difftool` to review changes before making a commit? The problem with that is that you get to see the diff of one file at a time. You can't easily stop it after few files and you can't go back to a previous file. `vimtabdiff.py` loads all the files with diffs, one in each vim tab page. You can move around any file and edit the diffs easily.
Show diff of files from two directories in vim tabs
positional arguments:
pathA
pathB
# Install
options:
-h, --help show this help message and exit
--vim VIM vim command to run
```bash
mkdir -p ~/bin
# for python version >= 3.10
curl -o ~/bin/vimtabdiff.py "https://raw.githubusercontent.com/balki/vimtabdiff/master/vimtabdiff.py"
# for python version < 3.10
curl -o ~/bin/vimtabdiff.py "https://raw.githubusercontent.com/balki/vimtabdiff/br-py38/vimtabdiff.py"
chmod +x ~/bin/vimtabdiff.py
```
# Git difftool
You may need to add `~/bin` to your PATH variable if not already done. See [here](https://wiki.archlinux.org/title/Environment_variables#Per_user) for help.
👍 this [issue](https://github.com/balki/vimtabdiff/issues/1) for `pip install` support
# Screenshot
![image](https://user-images.githubusercontent.com/189196/206880555-c71b472c-144c-4c82-a4ab-f8a4fd36f7a5.png)
# Usage
```help
usage: vimtabdiff.py [-h] [--vim VIM] [--onlydiffs] pathA pathB
Show diff of files from two directories in vim tabs
positional arguments:
pathA
pathB
options:
-h, --help show this help message and exit
--vim VIM vim command to run
--onlydiffs only open files where there is a diff
```
## Relevant vim tips
* `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
@ -34,30 +72,32 @@
## Using custom vim command
Using clean vim without reading `vimrc`
```bash
git config --global difftool.vimtabdiff.cmd 'vimtabdiff.py --vim "vim --clean" $LOCAL $REMOTE'
```
Git config file (`~/.gitconfig`) should look like this
```toml
```TOML
[alias]
...
dt = difftool --tool vimtabdiff --dir-diff
[difftool "vimtabdiff"]
cmd = vimtabdiff.py --vim \"vim --clean\" $LOCAL $REMOTE
```
Using better diff algorithm
```bash
git config --global difftool.vimtabdiff.cmd 'vimtabdiff.py --vim "vim +\"set diffopt+=algorithm:patience\"" $LOCAL $REMOTE'
# Known issues
```
1. If your path to custom vim has space, it does not work. i.e. Following does *not* work
```bash
git config --global difftool.vimtabdiff.cmd 'vimtabdiff.py --vim "/home/foo/my files/bin/vim" $LOCAL $REMOTE'
```
2. Not tested in non-linux OS. Pull requests welcome if found any issues.
*Note:* Not tested in non-linux OS. But I guess it should work fine. Pull requests welcome if found any issues.
# Similar
https://gist.github.com/Osse/4709787
* https://gist.github.com/Osse/4709787 is very similar, written as a `zsh` script.
* 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,33 +1,45 @@
#!/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 argparse
import pathlib
import itertools
import tempfile
import subprocess
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 """
return lambda args: f(*args)
def parse_args():
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Show diff of files from two directories in vim tabs")
parser.add_argument("pathA")
parser.add_argument("pathB")
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"
)
return parser.parse_args()
def get_dir_info(dirname):
if not dirname:
def get_dir_info(dirpath: Path | None) -> tuple[list[Path], list[Path]]:
if not dirpath:
return [], []
dirs, files = [], []
dirp = pathlib.Path(dirname)
for p in dirp.iterdir():
for p in dirpath.iterdir():
if p.is_dir():
dirs.append(p)
else:
@ -35,27 +47,26 @@ def get_dir_info(dirname):
return dirs, files
def get_pairs(aItems, bItems):
aItems = [(item, 'A') for item in aItems]
bItems = [(item, 'B') for item in bItems]
def get_pairs(aPaths: list[Path],
bPaths: list[Path]) -> Iterator[tuple[Path | None, Path | None]]:
aItems = [(item, 'A') for item in aPaths]
bItems = [(item, 'B') for item in bPaths]
abItems = aItems + bItems
abItems.sort(key=star(lambda item, tag: (item.name, tag)))
for _, items in itertools.groupby(abItems,
key=star(lambda item, _: item.name)):
items = list(items)
# NOTE: python 3.10's match expression can make this better
if len(items) == 2:
(aItem, _), (bItem, _) = items
yield aItem, bItem
else:
(item, tag), = items
if tag == 'A':
match list(items):
case [(aItem, _), (bItem, _)]:
yield aItem, bItem
case [(item, 'A'),]:
yield item, None
else:
case [(item, 'B'),]:
yield None, item
def get_file_pairs(a, b):
def get_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)
yield from get_pairs(aFiles, bFiles)
@ -63,22 +74,35 @@ def get_file_pairs(a, b):
yield from get_file_pairs(aDir, bDir)
def main():
def main() -> None:
args = parse_args()
vimCmdFile = tempfile.NamedTemporaryFile(mode='w', delete=False)
with vimCmdFile:
cmds = f"""
let s:spr = &splitright
set splitright
"""
print(cmds, file=vimCmdFile)
for a, b in get_file_pairs(args.pathA, args.pathB):
aPath = a.resolve() if a else os.devnull
bPath = b.resolve() if b else os.devnull
print(
f"tabedit {aPath} | diffthis | vsp {bPath} | diffthis | diffupdate",
file=vimCmdFile)
if (
args.onlydiffs
and a and b
and open(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(args.vim.split() + ["-S", vimCmdFile.name])
subprocess.run(shlex.split(args.vim) + ["-S", vimCmdFile.name])
if __name__ == '__main__':