Skip to content

Commit 0e50297

Browse files
committed
Fix restart for server.
1 parent b050908 commit 0e50297

File tree

5 files changed

+193
-69
lines changed

5 files changed

+193
-69
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ This extension contributes the following settings:
136136
* `shader-validator.glsl.targetClient`: Specify the OpenGL or Vulkan version for GLSL
137137
* `shader-validator.glsl.spirvVersion`: Specify the SPIRV version to target for GLSL
138138
139+
140+
## Commands
141+
142+
* `shader-validator.restartServer`: Restart the server if you have any issue
143+
* `shader-validator.addCurrentFileVariant`: Add a variant to the current file.
144+
* `shader-validator.dumpDependency`: Print dependency tree in logs. mostly for debug.
145+
* `shader-validator.dumpAst`: Print internal ast in logs. mostly for debug.
146+
139147
## Platform support
140148
141149
This extension is supported on every platform, but some limitations are to be expected on some:

package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@
120120
"type": "boolean",
121121
"default": false
122122
},
123+
"shader-validator.updateSymbolsOnVariantUpdate": {
124+
"description": "Automatically update the symbols on variant update. Will trigger a save on the file.",
125+
"type": "boolean",
126+
"default": false
127+
},
123128
"shader-validator.severity": {
124129
"type": "string",
125130
"description": "Minimum linting severity. Set it lower to display some hints aswell. Might not be supported by all languages.",
@@ -290,6 +295,12 @@
290295
}
291296
],
292297
"commands": [
298+
{
299+
"command": "shader-validator.restartServer",
300+
"title": "Restart server",
301+
"category": "Shader validator",
302+
"icon": "$(check)"
303+
},
293304
{
294305
"command": "shader-validator.validateFile",
295306
"title": "Validate file",

src/extension.ts

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Import the module and reference it with the alias vscode in your code below
33
import * as vscode from 'vscode';
44

5-
import { createLanguageClient, getServerPlatform, ServerPlatform } from './validator';
5+
import { createLanguageClient, getServerPlatform, ServerPlatform, ShaderLanguageClient } from './validator';
66
import { dumpAstRequest, dumpDependencyRequest } from './request';
77
import { ShaderVariantTreeDataProvider } from './shaderVariant';
88
import { DidChangeConfigurationNotification, LanguageClient } from 'vscode-languageclient';
@@ -35,73 +35,70 @@ export async function activate(context: vscode.ExtensionContext)
3535
},
3636
);
3737
} else {
38-
vscode.window.showErrorMessage("Extension shader-validator failed to install dependencies. It will not launch the validation server.");
38+
vscode.window.showErrorMessage("Extension shader-validator failed to install dependencies. It will not launch the shader language server.");
3939
return; // Extension failed to launch.
4040
}
4141
}
4242

4343
// Create language client
44-
const possiblyNullClient = await createLanguageClient(context);
45-
if (possiblyNullClient === null) {
44+
const server = new ShaderLanguageClient;
45+
context.subscriptions.push(server);
46+
const isInitialized = await server.start(context);
47+
if (!isInitialized) {
4648
console.error("Failed to launch shader-validator language server.");
4749
return;
4850
}
49-
let client = possiblyNullClient;
5051
let supportedLangId = ["hlsl", "glsl", "wgsl"];
5152

5253
// Create sidebar
53-
sidebar = new ShaderVariantTreeDataProvider(context, client);
54-
55-
// Subscribe for dispose
56-
context.subscriptions.push(vscode.Disposable.from(client));
54+
sidebar = new ShaderVariantTreeDataProvider(context, server);
5755

5856
// Subscribe commands
5957
context.subscriptions.push(vscode.commands.registerCommand("shader-validator.validateFile", (uri: vscode.Uri) => {
6058
//client.sendRequest()
6159
vscode.window.showInformationMessage("Cannot validate file manually for now");
6260
}));
61+
context.subscriptions.push(vscode.commands.registerCommand("shader-validator.restartServer", (uri: vscode.Uri) => {
62+
server.restart(context);
63+
}));
6364
context.subscriptions.push(vscode.commands.registerCommand("shader-validator.dumpAst", () => {
6465
let activeTextEditor = vscode.window.activeTextEditor;
6566
if (activeTextEditor && activeTextEditor.document.uri.scheme === 'file' && supportedLangId.includes(activeTextEditor.document.languageId)) {
66-
client.sendRequest(dumpAstRequest, {
67-
uri: client.code2ProtocolConverter.asUri(activeTextEditor.document.uri)
67+
server.sendRequest(dumpAstRequest, {
68+
uri: server.uriAsString(activeTextEditor.document.uri)
6869
}).then((value: string | null) => {
6970
console.info(value);
70-
client.outputChannel.appendLine(value || "No AST to dump");
71+
server.log(value || "No AST to dump");
7172
}, (reason: any) => {
72-
client.outputChannel.appendLine("Failed to get ast: " + reason);
73+
server.log("Failed to get ast: " + reason);
7374
});
7475
} else {
75-
client.outputChannel.appendLine("No active file for dumping ast");
76+
server.log("No active file for dumping ast");
7677
}
7778
}));
7879
context.subscriptions.push(vscode.commands.registerCommand("shader-validator.dumpDependency", () => {
7980
let activeTextEditor = vscode.window.activeTextEditor;
8081
if (activeTextEditor && activeTextEditor.document.uri.scheme === 'file' && supportedLangId.includes(activeTextEditor.document.languageId)) {
81-
client.sendRequest(dumpDependencyRequest, {
82-
uri: client.code2ProtocolConverter.asUri(activeTextEditor.document.uri)
82+
server.sendRequest(dumpDependencyRequest, {
83+
uri: server.uriAsString(activeTextEditor.document.uri)
8384
}).then((value: string | null) => {
8485
console.info(value);
85-
client.outputChannel.appendLine(value || "No deps tree to dump");
86+
server.log(value || "No deps tree to dump");
8687
}, (reason: any) => {
87-
client.outputChannel.appendLine("Failed to get deps tree: " + reason);
88+
server.log("Failed to get deps tree: " + reason);
8889
});
8990
} else {
90-
client.outputChannel.appendLine("No active file for dumping deps tree");
91+
server.log("No active file for dumping deps tree");
9192
}
9293
}));
9394
context.subscriptions.push(
9495
vscode.workspace.onDidChangeConfiguration(async (event : vscode.ConfigurationChangeEvent) => {
9596
if (event.affectsConfiguration("shader-validator")) {
9697
if (event.affectsConfiguration("shader-validator.trace.server") ||
9798
event.affectsConfiguration("shader-validator.serverPath")) {
98-
let newClient = await createLanguageClient(context);
99-
if (newClient !== null) {
100-
client.dispose();
101-
client = newClient;
102-
}
99+
server.restart(context);
103100
} else {
104-
await client.sendNotification(DidChangeConfigurationNotification.type, {
101+
await server.sendNotification(DidChangeConfigurationNotification.type, {
105102
settings: "",
106103
});
107104
}

src/shaderVariant.ts

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as vscode from 'vscode';
22
import { CancellationToken, DocumentSymbol, DocumentSymbolRequest, DocumentUri, LanguageClient, ProtocolNotificationType, ProtocolRequestType, Range, SymbolInformation, SymbolKind, TextDocumentIdentifier, TextDocumentItem, TextDocumentRegistrationOptions } from 'vscode-languageclient/node';
3-
import { resolveVSCodeVariables } from './validator';
3+
import { resolveVSCodeVariables, ShaderLanguageClient } from './validator';
44

55
interface ShaderVariantSerialized {
66
url: DocumentUri,
@@ -121,7 +121,7 @@ export class ShaderVariantTreeDataProvider implements vscode.TreeDataProvider<Sh
121121
// using vscode.Uri as key does not match well with Memento state storage...
122122
private files: Map<string, ShaderVariantFile>;
123123
private tree: vscode.TreeView<ShaderVariantNode>;
124-
private client: LanguageClient;
124+
private server: ShaderLanguageClient;
125125
private decorator: vscode.TextEditorDecorationType;
126126
private workspaceState: vscode.Memento;
127127
private shaderEntryPointList: Map<string, ShaderEntryPoint[]>;
@@ -143,12 +143,12 @@ export class ShaderVariantTreeDataProvider implements vscode.TreeDataProvider<Sh
143143
this.workspaceState.update(shaderVariantTreeKey, array);
144144
}
145145

146-
constructor(context: vscode.ExtensionContext, client: LanguageClient) {
146+
constructor(context: vscode.ExtensionContext, server: ShaderLanguageClient) {
147147
this.workspaceState = context.workspaceState;
148148
this.files = new Map;
149149
this.load();
150150
this.shaderEntryPointList = new Map;
151-
this.client = client;
151+
this.server = server;
152152
this.tree = vscode.window.createTreeView<ShaderVariantNode>("shader-validator-variants", {
153153
treeDataProvider: this
154154
// TODO: drag and drop for better ux.
@@ -252,6 +252,10 @@ export class ShaderVariantTreeDataProvider implements vscode.TreeDataProvider<Sh
252252
this.save();
253253
}));
254254
context.subscriptions.push(vscode.commands.registerCommand("shader-validator.gotoShaderEntryPoint", (uri: vscode.Uri, entryPointName: string) => {
255+
// sometimes, its goes in random place in file...
256+
// TODO: Should use regex & read diag region instead.
257+
let diagnostic = vscode.languages.getDiagnostics().find(([diagUri, diags]) => diagUri === uri);
258+
255259
this.goToShaderEntryPoint(uri, entryPointName, true);
256260
}));
257261
// Prepare entry point symbol cache
@@ -268,6 +272,35 @@ export class ShaderVariantTreeDataProvider implements vscode.TreeDataProvider<Sh
268272
context.subscriptions.push(vscode.workspace.onDidCloseTextDocument(document => {
269273
this.shaderEntryPointList.delete(document.uri.path);
270274
}));
275+
context.subscriptions.push(vscode.workspace.onDidRenameFiles(document => {
276+
for (const fileObj of document.files) {
277+
const { oldUri, newUri } = fileObj;
278+
// To update the key in a Map, you need to remove the old key and add the new one.
279+
const oldPath = oldUri.path;
280+
const newPath = newUri.path;
281+
const file = this.files.get(oldPath);
282+
if (file) {
283+
// Update the uri inside the file object
284+
file.uri = newUri;
285+
// Remove the old key and set the new key
286+
this.files.delete(oldPath);
287+
this.files.set(newPath, file);
288+
}
289+
// Also update entry point and async maps
290+
const entryPoints = this.shaderEntryPointList.get(oldPath);
291+
if (entryPoints) {
292+
this.shaderEntryPointList.delete(oldPath);
293+
this.shaderEntryPointList.set(newPath, entryPoints);
294+
}
295+
const asyncEntryPoint = this.asyncGoToShaderEntryPoint.get(oldUri);
296+
if (asyncEntryPoint) {
297+
this.asyncGoToShaderEntryPoint.delete(oldUri);
298+
this.asyncGoToShaderEntryPoint.set(newUri, asyncEntryPoint);
299+
}
300+
this.shaderEntryPointList;
301+
this.asyncGoToShaderEntryPoint;
302+
}
303+
}));
271304
this.updateDependencies();
272305
}
273306
private getActiveVariant() : ShaderVariant | null {
@@ -390,17 +423,17 @@ export class ShaderVariantTreeDataProvider implements vscode.TreeDataProvider<Sh
390423
// Open document to get language ID.
391424
// This does not open the document in the editor, only internally.
392425
vscode.workspace.openTextDocument(fileActiveVariant.uri).then(doc => {
393-
this.client.sendNotification(didChangeShaderVariantNotification, {
426+
this.server.sendNotification(didChangeShaderVariantNotification, {
394427
// Need this check again here because its async
395428
shaderVariant: fileActiveVariant ? shaderVariantToSerialized(
396-
this.client.code2ProtocolConverter.asUri(fileActiveVariant.uri),
429+
this.server.uriAsString(fileActiveVariant.uri),
397430
capitalizeFirstLetter(doc.languageId), // Server expect it with capitalized first letter.
398431
fileActiveVariant
399432
) : null,
400433
});
401434
});
402435
} else {
403-
this.client.sendNotification(didChangeShaderVariantNotification, {
436+
this.server.sendNotification(didChangeShaderVariantNotification, {
404437
shaderVariant: null,
405438
});
406439
}
@@ -421,24 +454,29 @@ export class ShaderVariantTreeDataProvider implements vscode.TreeDataProvider<Sh
421454
// Dirty hack to trigger document symbol update
422455
// Ideally, it should retrigger dependencies aswell.
423456
// See https://github.com/microsoft/vscode/issues/108722 (Old one https://github.com/microsoft/vscode/issues/71454)
424-
let visibleEditor = vscode.window.visibleTextEditors.find(e => e.document.uri.path === uri.path);
425-
if (visibleEditor) {
426-
let editor = visibleEditor;
427-
editor.edit(editBuilder => {
428-
for (let iLine = 0; iLine < editor.document.lineCount; iLine++) {
429-
// Find first non-empty line to avoid crashing on empty line with negative position.
430-
let line = editor.document.lineAt(iLine);
431-
if (line.text.length > 0) {
432-
const text = line.text;
433-
const c = line.range.end.character;
434-
// Remove last character of first line and add it back.
435-
editBuilder.delete(new vscode.Range(iLine, c-1, iLine, c));
436-
editBuilder.insert(new vscode.Position(iLine, c), text[c-1]);
437-
break;
457+
458+
// Only trigger it if requested by user as it may be a bit invasive.
459+
let updateSymbolsOnVariantUpdate = vscode.workspace.getConfiguration("shader-validator").get<boolean>("updateSymbolsOnVariantUpdate");
460+
if (updateSymbolsOnVariantUpdate) {
461+
let visibleEditor = vscode.window.visibleTextEditors.find(e => e.document.uri.path === uri.path);
462+
if (visibleEditor) {
463+
let editor = visibleEditor;
464+
editor.edit(editBuilder => {
465+
for (let iLine = 0; iLine < editor.document.lineCount; iLine++) {
466+
// Find first non-empty line to avoid crashing on empty line with negative position.
467+
let line = editor.document.lineAt(iLine);
468+
if (line.text.length > 0) {
469+
const text = line.text;
470+
const c = line.range.end.character;
471+
// Remove last character of first line and add it back.
472+
editBuilder.delete(new vscode.Range(iLine, c-1, iLine, c));
473+
editBuilder.insert(new vscode.Position(iLine, c), text[c-1]);
474+
break;
475+
}
438476
}
439-
}
440-
// All empty lines means no symbols !
441-
});
477+
// All empty lines means no symbols !
478+
});
479+
}
442480
}
443481
}
444482
private updateDependency(file: ShaderVariantFile) {
@@ -568,6 +606,24 @@ export class ShaderVariantTreeDataProvider implements vscode.TreeDataProvider<Sh
568606
if (uri.scheme !== 'file') {
569607
return;
570608
}
609+
// If adding active variant, remove all currently active ones.
610+
if (variant) {
611+
if (variant.isActive) {
612+
for (let [url, file] of this.files) {
613+
let needRefresh = false;
614+
for (let otherVariant of file.variants) {
615+
if (otherVariant.isActive) {
616+
needRefresh = true;
617+
otherVariant.isActive = false;
618+
}
619+
}
620+
if (needRefresh) {
621+
// Refresh file & all its childs
622+
this.refresh(file, file);
623+
}
624+
}
625+
}
626+
}
571627
let file = this.files.get(uri.path);
572628
if (!file) {
573629
let newFile : ShaderVariantFile = {

0 commit comments

Comments
 (0)