Skip to content

Commit 063ae58

Browse files
Adds option in switch to create/open worktree in single action
1 parent 3eefaca commit 063ae58

File tree

8 files changed

+120
-40
lines changed

8 files changed

+120
-40
lines changed

src/commands/git/switch.ts

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ interface State {
3737
reference: GitReference;
3838
createBranch?: string;
3939
fastForwardTo?: GitReference;
40+
skipWorktreeConfirmations?: boolean;
4041
}
4142

4243
type ConfirmationChoice =
@@ -220,23 +221,29 @@ export class SwitchGitCommand extends QuickCommand<State> {
220221
openOnly: true,
221222
overrides: {
222223
disallowBack: true,
223-
confirmation: {
224-
title: `Confirm Switch to Worktree \u2022 ${getReferenceLabel(state.reference, {
225-
icon: false,
226-
label: false,
227-
})}`,
228-
placeholder: `${getReferenceLabel(state.reference, {
229-
capitalize: true,
230-
icon: false,
231-
})} is linked to a worktree`,
232-
},
224+
confirmation: state.skipWorktreeConfirmations
225+
? undefined
226+
: {
227+
title: `Confirm Switch to Worktree \u2022 ${getReferenceLabel(
228+
state.reference,
229+
{
230+
icon: false,
231+
label: false,
232+
},
233+
)}`,
234+
placeholder: `${getReferenceLabel(state.reference, {
235+
capitalize: true,
236+
icon: false,
237+
})} is linked to a worktree`,
238+
},
233239
},
234240
repo: state.repos[0],
241+
skipWorktreeConfirmations: state.skipWorktreeConfirmations,
235242
},
236243
},
237244
this.pickedVia,
238245
);
239-
if (worktreeResult === StepResultBreak) continue;
246+
if (worktreeResult === StepResultBreak && !state.skipWorktreeConfirmations) continue;
240247

241248
endSteps(state);
242249
return;
@@ -253,6 +260,10 @@ export class SwitchGitCommand extends QuickCommand<State> {
253260

254261
state.createBranch = undefined;
255262
context.promptToCreateBranch = false;
263+
if (state.skipWorktreeConfirmations) {
264+
state.reference = context.canSwitchToLocalBranch;
265+
continue outer;
266+
}
256267
} else {
257268
context.promptToCreateBranch = true;
258269
}
@@ -308,11 +319,12 @@ export class SwitchGitCommand extends QuickCommand<State> {
308319
createBranch:
309320
result === 'switchToNewBranchViaWorktree' ? state.createBranch : undefined,
310321
repo: state.repos[0],
322+
skipWorktreeConfirmations: state.skipWorktreeConfirmations,
311323
},
312324
},
313325
this.pickedVia,
314326
);
315-
if (worktreeResult === StepResultBreak) continue outer;
327+
if (worktreeResult === StepResultBreak && !state.skipWorktreeConfirmations) continue outer;
316328

317329
endSteps(state);
318330
return;
@@ -331,6 +343,15 @@ export class SwitchGitCommand extends QuickCommand<State> {
331343
const isLocalBranch = isBranchReference(state.reference) && !state.reference.remote;
332344

333345
type StepType = QuickPickItemOfT<ConfirmationChoice>;
346+
if (state.skipWorktreeConfirmations && state.repos.length === 1) {
347+
if (isLocalBranch) {
348+
return 'switchViaWorktree';
349+
} else if (!state.createBranch && context.canSwitchToLocalBranch != null) {
350+
return 'switchToLocalBranchViaWorktree';
351+
}
352+
353+
return 'switchToNewBranchViaWorktree';
354+
}
334355

335356
const confirmations: StepType[] = [];
336357
if (!state.createBranch) {

src/commands/git/worktree.ts

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ interface CreateState {
9696
overrides?: {
9797
title?: string;
9898
};
99+
100+
skipWorktreeConfirmations?: boolean;
99101
}
100102

101103
type DeleteFlags = '--force';
@@ -129,6 +131,8 @@ interface OpenState {
129131
placeholder?: string;
130132
};
131133
};
134+
135+
skipWorktreeConfirmations?: boolean;
132136
}
133137

134138
interface CopyChangesState {
@@ -609,6 +613,7 @@ export class WorktreeGitCommand extends QuickCommand<State> {
609613
confirm: action === 'prompt',
610614
openOnly: true,
611615
overrides: { disallowBack: true },
616+
skipWorktreeConfirmations: state.skipWorktreeConfirmations,
612617
} satisfies OpenStepState,
613618
context,
614619
);
@@ -695,26 +700,28 @@ export class WorktreeGitCommand extends QuickCommand<State> {
695700
const isRemoteBranch = isBranchReference(state.reference) && state.reference?.remote;
696701

697702
type StepType = FlagsQuickPickItem<CreateFlags, CreateConfirmationChoice>;
703+
const defaultOption = createFlagsQuickPickItem<CreateFlags, Uri>(
704+
state.flags,
705+
[],
706+
{
707+
label: isRemoteBranch
708+
? 'Create Worktree for New Local Branch'
709+
: isBranch
710+
? 'Create Worktree for Branch'
711+
: context.title,
712+
description: '',
713+
detail: `Will create worktree in $(folder) ${recommendedFriendlyPath}`,
714+
},
715+
recommendedRootUri,
716+
);
698717

699718
const confirmations: StepType[] = [];
700719
if (!createDirectlyInFolder) {
701720
if (!state.createBranch) {
702-
confirmations.push(
703-
createFlagsQuickPickItem<CreateFlags, Uri>(
704-
state.flags,
705-
[],
706-
{
707-
label: isRemoteBranch
708-
? 'Create Worktree for New Local Branch'
709-
: isBranch
710-
? 'Create Worktree for Branch'
711-
: context.title,
712-
description: '',
713-
detail: `Will create worktree in $(folder) ${recommendedFriendlyPath}`,
714-
},
715-
recommendedRootUri,
716-
),
717-
);
721+
if (state.skipWorktreeConfirmations) {
722+
return [defaultOption.context, defaultOption.item];
723+
}
724+
confirmations.push(defaultOption);
718725
}
719726

720727
confirmations.push(
@@ -992,15 +999,21 @@ export class WorktreeGitCommand extends QuickCommand<State> {
992999
private *openCommandConfirmStep(state: OpenStepState, context: Context): StepResultGenerator<OpenFlags[]> {
9931000
type StepType = FlagsQuickPickItem<OpenFlags>;
9941001

1002+
const newWindowItem = createFlagsQuickPickItem<OpenFlags>(state.flags, ['--new-window'], {
1003+
label: `Open Worktree in a New Window`,
1004+
detail: 'Will open the worktree in a new window',
1005+
});
1006+
1007+
if (state.skipWorktreeConfirmations) {
1008+
return newWindowItem.item;
1009+
}
1010+
9951011
const confirmations: StepType[] = [
9961012
createFlagsQuickPickItem<OpenFlags>(state.flags, [], {
9971013
label: 'Open Worktree',
9981014
detail: 'Will open the worktree in the current window',
9991015
}),
1000-
createFlagsQuickPickItem<OpenFlags>(state.flags, ['--new-window'], {
1001-
label: `Open Worktree in a New Window`,
1002-
detail: 'Will open the worktree in a new window',
1003-
}),
1016+
newWindowItem,
10041017
createFlagsQuickPickItem<OpenFlags>(state.flags, ['--add-to-workspace'], {
10051018
label: `Add Worktree to Workspace`,
10061019
detail: 'Will add the worktree into the current workspace',

src/commands/quickCommand.buttons.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ export const ShowResultsInSideBarQuickInputButton: QuickInputButton = {
196196
tooltip: 'Show Results in Side Bar',
197197
};
198198

199+
export const OpenWorktreeInNewWindowQuickInputButton: QuickInputButton = {
200+
iconPath: new ThemeIcon('empty-window'),
201+
tooltip: 'Open Worktree in New Window',
202+
};
203+
199204
export const ShowTagsToggleQuickInputButton = class extends SelectableQuickInputButton {
200205
constructor(on = false) {
201206
super('Show Tags', { off: new ThemeIcon('tag'), on: 'icon-tag-selected' }, on);

src/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,7 @@ export type TelemetryEvents = {
12941294
| 'merge'
12951295
| 'soft-open'
12961296
| 'switch'
1297+
| 'open-worktree'
12971298
| 'switch-and-code-suggest'
12981299
| 'show-overview'
12991300
| 'open-changes'

src/plus/focus/focus.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
MergeQuickInputButton,
2222
OpenOnGitHubQuickInputButton,
2323
OpenOnWebQuickInputButton,
24+
OpenWorktreeInNewWindowQuickInputButton,
2425
PinQuickInputButton,
2526
RefreshQuickInputButton,
2627
SnoozeQuickInputButton,
@@ -283,9 +284,12 @@ export class FocusCommand extends QuickCommand<State> {
283284
case 'show-overview':
284285
void this.container.focus.switchTo(state.item);
285286
break;
287+
case 'open-worktree':
288+
void this.container.focus.switchTo(state.item, { skipWorktreeConfirmations: true });
289+
break;
286290
case 'switch-and-code-suggest':
287291
case 'code-suggest':
288-
void this.container.focus.switchTo(state.item, true);
292+
void this.container.focus.switchTo(state.item, { startCodeSuggestion: true });
289293
break;
290294
case 'open-changes':
291295
void this.container.focus.openChanges(state.item);
@@ -377,9 +381,14 @@ export class FocusCommand extends QuickCommand<State> {
377381
buttons.push(
378382
i.viewer.pinned ? UnpinQuickInputButton : PinQuickInputButton,
379383
i.viewer.snoozed ? UnsnoozeQuickInputButton : SnoozeQuickInputButton,
380-
OpenOnGitHubQuickInputButton,
381384
);
382385

386+
if (!i.openRepository?.localBranch?.current) {
387+
buttons.push(OpenWorktreeInNewWindowQuickInputButton);
388+
}
389+
390+
buttons.push(OpenOnGitHubQuickInputButton);
391+
383392
return {
384393
label: i.title.length > 60 ? `${i.title.substring(0, 60)}...` : i.title,
385394
// description: `${i.repoAndOwner}#${i.id}, by @${i.author}`,
@@ -511,6 +520,11 @@ export class FocusCommand extends QuickCommand<State> {
511520
this.sendItemActionTelemetry('merge', item, group, context);
512521
await this.container.focus.merge(item);
513522
break;
523+
524+
case OpenWorktreeInNewWindowQuickInputButton:
525+
this.sendItemActionTelemetry('open-worktree', item, group, context);
526+
await this.container.focus.switchTo(item, { skipWorktreeConfirmations: true });
527+
break;
514528
}
515529

516530
await updateItems(quickpick);
@@ -607,6 +621,17 @@ export class FocusCommand extends QuickCommand<State> {
607621
),
608622
);
609623
break;
624+
case 'open-worktree':
625+
confirmations.push(
626+
createQuickPickItemOfT(
627+
{
628+
label: 'Open Worktree in New Window',
629+
detail: 'Will create or open a worktree in a new window',
630+
},
631+
action,
632+
),
633+
);
634+
break;
610635
case 'switch-and-code-suggest':
611636
confirmations.push(
612637
createQuickPickItemOfT(

src/plus/focus/focusProvider.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ export type FocusAction =
135135
| 'soft-open'
136136
| 'switch'
137137
| 'switch-and-code-suggest'
138+
| 'open-worktree'
138139
| 'code-suggest'
139140
| 'show-overview'
140141
| 'open-changes'
@@ -164,7 +165,7 @@ export function getSuggestedActions(category: FocusActionCategory, isCurrentBran
164165
if (isCurrentBranch) {
165166
actions.push('show-overview', 'open-changes', 'code-suggest', 'open-in-graph');
166167
} else {
167-
actions.push('switch', 'switch-and-code-suggest', 'open-in-graph');
168+
actions.push('switch', 'open-worktree', 'switch-and-code-suggest', 'open-in-graph');
168169
}
169170
return actions;
170171
}
@@ -456,11 +457,14 @@ export class FocusProvider implements Disposable {
456457
}
457458

458459
@log<FocusProvider['switchTo']>({ args: { 0: i => `${i.id} (${i.provider.name} ${i.type})` } })
459-
async switchTo(item: FocusItem, startCodeSuggestion: boolean = false): Promise<void> {
460+
async switchTo(
461+
item: FocusItem,
462+
options?: { skipWorktreeConfirmations?: boolean; startCodeSuggestion?: boolean },
463+
): Promise<void> {
460464
if (item.openRepository?.localBranch?.current) {
461465
void showInspectView({
462466
type: 'wip',
463-
inReview: startCodeSuggestion,
467+
inReview: options?.startCodeSuggestion,
464468
repository: item.openRepository.repo,
465469
source: 'launchpad',
466470
} satisfies ShowWipArgs);
@@ -469,9 +473,11 @@ export class FocusProvider implements Disposable {
469473

470474
const deepLinkUrl = this.getItemBranchDeepLink(
471475
item,
472-
startCodeSuggestion
476+
options?.startCodeSuggestion
473477
? DeepLinkActionType.SwitchToAndSuggestPullRequest
474-
: DeepLinkActionType.SwitchToPullRequest,
478+
: options?.skipWorktreeConfirmations
479+
? DeepLinkActionType.SwitchToPullRequestWorktree
480+
: DeepLinkActionType.SwitchToPullRequest,
475481
);
476482
if (deepLinkUrl == null) return;
477483

src/uris/deepLinks/deepLink.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export enum DeepLinkType {
2020
export enum DeepLinkActionType {
2121
Switch = 'switch',
2222
SwitchToPullRequest = 'switch-to-pr',
23+
SwitchToPullRequestWorktree = 'switch-to-pr-worktree',
2324
SwitchToAndSuggestPullRequest = 'switch-to-and-suggest-pr',
2425
}
2526

src/uris/deepLinks/deepLinkService.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,7 @@ export class DeepLinkService implements Disposable {
10401040
if (
10411041
this._context.action === DeepLinkActionType.Switch ||
10421042
this._context.action === DeepLinkActionType.SwitchToPullRequest ||
1043+
this._context.action === DeepLinkActionType.SwitchToPullRequestWorktree ||
10431044
this._context.action === DeepLinkActionType.SwitchToAndSuggestPullRequest
10441045
) {
10451046
action = DeepLinkServiceAction.OpenSwitch;
@@ -1060,6 +1061,7 @@ export class DeepLinkService implements Disposable {
10601061
if (
10611062
this._context.action === DeepLinkActionType.Switch ||
10621063
this._context.action === DeepLinkActionType.SwitchToPullRequest ||
1064+
this._context.action === DeepLinkActionType.SwitchToPullRequestWorktree ||
10631065
this._context.action === DeepLinkActionType.SwitchToAndSuggestPullRequest
10641066
) {
10651067
action = DeepLinkServiceAction.OpenSwitch;
@@ -1268,12 +1270,18 @@ export class DeepLinkService implements Disposable {
12681270

12691271
await executeGitCommand({
12701272
command: 'switch',
1271-
state: { repos: repo, reference: ref },
1273+
state: {
1274+
repos: repo,
1275+
reference: ref,
1276+
skipWorktreeConfirmations:
1277+
this._context.action === DeepLinkActionType.SwitchToPullRequestWorktree,
1278+
},
12721279
});
12731280
}
12741281

12751282
if (
12761283
this._context.action === DeepLinkActionType.SwitchToPullRequest ||
1284+
this._context.action === DeepLinkActionType.SwitchToPullRequestWorktree ||
12771285
this._context.action === DeepLinkActionType.SwitchToAndSuggestPullRequest
12781286
) {
12791287
await showInspectView({

0 commit comments

Comments
 (0)