|
4 | 4 | import * as os from "os";
|
5 | 5 | import * as path from "path";
|
6 | 6 | import * as process from "process";
|
| 7 | +import vscode = require("vscode"); |
7 | 8 | import { integer } from "vscode-languageserver-protocol";
|
8 | 9 | import { ILogger } from "./logging";
|
9 |
| -import { PowerShellAdditionalExePathSettings } from "./settings"; |
| 10 | +import { changeSetting, getSettings, PowerShellAdditionalExePathSettings } from "./settings"; |
10 | 11 |
|
11 | 12 | // This uses require so we can rewire it in unit tests!
|
12 | 13 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-var-requires
|
@@ -149,8 +150,16 @@ export class PowerShellExeFinder {
|
149 | 150 | for (const additionalPwsh of this.enumerateAdditionalPowerShellInstallations()) {
|
150 | 151 | if (await additionalPwsh.exists()) {
|
151 | 152 | yield additionalPwsh;
|
152 |
| - } else { |
153 |
| - void this.logger.writeAndShowWarning(`Additional PowerShell '${additionalPwsh.displayName}' not found at '${additionalPwsh.exePath}'!`); |
| 153 | + } else if (!additionalPwsh.suppressWarning) { |
| 154 | + const message = `Additional PowerShell '${additionalPwsh.displayName}' not found at '${additionalPwsh.exePath}'!`; |
| 155 | + this.logger.writeWarning(message); |
| 156 | + |
| 157 | + if (!getSettings().suppressAdditionalExeNotFoundWarning) { |
| 158 | + const selection = await vscode.window.showWarningMessage(message, "Don't Show Again"); |
| 159 | + if (selection !== undefined) { |
| 160 | + await changeSetting("suppressAdditionalExeNotFoundWarning", true, true, this.logger); |
| 161 | + } |
| 162 | + } |
154 | 163 | }
|
155 | 164 | }
|
156 | 165 | }
|
@@ -223,9 +232,39 @@ export class PowerShellExeFinder {
|
223 | 232 | private *enumerateAdditionalPowerShellInstallations(): Iterable<IPossiblePowerShellExe> {
|
224 | 233 | for (const versionName in this.additionalPowerShellExes) {
|
225 | 234 | if (Object.prototype.hasOwnProperty.call(this.additionalPowerShellExes, versionName)) {
|
226 |
| - const exePath = this.additionalPowerShellExes[versionName]; |
227 |
| - if (exePath) { |
228 |
| - yield new PossiblePowerShellExe(exePath, versionName); |
| 235 | + let exePath = this.additionalPowerShellExes[versionName]; |
| 236 | + if (!exePath) { |
| 237 | + continue; |
| 238 | + } |
| 239 | + |
| 240 | + // Remove surrounding quotes from path (without regex) |
| 241 | + if (exePath.startsWith("'") && exePath.endsWith("'") |
| 242 | + || exePath.startsWith("\"") && exePath.endsWith("\"")) { |
| 243 | + exePath = exePath.slice(1, -1); |
| 244 | + } |
| 245 | + |
| 246 | + // Always search for what the user gave us first |
| 247 | + yield new PossiblePowerShellExe(exePath, versionName); |
| 248 | + |
| 249 | + // Also search for `pwsh[.exe]` and `powershell[.exe]` if missing |
| 250 | + const args: [string, undefined, boolean, boolean] |
| 251 | + // Must be a tuple type and is suppressing the warning |
| 252 | + = [versionName, undefined, true, true]; |
| 253 | + |
| 254 | + // Handle Windows where '.exe' and 'powershell' are things |
| 255 | + if (this.platformDetails.operatingSystem === OperatingSystem.Windows) { |
| 256 | + if (!exePath.endsWith("pwsh.exe") && !exePath.endsWith("powershell.exe")) { |
| 257 | + if (exePath.endsWith("pwsh") || exePath.endsWith("powershell")) { |
| 258 | + // Add extension if that was missing |
| 259 | + yield new PossiblePowerShellExe(exePath + ".exe", ...args); |
| 260 | + } |
| 261 | + // Also add full exe names (this isn't an else just in case |
| 262 | + // the folder was named "pwsh" or "powershell") |
| 263 | + yield new PossiblePowerShellExe(path.join(exePath, "pwsh.exe"), ...args); |
| 264 | + yield new PossiblePowerShellExe(path.join(exePath, "powershell.exe"), ...args); |
| 265 | + } |
| 266 | + } else if (!exePath.endsWith("pwsh")) { // Always just 'pwsh' on non-Windows |
| 267 | + yield new PossiblePowerShellExe(path.join(exePath, "pwsh"), ...args); |
229 | 268 | }
|
230 | 269 | }
|
231 | 270 | }
|
@@ -529,14 +568,16 @@ export function getWindowsSystemPowerShellPath(systemFolderName: string): string
|
529 | 568 |
|
530 | 569 | interface IPossiblePowerShellExe extends IPowerShellExeDetails {
|
531 | 570 | exists(): Promise<boolean>;
|
| 571 | + readonly suppressWarning: boolean; |
532 | 572 | }
|
533 | 573 |
|
534 | 574 | class PossiblePowerShellExe implements IPossiblePowerShellExe {
|
535 | 575 | constructor(
|
536 | 576 | public readonly exePath: string,
|
537 | 577 | public readonly displayName: string,
|
538 | 578 | private knownToExist?: boolean,
|
539 |
| - public readonly supportsProperArguments = true) { } |
| 579 | + public readonly supportsProperArguments = true, |
| 580 | + public readonly suppressWarning = false) { } |
540 | 581 |
|
541 | 582 | public async exists(): Promise<boolean> {
|
542 | 583 | if (this.knownToExist === undefined) {
|
|
0 commit comments