|
1 | 1 | import * as vscode from 'vscode'; |
2 | 2 |
|
3 | 3 | import { GitExecutor } from '../../common/git/gitExecutor'; |
4 | | -import { BaseCommand } from '../command'; |
5 | 4 | import { IGitRef } from '../../common/git/types'; |
| 5 | +import { ConfigurationManager } from '../../configuration/configurationManager'; |
| 6 | +import { LoggingService } from '../../logging/loggingService'; |
| 7 | +import { AutoStashService } from '../../services/autoStashService'; |
| 8 | +import { getRepoId } from '../../utils/getRepoId'; |
| 9 | +import { BaseCommand } from '../command'; |
| 10 | +import { getMergedBranchLists } from '../utils/getMergedBranchLists'; |
6 | 11 | import { |
7 | 12 | getRefDescription, |
8 | 13 | getRefDetails, |
9 | 14 | getRefLabel, |
| 15 | + getRefLabelWithStar, |
10 | 16 | ICON_BRANCH, |
11 | 17 | ICON_PLUS, |
12 | | - ICON_REMOTE_BRANCH, |
| 18 | + ICON_REMOTE_BRANCH |
13 | 19 | } from '../utils/refFormatting'; |
14 | | -import { getMergedBranchLists } from '../utils/getMergedBranchLists'; |
15 | | -import { ConfigurationManager } from '../../configuration/configurationManager'; |
16 | | -import { LoggingService } from '../../logging/loggingService'; |
17 | | -import { AutoStashService } from '../../services/autoStashService'; |
18 | 20 |
|
19 | 21 | export const LABEL_CREATE_NEW_BRANCH = `${ICON_PLUS} Create new branch...`; |
20 | 22 | export const LABEL_CREATE_NEW_BRANCH_FROM = `${ICON_PLUS} Create new branch from...`; |
@@ -99,67 +101,136 @@ export class CheckoutToCommand extends BaseCommand { |
99 | 101 | throw new Error('The current workspace is not a git repository.'); |
100 | 102 | } |
101 | 103 |
|
| 104 | + const repoId = await getRepoId(git); |
102 | 105 | // Get the list of branches from the separate function |
103 | 106 | const branchList = await this.getBranchList(git); |
| 107 | + const existingFullSet = new Set( |
| 108 | + branchList.map((ref) => |
| 109 | + ref.isTag |
| 110 | + ? `refs/tags/${ref.name}` |
| 111 | + : ref.remote |
| 112 | + ? `refs/remotes/${ref.remote}/${ref.name}` |
| 113 | + : `refs/heads/${ref.name}` |
| 114 | + ) |
| 115 | + ); |
| 116 | + await this.configManager.cleanupMissing(repoId, existingFullSet); |
104 | 117 |
|
105 | 118 | const [locals, remotes] = getMergedBranchLists(branchList, currentBranch); |
106 | 119 |
|
107 | | - const quickPickTags = branchList |
108 | | - .filter((branch) => branch.isTag) |
109 | | - .map((tag) => ({ |
110 | | - label: getRefLabel(tag), |
111 | | - description: getRefDescription(tag), |
112 | | - detail: getRefDetails(tag), |
113 | | - })); |
114 | | - |
115 | 120 | const quickPickActions = [ |
116 | 121 | { label: LABEL_CREATE_NEW_BRANCH }, |
117 | 122 | { label: LABEL_CREATE_NEW_BRANCH_FROM }, |
118 | 123 | ]; |
119 | 124 |
|
120 | | - const quickPickItems: vscode.QuickPickItem[] = [ |
121 | | - ...quickPickActions, |
122 | | - { |
123 | | - label: 'Branches', |
124 | | - kind: vscode.QuickPickItemKind.Separator, |
125 | | - }, |
126 | | - ...locals.map((branch) => ({ |
127 | | - label: getRefLabel(branch), |
128 | | - description: getRefDescription(branch), |
129 | | - detail: getRefDetails(branch), |
130 | | - })), |
131 | | - { |
132 | | - label: 'Remote branches', |
133 | | - kind: vscode.QuickPickItemKind.Separator, |
134 | | - }, |
135 | | - |
136 | | - ...remotes.map((branch) => ({ |
137 | | - label: getRefLabel(branch), |
138 | | - description: getRefDescription(branch), |
139 | | - detail: getRefDetails(branch), |
140 | | - })), |
141 | | - |
142 | | - { |
143 | | - label: 'Tags', |
144 | | - kind: vscode.QuickPickItemKind.Separator, |
145 | | - }, |
146 | | - ...quickPickTags, |
147 | | - ]; |
| 125 | + const preferredLocal = locals.filter((b) => this.configManager.isPreferred(repoId, b)); |
| 126 | + const preferredRemote = remotes.filter((b) => this.configManager.isPreferred(repoId, b)); |
| 127 | + const nonPreferredLocal = locals.filter((b) => !this.configManager.isPreferred(repoId, b)); |
| 128 | + const nonPreferredRemote = remotes.filter((b) => !this.configManager.isPreferred(repoId, b)); |
| 129 | + const preferredTags = branchList.filter((t) => t.isTag && this.configManager.isPreferred(repoId, t)); |
| 130 | + const otherTags = branchList.filter((t) => t.isTag && !this.configManager.isPreferred(repoId, t)); |
| 131 | + |
| 132 | + const qp = vscode.window.createQuickPick< |
| 133 | + vscode.QuickPickItem & { ref?: IGitRef; type?: 'action' | 'ref' } |
| 134 | + >(); |
| 135 | + qp.title = 'Checkout to...'; |
| 136 | + qp.placeholder = 'Select a branch to checkout'; |
| 137 | + |
| 138 | + const toItem = (ref: IGitRef): (vscode.QuickPickItem & { ref: IGitRef; type: 'ref' }) => ({ |
| 139 | + label: getRefLabelWithStar(ref, this.configManager.isPreferred(repoId, ref)), |
| 140 | + description: getRefDescription(ref), |
| 141 | + detail: getRefDetails(ref), |
| 142 | + buttons: [ |
| 143 | + { |
| 144 | + iconPath: new vscode.ThemeIcon( |
| 145 | + this.configManager.isPreferred(repoId, ref) ? 'star-full' : 'star' |
| 146 | + ), |
| 147 | + tooltip: this.configManager.isPreferred(repoId, ref) ? 'Unstar' : 'Star', |
| 148 | + }, |
| 149 | + ], |
| 150 | + ref, |
| 151 | + type: 'ref', |
| 152 | + }); |
148 | 153 |
|
149 | | - // Show the quick pick list |
150 | | - const pickedItem = await vscode.window.showQuickPick(quickPickItems, { |
151 | | - // Options |
152 | | - placeHolder: 'Select a branch to checkout', |
| 154 | + const buildItems = () => { |
| 155 | + const items: (vscode.QuickPickItem & { ref?: IGitRef; type?: 'action' | 'ref' })[] = []; |
| 156 | + items.push(...quickPickActions.map((a) => ({ label: a.label, type: 'action' as const }))); |
| 157 | + |
| 158 | + // if (preferredLocal.length > 0) { |
| 159 | + // items.push({ label: 'Preferred branches', kind: vscode.QuickPickItemKind.Separator }); |
| 160 | + // items.push(...preferredLocal.map(toItem)); |
| 161 | + // } |
| 162 | + |
| 163 | + // if (preferredRemote.length > 0) { |
| 164 | + // items.push({ label: 'Preferred remote branches', kind: vscode.QuickPickItemKind.Separator }); |
| 165 | + // items.push(...preferredRemote.map(toItem)); |
| 166 | + // } |
| 167 | + |
| 168 | + items.push({ label: 'Branches', kind: vscode.QuickPickItemKind.Separator }); |
| 169 | + items.push(...preferredLocal.map(toItem), ...nonPreferredLocal.map(toItem)); |
| 170 | + |
| 171 | + items.push({ label: 'Remote branches', kind: vscode.QuickPickItemKind.Separator }); |
| 172 | + items.push(...preferredRemote.map(toItem), ...nonPreferredRemote.map(toItem)); |
| 173 | + |
| 174 | + // if (preferredTags.length > 0) { |
| 175 | + // items.push({ label: 'Preferred tags', kind: vscode.QuickPickItemKind.Separator }); |
| 176 | + // items.push(...preferredTags.map(toItem)); |
| 177 | + // } |
| 178 | + items.push({ label: 'Tags', kind: vscode.QuickPickItemKind.Separator }); |
| 179 | + items.push(...preferredTags.map(toItem), ...otherTags.map(toItem)); |
| 180 | + return items; |
| 181 | + }; |
| 182 | + |
| 183 | + qp.items = buildItems(); |
| 184 | + |
| 185 | + qp.onDidTriggerItemButton(async (e) => { |
| 186 | + const ref = (e.item as any).ref as IGitRef | undefined; |
| 187 | + if (!ref) { |
| 188 | + return; |
| 189 | + } |
| 190 | + await this.configManager.togglePreferred(repoId, ref, branchList); |
| 191 | + qp.items = buildItems(); |
153 | 192 | }); |
154 | 193 |
|
155 | | - // If the user didn't select anything, return |
156 | | - if (!pickedItem) { |
| 194 | + const picked = await new Promise< |
| 195 | + | { kind: 'action'; label: string } |
| 196 | + | { kind: 'ref'; ref: IGitRef; label: string } |
| 197 | + | undefined |
| 198 | + >((resolve) => { |
| 199 | + qp.onDidAccept(() => { |
| 200 | + const sel = qp.selectedItems[0] as any; |
| 201 | + if (!sel) { |
| 202 | + resolve(undefined); |
| 203 | + qp.hide(); |
| 204 | + return; |
| 205 | + } |
| 206 | + if (sel.type === 'action') { |
| 207 | + resolve({ kind: 'action', label: sel.label }); |
| 208 | + } else if (sel.type === 'ref' && sel.ref) { |
| 209 | + resolve({ kind: 'ref', ref: sel.ref, label: sel.label }); |
| 210 | + } else { |
| 211 | + resolve(undefined); |
| 212 | + } |
| 213 | + qp.hide(); |
| 214 | + }); |
| 215 | + qp.onDidHide(() => resolve(undefined)); |
| 216 | + qp.show(); |
| 217 | + }); |
| 218 | + |
| 219 | + if (!picked) { |
157 | 220 | throw new Error(); |
158 | 221 | } |
159 | 222 |
|
| 223 | + if (picked.kind === 'action') { |
| 224 | + return { |
| 225 | + currentBranch, |
| 226 | + selection: picked.label, |
| 227 | + branchList, |
| 228 | + }; |
| 229 | + } |
| 230 | + |
160 | 231 | return { |
161 | 232 | currentBranch, |
162 | | - selection: pickedItem.label, |
| 233 | + selection: getRefLabel(picked.ref), |
163 | 234 | branchList, |
164 | 235 | }; |
165 | 236 | } |
|
0 commit comments