vde-worktree 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +52 -0
- package/README.md +52 -0
- package/completions/fish/vw.fish +170 -0
- package/completions/zsh/_vw +287 -0
- package/dist/index.mjs +161 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
package/README.ja.md
CHANGED
|
@@ -25,6 +25,14 @@
|
|
|
25
25
|
|
|
26
26
|
## インストール / ビルド
|
|
27
27
|
|
|
28
|
+
グローバルインストール:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install -g vde-worktree
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
ローカルビルド:
|
|
35
|
+
|
|
28
36
|
```bash
|
|
29
37
|
pnpm install
|
|
30
38
|
pnpm run build
|
|
@@ -44,6 +52,38 @@ vw switch feature/foo
|
|
|
44
52
|
cd "$(vw cd)"
|
|
45
53
|
```
|
|
46
54
|
|
|
55
|
+
`vw cd` は選択した worktree の path を出力するコマンドです。親シェルのディレクトリは直接変更できません。
|
|
56
|
+
|
|
57
|
+
## シェル補完
|
|
58
|
+
|
|
59
|
+
コマンドから補完スクリプトを出力:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
vw completion zsh
|
|
63
|
+
vw completion fish
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
デフォルトの配置先にインストール:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
vw completion zsh --install
|
|
70
|
+
vw completion fish --install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
カスタム配置先にインストール:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
vw completion zsh --install --path ~/.zsh/completions/_vw
|
|
77
|
+
vw completion fish --install --path ~/.config/fish/completions/vw.fish
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
zsh は `fpath` に補完ディレクトリを追加して `compinit` を実行してください:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
fpath=(~/.zsh/completions $fpath)
|
|
84
|
+
autoload -Uz compinit && compinit
|
|
85
|
+
```
|
|
86
|
+
|
|
47
87
|
## 管理ディレクトリ
|
|
48
88
|
|
|
49
89
|
`vw init` 実行後に次を管理します:
|
|
@@ -292,6 +332,18 @@ cd "$(vw cd)"
|
|
|
292
332
|
- `fzf` で worktree を対話選択
|
|
293
333
|
- 選択した絶対 path を stdout に出力
|
|
294
334
|
|
|
335
|
+
### `completion`
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
vw completion zsh
|
|
339
|
+
vw completion fish
|
|
340
|
+
vw completion zsh --install
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
機能:
|
|
344
|
+
- zsh / fish 向け補完スクリプトを出力
|
|
345
|
+
- `--install` 指定時はデフォルトまたは `--path` に補完ファイルを書き込む
|
|
346
|
+
|
|
295
347
|
## merged 判定(ローカル + PR)
|
|
296
348
|
|
|
297
349
|
各 worktree で次を評価します:
|
package/README.md
CHANGED
|
@@ -25,6 +25,14 @@ Japanese documentation: [README.ja.md](./README.ja.md)
|
|
|
25
25
|
|
|
26
26
|
## Install / Build
|
|
27
27
|
|
|
28
|
+
Global install:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install -g vde-worktree
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Local build:
|
|
35
|
+
|
|
28
36
|
```bash
|
|
29
37
|
pnpm install
|
|
30
38
|
pnpm run build
|
|
@@ -44,6 +52,38 @@ vw switch feature/foo
|
|
|
44
52
|
cd "$(vw cd)"
|
|
45
53
|
```
|
|
46
54
|
|
|
55
|
+
`vw cd` prints the selected worktree path. It cannot change the parent shell directory by itself.
|
|
56
|
+
|
|
57
|
+
## Shell Completion
|
|
58
|
+
|
|
59
|
+
Generate from command:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
vw completion zsh
|
|
63
|
+
vw completion fish
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Install to default locations:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
vw completion zsh --install
|
|
70
|
+
vw completion fish --install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Install to custom file path:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
vw completion zsh --install --path ~/.zsh/completions/_vw
|
|
77
|
+
vw completion fish --install --path ~/.config/fish/completions/vw.fish
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
For zsh, ensure completion path is loaded:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
fpath=(~/.zsh/completions $fpath)
|
|
84
|
+
autoload -Uz compinit && compinit
|
|
85
|
+
```
|
|
86
|
+
|
|
47
87
|
## Managed Directories
|
|
48
88
|
|
|
49
89
|
After `vw init`, the tool manages:
|
|
@@ -292,6 +332,18 @@ What it does:
|
|
|
292
332
|
- Interactive worktree picker via `fzf`
|
|
293
333
|
- Prints selected absolute path to stdout
|
|
294
334
|
|
|
335
|
+
### `completion`
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
vw completion zsh
|
|
339
|
+
vw completion fish
|
|
340
|
+
vw completion zsh --install
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
What it does:
|
|
344
|
+
- Prints completion script for zsh/fish
|
|
345
|
+
- With `--install`, writes completion file to shell default path or `--path`
|
|
346
|
+
|
|
295
347
|
## Merge Status (Local + PR)
|
|
296
348
|
|
|
297
349
|
Each worktree reports:
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
function __vw_worktree_branches
|
|
2
|
+
command git rev-parse --is-inside-work-tree >/dev/null 2>/dev/null; or return 0
|
|
3
|
+
command git worktree list --porcelain 2>/dev/null \
|
|
4
|
+
| string match -r '^branch refs/heads/.+$' \
|
|
5
|
+
| string replace 'branch refs/heads/' '' \
|
|
6
|
+
| sort -u
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
function __vw_current_bin
|
|
10
|
+
set -l tokens (commandline -opc)
|
|
11
|
+
if test (count $tokens) -ge 1
|
|
12
|
+
set -l candidate $tokens[1]
|
|
13
|
+
if command -sq $candidate
|
|
14
|
+
echo $candidate
|
|
15
|
+
return
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if command -sq vw
|
|
20
|
+
echo vw
|
|
21
|
+
return
|
|
22
|
+
end
|
|
23
|
+
if command -sq vde-worktree
|
|
24
|
+
echo vde-worktree
|
|
25
|
+
return
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
function __vw_worktree_candidates_with_meta
|
|
30
|
+
command git rev-parse --is-inside-work-tree >/dev/null 2>/dev/null; or return 0
|
|
31
|
+
set -l vw_bin (__vw_current_bin)
|
|
32
|
+
test -n "$vw_bin"; or return 0
|
|
33
|
+
|
|
34
|
+
command $vw_bin list --json 2>/dev/null | command node -e '
|
|
35
|
+
const fs = require("fs")
|
|
36
|
+
const home = process.env.HOME || ""
|
|
37
|
+
const toDisplayPath = (path) => {
|
|
38
|
+
if (typeof path !== "string" || path.length === 0) return ""
|
|
39
|
+
if (home.length === 0) return path
|
|
40
|
+
if (path === home) return "~"
|
|
41
|
+
if (path.startsWith(`${home}/`)) return `~${path.slice(home.length)}`
|
|
42
|
+
return path
|
|
43
|
+
}
|
|
44
|
+
const toFlag = (value) => {
|
|
45
|
+
if (value === true) return "yes"
|
|
46
|
+
if (value === false) return "no"
|
|
47
|
+
return "unknown"
|
|
48
|
+
}
|
|
49
|
+
let payload
|
|
50
|
+
try {
|
|
51
|
+
payload = JSON.parse(fs.readFileSync(0, "utf8"))
|
|
52
|
+
} catch {
|
|
53
|
+
process.exit(0)
|
|
54
|
+
}
|
|
55
|
+
const worktrees = Array.isArray(payload.worktrees) ? payload.worktrees : []
|
|
56
|
+
for (const worktree of worktrees) {
|
|
57
|
+
if (typeof worktree?.branch !== "string" || worktree.branch.length === 0) continue
|
|
58
|
+
const merged = toFlag(worktree?.merged?.overall)
|
|
59
|
+
const dirty = worktree?.dirty === true ? "yes" : "no"
|
|
60
|
+
const locked = worktree?.locked?.value === true ? "yes" : "no"
|
|
61
|
+
const path = toDisplayPath(worktree?.path)
|
|
62
|
+
const summary = `merged=${merged} dirty=${dirty} locked=${locked}${path ? ` path=${path}` : ""}`
|
|
63
|
+
const sanitized = summary.replace(/[\t\r\n]+/g, " ").trim()
|
|
64
|
+
process.stdout.write(`${worktree.branch}\t${sanitized}\n`)
|
|
65
|
+
}
|
|
66
|
+
' 2>/dev/null
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
function __vw_local_branches
|
|
70
|
+
command git rev-parse --is-inside-work-tree >/dev/null 2>/dev/null; or return 0
|
|
71
|
+
command git for-each-ref --format='%(refname:short)' refs/heads 2>/dev/null | sort -u
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
function __vw_switch_branches
|
|
75
|
+
__vw_worktree_branches
|
|
76
|
+
__vw_local_branches
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
function __vw_remote_branches
|
|
80
|
+
command git rev-parse --is-inside-work-tree >/dev/null 2>/dev/null; or return 0
|
|
81
|
+
command git for-each-ref --format='%(refname:short)' refs/remotes 2>/dev/null \
|
|
82
|
+
| string match -rv '.*/HEAD$' \
|
|
83
|
+
| sort -u
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
function __vw_hook_names
|
|
87
|
+
command git rev-parse --is-inside-work-tree >/dev/null 2>/dev/null; or return 0
|
|
88
|
+
set -l repo_root (command git rev-parse --show-toplevel 2>/dev/null); or return 0
|
|
89
|
+
if test -d "$repo_root/.vde/worktree/hooks"
|
|
90
|
+
command ls -1 "$repo_root/.vde/worktree/hooks" 2>/dev/null | string match -r '^(pre|post)-' | sort -u
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
set -l __vw_commands init list status path new switch mv del gone get extract use exec invoke copy link lock unlock cd completion help
|
|
95
|
+
|
|
96
|
+
for __vw_bin in vw vde-worktree
|
|
97
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a init -d "Initialize directories, hooks, and managed exclude entries"
|
|
98
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a list -d "List worktrees with status metadata"
|
|
99
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a status -d "Show a single worktree status"
|
|
100
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a path -d "Print absolute worktree path for branch"
|
|
101
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a new -d "Create branch + worktree under .worktree"
|
|
102
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a switch -d "Idempotent branch entrypoint"
|
|
103
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a mv -d "Rename current non-primary worktree branch"
|
|
104
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a del -d "Delete worktree + branch with safety checks"
|
|
105
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a gone -d "Bulk cleanup by safety-filtered candidate selection"
|
|
106
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a get -d "Fetch remote branch and attach worktree"
|
|
107
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a extract -d "Extract current primary branch into .worktree"
|
|
108
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a use -d "Checkout target branch in primary worktree"
|
|
109
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a exec -d "Run command in target branch worktree"
|
|
110
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a invoke -d "Manually run hook script"
|
|
111
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a copy -d "Copy repo-root files/dirs to target worktree"
|
|
112
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a link -d "Create symlink from target worktree to repo-root file"
|
|
113
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a lock -d "Create or update lock metadata"
|
|
114
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a unlock -d "Remove lock metadata"
|
|
115
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a cd -d "Interactive fzf picker"
|
|
116
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a completion -d "Print or install shell completion scripts"
|
|
117
|
+
complete -c $__vw_bin -f -n "not __fish_seen_subcommand_from $__vw_commands" -a help -d "Show help"
|
|
118
|
+
|
|
119
|
+
complete -c $__vw_bin -l json -d "Output machine-readable JSON"
|
|
120
|
+
complete -c $__vw_bin -l verbose -d "Enable verbose logs"
|
|
121
|
+
complete -c $__vw_bin -l no-hooks -d "Disable hooks for this run (requires --allow-unsafe)"
|
|
122
|
+
complete -c $__vw_bin -l allow-unsafe -d "Explicit unsafe override in non-TTY mode"
|
|
123
|
+
complete -c $__vw_bin -l strict-post-hooks -d "Fail when post hooks fail"
|
|
124
|
+
complete -c $__vw_bin -l hook-timeout-ms -r -d "Override hook timeout"
|
|
125
|
+
complete -c $__vw_bin -l lock-timeout-ms -r -d "Override lock timeout"
|
|
126
|
+
complete -c $__vw_bin -s h -l help -d "Show help"
|
|
127
|
+
complete -c $__vw_bin -s v -l version -d "Show version"
|
|
128
|
+
|
|
129
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from status" -a "(__vw_worktree_candidates_with_meta)"
|
|
130
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from path" -a "(__vw_worktree_candidates_with_meta)"
|
|
131
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from switch" -a "(__vw_switch_branches)"
|
|
132
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from mv" -a "(__vw_local_branches)"
|
|
133
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from del" -a "(__vw_worktree_candidates_with_meta)"
|
|
134
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from get" -a "(__vw_remote_branches)"
|
|
135
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from use" -a "(__vw_switch_branches)"
|
|
136
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from exec" -a "(__vw_worktree_candidates_with_meta)"
|
|
137
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from invoke" -a "(__vw_hook_names)"
|
|
138
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from lock" -a "(__vw_worktree_candidates_with_meta)"
|
|
139
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from unlock" -a "(__vw_worktree_candidates_with_meta)"
|
|
140
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from help" -a "$__vw_commands"
|
|
141
|
+
|
|
142
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from del" -l force-dirty -d "Allow dirty worktree for del"
|
|
143
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from del" -l allow-unpushed -d "Allow unpushed commits for del"
|
|
144
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from del" -l force-unmerged -d "Allow unmerged worktree for del"
|
|
145
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from del" -l force-locked -d "Allow deleting locked worktree"
|
|
146
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from del" -l force -d "Enable all del force flags"
|
|
147
|
+
|
|
148
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from gone" -l apply -d "Apply deletion"
|
|
149
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from gone" -l dry-run -d "Dry-run mode"
|
|
150
|
+
|
|
151
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from extract" -l current -d "Extract current worktree branch"
|
|
152
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from extract" -l from -r -d "Path used by extract --from"
|
|
153
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from extract" -l stash -d "Allow stash when dirty"
|
|
154
|
+
|
|
155
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from use" -l allow-agent -d "Allow non-TTY execution for use"
|
|
156
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from use" -l allow-unsafe -d "Allow unsafe behavior in non-TTY mode"
|
|
157
|
+
|
|
158
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from link" -l no-fallback -d "Disable copy fallback when symlink fails"
|
|
159
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from lock" -l owner -r -d "Lock owner"
|
|
160
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from lock" -l reason -r -d "Lock reason"
|
|
161
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from unlock" -l owner -r -d "Unlock owner"
|
|
162
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from unlock" -l force -d "Force unlock"
|
|
163
|
+
|
|
164
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from cd" -l prompt -r -d "Custom fzf prompt"
|
|
165
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from cd" -l fzf-arg -r -d "Extra argument passed to fzf"
|
|
166
|
+
|
|
167
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from completion" -a "zsh fish" -d "Shell name"
|
|
168
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from completion" -l install -d "Install completion file"
|
|
169
|
+
complete -c $__vw_bin -n "__fish_seen_subcommand_from completion" -l path -r -d "Install destination file path"
|
|
170
|
+
end
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
#compdef vw vde-worktree
|
|
2
|
+
|
|
3
|
+
_vw_worktree_branches_raw() {
|
|
4
|
+
command git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 0
|
|
5
|
+
command git worktree list --porcelain 2>/dev/null \
|
|
6
|
+
| command sed -n 's/^branch refs\/heads\///p' \
|
|
7
|
+
| command sort -u
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
_vw_worktree_candidate_rows_raw() {
|
|
11
|
+
command git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 0
|
|
12
|
+
local vw_bin="${words[1]:-vw}"
|
|
13
|
+
command -v "$vw_bin" >/dev/null 2>&1 || return 0
|
|
14
|
+
|
|
15
|
+
command "$vw_bin" list --json 2>/dev/null | command node -e '
|
|
16
|
+
const fs = require("fs")
|
|
17
|
+
const home = process.env.HOME || ""
|
|
18
|
+
const toDisplayPath = (path) => {
|
|
19
|
+
if (typeof path !== "string" || path.length === 0) return ""
|
|
20
|
+
if (home.length === 0) return path
|
|
21
|
+
if (path === home) return "~"
|
|
22
|
+
if (path.startsWith(`${home}/`)) return `~${path.slice(home.length)}`
|
|
23
|
+
return path
|
|
24
|
+
}
|
|
25
|
+
const toFlag = (value) => {
|
|
26
|
+
if (value === true) return "yes"
|
|
27
|
+
if (value === false) return "no"
|
|
28
|
+
return "unknown"
|
|
29
|
+
}
|
|
30
|
+
let payload
|
|
31
|
+
try {
|
|
32
|
+
payload = JSON.parse(fs.readFileSync(0, "utf8"))
|
|
33
|
+
} catch {
|
|
34
|
+
process.exit(0)
|
|
35
|
+
}
|
|
36
|
+
const worktrees = Array.isArray(payload.worktrees) ? payload.worktrees : []
|
|
37
|
+
for (const worktree of worktrees) {
|
|
38
|
+
if (typeof worktree?.branch !== "string" || worktree.branch.length === 0) continue
|
|
39
|
+
const merged = toFlag(worktree?.merged?.overall)
|
|
40
|
+
const dirty = worktree?.dirty === true ? "yes" : "no"
|
|
41
|
+
const locked = worktree?.locked?.value === true ? "yes" : "no"
|
|
42
|
+
const path = toDisplayPath(worktree?.path)
|
|
43
|
+
const summary = `merged=${merged} dirty=${dirty} locked=${locked}${path ? ` path=${path}` : ""}`
|
|
44
|
+
const sanitized = summary.replace(/[\t\r\n]+/g, " ").trim()
|
|
45
|
+
process.stdout.write(`${worktree.branch}\t${sanitized}\n`)
|
|
46
|
+
}
|
|
47
|
+
' 2>/dev/null
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
_vw_local_branches_raw() {
|
|
51
|
+
command git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 0
|
|
52
|
+
command git for-each-ref --format='%(refname:short)' refs/heads 2>/dev/null | command sort -u
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
_vw_remote_branches_raw() {
|
|
56
|
+
command git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 0
|
|
57
|
+
command git for-each-ref --format='%(refname:short)' refs/remotes 2>/dev/null \
|
|
58
|
+
| command sed '/\/HEAD$/d' \
|
|
59
|
+
| command sort -u
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
_vw_hook_names_raw() {
|
|
63
|
+
command git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 0
|
|
64
|
+
local repo_root
|
|
65
|
+
repo_root="$(command git rev-parse --show-toplevel 2>/dev/null)" || return 0
|
|
66
|
+
command ls -1 "$repo_root/.vde/worktree/hooks" 2>/dev/null \
|
|
67
|
+
| command grep -E '^(pre|post)-' \
|
|
68
|
+
| command sort -u
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_vw_describe_values() {
|
|
72
|
+
local label="$1"
|
|
73
|
+
shift
|
|
74
|
+
local -a values
|
|
75
|
+
values=("$@")
|
|
76
|
+
if (( ${#values} == 0 )); then
|
|
77
|
+
_message "no ${label} candidates"
|
|
78
|
+
return 0
|
|
79
|
+
fi
|
|
80
|
+
_describe -t "${label}" "${label}" values
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
_vw_complete_worktree_branches() {
|
|
84
|
+
local -a values
|
|
85
|
+
values=("${(@f)$(_vw_worktree_branches_raw)}")
|
|
86
|
+
_vw_describe_values "worktree-branch" "${values[@]}"
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
_vw_complete_worktree_branches_with_meta() {
|
|
90
|
+
local -a rows branches descriptions
|
|
91
|
+
local row branch summary
|
|
92
|
+
rows=("${(@f)$(_vw_worktree_candidate_rows_raw)}")
|
|
93
|
+
|
|
94
|
+
for row in "${rows[@]}"; do
|
|
95
|
+
branch="${row%%$'\t'*}"
|
|
96
|
+
summary="${row#*$'\t'}"
|
|
97
|
+
if [[ -z "${branch}" ]]; then
|
|
98
|
+
continue
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
branches+=("${branch}")
|
|
102
|
+
descriptions+=("${summary}")
|
|
103
|
+
done
|
|
104
|
+
|
|
105
|
+
if (( ${#branches} > 0 )); then
|
|
106
|
+
compadd -Ql -d descriptions -a branches
|
|
107
|
+
return 0
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
_vw_complete_worktree_branches
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_vw_complete_local_branches() {
|
|
114
|
+
local -a values
|
|
115
|
+
values=("${(@f)$(_vw_local_branches_raw)}")
|
|
116
|
+
_vw_describe_values "local-branch" "${values[@]}"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
_vw_complete_switch_branches() {
|
|
120
|
+
local -a values
|
|
121
|
+
values=("${(@u)${(@f)$(_vw_worktree_branches_raw)} ${(@f)$(_vw_local_branches_raw)}}")
|
|
122
|
+
_vw_describe_values "branch" "${values[@]}"
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
_vw_complete_remote_branches() {
|
|
126
|
+
local -a values
|
|
127
|
+
values=("${(@f)$(_vw_remote_branches_raw)}")
|
|
128
|
+
_vw_describe_values "remote-branch" "${values[@]}"
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
_vw_complete_hooks() {
|
|
132
|
+
local -a values
|
|
133
|
+
values=("${(@f)$(_vw_hook_names_raw)}")
|
|
134
|
+
_vw_describe_values "hook" "${values[@]}"
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
_vw() {
|
|
138
|
+
local curcontext="$curcontext" state
|
|
139
|
+
local -a line
|
|
140
|
+
typeset -a commands
|
|
141
|
+
typeset -a global_options
|
|
142
|
+
|
|
143
|
+
commands=(
|
|
144
|
+
"init:Initialize directories, hooks, and managed exclude entries"
|
|
145
|
+
"list:List worktrees with status metadata"
|
|
146
|
+
"status:Show a single worktree status"
|
|
147
|
+
"path:Print absolute worktree path for branch"
|
|
148
|
+
"new:Create branch + worktree under .worktree"
|
|
149
|
+
"switch:Idempotent branch entrypoint"
|
|
150
|
+
"mv:Rename current non-primary worktree branch and move its directory"
|
|
151
|
+
"del:Delete worktree + branch with safety checks"
|
|
152
|
+
"gone:Bulk cleanup by safety-filtered candidate selection"
|
|
153
|
+
"get:Fetch remote branch and attach worktree"
|
|
154
|
+
"extract:Extract current primary branch into .worktree"
|
|
155
|
+
"use:Checkout target branch in primary worktree"
|
|
156
|
+
"exec:Run command in target branch worktree"
|
|
157
|
+
"invoke:Manually run hook script"
|
|
158
|
+
"copy:Copy repo-root files/dirs to target worktree"
|
|
159
|
+
"link:Create symlink from target worktree to repo-root file"
|
|
160
|
+
"lock:Create or update lock metadata"
|
|
161
|
+
"unlock:Remove lock metadata"
|
|
162
|
+
"cd:Interactive fzf picker that prints selected worktree path"
|
|
163
|
+
"completion:Print or install shell completion scripts"
|
|
164
|
+
"help:Show help"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
global_options=(
|
|
168
|
+
"--json[Output machine-readable JSON]"
|
|
169
|
+
"--verbose[Enable verbose logs]"
|
|
170
|
+
"--no-hooks[Disable hooks for this run]"
|
|
171
|
+
"--allow-unsafe[Allow unsafe behavior in non-TTY mode]"
|
|
172
|
+
"--strict-post-hooks[Fail when post hooks fail]"
|
|
173
|
+
"--hook-timeout-ms[Override hook timeout]:ms:"
|
|
174
|
+
"--lock-timeout-ms[Override repository lock timeout]:ms:"
|
|
175
|
+
"--help[Show help]"
|
|
176
|
+
"--version[Show version]"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
_arguments -C \
|
|
180
|
+
$global_options \
|
|
181
|
+
"1:command:->command" \
|
|
182
|
+
"*:: :->arguments"
|
|
183
|
+
|
|
184
|
+
case $state in
|
|
185
|
+
command)
|
|
186
|
+
_describe -t commands "vw command" commands
|
|
187
|
+
return
|
|
188
|
+
;;
|
|
189
|
+
arguments)
|
|
190
|
+
local current_command="${line[1]:-${words[2]}}"
|
|
191
|
+
case "${current_command}" in
|
|
192
|
+
status)
|
|
193
|
+
_arguments \
|
|
194
|
+
"1:branch:_vw_complete_worktree_branches_with_meta"
|
|
195
|
+
;;
|
|
196
|
+
path)
|
|
197
|
+
_arguments \
|
|
198
|
+
"1:branch:_vw_complete_worktree_branches_with_meta"
|
|
199
|
+
;;
|
|
200
|
+
switch)
|
|
201
|
+
_arguments \
|
|
202
|
+
"1:branch:_vw_complete_switch_branches"
|
|
203
|
+
;;
|
|
204
|
+
mv)
|
|
205
|
+
_arguments \
|
|
206
|
+
"1:new-branch:_vw_complete_local_branches"
|
|
207
|
+
;;
|
|
208
|
+
del)
|
|
209
|
+
_arguments \
|
|
210
|
+
"1:branch:_vw_complete_worktree_branches_with_meta" \
|
|
211
|
+
"--force-dirty[Allow dirty worktree for del]" \
|
|
212
|
+
"--allow-unpushed[Allow unpushed commits for del]" \
|
|
213
|
+
"--force-unmerged[Allow unmerged worktree for del]" \
|
|
214
|
+
"--force-locked[Allow deleting locked worktree]" \
|
|
215
|
+
"--force[Enable all del force flags]"
|
|
216
|
+
;;
|
|
217
|
+
gone)
|
|
218
|
+
_arguments \
|
|
219
|
+
"--apply[Apply deletion]" \
|
|
220
|
+
"--dry-run[Dry-run mode]"
|
|
221
|
+
;;
|
|
222
|
+
get)
|
|
223
|
+
_arguments \
|
|
224
|
+
"1:remote-branch:_vw_complete_remote_branches"
|
|
225
|
+
;;
|
|
226
|
+
extract)
|
|
227
|
+
_arguments \
|
|
228
|
+
"--current[Extract current worktree branch]" \
|
|
229
|
+
"--from[Path used by extract --from]:path:_files" \
|
|
230
|
+
"--stash[Allow stash when dirty]"
|
|
231
|
+
;;
|
|
232
|
+
use)
|
|
233
|
+
_arguments \
|
|
234
|
+
"1:branch:_vw_complete_switch_branches" \
|
|
235
|
+
"--allow-agent[Allow non-TTY execution for use]" \
|
|
236
|
+
"--allow-unsafe[Allow unsafe behavior in non-TTY mode]"
|
|
237
|
+
;;
|
|
238
|
+
exec)
|
|
239
|
+
_arguments \
|
|
240
|
+
"1:branch:_vw_complete_worktree_branches_with_meta"
|
|
241
|
+
;;
|
|
242
|
+
invoke)
|
|
243
|
+
_arguments \
|
|
244
|
+
"1:hook:_vw_complete_hooks"
|
|
245
|
+
;;
|
|
246
|
+
copy)
|
|
247
|
+
_arguments \
|
|
248
|
+
"*:repo-relative-path:_files"
|
|
249
|
+
;;
|
|
250
|
+
link)
|
|
251
|
+
_arguments \
|
|
252
|
+
"*:repo-relative-path:_files" \
|
|
253
|
+
"--no-fallback[Disable copy fallback when symlink fails]"
|
|
254
|
+
;;
|
|
255
|
+
lock)
|
|
256
|
+
_arguments \
|
|
257
|
+
"1:branch:_vw_complete_worktree_branches_with_meta" \
|
|
258
|
+
"--owner[Lock owner]:owner:" \
|
|
259
|
+
"--reason[Lock reason]:reason:"
|
|
260
|
+
;;
|
|
261
|
+
unlock)
|
|
262
|
+
_arguments \
|
|
263
|
+
"1:branch:_vw_complete_worktree_branches_with_meta" \
|
|
264
|
+
"--owner[Unlock owner]:owner:" \
|
|
265
|
+
"--force[Force unlock]"
|
|
266
|
+
;;
|
|
267
|
+
cd)
|
|
268
|
+
_arguments \
|
|
269
|
+
"--prompt[Custom fzf prompt]:prompt:" \
|
|
270
|
+
"--fzf-arg[Extra argument passed to fzf]:arg:"
|
|
271
|
+
;;
|
|
272
|
+
completion)
|
|
273
|
+
_arguments \
|
|
274
|
+
"1:shell:(zsh fish)" \
|
|
275
|
+
"--install[Install completion file to default or --path]" \
|
|
276
|
+
"--path[Install destination file path]:path:_files"
|
|
277
|
+
;;
|
|
278
|
+
help)
|
|
279
|
+
_arguments \
|
|
280
|
+
"1:command:(${(j: :)${commands%%:*}})"
|
|
281
|
+
;;
|
|
282
|
+
esac
|
|
283
|
+
;;
|
|
284
|
+
esac
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
compdef _vw vw vde-worktree
|