From 65c37ca44ded793008c28bea2fe2f38364ef2aa8 Mon Sep 17 00:00:00 2001 From: nerditation Date: Sat, 16 Sep 2023 20:02:34 +0800 Subject: [PATCH 1/5] use `which` to search `nu` location, add icon too. --- client/package.json | 3 +- client/src/extension.ts | 72 ++++++++++++++--------------------------- 2 files changed, 26 insertions(+), 49 deletions(-) diff --git a/client/package.json b/client/package.json index d84cdfd..6c64725 100644 --- a/client/package.json +++ b/client/package.json @@ -13,7 +13,8 @@ "vscode": "^1.75.0" }, "dependencies": { - "vscode-languageclient": "^8.1.0" + "vscode-languageclient": "^8.1.0", + "which": "^4.0.0" }, "devDependencies": { "@types/vscode": "^1.75.1", diff --git a/client/src/extension.ts b/client/src/extension.ts index bc53932..9774b65 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -24,22 +24,21 @@ export function activate(context: vscode.ExtensionContext) { provideTerminalProfile( token: vscode.CancellationToken ): vscode.ProviderResult { + const which = require("which"); const path = require("path"); - const fs = require("fs"); - const glob = require("glob"); - const os = require("os"); + const PATH_FROM_ENV = process.env["PATH"]; const pathsToCheck = [ + PATH_FROM_ENV, // cargo install location - "~/.cargo/bin/nu", - "~/.cargo/bin/nu.exe", + "~/.cargo/bin", // winget on Windows install location - "c:\\program files\\nu\\bin\\nu.exe", + "c:\\program files\\nu\\bin", // just add a few other drives for fun - "d:\\program files\\nu\\bin\\nu.exe", - "e:\\program files\\nu\\bin\\nu.exe", - "f:\\program files\\nu\\bin\\nu.exe", + "d:\\program files\\nu\\bin", + "e:\\program files\\nu\\bin", + "f:\\program files\\nu\\bin", // SCOOP:TODO // all user installed programs and scoop itself install to @@ -47,8 +46,9 @@ export function activate(context: vscode.ExtensionContext) { // globally installed programs go in // c:\programdata\scoop unless SCOOP_GLOBAL env var is set // scoop install location - "~/scoop/apps/nu/*/nu.exe", - "~/scoop/shims/nu.exe", + // SCOOP should already set up the correct `PATH` env var + //"~/scoop/apps/nu/*/nu.exe", + //"~/scoop/shims/nu.exe", // chocolatey install location - same as winget // 'c:\\program files\\nu\\bin\\nu.exe', @@ -60,53 +60,29 @@ export function activate(context: vscode.ExtensionContext) { // brew install location mac // intel - "/usr/local/bin/nu", + "/usr/local/bin", // arm - "/opt/homebrew/bin/nu", + "/opt/homebrew/bin", // native package manager install location - "/usr/bin/nu", + // standard location should be in `PATH` env var + //"/usr/bin/nu", ]; - let found_nushell_path = ""; - const home = os.homedir(); - - for (const cur_val of pathsToCheck) { - // console.log("Inspecting location: " + cur_val); - let constructed_file = ""; - if (cur_val.startsWith("~/scoop")) { - // console.log("Found scoop: " + cur_val); - const p = path.join(home, cur_val.slice(1)); - // console.log("Expanded ~: " + p); - const file = glob.sync(p, "debug").toString(); - // console.log("Glob for files: " + file); - - if (file) { - // console.log("Found some file: " + file); - // if there are slashes, reverse them to back slashes - constructed_file = file.replace(/\//g, "\\"); - } - } else if (cur_val.startsWith("~")) { - constructed_file = path.join(home, cur_val.slice(1)); - // console.log("Found ~, constructing path: " + constructed_file); - } else { - constructed_file = cur_val; - } - - if (fs.existsSync(constructed_file)) { - // console.log("File exists, returning: " + constructed_file); - found_nushell_path = constructed_file; - break; - } else { - // console.log("File not found: " + constructed_file); - } - } + const found_nushell_path = which.sync("nu", { + nothrow: true, + path: pathsToCheck.join(path.delimiter), + }); - if (found_nushell_path.length > 0) { + if (found_nushell_path != null) { return { options: { name: "Nushell", shellPath: found_nushell_path, + iconPath: vscode.Uri.joinPath( + context.extensionUri, + "assets/nu.svg" + ), }, }; } else { From 9c3fa8b8da2131d74a1d2b9e172700a150cb76a8 Mon Sep 17 00:00:00 2001 From: nerditation Date: Sat, 16 Sep 2023 20:17:49 +0800 Subject: [PATCH 2/5] also use `env:CARGO_HOME` and fallback to `~/.cargo/` --- client/src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/extension.ts b/client/src/extension.ts index 9774b65..8318e95 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -31,7 +31,7 @@ export function activate(context: vscode.ExtensionContext) { const pathsToCheck = [ PATH_FROM_ENV, // cargo install location - "~/.cargo/bin", + (process.env["CARGO_HOME"] || "~/.cargo") + "/bin", // winget on Windows install location "c:\\program files\\nu\\bin", From 122138d8ce7787b0deae8ae522a8bdea99ef8ebc Mon Sep 17 00:00:00 2001 From: nerditation Date: Sat, 16 Sep 2023 20:31:24 +0800 Subject: [PATCH 3/5] change behavior in case `nu` cannot be found. if the profile provider returns undefined, users will get a confusing error message: ``` No terminal profile options provided for id "nushell_default" ``` if we instead just return a program name "nu", the error message became: ``` path to shell executable "nu" does not exist ``` which should give the user more clue what went wrong. --- client/src/extension.ts | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/client/src/extension.ts b/client/src/extension.ts index 8318e95..018b3a5 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -74,21 +74,22 @@ export function activate(context: vscode.ExtensionContext) { path: pathsToCheck.join(path.delimiter), }); - if (found_nushell_path != null) { - return { - options: { - name: "Nushell", - shellPath: found_nushell_path, - iconPath: vscode.Uri.joinPath( - context.extensionUri, - "assets/nu.svg" - ), - }, - }; - } else { - console.log("Nushell not found, returning undefined"); - return undefined; + if (found_nushell_path == null) { + console.log( + "Nushell not found in env:PATH or any of the heuristic locations." + ); } + + return { + options: { + name: "Nushell", + shellPath: found_nushell_path || "nu", + iconPath: vscode.Uri.joinPath( + context.extensionUri, + "assets/nu.svg" + ), + }, + }; }, }) ); From 8f4af9cf5bcae5af92af8314bce015dc7e1a294f Mon Sep 17 00:00:00 2001 From: nerditation Date: Sat, 16 Sep 2023 23:40:46 +0800 Subject: [PATCH 4/5] add detailed error message on failure. the error message also guide the user to install `nushell` from website and reload vscode. --- client/src/extension.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/client/src/extension.ts b/client/src/extension.ts index 018b3a5..7ec4d32 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -78,12 +78,33 @@ export function activate(context: vscode.ExtensionContext) { console.log( "Nushell not found in env:PATH or any of the heuristic locations." ); + // use an async arrow funciton to use `await` inside + return (async () => { + if ( + (await vscode.window.showErrorMessage( + "We cannot find a nushell executable in your path or pre-defined locations", + "install from website" + )) && + (await vscode.env.openExternal( + vscode.Uri.parse("https://www.nushell.sh/") + )) && + (await vscode.window.showInformationMessage( + "after you install nushell, you might need to reload vscode", + "reload now" + )) + ) { + vscode.commands.executeCommand("workbench.action.reloadWindow"); + } + // user has already seen error messages, but they didn't click through + // return a promise that never resolve to supress the confusing error + return await new Promise(() => {}); + })(); } return { options: { name: "Nushell", - shellPath: found_nushell_path || "nu", + shellPath: found_nushell_path, iconPath: vscode.Uri.joinPath( context.extensionUri, "assets/nu.svg" From ca67d6eb4d162c0aa2a22be07bc432eb1c099cb5 Mon Sep 17 00:00:00 2001 From: nerditation Date: Sun, 17 Sep 2023 08:45:53 +0800 Subject: [PATCH 5/5] fix CI failure caused by empty function lint --- client/src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/extension.ts b/client/src/extension.ts index 7ec4d32..bca501b 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -97,7 +97,7 @@ export function activate(context: vscode.ExtensionContext) { } // user has already seen error messages, but they didn't click through // return a promise that never resolve to supress the confusing error - return await new Promise(() => {}); + return await new Promise(() => undefined); })(); }