Skip to content

Commit 67eca51

Browse files
authored
Merge pull request #97 from senkenn/senkenn/issue73
Restart SQL Language Server
2 parents 94c0083 + d03fffc commit 67eca51

File tree

9 files changed

+136
-61
lines changed

9 files changed

+136
-61
lines changed

.vscode/settings.json

+1-4
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@
2525
"./sql-extraction/rs/Cargo.toml",
2626
"./vsce-test/test-workspace-rs/Cargo.toml"
2727
],
28-
"github-actions.workflows.pinned.workflows": [
29-
".github/workflows/e2e-test.yaml",
30-
".github/workflows/rust-test.yaml"
31-
],
28+
"github-actions.workflows.pinned.workflows": [".github/workflows/test.yaml"],
3229
"github-actions.workflows.pinned.refresh.interval": 3,
3330
"github-actions.workflows.pinned.refresh.enabled": true,
3431
"markdown.copyFiles.destination": {

vsce-test/test/suite-ts/extension.test.ts

+27
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,33 @@ describe("Install sqls if not found in PATH", () => {
3434
});
3535
});
3636

37+
describe("Restart Language Server Test", () => {
38+
test("Should restart SQL language server", async () => {
39+
await vscode.commands.executeCommand("sqlsurge.restartSqlLanguageServer");
40+
41+
// confirm completion
42+
const filePath = path.resolve(wsPath, "src", "index.ts");
43+
const docUri = vscode.Uri.file(filePath);
44+
const doc = await vscode.workspace.openTextDocument(docUri);
45+
46+
// Wait for server activation
47+
await sleep(waitingTimeCompletion);
48+
49+
const pos = new vscode.Position(5, 44);
50+
const actualCompletionList =
51+
await vscode.commands.executeCommand<vscode.CompletionList>(
52+
"vscode.executeCompletionItemProvider",
53+
docUri,
54+
pos,
55+
);
56+
57+
expect(actualCompletionList.items.length).toBe(1);
58+
const { label, kind } = actualCompletionList.items[0];
59+
expect(label).toBe("SELECT");
60+
expect(kind).toBe(vscode.CompletionItemKind.Keyword);
61+
});
62+
});
63+
3764
describe("Completion Test", () => {
3865
test('Should be completed "SELECT" with $queryRaw single line', async () => {
3966
const filePath = path.resolve(wsPath, "src", "index.ts");

vsce/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ const someQuery = await entityManager.query(
102102
}
103103
```
104104

105+
## VS Code Commands <!-- omit in toc -->
106+
107+
- `sqlsurge: Install sqls`: Install sqls.
108+
- `sqlsurge: Restart SQL Language Server`: Restart SQL Language Server.
109+
- This command is useful when you update sqls or change the configuration.
110+
- `sqlsurge: Format SQL`: Format Raw SQL query.
111+
- `Format Document`: Format SQL file with sqls.
112+
105113
## TODOs <!-- omit in toc -->
106114

107115
- [x] Support for Prisma in TypeScript

vsce/package.json

+4
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@
117117
"command": "sqlsurge.installSqls",
118118
"title": "sqlsurge: Install sqls"
119119
},
120+
{
121+
"command": "sqlsurge.restartSqlLanguageServer",
122+
"title": "sqlsurge: Restart SQL Language Server"
123+
},
120124
{
121125
"command": "sqlsurge.formatSql",
122126
"title": "sqlsurge: Format SQL"

vsce/src/commands/installSqls.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ export const command = vscode.commands.registerCommand(
4747
.createOutputChannel("sqlsurge")
4848
.appendLine("sqls is installed.");
4949
const actions = await vscode.window.showInformationMessage(
50-
"sqls was successfully installed! Reload window to enable SQL language features.",
51-
"Reload Window",
50+
"sqls was successfully installed! Restart language server to enable SQL language features.",
51+
"Restart Language Server",
5252
);
53-
if (actions === "Reload Window") {
54-
vscode.commands.executeCommand("workbench.action.reloadWindow");
53+
if (actions === "Restart Language Server") {
54+
vscode.commands.executeCommand("sqlsurge.restartSqlLanguageServer");
5555
}
5656
},
5757
);

vsce/src/commands/restartLS.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as vscode from "vscode";
2+
import { restartLanguageServer } from "../startSqlsClient";
3+
4+
export const command = vscode.commands.registerCommand(
5+
"sqlsurge.restartSqlLanguageServer",
6+
async () => {
7+
await restartLanguageServer();
8+
},
9+
);

vsce/src/completion.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export async function completionProvider(
1717
) {
1818
const logger = createLogger();
1919

20-
logger.info("[provideCompletionItems]", "Starting completion...");
20+
logger.debug("[provideCompletionItems]", "Starting completion...");
2121
logger.debug("[provideCompletionItems]", "file: ", document.fileName);
2222
const sqlNodes = await refresh(document);
2323
const sqlNode = sqlNodes.find(({ code_range: { start, end } }) => {
@@ -47,7 +47,7 @@ export async function completionProvider(
4747
const vDocUriString = `${ORIGINAL_SCHEME}:${sqlNode.vFileName}`;
4848
const vDocUri = vscode.Uri.parse(vDocUriString);
4949

50-
logger.info("[provideCompletionItems] Finished completion.");
50+
logger.debug("[provideCompletionItems] Finished completion.");
5151
return vscode.commands.executeCommand<vscode.CompletionList>(
5252
"vscode.executeCompletionItemProvider",
5353
vDocUri,

vsce/src/extension.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as vscode from "vscode";
77

88
import { commandFormatSqlProvider } from "./commands/formatSql";
99
import { command as commandInstallSqls } from "./commands/installSqls";
10+
import { command as commandRestartLS } from "./commands/restartLS";
1011
import { completionProvider } from "./completion";
1112
import { getWorkspaceConfig } from "./extConfig";
1213
import {
@@ -20,7 +21,7 @@ import { client, startSqlsClient } from "./startSqlsClient";
2021
export async function activate(context: vscode.ExtensionContext) {
2122
const logger = createLogger();
2223

23-
startSqlsClient().catch((err) => {
24+
await startSqlsClient().catch((err) => {
2425
logger.error(err, "[startSqlsClient] Failed to start sqls client.");
2526
vscode.window.showErrorMessage("sqlsurge: Failed to start sqls client.");
2627
});
@@ -48,6 +49,7 @@ export async function activate(context: vscode.ExtensionContext) {
4849
completion,
4950
commandInstallSqls,
5051
commandFormatSql,
52+
commandRestartLS,
5153
);
5254

5355
// on save event
@@ -111,7 +113,7 @@ export async function activate(context: vscode.ExtensionContext) {
111113
async function refresh(
112114
document: vscode.TextDocument,
113115
): Promise<(SqlNode & { vFileName: string })[]> {
114-
logger.info("[refresh]", "Refreshing...");
116+
logger.debug("[refresh]", "Refreshing...");
115117
try {
116118
const service = getOrCreateLanguageService(document.uri)!;
117119
const fileName = document.fileName;
@@ -169,7 +171,7 @@ export async function activate(context: vscode.ExtensionContext) {
169171
index: idx,
170172
};
171173
});
172-
logger.info("[refresh]", "Refreshed.");
174+
logger.debug("[refresh]", "Refreshed.");
173175
return sqlNodesWithVirtualDoc;
174176
} catch (e) {
175177
logger.error("[refresh]", `${e}`);

vsce/src/startSqlsClient.ts

+76-48
Original file line numberDiff line numberDiff line change
@@ -4,59 +4,29 @@ import {
44
LanguageClient,
55
type LanguageClientOptions,
66
type ServerOptions,
7+
State,
78
} from "vscode-languageclient/node";
89
import { createLogger } from "./outputChannel";
910

1011
interface LanguageServerConfig {
1112
flags: string[];
1213
}
1314

14-
export let client: LanguageClient;
15+
export let client: LanguageClient | undefined = undefined;
1516

16-
export async function startSqlsClient() {
17-
const logger = createLogger();
17+
const logger = createLogger();
1818

19-
logger.info("[startSqlsClient]", "Starting sqls client...");
19+
export async function startSqlsClient() {
20+
logger.debug("[startSqlsClient]", "Starting sqls client...");
2021
const sqlsConfig = vscode.workspace.getConfiguration("sqlsurge");
2122
const config: LanguageServerConfig = {
2223
flags: sqlsConfig.languageServerFlags || [],
2324
};
2425

25-
let sqlsInPATH = await findSqlsInPath();
26+
const sqlsInPATH = await findSqlsInPath();
2627
if (!sqlsInPATH) {
27-
// not found sqls, install sqls automatically
28-
const action = await vscode.window.showInformationMessage(
29-
"sqls is not installed yet. You need to install sqls to enable SQL language features.",
30-
"Install with command",
31-
"Install manually (Jump to the installation guide)",
32-
);
33-
switch (action) {
34-
case "Install with command":
35-
await vscode.commands.executeCommand("sqlsurge.installSqls");
36-
break;
37-
case "Install manually (Jump to the installation guide)":
38-
await vscode.commands.executeCommand(
39-
"vscode.open",
40-
vscode.Uri.parse(
41-
"https://github.com/sqls-server/sqls?tab=readme-ov-file#installation",
42-
),
43-
);
44-
vscode.window
45-
.createOutputChannel("sqlsurge")
46-
.appendLine("sqls is not installed.");
47-
return;
48-
default:
49-
vscode.window
50-
.createOutputChannel("sqlsurge")
51-
.appendLine("sqls is not installed.");
52-
return;
53-
}
54-
55-
// check again
56-
sqlsInPATH = await findSqlsInPath();
57-
if (!sqlsInPATH) {
58-
throw new Error("sqls should be installed but not found in PATH");
59-
}
28+
showSqlsNotFoundMessage();
29+
return;
6030
}
6131

6232
const serverOptions: ServerOptions = {
@@ -74,6 +44,37 @@ export async function startSqlsClient() {
7444
logger.info("[startSqlsClient]", "Started sqls client.");
7545
}
7646

47+
export async function restartLanguageServer() {
48+
logger.debug("[restartLanguageServer]", "Restarting SQL language server...");
49+
if (!client) {
50+
await startSqlsClient();
51+
return;
52+
}
53+
54+
const sqlsInPATH = await findSqlsInPath();
55+
if (!sqlsInPATH) {
56+
showSqlsNotFoundMessage();
57+
return;
58+
}
59+
60+
if (client.state === State.Stopped) {
61+
await client.start();
62+
logger.debug("[restartLanguageServer]", "Started SQL language server.");
63+
}
64+
if (client.state === State.Running) {
65+
await client.restart();
66+
logger.debug("[restartLanguageServer]", "Restarted SQL language server.");
67+
}
68+
69+
vscode.window.showInformationMessage(
70+
"Successfully restarted SQL language server.",
71+
);
72+
logger.info(
73+
"[restartLanguageServer]",
74+
"Successfully restarted SQL language server.",
75+
);
76+
}
77+
7778
export async function findSqlsInPath(): Promise<vscode.Uri | undefined> {
7879
const path = process.env.PATH;
7980
if (!path) {
@@ -83,22 +84,49 @@ export async function findSqlsInPath(): Promise<vscode.Uri | undefined> {
8384
const sqlsFileName = process.platform === "win32" ? "sqls.exe" : "sqls";
8485
for (const dir of path.split(delimiter)) {
8586
const sqls = vscode.Uri.joinPath(vscode.Uri.file(dir), sqlsFileName);
86-
if (await fileExists(sqls)) {
87+
if (await existsFile(sqls)) {
8788
return sqls;
8889
}
8990
}
9091

9192
return;
9293
}
9394

94-
async function fileExists(path: vscode.Uri) {
95-
try {
96-
await vscode.workspace.fs.stat(path);
97-
return true;
98-
} catch (err: any) {
99-
if (err.code === "ENOENT" || err.code === "FileNotFound") {
100-
return false;
101-
}
102-
throw err;
95+
async function existsFile(path: vscode.Uri) {
96+
return vscode.workspace.fs.stat(path).then(
97+
() => true,
98+
(err) => {
99+
logger.debug("[existsFile]", err);
100+
if (err.code === "ENOENT" || err.code === "FileNotFound") {
101+
return false;
102+
}
103+
throw err;
104+
},
105+
);
106+
}
107+
108+
async function showSqlsNotFoundMessage() {
109+
// not found sqls, install sqls automatically
110+
const action = await vscode.window.showInformationMessage(
111+
"sqls is not installed yet or not found in PATH. Install sqls to enable SQL language features.",
112+
"Install with command",
113+
"Install manually (Jump to the installation guide)",
114+
);
115+
switch (action) {
116+
case "Install with command":
117+
await vscode.commands.executeCommand("sqlsurge.installSqls");
118+
break;
119+
case "Install manually (Jump to the installation guide)":
120+
await vscode.commands.executeCommand(
121+
"vscode.open",
122+
vscode.Uri.parse(
123+
"https://github.com/sqls-server/sqls?tab=readme-ov-file#installation",
124+
),
125+
);
126+
logger.info("[startSqlsClient]", "sqls is not installed.");
127+
return;
128+
default:
129+
logger.info("[startSqlsClient]", "sqls is not installed.");
130+
return;
103131
}
104132
}

0 commit comments

Comments
 (0)