Skip to content

Commit af8fe1d

Browse files
committed
feat: add multi-root workspaces support Closes #33
other changes: - remove server code & switch to gql-language-server
1 parent 7ad1202 commit af8fe1d

File tree

13 files changed

+1048
-4171
lines changed

13 files changed

+1048
-4171
lines changed

.prettierrc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{
22
"bracketSpacing": true,
3+
"jsxBracketSameLine": false,
34
"printWidth": 80,
45
"semi": true,
56
"singleQuote": true,
67
"tabWidth": 2,
78
"trailingComma": "all",
8-
"useTabs": false
9+
"useTabs": false,
10+
"parser": "typescript"
911
}

package.json

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"url": "https://github.com/kumarharsh"
1010
},
1111
"keywords": [
12+
"multi-root ready",
1213
"graphql",
1314
"linter",
1415
"ide",
@@ -44,7 +45,7 @@
4445
"activationEvents": [
4546
"workspaceContains:.gqlconfig"
4647
],
47-
"main": "./out/client/extension",
48+
"main": "./out/extension",
4849
"badges": [
4950
{
5051
"url": "https://img.shields.io/badge/%20%20%F0%9F%9A%80-semantic--release-e10079.svg",
@@ -58,20 +59,60 @@
5859
"title": "Graphql Configuration",
5960
"properties": {
6061
"graphqlForVSCode.nodePath": {
61-
"type": [
62-
"string",
63-
"null"
62+
"scope": "resource",
63+
"type": "string",
64+
"description": "A path used for resolving the @playlyfe/gql module. (default: workspaceFolder)",
65+
"default": "."
66+
},
67+
"graphqlForVSCode.loglevel": {
68+
"scope": "resource",
69+
"type": "string",
70+
"default": "info",
71+
"enum": [
72+
"debug",
73+
"info",
74+
"error",
75+
"off"
6476
],
65-
"default": null,
66-
"description": "A path added to NODE_PATH when resolving the @playlyfe/gql module."
77+
"description": "log level."
6778
},
68-
"graphqlForVSCode.debug": {
69-
"type": [
70-
"boolean",
71-
"null"
79+
"graphqlForVSCode.trace.server": {
80+
"scope": "window",
81+
"anyOf": [
82+
{
83+
"type": "string",
84+
"enum": [
85+
"off",
86+
"messages",
87+
"verbose"
88+
],
89+
"default": "off"
90+
},
91+
{
92+
"type": "object",
93+
"properties": {
94+
"verbosity": {
95+
"type": "string",
96+
"enum": [
97+
"off",
98+
"messages",
99+
"verbose"
100+
],
101+
"default": "off"
102+
},
103+
"format": {
104+
"type": "string",
105+
"enum": [
106+
"text",
107+
"json"
108+
],
109+
"default": "text"
110+
}
111+
}
112+
}
72113
],
73-
"default": false,
74-
"description": "enable debug logs."
114+
"default": "off",
115+
"description": "Traces the communication between VSCode and the gql language server."
75116
}
76117
}
77118
},
@@ -165,14 +206,12 @@
165206
]
166207
},
167208
"scripts": {
168-
"vscode:prepublish": "yarn install && yarn clean && yarn compile-server && yarn compile",
209+
"vscode:prepublish": "yarn install && yarn clean && yarn compile",
169210
"postinstall": "node ./node_modules/vscode/bin/install",
170211
"clean": "rimraf out",
171-
"compile-server": "yarn install && tsc -p src/server",
172-
"compile": "yarn install && tsc -p src/client",
173-
"watch-server": "tsc -watch -p src/server",
174-
"watch": "tsc -watch -p src/client",
175-
"dev": "yarn clean && yarn compile-server && yarn watch",
212+
"compile": "yarn install && tsc -p src",
213+
"watch": "tsc -watch -p src",
214+
"dev": "yarn clean && yarn watch",
176215
"package": "yarn install && vsce package"
177216
},
178217
"devDependencies": {
@@ -196,10 +235,8 @@
196235
"vscode": "^1.1.34"
197236
},
198237
"dependencies": {
199-
"semver": "^6.0.0",
200-
"vscode-languageclient": "^5.2.1",
201-
"vscode-languageserver": "^5.2.1",
202-
"vscode-uri": "^2.0.1"
238+
"@playlyfe/gql-language-server": "0.1.0",
239+
"vscode-languageclient": "^5.2.1"
203240
},
204241
"galleryBanner": {
205242
"color": "#2e2348",

src/ClientStatusBarItem.ts

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
'use strict';
2+
3+
import {
4+
commands,
5+
languages,
6+
StatusBarAlignment,
7+
StatusBarItem,
8+
TextDocument,
9+
TextEditor,
10+
ThemeColor,
11+
window,
12+
workspace,
13+
} from 'vscode';
14+
15+
import { LanguageClient, State } from 'vscode-languageclient';
16+
17+
enum Status {
18+
init = 1,
19+
ok = 2,
20+
error = 3,
21+
}
22+
23+
interface IStatusBarItemConfig {
24+
icon: string;
25+
tooltip: string;
26+
color: string;
27+
}
28+
29+
const STATUS_BAR_ITEM_NAME = 'GQL';
30+
const STATUS_BAR_UI = {
31+
[Status.init]: {
32+
icon: 'sync',
33+
color: 'progressBar.background',
34+
tooltip: 'Graphql language server is initializing.',
35+
},
36+
[Status.ok]: {
37+
icon: 'plug',
38+
color: 'statusBar.foreground',
39+
tooltip: 'Graphql language server is running.',
40+
},
41+
[Status.error]: {
42+
icon: 'stop',
43+
color: 'editorError.foreground',
44+
tooltip: 'Graphql language server is not running.',
45+
},
46+
};
47+
export default class ClientStatusBarItem {
48+
private _item: StatusBarItem;
49+
private _client: LanguageClient;
50+
private _disposables: Array<{ dispose: () => any }> = [];
51+
52+
constructor(client: LanguageClient) {
53+
this._item = window.createStatusBarItem(StatusBarAlignment.Right, 0);
54+
this._client = client;
55+
56+
this._disposables.push(this._item);
57+
this._disposables.push(this._addOnClickToShowOutputChannel());
58+
59+
// update status bar depending on client state
60+
this._setStatus(Status.init);
61+
this._registerStatusChangeListeners();
62+
63+
// update visibility of statusBarItem depending on current activeTextEditor
64+
this._updateVisibility(window.activeTextEditor);
65+
window.onDidChangeActiveTextEditor(this._updateVisibility);
66+
}
67+
68+
public dispose() {
69+
this._disposables.forEach(item => {
70+
item.dispose();
71+
});
72+
this._item = null;
73+
this._client = null;
74+
}
75+
76+
private _registerStatusChangeListeners() {
77+
this._client.onDidChangeState(({ oldState, newState }) => {
78+
if (newState === State.Running) {
79+
this._setStatus(Status.ok);
80+
} else if (newState === State.Stopped) {
81+
this._setStatus(Status.error);
82+
}
83+
});
84+
85+
this._client.onReady().then(
86+
() => {
87+
this._setStatus(Status.ok);
88+
},
89+
() => {
90+
this._setStatus(Status.error);
91+
},
92+
);
93+
}
94+
95+
private _addOnClickToShowOutputChannel() {
96+
const commandName = `showOutputChannel-${this._client.outputChannel.name}`;
97+
const disposable = commands.registerCommand(commandName, () => {
98+
this._client.outputChannel.show();
99+
});
100+
this._item.command = commandName;
101+
return disposable;
102+
}
103+
104+
private _updateVisibility = (textEditor: TextEditor) => {
105+
let hide = true;
106+
107+
if (textEditor && this._checkDocumentInsideWorkspace(textEditor.document)) {
108+
if (this._client.initializeResult) {
109+
// if client is initialized then show only for file extensions
110+
// defined in .gqlconfig
111+
// @TODO: if possible, match against patterns defined in .gqlconfig
112+
// instead of extensions.
113+
const extensions = this._client.initializeResult.fileExtensions;
114+
const score = languages.match(
115+
{ scheme: 'file', pattern: `**/*.{${extensions.join(',')}}` },
116+
textEditor.document,
117+
);
118+
hide = score === 0;
119+
} else {
120+
// while server is initializing show status bar item
121+
// for all files inside worspace
122+
hide = false;
123+
}
124+
}
125+
126+
hide ? this._hide() : this._show();
127+
};
128+
129+
private _checkDocumentInsideWorkspace(document: TextDocument): boolean {
130+
const folder = workspace.getWorkspaceFolder(document.uri);
131+
return folder && folder.uri.toString() === this._getWorkspace();
132+
}
133+
134+
private _getWorkspace(): string {
135+
return this._client.clientOptions.workspaceFolder.uri.toString();
136+
}
137+
138+
private _show() {
139+
this._item.show();
140+
}
141+
142+
private _hide() {
143+
this._item.hide();
144+
}
145+
146+
private _setStatus(status: Status) {
147+
const ui: IStatusBarItemConfig = STATUS_BAR_UI[status];
148+
this._item.text = `$(${ui.icon}) ${STATUS_BAR_ITEM_NAME}`;
149+
this._item.tooltip = ui.tooltip;
150+
this._item.color = new ThemeColor(ui.color);
151+
}
152+
}

0 commit comments

Comments
 (0)