-
-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Show webview about missing installation dependencies (#2720)
If the user is missing some installation dependencies. eg talon, cursorless-talon, command server, we now show a web view informing them Fixes #1953 Fixes #528 <img width="689" alt="Screenshot 2025-01-11T15-11-03 - Visual Studio Code" src="https://github.com/user-attachments/assets/6692cd78-fe4b-437b-a67f-8e906a4ffa4e" /> ## Checklist - [/] I have added [tests](https://www.cursorless.org/docs/contributing/test-case-recorder/) - [/] I have updated the [docs](https://github.com/cursorless-dev/cursorless/tree/main/docs) and [cheatsheet](https://github.com/cursorless-dev/cursorless/tree/main/cursorless-talon/src/cheatsheet) - [/] I have not broken the cheatsheet --------- Co-authored-by: Phil Cohen <[email protected]> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
- Loading branch information
1 parent
66d77a6
commit ca1a80e
Showing
12 changed files
with
422 additions
and
172 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,7 +47,6 @@ | |
}, | ||
"pnpm": { | ||
"patchedDependencies": { | ||
"@docusaurus/theme-search-algolia": "patches/@[email protected]", | ||
"@types/[email protected]": "patches/@[email protected]", | ||
"[email protected]": "patches/[email protected]" | ||
}, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
82 changes: 82 additions & 0 deletions
82
packages/cursorless-vscode/resources/installationDependencies.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta http-equiv="Content-Security-Policy" content="META_CONTENT" /> | ||
<style> | ||
.hide { | ||
display: none; | ||
} | ||
</style> | ||
</head> | ||
|
||
<body> | ||
<h2>Cursorless extension is now running!</h2> | ||
|
||
<a href="https://www.cursorless.org/docs/user/installation"> | ||
Click here to learn how to install Cursorless | ||
</a> | ||
|
||
<p>Let's check if all dependencies are installed.</p> | ||
|
||
<div id="msg-talon" class="hide"> | ||
<h4>Talon not installed</h4> | ||
<p> | ||
Cursorless requires Talon to function by voice. | ||
<br /> | ||
You can download Talon from | ||
<a href="https://talonvoice.com">talonvoice.com</a> | ||
</p> | ||
<p> | ||
<i> | ||
If you're using Cursorless by keyboard, you can ignore this message. | ||
</i> | ||
</p> | ||
</div> | ||
|
||
<div id="msg-cursorless-talon" class="hide"> | ||
<h4>Cursorless Talon scripts missing</h4> | ||
<p> | ||
Cursorless requires Talon user scripts to function by voice. | ||
<br /> | ||
The installation steps for the scripts are available at | ||
<a | ||
href="https://www.cursorless.org/docs/user/installation/#installing-the-talon-side" | ||
> | ||
github.com/cursorless-dev/cursorless-talon | ||
</a> | ||
</p> | ||
</div> | ||
|
||
<div id="msg-command-server" class="hide"> | ||
<h4>Command server extension not installed</h4> | ||
<p> | ||
Cursorless requires the command server extension to function by voice. | ||
<br /> | ||
The extension is available at the | ||
<a | ||
href="https://marketplace.visualstudio.com/items?itemName=pokey.command-server" | ||
> | ||
Visual Studio Marketplace | ||
</a> | ||
</p> | ||
<p> | ||
<i> | ||
If you're using Cursorless by keyboard, you can ignore this message. | ||
</i> | ||
</p> | ||
</div> | ||
|
||
<div id="msg-all-installed" class="hide"> | ||
<h4>All dependencies are installed!</h4> | ||
</div> | ||
|
||
<div style="margin-top: 1rem"> | ||
<label> | ||
<input id="input-dont-show" type="checkbox" /> | ||
Don't show again | ||
</label> | ||
</div> | ||
|
||
<script src="SCRIPT_SOURCE"></script> | ||
</body> | ||
</html> |
26 changes: 26 additions & 0 deletions
26
packages/cursorless-vscode/resources/installationDependencies.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
const vscode = acquireVsCodeApi(); | ||
const msgTalon = document.getElementById("msg-talon"); | ||
const msgCursorlessTalon = document.getElementById("msg-cursorless-talon"); | ||
const msgCommandServer = document.getElementById("msg-command-server"); | ||
const msgAllInstalled = document.getElementById("msg-all-installed"); | ||
const inputDontShow = document.getElementById("input-dont-show"); | ||
|
||
inputDontShow.onchange = (e) => { | ||
const command = { type: "dontShow", checked: e.target.checked }; | ||
vscode.postMessage(command); | ||
}; | ||
|
||
window.addEventListener("message", (event) => { | ||
const { dontShow, hasMissingDependencies, dependencies } = event.data; | ||
|
||
hide(msgTalon, dependencies.talon); | ||
// No need to show missing Cursorless Talon if Talon itself is missing | ||
hide(msgCursorlessTalon, dependencies.cursorlessTalon || !dependencies.talon); | ||
hide(msgCommandServer, dependencies.commandServer); | ||
hide(msgAllInstalled, hasMissingDependencies); | ||
inputDontShow.checked = dontShow; | ||
}); | ||
|
||
function hide(element, doHide) { | ||
element.className = doHide ? "hide" : ""; | ||
} |
148 changes: 148 additions & 0 deletions
148
packages/cursorless-vscode/src/InstallationDependencies.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import { COMMAND_SERVER_EXTENSION_ID } from "@cursorless/vscode-common"; | ||
import { globSync } from "glob"; | ||
import * as fs from "node:fs"; | ||
import * as os from "node:os"; | ||
import * as path from "node:path"; | ||
import * as vscode from "vscode"; | ||
|
||
const STATE_KEY = "dontShowInstallationDependencies"; | ||
|
||
export class InstallationDependencies { | ||
private panel: vscode.WebviewPanel | undefined; | ||
|
||
constructor(private extensionContext: vscode.ExtensionContext) { | ||
this.show = this.show.bind(this); | ||
this.maybeShow = this.maybeShow.bind(this); | ||
} | ||
|
||
/** | ||
* Shows the installation dependencies webview. | ||
*/ | ||
show() { | ||
this.createWebview(); | ||
} | ||
|
||
/** | ||
* Shows the installation dependencies webview if there are missing dependencies. | ||
*/ | ||
maybeShow() { | ||
const state = this.getState(); | ||
if (state.hasMissingDependencies && !state.dontShow) { | ||
this.createWebview(); | ||
} | ||
} | ||
|
||
private getState() { | ||
const dependencies = getDependencies(); | ||
const hasMissingDependencies = Object.values(dependencies).some( | ||
(value) => !value, | ||
); | ||
return { | ||
dontShow: !!this.extensionContext.globalState.get<boolean>(STATE_KEY), | ||
hasMissingDependencies, | ||
dependencies, | ||
}; | ||
} | ||
|
||
private createWebview() { | ||
if (this.panel != null) { | ||
this.panel.reveal(); | ||
return; | ||
} | ||
|
||
this.panel = vscode.window.createWebviewPanel( | ||
"cursorless.installationDependencies", | ||
"Cursorless dependencies", | ||
{ | ||
viewColumn: vscode.ViewColumn.Active, | ||
}, | ||
{ | ||
enableScripts: true, | ||
}, | ||
); | ||
|
||
this.panel.webview.html = this.getWebviewContent(); | ||
|
||
const updateWebview = () => { | ||
this.panel?.webview.postMessage(this.getState()); | ||
}; | ||
|
||
this.panel.onDidChangeViewState(updateWebview); | ||
|
||
this.panel.webview.onDidReceiveMessage((message) => { | ||
if (message.type === "dontShow") { | ||
const checked = message.checked; | ||
this.extensionContext.globalState.update(STATE_KEY, checked); | ||
} else { | ||
console.error(`Unknown message: ${message}`); | ||
} | ||
}); | ||
|
||
const interval = setInterval(updateWebview, 5000); | ||
|
||
this.panel.onDidDispose(() => { | ||
clearInterval(interval); | ||
this.panel = undefined; | ||
}); | ||
|
||
this.panel.webview.postMessage(this.getState()); | ||
} | ||
|
||
private getWebviewContent() { | ||
if (this.panel == null) { | ||
throw new Error("Panel not created yet"); | ||
} | ||
const htmlPath = this.getResourceUri("installationDependencies.html"); | ||
const jsUri = this.getResourceUri("installationDependencies.js"); | ||
const template = fs | ||
.readFileSync(htmlPath.fsPath, "utf8") | ||
.replace("META_CONTENT", `script-src ${this.panel.webview.cspSource};`) | ||
.replace("SCRIPT_SOURCE", jsUri.toString()); | ||
return template; | ||
} | ||
|
||
private getResourceUri(name: string): vscode.Uri { | ||
if (this.panel == null) { | ||
throw new Error("Panel not created yet"); | ||
} | ||
return this.panel.webview.asWebviewUri( | ||
vscode.Uri.joinPath( | ||
this.extensionContext.extensionUri, | ||
"resources", | ||
name, | ||
), | ||
); | ||
} | ||
} | ||
|
||
function getDependencies(): Record<string, boolean> { | ||
return { | ||
talon: talonHomeExists(), | ||
cursorlessTalon: cursorlessTalonExists(), | ||
commandServer: commandServerInstalled(), | ||
}; | ||
} | ||
|
||
function talonHomeExists() { | ||
return fs.existsSync(getTalonHomePath()); | ||
} | ||
|
||
function cursorlessTalonExists() { | ||
const talonUserPath = path.join(getTalonHomePath(), "user"); | ||
const files = globSync("**/*/src/cursorless.talon", { | ||
cwd: talonUserPath, | ||
maxDepth: 3, | ||
}); | ||
return files.length > 0; | ||
} | ||
|
||
function commandServerInstalled() { | ||
const extension = vscode.extensions.getExtension(COMMAND_SERVER_EXTENSION_ID); | ||
return extension != null; | ||
} | ||
|
||
function getTalonHomePath() { | ||
return os.platform() === "win32" | ||
? `${os.homedir()}\\AppData\\Roaming\\talon` | ||
: `${os.homedir()}/.talon`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.