diff --git a/extension/src/client/command/TriggerCollection.ts b/extension/src/client/command/TriggerCollection.ts index e9b66ffe..aff4053e 100644 --- a/extension/src/client/command/TriggerCollection.ts +++ b/extension/src/client/command/TriggerCollection.ts @@ -7,7 +7,7 @@ import { AutoWire, Logger, sleep } from "@vmware/vrdt-common" import { remote } from "@vmware/vro-language-server" import * as vscode from "vscode" -import { Commands } from "../constants" +import { Commands, LanguageServerConfig } from "../constants" import { LanguageServices } from "../lang" import { Command } from "./Command" @@ -30,7 +30,7 @@ export class TriggerCollection extends Command { const languageClient = this.languageServices.client if (!languageClient) { - this.logger.warn("The vRO language server is not running") + this.logger.warn(`The ${LanguageServerConfig.DisplayName} is not running`) return } await vscode.commands.executeCommand(Commands.EventCollectionStart) @@ -48,15 +48,13 @@ export class TriggerCollection extends Command { while (status && !status.finished) { this.logger.info("Collection status:", status) progress.report(status) - await sleep(1000) + await sleep(LanguageServerConfig.SleepTime) status = await languageClient.sendRequest(remote.server.giveVroCollectionStatus) } this.logger.info("Collection finished:", status) - if (status.error !== undefined) { await vscode.commands.executeCommand(Commands.EventCollectionError, status.error) - if (status.data.hintsPluginBuild === 0) { vscode.window.showErrorMessage( "The vRO Hint plug-in is not installed on the configured vRO server" diff --git a/extension/src/client/constants.ts b/extension/src/client/constants.ts index f3056f6d..77bf7a57 100644 --- a/extension/src/client/constants.ts +++ b/extension/src/client/constants.ts @@ -110,3 +110,11 @@ export enum ProjectArchetypes { VraNg = "com.vmware.pscoe.vra-ng:vra-ng-package", Polyglot = "com.vmware.pscoe.polyglot:polyglot-project" } + +export enum LanguageServerConfig { + Port = 6014, + LoadType = "nolazy", + NodeType = "node-ipc", + DisplayName = "vRO Language Server", + SleepTime = 1000 +} diff --git a/extension/src/client/lang/LanguageServices.ts b/extension/src/client/lang/LanguageServices.ts index 51709e6f..fff3bb7c 100644 --- a/extension/src/client/lang/LanguageServices.ts +++ b/extension/src/client/lang/LanguageServices.ts @@ -10,7 +10,7 @@ import { remote } from "@vmware/vro-language-server" import * as vscode from "vscode" import * as client from "vscode-languageclient" -import { OutputChannels } from "../constants" +import { LanguageServerConfig, OutputChannels } from "../constants" import { Registrable } from "../Registrable" import { ConfigurationManager, EnvironmentManager } from "../system" @@ -82,20 +82,23 @@ export class LanguageServices implements Registrable, vscode.Disposable { ? path.join(module, "dist", "langserver.js") : path.join(module, "out", "server", "langserver.js") - this.logger.info(`Starting vRO language server on port 6014`) + this.logger.info(`Starting vRO language server on port '${LanguageServerConfig.Port}'`) const serverOptions = { run: { module: executable, transport: client.TransportKind.ipc, - args: ["--node-ipc"], + args: [`--${LanguageServerConfig.NodeType}`], options: { cwd: module } }, debug: { module: executable, transport: client.TransportKind.ipc, - args: ["--node-ipc"], - options: { cwd: module, execArgv: ["--nolazy", "--inspect=6014"] } + args: [`--${LanguageServerConfig.NodeType}`], + options: { + cwd: module, + execArgv: [`--${LanguageServerConfig.LoadType}`, `--inspect=${LanguageServerConfig.Port}`] + } } } @@ -119,6 +122,6 @@ export class LanguageServices implements Registrable, vscode.Disposable { ] } } - return new client.LanguageClient("vRO LS", serverOptions, clientOptions) + return new client.LanguageClient(LanguageServerConfig.DisplayName, serverOptions, clientOptions) } } diff --git a/package.json b/package.json index 63ba924e..fa5ce75c 100644 --- a/package.json +++ b/package.json @@ -525,7 +525,7 @@ "vrdev.vro.inventory.cache": { "type": "boolean", "default": true, - "description": "Enable / Disable vRO Inventory Caching", + "description": "Enable vRO inventory caching (can be used in heavily loaded environments)", "scope": "window" } } diff --git a/packages/node/vrdt-common/src/rest/VroRestClient.ts b/packages/node/vrdt-common/src/rest/VroRestClient.ts index 1147f2cf..3f3b31bb 100644 --- a/packages/node/vrdt-common/src/rest/VroRestClient.ts +++ b/packages/node/vrdt-common/src/rest/VroRestClient.ts @@ -43,7 +43,7 @@ export class VroRestClient { constructor(private settings: BaseConfiguration) { this.auth = this.getInitialAuth() - this.isCachingEnabled = this.settings?.vrdev?.vro?.inventory?.cache ?? false + this.loadCacheConfiguration() } private get hostname(): string { @@ -182,6 +182,8 @@ export class VroRestClient { options?: Partial ): Promise { const url = route.indexOf("://") > 0 ? route : `https://${this.hostname}:${this.port}/vco/api/${route}` + // reload the cache configuration in order cache to take effect when settings are changed + this.loadCacheConfiguration() return request({ headers: { "Accept": "application/json", @@ -675,15 +677,12 @@ export class VroRestClient { if (!child.attributes) { return undefined } - const id = child.attributes.find(att => att.name === "id") ?? child.attributes.find(att => att.name === "dunesId") - const name = child.attributes.find(att => att.name === "displayName") ?? child.attributes.find(att => att.name === "name") - const type = child.attributes.find(att => att.name === "type") ?? child.attributes.find(att => att.name === "@type") @@ -825,4 +824,8 @@ export class VroRestClient { async getPluginDetails(link: string) { return this.send("GET", `server-configuration/api/plugins/${link}`) } + + private loadCacheConfiguration(): void { + this.isCachingEnabled = this.settings?.vrdev?.vro?.inventory?.cache ?? false + } } diff --git a/packages/node/vro-language-server/src/constants.ts b/packages/node/vro-language-server/src/constants.ts index 1cb5654c..c9b63cef 100644 --- a/packages/node/vro-language-server/src/constants.ts +++ b/packages/node/vro-language-server/src/constants.ts @@ -42,3 +42,12 @@ message Action { export const Timeout = { ONE_SECOND: 1000 } + +export enum CompletionPrefixKind { + UNKNOWN = "Unknown", + CLASS_IMPORT = "Class Import", + CLASS_REFERENCE = "Class Reference", + STATIC_MEMBER_REFERENCE = "Static Member Reference", + NEW_INSTANCE = "New Instance", + MODULE_IMPORT = "Module Import" +} diff --git a/packages/node/vro-language-server/src/server/feature/CompletionProvider.ts b/packages/node/vro-language-server/src/server/feature/CompletionProvider.ts index 9e0727cb..f6e9e40c 100644 --- a/packages/node/vro-language-server/src/server/feature/CompletionProvider.ts +++ b/packages/node/vro-language-server/src/server/feature/CompletionProvider.ts @@ -17,15 +17,8 @@ import { URI } from "vscode-uri" import { ConnectionLocator, Environment, HintLookup } from "../core" import { Synchronizer, TextDocumentWrapper } from "../document" import { Previewer } from "../util" - -enum CompletionPrefixKind { - UNKNOWN = "Unknown", - CLASS_IMPORT = "Class Import", - CLASS_REFERENCE = "Class Reference", - STATIC_MEMBER_REFERENCE = "Static Member Reference", - NEW_INSTANCE = "New Instance", - MODULE_IMPORT = "Module Import" -} +import { CompletionPrefixKind } from "../../constants" +import { vmw } from "../../proto" interface CompletionPrefix { readonly value: string @@ -172,7 +165,7 @@ export class CompletionProvider { .concat(this.hints.getFunctionSets()) .filter(cls => !!cls.name && cls.name.startsWith(prefix.filter || "")) .map(cls => { - const name = cls.name || "" + const name = cls.name ?? "" const completionItem = CompletionItem.create(name) completionItem.kind = CompletionItemKind.Class completionItem.documentation = cls.description ? cls.description.trim() : undefined @@ -196,44 +189,63 @@ export class CompletionProvider { if (!cls) return [] const suggestions: CompletionItem[] = [] + const methods: CompletionItem[] = this.getMethodsSuggestions(cls, prefix) + const properties: CompletionItem[] = this.getPropertiesSuggestions(cls, prefix) - if (cls.methods && cls.methods.length > 0) { - cls.methods - .filter(method => !!method.name && method.name.startsWith(prefix.filter || "")) - .forEach(method => { - const name = method.name || "" - const completionItem = CompletionItem.create(name) - completionItem.kind = CompletionItemKind.Method - completionItem.documentation = Previewer.extendDescriptionWithParams( - method.description, - method.parameters - ) - completionItem.detail = Previewer.computeDetailsForMethod(method) - completionItem.sortText = `000${name}` - suggestions.push(completionItem) - }) + methods.forEach(item => suggestions.push(item)) + properties.forEach(item => suggestions.push(item)) + + return suggestions + } + + private getMethodsSuggestions(cls: vmw.pscoe.hints.IClass, prefix: CompletionPrefix): CompletionItem[] { + if (!cls.methods?.length) { + return [] } - if (cls.properties && cls.properties.length > 0) { - cls.properties - .filter(prop => !!prop.name && prop.name.startsWith(prefix.filter || "")) - .forEach(prop => { - const name = prop.name || "" - const completionItem = CompletionItem.create(name) - completionItem.kind = CompletionItemKind.Variable + const suggestions: CompletionItem[] = [] + cls.methods + .filter((method: vmw.pscoe.hints.IMethod) => !!method.name && method.name.startsWith(prefix.filter || "")) + .forEach((method: vmw.pscoe.hints.IMethod) => { + const name = method.name ?? "" + const completionItem = CompletionItem.create(name) + completionItem.kind = CompletionItemKind.Method + completionItem.documentation = Previewer.extendDescriptionWithParams( + method.description, + method.parameters + ) + completionItem.detail = Previewer.computeDetailsForMethod(method) + completionItem.sortText = `000${name}` + suggestions.push(completionItem) + }) - if (prop.readOnly) { - completionItem.kind = - name.toUpperCase() === name ? CompletionItemKind.Enum : CompletionItemKind.Value - } + return suggestions + } - completionItem.documentation = prop.description ? prop.description.trim() : undefined - completionItem.detail = Previewer.computeDetailsForProperty(prop) - completionItem.sortText = `000${name}` - suggestions.push(completionItem) - }) + private getPropertiesSuggestions(cls: vmw.pscoe.hints.IClass, prefix: CompletionPrefix): CompletionItem[] { + if (!cls.properties?.length) { + return [] } + const suggestions: CompletionItem[] = [] + cls.properties + .filter((prop: vmw.pscoe.hints.IProperty) => !!prop.name && prop.name.startsWith(prefix.filter || "")) + .forEach((prop: vmw.pscoe.hints.IProperty) => { + const name = prop.name ?? "" + const completionItem = CompletionItem.create(name) + completionItem.kind = CompletionItemKind.Variable + + if (prop.readOnly) { + completionItem.kind = + name.toUpperCase() === name ? CompletionItemKind.Enum : CompletionItemKind.Value + } + + completionItem.documentation = prop.description ? prop.description.trim() : undefined + completionItem.detail = Previewer.computeDetailsForProperty(prop) + completionItem.sortText = `000${name}` + suggestions.push(completionItem) + }) + return suggestions } @@ -246,7 +258,7 @@ export class CompletionProvider { .forEach(cls => { if (cls.constructors && cls.constructors.length > 0) { for (const constr of cls.constructors) { - const name = cls.name || "" + const name = cls.name ?? "" const completionItem = CompletionItem.create(name) completionItem.kind = CompletionItemKind.Constructor @@ -274,9 +286,9 @@ export class CompletionProvider { .getActionsIn(prefix.value, workspaceFolder) .filter(a => !!a.name && a.name.startsWith(prefix.filter || "")) .map(action => { - const name = action.name || "" + const name = action.name ?? "" const completionItem = CompletionItem.create(name) - const isClass = name[0] === name[0].toUpperCase() + const isClass = name[0].startsWith(name[0].toUpperCase()) completionItem.kind = isClass ? CompletionItemKind.Class : CompletionItemKind.Function completionItem.documentation = Previewer.extendDescriptionWithParams( action.description, diff --git a/packages/node/vro-language-server/src/server/request/collection/ServerCollection.ts b/packages/node/vro-language-server/src/server/request/collection/ServerCollection.ts index 31682c5b..84a25c41 100644 --- a/packages/node/vro-language-server/src/server/request/collection/ServerCollection.ts +++ b/packages/node/vro-language-server/src/server/request/collection/ServerCollection.ts @@ -162,7 +162,7 @@ export class ServerCollection { this.logger.error("No vRO objects found") } else { for (const plugin of plugins) { - const link = plugin.detailsLink.match(regex) + const link = RegExp(regex).exec(plugin.detailsLink) if (!link) { throw new Error(`No plugin details found`) }