Skip to content

Commit 3a34152

Browse files
committed
Merge branch 'pw/worktree-list-display-width-fix' into next
"git worktree list" attempts to show paths to worktrees while aligning them, but miscounted display columns for the paths when non-ASCII characters were involved, which has been corrected. * pw/worktree-list-display-width-fix: worktree list: quote paths worktree list: fix column spacing
2 parents 4c43c53 + 08dfa59 commit 3a34152

File tree

2 files changed

+53
-25
lines changed

2 files changed

+53
-25
lines changed

builtin/worktree.c

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -975,14 +975,18 @@ static void show_worktree_porcelain(struct worktree *wt, int line_terminator)
975975
fputc(line_terminator, stdout);
976976
}
977977

978-
static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
978+
struct worktree_display {
979+
char *path;
980+
int width;
981+
};
982+
983+
static void show_worktree(struct worktree *wt, struct worktree_display *display,
984+
int path_maxwidth, int abbrev_len)
979985
{
980986
struct strbuf sb = STRBUF_INIT;
981-
int cur_path_len = strlen(wt->path);
982-
int path_adj = cur_path_len - utf8_strwidth(wt->path);
983987
const char *reason;
984988

985-
strbuf_addf(&sb, "%-*s ", 1 + path_maxlen + path_adj, wt->path);
989+
strbuf_addf(&sb, "%s%*s", display->path, 1 + path_maxwidth - display->width, "");
986990
if (wt->is_bare)
987991
strbuf_addstr(&sb, "(bare)");
988992
else {
@@ -1016,20 +1020,27 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
10161020
strbuf_release(&sb);
10171021
}
10181022

1019-
static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen)
1023+
static void measure_widths(struct worktree **wt, int *abbrev,
1024+
struct worktree_display **d, int *maxwidth)
10201025
{
1021-
int i;
1026+
int i, display_alloc = 0;
1027+
struct worktree_display *display = NULL;
1028+
struct strbuf buf = STRBUF_INIT;
10221029

10231030
for (i = 0; wt[i]; i++) {
10241031
int sha1_len;
1025-
int path_len = strlen(wt[i]->path);
1032+
ALLOC_GROW(display, i + 1, display_alloc);
1033+
quote_path(wt[i]->path, NULL, &buf, 0);
1034+
display[i].width = utf8_strwidth(buf.buf);
1035+
display[i].path = strbuf_detach(&buf, NULL);
10261036

1027-
if (path_len > *maxlen)
1028-
*maxlen = path_len;
1037+
if (display[i].width > *maxwidth)
1038+
*maxwidth = display[i].width;
10291039
sha1_len = strlen(repo_find_unique_abbrev(the_repository, &wt[i]->head_oid, *abbrev));
10301040
if (sha1_len > *abbrev)
10311041
*abbrev = sha1_len;
10321042
}
1043+
*d = display;
10331044
}
10341045

10351046
static int pathcmp(const void *a_, const void *b_)
@@ -1075,21 +1086,27 @@ static int list(int ac, const char **av, const char *prefix,
10751086
die(_("the option '%s' requires '%s'"), "-z", "--porcelain");
10761087
else {
10771088
struct worktree **worktrees = get_worktrees();
1078-
int path_maxlen = 0, abbrev = DEFAULT_ABBREV, i;
1089+
int path_maxwidth = 0, abbrev = DEFAULT_ABBREV, i;
1090+
struct worktree_display *display = NULL;
10791091

10801092
/* sort worktrees by path but keep main worktree at top */
10811093
pathsort(worktrees + 1);
10821094

10831095
if (!porcelain)
1084-
measure_widths(worktrees, &abbrev, &path_maxlen);
1096+
measure_widths(worktrees, &abbrev,
1097+
&display, &path_maxwidth);
10851098

10861099
for (i = 0; worktrees[i]; i++) {
10871100
if (porcelain)
10881101
show_worktree_porcelain(worktrees[i],
10891102
line_terminator);
10901103
else
1091-
show_worktree(worktrees[i], path_maxlen, abbrev);
1104+
show_worktree(worktrees[i],
1105+
&display[i], path_maxwidth, abbrev);
10921106
}
1107+
for (i = 0; display && worktrees[i]; i++)
1108+
free(display[i].path);
1109+
free(display);
10931110
free_worktrees(worktrees);
10941111
}
10951112
return 0;

t/t2402-worktree-list.sh

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,34 @@ test_expect_success 'rev-parse --git-path objects linked worktree' '
2929
test_cmp expect actual
3030
'
3131

32-
test_expect_success '"list" all worktrees from main' '
33-
echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect &&
34-
test_when_finished "rm -rf here out actual expect && git worktree prune" &&
35-
git worktree add --detach here main &&
36-
echo "$(git -C here rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >>expect &&
37-
git worktree list >out &&
38-
sed "s/ */ /g" <out >actual &&
32+
test_expect_success '"list" all worktrees from main core.quotepath=false' '
33+
test_config core.quotepath false &&
34+
echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect &&
35+
test_when_finished "rm -rf áááá out actual expect && git worktree prune" &&
36+
git worktree add --detach áááá main &&
37+
echo "$(git -C áááá rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >>expect &&
38+
git worktree list >actual &&
39+
test_cmp expect actual
40+
'
41+
42+
test_expect_success '"list" all worktrees from main core.quotepath=true' '
43+
test_config core.quotepath true &&
44+
echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect &&
45+
test_when_finished "rm -rf á out actual expect && git worktree prune" &&
46+
git worktree add --detach á main &&
47+
echo "\"$(git -C á rev-parse --show-toplevel)\" $(git rev-parse --short HEAD) (detached HEAD)" |
48+
sed s/á/\\\\303\\\\241/g >>expect &&
49+
git worktree list >actual &&
3950
test_cmp expect actual
4051
'
4152

4253
test_expect_success '"list" all worktrees from linked' '
43-
echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect &&
44-
test_when_finished "rm -rf here out actual expect && git worktree prune" &&
45-
git worktree add --detach here main &&
46-
echo "$(git -C here rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >>expect &&
47-
git -C here worktree list >out &&
48-
sed "s/ */ /g" <out >actual &&
54+
test_config core.quotepath false &&
55+
echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect &&
56+
test_when_finished "rm -rf áááá out actual expect && git worktree prune" &&
57+
git worktree add --detach áááá main &&
58+
echo "$(git -C áááá rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >>expect &&
59+
git -C áááá worktree list >actual &&
4960
test_cmp expect actual
5061
'
5162

0 commit comments

Comments
 (0)