Skip to content

Commit

Permalink
Add LSP server support
Browse files Browse the repository at this point in the history
Qbs implements the LSP server partially starts from Qbs v2.2.0,
but a more usefull LSP support starts from Qbs v2.3.0.

This suport belongs to Qbs API level greater than 4, so, right
now, the VSCode extension will use the LSP features for Qbs
language only for that mention Qbs versions, and more newest.
  • Loading branch information
denis-shienkov committed Oct 17, 2024
1 parent 0171027 commit f4c9d19
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 2 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
reads the available Qbs profiles and fills the profile selector.
Also this command runs once instead of **Qbs: Scan Build Profiles**
when the extension loading to avoid the Qbs profiles re-detection.
- Improve hihgliting for the Qbs language syntax in editor.
- Improved hihgliting for the Qbs language syntax in editor.
- Added support for LSP server provided by Qbs session.

## 2.1.6

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@
"jsonc-parser": "^3.0.0",
"uuid": "^9.0.0",
"vscode-cpptools": "^6.1.0",
"vscode-languageclient": "^9.0.1",
"vscode-nls": "^5.0.0",
"which": "~2.0.2"
},
Expand Down
1 change: 1 addition & 0 deletions src/protocol/qbsprotocoldatakey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export enum QbsProtocolDataKey {
Location = 'location',
LogData = 'log-data',
LogLevel = 'log-level',
LspSocket = 'lsp-socket',
MaxJobCount = 'max-job-count',
MaxProgress = 'max-progress',
Message = 'message',
Expand Down
2 changes: 2 additions & 0 deletions src/protocol/qbsprotocolhelloresponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { QbsProtocolDataKey } from './qbsprotocoldatakey';
export class QbsProtocolHelloResponse {
public readonly apiLevel: number = 0;
public readonly apiCompatibilityLevel: number = 0;
public readonly lspSocket?: string;

public constructor(response: any) {
this.apiLevel = parseInt(response[QbsProtocolDataKey.ApiLevel]);
this.apiCompatibilityLevel = parseInt(response[QbsProtocolDataKey.ApiCompatLevel]);
this.lspSocket = response[QbsProtocolDataKey.LspSocket];
}
}
41 changes: 41 additions & 0 deletions src/qbslanguageclient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as vscode from 'vscode';

import {
LanguageClient,
LanguageClientOptions,
MessageTransports,
} from 'vscode-languageclient/node';

import { createServerPipeTransport } from 'vscode-languageserver-protocol/node';

export class QbsLanguageClient implements vscode.Disposable {
private languageClient?: LanguageClient;

public constructor(pipeName: string) {
const serverOptions = this.createMessageTransports(pipeName);
const clientOptions: LanguageClientOptions = {
documentSelector: [{ language: 'qbs' }],
};
console.info('Starting Qbs language client on pipe: ' + pipeName);
this.languageClient = new LanguageClient('Qbs', (async () => serverOptions), clientOptions, true);
this.languageClient
.start()
.then(async () => {
console.info('Qbs language client started on pipe: ' + pipeName);
})
.catch((reason) => {
void vscode.window.showErrorMessage('Cannot start Qbs language server');
console.error('Unable to start Qbs language client on pipe: ' + pipeName + ', ' + reason);
});

}

public dispose(): void { this.languageClient?.dispose(); }

private async createMessageTransports(pipeName: string): Promise<MessageTransports> {
return new Promise<MessageTransports>(async (resolve) => {
const transport = createServerPipeTransport(pipeName);
resolve({ reader: transport[0], writer: transport[1] });
});
}
}
13 changes: 12 additions & 1 deletion src/qbssession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { QbsProtocolTaskMaxProgressResponse } from './protocol/qbsprotocoltaskma
import { QbsProtocolTaskProgressResponse } from './protocol/qbsprotocoltaskprogressresponse';
import { QbsProtocolTaskStartedResponse } from './protocol/qbsprotocoltaskstartedresponse';

import { QbsLanguageClient } from './qbslanguageclient';

const localize = nls.config({ messageFormat: nls.MessageFormat.file })();

export enum QbsSessionState {
Expand All @@ -40,6 +42,7 @@ export class QbsSessionProjectData {
export class QbsSession implements vscode.Disposable {
private engine: QbsProtocolEngine = new QbsProtocolEngine();
private state: QbsSessionState = QbsSessionState.Stopped;
private languageClient?: QbsLanguageClient;

private readonly stateChanged: vscode.EventEmitter<QbsSessionState> = new vscode.EventEmitter<QbsSessionState>();

Expand Down Expand Up @@ -135,6 +138,8 @@ export class QbsSession implements vscode.Disposable {
if (type === QbsProtocolDataKey.Hello) {
const result = new QbsProtocolHelloResponse(response)
this.helloReceived.fire(result);
if (result.lspSocket)
this.startupLanguageClient(result.lspSocket, result.apiLevel);
} else if (type === QbsProtocolDataKey.ProjectResolved) {
const data = new QbsProtocolProjectData(response[QbsProtocolDataKey.ProjectData]);
const msg = new QbsProtocolMessageResponse(response[QbsProtocolDataKey.Error]);
Expand Down Expand Up @@ -192,6 +197,12 @@ export class QbsSession implements vscode.Disposable {
this.stateChanged.fire(this.state);
}

private startupLanguageClient(pipeName: string, apiLevel: number) {
if (apiLevel <= 4)
return; // LSP supports by Qbs from the Qbs API Level version 4 and greather!
this.languageClient = new QbsLanguageClient(pipeName);
}

private static convert(status: QbsProtocolEngineState): QbsSessionState {
switch (status) {
case QbsProtocolEngineState.Started:
Expand All @@ -217,7 +228,7 @@ export class QbsSession implements vscode.Disposable {
return false;
} else if (!fs.existsSync(qbsPath)) {
await vscode.window.showErrorMessage(localize('qbs.executable.not-found.error.message',
`Qbs executable not found.`));
'Qbs executable not found.'));
return false;
}
return true;
Expand Down

0 comments on commit f4c9d19

Please sign in to comment.