Skip to content

Commit 309f31a

Browse files
Use html template file
1 parent f01d307 commit 309f31a

File tree

4 files changed

+143
-123
lines changed

4 files changed

+143
-123
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta http-equiv="Content-Security-Policy" content="META_CONTENT" />
5+
<style>
6+
.hide {
7+
display: none;
8+
}
9+
</style>
10+
</head>
11+
12+
<body>
13+
<h2>Cursorless extension is now running!</h2>
14+
15+
<a href="https://www.cursorless.org/docs/user/installation">
16+
Click here to learn how to install Cursorless
17+
</a>
18+
19+
<p>Let's check if all dependencies are installed.</p>
20+
21+
<div id="msg-talon" class="hide">
22+
<h4>Talon not installed</h4>
23+
<p>
24+
Cursorless requires Talon to function by voice.
25+
<br />
26+
You can download Talon from
27+
<a href="https://talonvoice.com"> talonvoice.com </a>
28+
</p>
29+
<p>
30+
<i
31+
>If you're using Cursorless by keyboard, you can ignore this
32+
message.</i
33+
>
34+
</p>
35+
</div>
36+
37+
<div id="msg-cursorless-talon" class="hide">
38+
<h4>Cursorless Talon scripts missing</h4>
39+
<p>
40+
Cursorless requires Talon user scripts to function by voice.
41+
<br />
42+
The scripts are available at
43+
<a href="https://github.com/cursorless-dev/cursorless-talon">
44+
github.com/cursorless-dev/cursorless-talon
45+
</a>
46+
</p>
47+
</div>
48+
49+
<div id="msg-command-server" class="hide">
50+
<h4>Command server extension not installed</h4>
51+
<p>
52+
Cursorless requires the command server extension to function by voice.
53+
<br />
54+
The extension is available at the
55+
<a
56+
href="https://marketplace.visualstudio.com/items?itemName=pokey.command-server"
57+
>
58+
Visual Studio Marketplace
59+
</a>
60+
</p>
61+
<p>
62+
<i
63+
>If you're using Cursorless by keyboard, you can ignore this
64+
message.</i
65+
>
66+
</p>
67+
</div>
68+
69+
<div id="msg-all-installed" class="hide">
70+
<h4>All dependencies are installed!</h4>
71+
</div>
72+
73+
<div style="margin-top: 1rem">
74+
<label>
75+
<input id="input-dont-show" type="checkbox" />
76+
Don't show again
77+
</label>
78+
</div>
79+
80+
<script src="SCRIPT_SOURCE"></script>
81+
</body>
82+
</html>
Lines changed: 19 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,26 @@
11
const vscode = acquireVsCodeApi();
2+
const msgTalon = document.getElementById("msg-talon");
3+
const msgCursorlessTalon = document.getElementById("msg-cursorless-talon");
4+
const msgCommandServer = document.getElementById("msg-command-server");
5+
const msgAllInstalled = document.getElementById("msg-all-installed");
6+
const inputDontShow = document.getElementById("input-dont-show");
27

3-
const root = document.getElementById("root");
4-
5-
const header = document.createElement("h2");
6-
header.textContent = "Cursorless extension is now running!";
7-
8-
const description = document.createElement("p");
9-
const aDocs = link(
10-
"https://www.cursorless.org/docs/user/installation",
11-
"Click here to learn how to install Cursorless",
12-
);
13-
description.innerHTML = `<p>Let's check if all dependencies are installed.</p>${aDocs}`;
14-
15-
const messages = document.createElement("div");
16-
17-
root.append(header, description, messages);
18-
19-
const keyboardUserMessage =
20-
"<p><i>If you're using Cursorless by keyboard, you can ignore this message.</i></p>";
8+
inputDontShow.onchange = (e) => {
9+
const command = { type: "dontShow", checked: e.target.checked };
10+
vscode.postMessage(command);
11+
};
2112

2213
window.addEventListener("message", (event) => {
23-
const { dontShow, dependencies } = event.data;
24-
const children = [];
25-
26-
if (!dependencies.talon) {
27-
const a = link("https://talonvoice.com", "talonvoice.com");
28-
children.push(
29-
getChild(
30-
"Talon not installed",
31-
`Cursorless requires Talon to function by voice.</br>You can download Talon from ${a}.${keyboardUserMessage}`,
32-
),
33-
);
34-
} else if (!dependencies.cursorlessTalon) {
35-
const a = link(
36-
"https://github.com/cursorless-dev/cursorless-talon",
37-
"github.com/cursorless-dev/cursorless-talon",
38-
);
39-
children.push(
40-
getChild(
41-
"Cursorless Talon scripts missing",
42-
`Cursorless requires Talon user scripts to function by voice.</br>The scripts are available at ${a}.`,
43-
),
44-
);
45-
}
46-
47-
if (!dependencies.commandServer) {
48-
const a = link(
49-
"https://marketplace.visualstudio.com/items?itemName=pokey.command-server",
50-
"vscode marketplace",
51-
);
52-
children.push(
53-
getChild(
54-
"Command server extension not installed",
55-
`Cursorless requires the command server extension to function by voice.</br>The extension is available at the ${a}.${keyboardUserMessage}`,
56-
),
57-
);
58-
}
59-
60-
if (children.length === 0) {
61-
children.push(getChild("All dependencies are installed!"));
62-
}
63-
64-
const dontShowCheckbox = getDontShowCheckbox(dontShow);
65-
66-
messages.replaceChildren(...children, dontShowCheckbox);
14+
const { dontShow, hasMissingDependencies, dependencies } = event.data;
15+
16+
hide(msgTalon, dependencies.talon);
17+
// No need to show missing Cursorless Talon if Talon itself is missing
18+
hide(msgCursorlessTalon, dependencies.cursorlessTalon || !dependencies.talon);
19+
hide(msgCommandServer, dependencies.commandServer);
20+
hide(msgAllInstalled, hasMissingDependencies);
21+
inputDontShow.checked = dontShow;
6722
});
6823

69-
function link(href, text) {
70-
return `<a href="${href}">${text}</a>`;
71-
}
72-
73-
function getChild(title, body) {
74-
const child = document.createElement("div");
75-
const titleElement = document.createElement("h4");
76-
titleElement.textContent = title;
77-
child.append(titleElement);
78-
if (body != null) {
79-
const bodyElement = document.createElement("p");
80-
bodyElement.innerHTML = body;
81-
child.append(bodyElement);
82-
}
83-
return child;
84-
}
85-
86-
function getDontShowCheckbox(dontShow) {
87-
const checkbox = document.createElement("input");
88-
checkbox.type = "checkbox";
89-
checkbox.checked = dontShow;
90-
checkbox.onchange = () => {
91-
const command = { type: "dontShow", checked: checkbox.checked };
92-
vscode.postMessage(command);
93-
};
94-
const label = document.createElement("label");
95-
label.style.marginTop = "1rem";
96-
const text = document.createTextNode("Don't show again");
97-
label.append(checkbox, text);
98-
return label;
24+
function hide(element, doHide) {
25+
element.className = doHide ? "hide" : "";
9926
}

packages/cursorless-vscode/src/InstallationDependencies.ts

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,20 @@ export class InstallationDependencies {
2727
*/
2828
maybeShow() {
2929
const state = this.getState();
30-
if (!state.dontShow && hasMissingDependencies(state.dependencies)) {
30+
if (state.hasMissingDependencies && !state.dontShow) {
3131
this.createWebview();
3232
}
3333
}
3434

3535
private getState() {
36+
const dependencies = getDependencies();
37+
const hasMissingDependencies = Object.values(dependencies).some(
38+
(value) => !value,
39+
);
3640
return {
3741
dontShow: !!this.extensionContext.globalState.get<boolean>(STATE_KEY),
38-
dependencies: getDependencies(),
42+
hasMissingDependencies,
43+
dependencies,
3944
};
4045
}
4146

@@ -56,15 +61,7 @@ export class InstallationDependencies {
5661
},
5762
);
5863

59-
const jsUri = this.panel.webview.asWebviewUri(
60-
vscode.Uri.joinPath(
61-
this.extensionContext.extensionUri,
62-
"resources",
63-
"installationDependencies.js",
64-
),
65-
);
66-
67-
this.panel.webview.html = getWebviewContent(this.panel.webview, jsUri);
64+
this.panel.webview.html = this.getWebviewContent();
6865

6966
const updateWebview = () => {
7067
this.panel?.webview.postMessage(this.getState());
@@ -90,6 +87,32 @@ export class InstallationDependencies {
9087

9188
this.panel.webview.postMessage(this.getState());
9289
}
90+
91+
private getWebviewContent() {
92+
if (this.panel == null) {
93+
throw new Error("Panel not created yet");
94+
}
95+
const htmlPath = this.getResourceUri("installationDependencies.html");
96+
const jsUri = this.getResourceUri("installationDependencies.js");
97+
const template = fs
98+
.readFileSync(htmlPath.fsPath, "utf8")
99+
.replace("META_CONTENT", `script-src ${this.panel.webview.cspSource};`)
100+
.replace("SCRIPT_SOURCE", jsUri.toString());
101+
return template;
102+
}
103+
104+
private getResourceUri(name: string): vscode.Uri {
105+
if (this.panel == null) {
106+
throw new Error("Panel not created yet");
107+
}
108+
return this.panel.webview.asWebviewUri(
109+
vscode.Uri.joinPath(
110+
this.extensionContext.extensionUri,
111+
"resources",
112+
name,
113+
),
114+
);
115+
}
93116
}
94117

95118
function getDependencies(): Record<string, boolean> {
@@ -100,17 +123,16 @@ function getDependencies(): Record<string, boolean> {
100123
};
101124
}
102125

103-
function hasMissingDependencies(dependencies: Record<string, boolean>) {
104-
return Object.values(dependencies).some((value) => !value);
105-
}
106-
107126
function talonHomeExists() {
108127
return fs.existsSync(getTalonHomePath());
109128
}
110129

111130
function cursorlessTalonExists() {
112131
const talonUserPath = path.join(getTalonHomePath(), "user");
113-
const files = globSync("*/src/cursorless.talon", { cwd: talonUserPath });
132+
const files = globSync("**/*/src/cursorless.talon", {
133+
cwd: talonUserPath,
134+
maxDepth: 3,
135+
});
114136
return files.length > 0;
115137
}
116138

@@ -124,18 +146,3 @@ function getTalonHomePath() {
124146
? `${os.homedir()}\\AppData\\Roaming\\talon`
125147
: `${os.homedir()}/.talon`;
126148
}
127-
128-
function getWebviewContent(webview: vscode.Webview, jsUri: vscode.Uri) {
129-
return `
130-
<!DOCTYPE html>
131-
<html lang="en">
132-
<head>
133-
<meta http-equiv="Content-Security-Policy" content="script-src ${webview.cspSource};" />
134-
</head>
135-
136-
<body>
137-
<div id="root"></div>
138-
<script src="${jsUri}"></script>
139-
</body>
140-
</html>`;
141-
}

packages/cursorless-vscode/src/scripts/populateDist/assets.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export const assets: Asset[] = [
4242
source: "resources/font_measurements.js",
4343
destination: "resources/font_measurements.js",
4444
},
45+
{
46+
source: "resources/installationDependencies.html",
47+
destination: "resources/installationDependencies.html",
48+
},
4549
{
4650
source: "resources/installationDependencies.js",
4751
destination: "resources/installationDependencies.js",

0 commit comments

Comments
 (0)