|
4 | 4 | *--------------------------------------------------------------------------------------------*/ |
5 | 5 |
|
6 | 6 | import * as vscode from 'vscode'; |
| 7 | +import * as path from 'path'; |
7 | 8 | import { PlatformInformation } from './platform'; |
8 | 9 | import { VbNetLanguageClient } from './languageClient'; |
9 | 10 | import { VbNetStatusBar } from './statusBar'; |
@@ -175,6 +176,127 @@ function registerCommands(context: vscode.ExtensionContext): void { |
175 | 176 | outputChannel?.show(); |
176 | 177 | }) |
177 | 178 | ); |
| 179 | + |
| 180 | + context.subscriptions.push( |
| 181 | + vscode.commands.registerCommand('vbnet.selectWorkspaceSolution', async () => { |
| 182 | + try { |
| 183 | + await selectWorkspaceSolution(); |
| 184 | + } catch (error) { |
| 185 | + const message = error instanceof Error ? error.message : String(error); |
| 186 | + outputChannel?.appendLine(`Failed to select workspace solution: ${message}`); |
| 187 | + vscode.window.showErrorMessage(`Failed to select workspace solution: ${message}`); |
| 188 | + } |
| 189 | + }) |
| 190 | + ); |
| 191 | +} |
| 192 | + |
| 193 | +interface SolutionPickItem extends vscode.QuickPickItem { |
| 194 | + solutionPath?: string; |
| 195 | + action?: 'clear'; |
| 196 | +} |
| 197 | + |
| 198 | +async function selectWorkspaceSolution(): Promise<void> { |
| 199 | + const workspaceFolders = vscode.workspace.workspaceFolders; |
| 200 | + if (!workspaceFolders || workspaceFolders.length === 0) { |
| 201 | + vscode.window.showWarningMessage('No workspace folder is open.'); |
| 202 | + return; |
| 203 | + } |
| 204 | + |
| 205 | + const config = vscode.workspace.getConfiguration('vbnet'); |
| 206 | + const defaultExclude = '**/node_modules/**,**/.git/**,**/bower_components/**'; |
| 207 | + const excludePattern = config.get<string>('workspace.projectFilesExcludePattern', defaultExclude); |
| 208 | + |
| 209 | + const resources = await vscode.workspace.findFiles( |
| 210 | + '{**/*.sln,**/*.slnf,**/*.slnx}', |
| 211 | + `{${excludePattern}}` |
| 212 | + ); |
| 213 | + |
| 214 | + if (resources.length === 0) { |
| 215 | + vscode.window.showInformationMessage('No solution files were found in this workspace.'); |
| 216 | + return; |
| 217 | + } |
| 218 | + |
| 219 | + const workspaceRoot = workspaceFolders[0].uri.fsPath; |
| 220 | + const configuredSolution = (config.get<string>('workspace.solutionPath', '') || '').trim(); |
| 221 | + const configuredResolved = configuredSolution |
| 222 | + ? path.normalize(path.resolve(workspaceRoot, configuredSolution)) |
| 223 | + : ''; |
| 224 | + |
| 225 | + const items: SolutionPickItem[] = []; |
| 226 | + items.push({ |
| 227 | + label: 'Auto-detect', |
| 228 | + description: 'Clear workspace solution override', |
| 229 | + action: 'clear' |
| 230 | + }); |
| 231 | + |
| 232 | + const candidates = resources |
| 233 | + .map((resource) => resource.fsPath) |
| 234 | + .sort((a, b) => a.localeCompare(b)); |
| 235 | + |
| 236 | + for (const candidate of candidates) { |
| 237 | + const resolved = path.normalize(candidate); |
| 238 | + const relative = path.relative(workspaceRoot, candidate); |
| 239 | + const isRelative = relative && !relative.startsWith('..') && !path.isAbsolute(relative); |
| 240 | + const label = isRelative ? relative : path.basename(candidate); |
| 241 | + |
| 242 | + const hasVb = await solutionLikelyHasVbProjects(candidate); |
| 243 | + let description: string | undefined = undefined; |
| 244 | + if (configuredResolved && resolved === configuredResolved) { |
| 245 | + description = 'Current selection'; |
| 246 | + } else if (!hasVb) { |
| 247 | + description = 'No .vbproj references detected'; |
| 248 | + } |
| 249 | + |
| 250 | + items.push({ |
| 251 | + label, |
| 252 | + description, |
| 253 | + detail: candidate, |
| 254 | + solutionPath: candidate |
| 255 | + }); |
| 256 | + } |
| 257 | + |
| 258 | + const pick = await vscode.window.showQuickPick(items, { |
| 259 | + placeHolder: 'Select a workspace solution for VB.NET (clears auto-detection)', |
| 260 | + canPickMany: false |
| 261 | + }); |
| 262 | + |
| 263 | + if (!pick) { |
| 264 | + return; |
| 265 | + } |
| 266 | + |
| 267 | + if (pick.action === 'clear') { |
| 268 | + await config.update('workspace.solutionPath', '', vscode.ConfigurationTarget.Workspace); |
| 269 | + outputChannel?.appendLine('Workspace solution override cleared (auto-detect enabled).'); |
| 270 | + vscode.window.showInformationMessage('Workspace solution override cleared (auto-detect enabled).'); |
| 271 | + return; |
| 272 | + } |
| 273 | + |
| 274 | + if (!pick.solutionPath) { |
| 275 | + return; |
| 276 | + } |
| 277 | + |
| 278 | + const relative = path.relative(workspaceRoot, pick.solutionPath); |
| 279 | + const configValue = relative && !relative.startsWith('..') && !path.isAbsolute(relative) |
| 280 | + ? relative |
| 281 | + : pick.solutionPath; |
| 282 | + |
| 283 | + await config.update('workspace.solutionPath', configValue, vscode.ConfigurationTarget.Workspace); |
| 284 | + outputChannel?.appendLine(`Workspace solution override set to: ${configValue}`); |
| 285 | + vscode.window.showInformationMessage(`Workspace solution set to ${configValue}`); |
| 286 | +} |
| 287 | + |
| 288 | +async function solutionLikelyHasVbProjects(solutionPath: string): Promise<boolean> { |
| 289 | + if (solutionPath.toLowerCase().endsWith('.slnx')) { |
| 290 | + return true; |
| 291 | + } |
| 292 | + |
| 293 | + try { |
| 294 | + const content = await vscode.workspace.fs.readFile(vscode.Uri.file(solutionPath)); |
| 295 | + const text = Buffer.from(content).toString('utf8'); |
| 296 | + return text.toLowerCase().includes('.vbproj'); |
| 297 | + } catch { |
| 298 | + return true; |
| 299 | + } |
178 | 300 | } |
179 | 301 |
|
180 | 302 | /** |
|
0 commit comments