Skip to content

Commit 67a80a0

Browse files
authored
Merge pull request #137 from glennsarti/make-client-langserver-better
(GH-136)(GH-61) Make client langserver better
2 parents 30e8fec + 8b55b9a commit 67a80a0

File tree

12 files changed

+224
-43
lines changed

12 files changed

+224
-43
lines changed

client/package.json

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
],
3939
"activationEvents": [
4040
"onLanguage:puppet",
41+
"onCommand:extension.puppetRestartSession",
42+
"onCommand:extension.puppetShowConnectionLogs",
43+
"onCommand:extension.puppetShowConnectionMenu",
4144
"onCommand:extension.puppetLint",
4245
"onCommand:extension.puppetParserValidate",
4346
"onCommand:extension.puppetShowNodeGraphToSide",
@@ -87,6 +90,16 @@
8790
}
8891
],
8992
"commands": [
93+
{
94+
"command": "extension.puppetRestartSession",
95+
"category": "Puppet",
96+
"title": "Restart Current Session"
97+
},
98+
{
99+
"command": "extension.puppetShowConnectionLogs",
100+
"category": "Puppet",
101+
"title": "Show Connection Logs"
102+
},
90103
{
91104
"command": "extension.pdkNewModule",
92105
"category": "Puppet",
@@ -128,6 +141,12 @@
128141
],
129142
"menus": {
130143
"commandPalette": [
144+
{
145+
"command": "extension.puppetRestartSession"
146+
},
147+
{
148+
"command": "extension.puppetShowConnectionLogs"
149+
},
131150
{
132151
"command": "extension.pdkNewModule"
133152
},
@@ -255,7 +274,8 @@
255274
"puppet.languageclient.minimumUserLogLevel": {
256275
"type": "string",
257276
"default": "normal",
258-
"description": "Set the minimum log level that the user will see on the Puppet OutputChannel (Allowed values: verbose, debug, normal, warning, error)"
277+
"description": "Set the minimum log level that the user will see on the Puppet connection logs",
278+
"enum": ["verbose", "debug", "normal", "warning", "error" ]
259279
},
260280
"puppet.puppetAgentDir": {
261281
"type": "string",

client/src/commands/puppetcommands.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,19 @@ export function setupPuppetCommands(langID:string, connManager:IConnectionManage
1919
ctx.subscriptions.push(vscode.commands.registerCommand(messages.PuppetCommandStrings.PuppetNodeGraphToTheSideCommandId,
2020
uri => showNodeGraph(uri, true))
2121
);
22-
22+
23+
ctx.subscriptions.push(vscode.commands.registerCommand(messages.PuppetCommandStrings.PuppetShowConnectionMenuCommandId,
24+
() => { connManager.showConnectionMenu(); }
25+
));
26+
27+
ctx.subscriptions.push(vscode.commands.registerCommand(messages.PuppetCommandStrings.PuppetShowConnectionLogsCommandId,
28+
() => { connManager.showLogger(); }
29+
));
30+
31+
ctx.subscriptions.push(vscode.commands.registerCommand(messages.PuppetCommandStrings.PuppetRestartSessionCommandId,
32+
() => { connManager.restartConnection(); }
33+
));
34+
2335
const contentProvider = new PuppetNodeGraphContentProvider(ctx, connManager);
2436
const contentProviderRegistration = vscode.workspace.registerTextDocumentContentProvider(langID, contentProvider);
2537

client/src/configuration.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
import * as vscode from 'vscode';
4+
5+
import { ConnectionManager, IConnectionConfiguration, ConnectionType } from './connection';
6+
7+
export class ConnectionConfiguration implements IConnectionConfiguration {
8+
public type: ConnectionType = ConnectionType.Unknown;
9+
public host: string = undefined;
10+
public port: number = undefined;
11+
public timeout: number = undefined;
12+
public preLoadPuppet: boolean = undefined;
13+
public debugFilePath: string = undefined;
14+
public puppetAgentDir: string = undefined;
15+
16+
constructor(context: vscode.ExtensionContext) {
17+
let config = vscode.workspace.getConfiguration('puppet');
18+
19+
this.host = config['languageserver']['address'];
20+
this.port = config['languageserver']['port'];
21+
this.timeout = config['languageserver']['timeout'];
22+
this.preLoadPuppet = config['languageserver']['preLoadPuppet'];
23+
this.debugFilePath = config['languageserver']['debugFilePath'];
24+
25+
this.puppetAgentDir = config['puppetAgentDir'];
26+
}
27+
}

client/src/connection.ts

Lines changed: 89 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import vscode = require('vscode');
44
import cp = require('child_process');
55
import { Logger } from '../src/logging';
66
import { LanguageClient, LanguageClientOptions, ServerOptions } from 'vscode-languageclient';
7+
import { ConnectionConfiguration } from './configuration';
78
import { setupPuppetCommands } from '../src/commands/puppetcommands';
89
import { setupPDKCommands } from '../src/commands/pdkcommands';
910
import { reporter } from './telemetry/telemetry';
@@ -39,6 +40,9 @@ export interface IConnectionConfiguration {
3940
export interface IConnectionManager {
4041
status: ConnectionStatus;
4142
languageClient: LanguageClient;
43+
showConnectionMenu();
44+
showLogger();
45+
restartConnection(connectionConfig?: IConnectionConfiguration);
4246
}
4347

4448
export class ConnectionManager implements IConnectionManager {
@@ -58,6 +62,9 @@ export class ConnectionManager implements IConnectionManager {
5862
public get languageClient() : LanguageClient {
5963
return this.languageServerClient;
6064
}
65+
public showLogger() {
66+
this.logger.show()
67+
}
6168

6269
constructor(context: vscode.ExtensionContext, logger: Logger) {
6370
this.logger = logger;
@@ -78,7 +85,7 @@ export class ConnectionManager implements IConnectionManager {
7885
this.terminal = vscode.window.createTerminal('Puppet PDK');
7986
this.terminal.processId.then(
8087
pid => {
81-
console.log("pdk shell started, pid: " + pid);
88+
this.logger.debug("pdk shell started, pid: " + pid);
8289
});
8390
setupPDKCommands(langID, this, this.extensionContext, this.logger, this.terminal);
8491
this.extensionContext.subscriptions.push(this.terminal);
@@ -325,9 +332,11 @@ export class ConnectionManager implements IConnectionManager {
325332
var languageServerClient = new LanguageClient(title, serverOptions, clientOptions)
326333
languageServerClient.onReady().then(() => {
327334
langClient.logger.debug('Language server client started, setting puppet version')
328-
languageServerClient.sendRequest(messages.PuppetVersionRequest.type).then((versionDetails) => {
329-
this.setConnectionStatus(versionDetails.puppetVersion, ConnectionStatus.Running);
330-
if (reporter) {
335+
this.setConnectionStatus("Loading Puppet", ConnectionStatus.Starting);
336+
this.queryLanguageServerStatus();
337+
// Send telemetry
338+
if (reporter) {
339+
languageServerClient.sendRequest(messages.PuppetVersionRequest.type).then((versionDetails) => {
331340
reporter.sendTelemetryEvent('puppetVersion' +versionDetails.puppetVersion);
332341
reporter.sendTelemetryEvent('facterVersion' + versionDetails.facterVersion);
333342
reporter.sendTelemetryEvent('languageServerVersion' + versionDetails.languageServerVersion);
@@ -336,26 +345,66 @@ export class ConnectionManager implements IConnectionManager {
336345
facterVersion: versionDetails.facterVersion,
337346
languageServerVersion: versionDetails.languageServerVersion,
338347
});
339-
}
340-
});
348+
});
349+
}
341350
}, (reason) => {
342351
this.setSessionFailure("Could not start language service: ", reason);
343352
});
344353

345354
return languageServerClient;
346355
}
347356

348-
private restartConnection(connectionConfig?: IConnectionConfiguration) {
349-
this.stop();
350-
this.start(connectionConfig);
357+
private queryLanguageServerStatus() {
358+
let connectionManager = this;
359+
360+
return new Promise((resolve, reject) => {
361+
let count = 0;
362+
let lastVersionResponse = null;
363+
let handle = setInterval(() => {
364+
count++;
365+
366+
// After 30 seonds timeout the progress
367+
if (count >= 30 || connectionManager.languageClient == undefined) {
368+
clearInterval(handle);
369+
connectionManager.setConnectionStatus(lastVersionResponse.puppetVersion, ConnectionStatus.Running);
370+
resolve();
371+
}
372+
373+
connectionManager.languageClient.sendRequest(messages.PuppetVersionRequest.type).then((versionDetails) => {
374+
lastVersionResponse = versionDetails
375+
if (versionDetails.factsLoaded && versionDetails.functionsLoaded && versionDetails.typesLoaded) {
376+
clearInterval(handle);
377+
connectionManager.setConnectionStatus(lastVersionResponse.puppetVersion, ConnectionStatus.Running);
378+
resolve();
379+
} else {
380+
let progress = 0;
381+
382+
if (versionDetails.factsLoaded) { progress++; }
383+
if (versionDetails.functionsLoaded) { progress++; }
384+
if (versionDetails.typesLoaded) { progress++; }
385+
progress = Math.round(progress / 3.0 * 100);
386+
387+
this.setConnectionStatus("Loading Puppet (" + progress.toString() + "%)", ConnectionStatus.Starting);
388+
}
389+
});
390+
391+
}, 1000);
392+
});
393+
}
394+
395+
public restartConnection(connectionConfig?: IConnectionConfiguration) {
396+
if (connectionConfig == undefined) {
397+
connectionConfig = new ConnectionConfiguration(this.extensionContext);
398+
}
399+
this.stop();
400+
this.start(connectionConfig);
351401
}
352402

353403
private createStatusBarItem() {
354404
if (this.statusBarItem === undefined) {
355405
this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 1);
356406

357-
// TODO: Add a command here to show the connection menu
358-
// this.statusBarItem.command = this.ShowConnectionMenuCommandName;
407+
this.statusBarItem.command = messages.PuppetCommandStrings.PuppetShowConnectionMenuCommandId;
359408
this.statusBarItem.show();
360409
vscode.window.onDidChangeActiveTextEditor(textEditor => {
361410
if (textEditor === undefined || textEditor.document.languageId !== "puppet") {
@@ -368,6 +417,27 @@ export class ConnectionManager implements IConnectionManager {
368417
}
369418
}
370419

420+
public showConnectionMenu() {
421+
var menuItems: ConnectionMenuItem[] = [];
422+
423+
menuItems.push(
424+
new ConnectionMenuItem(
425+
"Restart Current Puppet Session",
426+
() => { vscode.commands.executeCommand(messages.PuppetCommandStrings.PuppetRestartSessionCommandId); }),
427+
)
428+
429+
menuItems.push(
430+
new ConnectionMenuItem(
431+
"Show Puppet Session Logs",
432+
() => { vscode.commands.executeCommand(messages.PuppetCommandStrings.PuppetShowConnectionLogsCommandId); }),
433+
)
434+
435+
vscode
436+
.window
437+
.showQuickPick<ConnectionMenuItem>(menuItems)
438+
.then((selectedItem) => { selectedItem.callback(); });
439+
}
440+
371441
private setConnectionStatus(statusText: string, status: ConnectionStatus): void {
372442
// Set color and icon for 'Running' by default
373443
var statusIconText = "$(terminal) ";
@@ -391,3 +461,11 @@ export class ConnectionManager implements IConnectionManager {
391461
this.setConnectionStatus("Starting Error", ConnectionStatus.Failed);
392462
}
393463
}
464+
465+
class ConnectionMenuItem implements vscode.QuickPickItem {
466+
public description: string;
467+
468+
constructor(public readonly label: string, public readonly callback: () => void = () => { })
469+
{
470+
}
471+
}

client/src/extension.ts

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as vscode from 'vscode';
44
import * as path from 'path';
55

66
import { ConnectionManager, IConnectionConfiguration, ConnectionType } from './connection';
7+
import { ConnectionConfiguration } from './configuration';
78
import { Logger } from './logging';
89
import { Reporter } from './telemetry/telemetry';
910

@@ -13,28 +14,6 @@ var serverProc;
1314

1415
var connManager: ConnectionManager = undefined;
1516

16-
export class ConnectionConfiguration implements IConnectionConfiguration {
17-
public type: ConnectionType = ConnectionType.Unknown;
18-
public host: string = undefined;
19-
public port: number = undefined;
20-
public timeout: number = undefined;
21-
public preLoadPuppet: boolean = undefined;
22-
public debugFilePath: string = undefined;
23-
public puppetAgentDir: string = undefined;
24-
25-
constructor(context: vscode.ExtensionContext) {
26-
let config = vscode.workspace.getConfiguration('puppet');
27-
28-
this.host = config['languageserver']['address'];
29-
this.port = config['languageserver']['port'];
30-
this.timeout = config['languageserver']['timeout'];
31-
this.preLoadPuppet = config['languageserver']['preLoadPuppet'];
32-
this.debugFilePath = config['languageserver']['debugFilePath'];
33-
34-
this.puppetAgentDir = config['puppetAgentDir'];
35-
}
36-
}
37-
3817
export function activate(context: vscode.ExtensionContext) {
3918
const puppetExtension = vscode.extensions.getExtension('jpogran.puppet-vscode')!;
4019
const puppetExtensionVersion = puppetExtension.packageJSON.version;

client/src/logging.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ export class Logger {
1919

2020
constructor() {
2121
this.logChannel = vscode.window.createOutputChannel("Puppet");
22-
this.logChannel.show();
2322

2423
let config = vscode.workspace.getConfiguration('puppet');
2524
let logLevelName = config['languageclient']['minimumUserLogLevel'];
@@ -33,6 +32,10 @@ export class Logger {
3332
}
3433
}
3534

35+
public show(){
36+
this.logChannel.show();
37+
}
38+
3639
public verbose(message: string) {
3740
this.logWithLevel(LogLevel.Verbose, message);
3841
}
@@ -54,7 +57,7 @@ export class Logger {
5457
}
5558

5659
private logWithLevel(level: LogLevel, message) {
57-
let logMessage = this.logLevelPrefixAsString(level) + message
60+
let logMessage = this.logLevelPrefixAsString(level) + (new Date().toISOString()) + ' ' + message
5861

5962
console.log(logMessage);
6063
if (level >= this.minimumUserLogLevel) {

client/src/messages.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ export interface PuppetVersionDetails {
88
puppetVersion: string;
99
facterVersion: string;
1010
languageServerVersion: string;
11+
factsLoaded: boolean;
12+
functionsLoaded: boolean;
13+
typesLoaded: boolean;
1114
}
1215

1316
export interface PuppetResourceRequestParams {
@@ -37,6 +40,9 @@ export interface CompileNodeGraphResponse {
3740
export class PuppetCommandStrings{
3841
static PuppetResourceCommandId:string = 'extension.puppetResource';
3942
static PuppetNodeGraphToTheSideCommandId = 'extension.puppetShowNodeGraphToSide';
43+
static PuppetShowConnectionMenuCommandId = 'extension.puppetShowConnectionMenu';
44+
static PuppetShowConnectionLogsCommandId = 'extension.puppetShowConnectionLogs';
45+
static PuppetRestartSessionCommandId = 'extension.puppetRestartSession';
4046
}
4147

4248
export class PDKCommandStrings {

server/lib/languageserver/puppet_version.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
module LanguageServer
22
module PuppetVersion
33
# export interface PuppetVersionDetails {
4-
# puppetVersion: string;
5-
# facterVersion: string;
6-
# languageServerVersion: string;
4+
# puppetVersion: string;
5+
# facterVersion: string;
6+
# languageServerVersion: string;
7+
# factsLoaded: boolean;
8+
# functionsLoaded: boolean;
9+
# typesLoaded: boolean;
710
# }
811

912
def self.create(options)
@@ -13,6 +16,11 @@ def self.create(options)
1316

1417
result['puppetVersion'] = options['puppetVersion']
1518
result['facterVersion'] = options['facterVersion']
19+
20+
result['factsLoaded'] = options['factsLoaded'] unless options['factsLoaded'].nil?
21+
result['functionsLoaded'] = options['functionsLoaded'] unless options['functionsLoaded'].nil?
22+
result['typesLoaded'] = options['typesLoaded'] unless options['typesLoaded'].nil?
23+
1624
result['languageServerVersion'] = PuppetLanguageServer.version
1725

1826
result

0 commit comments

Comments
 (0)