diff --git a/src/server/haLanguageService.ts b/src/server/haLanguageService.ts index 7bbe73c2e3..1ec39061f1 100644 --- a/src/server/haLanguageService.ts +++ b/src/server/haLanguageService.ts @@ -1,28 +1,26 @@ -import { TextDocuments, CompletionList, TextDocumentChangeEvent, DidChangeWatchedFilesParams, DidOpenTextDocumentParams, TextDocument, Position, CompletionItem, TextEdit, Definition, DefinitionLink, TextDocumentPositionParams, Location, IConnection, Diagnostic } from "vscode-languageserver"; +import { TextDocuments, CompletionList, TextDocumentChangeEvent, DidChangeWatchedFilesParams, DidOpenTextDocumentParams, TextDocument, Position, CompletionItem, TextEdit, Definition, DefinitionLink, TextDocumentPositionParams, Location, IConnection, Diagnostic, Hover } from "vscode-languageserver"; import { completionHelper } from "./completionHelpers/utils"; -import { parse as parseYAML } from "yaml-language-server/out/server/src/languageservice/parser/yamlParser04"; -import { YamlLanguageServiceWrapper } from "./yamlLanguageServiceWrapper"; +import { parse as parseYAML } from "yaml-language-server/out/server/src/languageservice/parser/yamlParser07"; +import { YamlLanguageService } from "./yamlLanguageService"; import { SchemaServiceForIncludes } from "./schemas/schemaService"; import { EntityIdCompletionContribution } from "./completionHelpers/entityIds"; import { getLineOffsets } from "yaml-language-server/out/server/src/languageservice/utils/arrUtils"; import { HaConnection } from "./home-assistant/haConnection"; import { ServicesCompletionContribution } from "./completionHelpers/services"; -import { Includetype } from "./haConfig/dto"; import { DefinitionProvider } from "./definition/definition"; import { HomeAssistantConfiguration } from "./haConfig/haConfig"; -export class HomeAssistantLanguageService { - private schemaServiceForIncludes: SchemaServiceForIncludes; + +export class HomeAssistantLanguageService { constructor( private documents: TextDocuments, - private yamlLanguageService: YamlLanguageServiceWrapper, + private yamlLanguageService: YamlLanguageService, private haConfig: HomeAssistantConfiguration, private haConnection: HaConnection, - private definitionProviders: DefinitionProvider[] - ) { - this.schemaServiceForIncludes = new SchemaServiceForIncludes(this.yamlLanguageService.jsonSchemaService); - } + private definitionProviders: DefinitionProvider[], + private schemaServiceForIncludes: SchemaServiceForIncludes + ) { } public findAndApplySchemas = async (connection: IConnection) => { @@ -94,15 +92,7 @@ export class HomeAssistantLanguageService { return; } - let yamlDocument = parseYAML(document.getText(), this.getValidYamlTags()); - if (!yamlDocument) { - return; - } - - var diagnosticResults = await this.yamlLanguageService.doValidation( - document, - yamlDocument - ); + var diagnosticResults = await this.yamlLanguageService.doValidation(document); if (!diagnosticResults) { return; @@ -123,9 +113,8 @@ export class HomeAssistantLanguageService { if (!document) { return; } - - let jsonDocument = parseYAML(document.getText()); - return this.yamlLanguageService.findDocumentSymbols(document, jsonDocument); + + return this.yamlLanguageService.findDocumentSymbols(document); } public onDocumentFormatting = (formatParams): TextEdit[] => { @@ -152,12 +141,7 @@ export class HomeAssistantLanguageService { return Promise.resolve(result); } - let completionFix = completionHelper(textDocument, textDocumentPosition.position); - - let newText = completionFix.newText; - let jsonDocument = parseYAML(newText); - - var completions: CompletionList = await this.yamlLanguageService.doComplete(textDocument, textDocumentPosition.position, jsonDocument); + var completions: CompletionList = await this.yamlLanguageService.doComplete(textDocument, textDocumentPosition.position); var additionalCompletions = await this.getServiceAndEntityCompletions(textDocument, textDocumentPosition.position, completions); if (additionalCompletions.length > 0) { @@ -166,20 +150,18 @@ export class HomeAssistantLanguageService { return completions; } - public onCompletionResolve = (completionItem) => { - return this.yamlLanguageService.doResolve(completionItem); + public onCompletionResolve = async (completionItem): Promise => { + return await this.yamlLanguageService.doResolve(completionItem); } - public onHover = (textDocumentPositionParams) => { + public onHover = async (textDocumentPositionParams): Promise => { let document = this.documents.get(textDocumentPositionParams.textDocument.uri); if (!document) { - return Promise.resolve(void 0); + return; } - let jsonDocument = parseYAML(document.getText()); - - return this.yamlLanguageService.doHover(document, textDocumentPositionParams.position, jsonDocument); + return await this.yamlLanguageService.doHover(document, textDocumentPositionParams.position); } public onDefinition = async (textDocumentPositionParams: TextDocumentPositionParams): Promise => { @@ -204,17 +186,6 @@ export class HomeAssistantLanguageService { return definitions; } - private getValidYamlTags(): string[] { - var validTags: string[] = []; - for (let item in Includetype) { - if (isNaN(Number(item))) { - validTags.push(`!${item} scalar`); - } - } - validTags.push("!secret scalar"); - return validTags; - } - private getServiceAndEntityCompletions = async (document: TextDocument, textDocumentPosition: Position, currentCompletions: CompletionList): Promise => { // sadly this is needed here. // the normal completion engine cannot provide completions for type `string | string[]` diff --git a/src/server/jsonLanguageService.ts b/src/server/jsonLanguageService.ts new file mode 100644 index 0000000000..5586e47319 --- /dev/null +++ b/src/server/jsonLanguageService.ts @@ -0,0 +1,78 @@ +import { JSONSchemaService } from "yaml-language-server/out/server/src/languageservice/services/jsonSchemaService"; +import { TextDocument, TextEdit, Diagnostic, ColorInformation, ColorPresentation, DocumentSymbol } from "vscode-languageserver-types"; +import { JSONValidation } from "vscode-json-languageservice/lib/umd/services/jsonValidation"; +import { JSONHover } from "vscode-json-languageservice/lib/umd/services/jsonHover"; +import { JSONDocumentSymbols } from "vscode-json-languageservice/lib/umd/services/jsonDocumentSymbols"; +import { JSONWorkerContribution, SymbolInformation, Hover, CompletionItem, CompletionList, LanguageService, JSONDocument, Color, Position, Range, FormattingOptions, FoldingRange, SelectionRange, ASTNode, DocumentLanguageSettings, JSONSchema } from "vscode-json-languageservice"; +import { LanguageSettings } from "yaml-language-server/out/server/src/languageservice/yamlLanguageService"; + +export class JsonLanguageService implements LanguageService { + + jsonValidation: JSONValidation; + jsonHover: JSONHover; + jsonDocumentSymbols: JSONDocumentSymbols; + + constructor(jsonSchemaService: JSONSchemaService, jsonWorkerContributions: JSONWorkerContribution[]) { + this.jsonValidation = new JSONValidation(jsonSchemaService, Promise); + this.jsonHover = new JSONHover(jsonSchemaService, jsonWorkerContributions, Promise); + this.jsonDocumentSymbols = new JSONDocumentSymbols(jsonSchemaService); + } + + public async doValidation(document: TextDocument, jsonDocument: JSONDocument, documentSettings?: DocumentLanguageSettings, schema?: JSONSchema): Promise { + return await this.jsonValidation.doValidation(document, jsonDocument, documentSettings, schema); + } + + public findDocumentSymbols(document: TextDocument, doc: JSONDocument): SymbolInformation[] { + return this.jsonDocumentSymbols.findDocumentSymbols(document, doc); + } + + public findDocumentSymbols2(document: TextDocument, doc: JSONDocument): DocumentSymbol[] { + return this.jsonDocumentSymbols.findDocumentSymbols2(document, doc); + } + + public async findColorSymbols(document: TextDocument, doc: JSONDocument): Promise { + return await this.jsonDocumentSymbols.findColorSymbols(document, doc); + } + + public async findDocumentColors(document: TextDocument, doc: JSONDocument): Promise { + return await this.jsonDocumentSymbols.findDocumentColors(document, doc); + } + + public getColorPresentations(document: TextDocument, doc: JSONDocument, color: Color, range: Range): ColorPresentation[] { + return this.jsonDocumentSymbols.getColorPresentations(document, doc, color, range); + } + + public async doHover(document: TextDocument, position: Position, doc: JSONDocument): Promise { + return await this.jsonHover.doHover(document, position, doc); + } + + // Methods below are not implemented since the YAML Language Service does not use them + + configure(settings: LanguageSettings): void { + throw new Error("Method not implemented."); + } + parseJSONDocument(document: TextDocument): JSONDocument { + throw new Error("Method not implemented."); + } + newJSONDocument(rootNode: ASTNode, syntaxDiagnostics?: Diagnostic[]): JSONDocument { + throw new Error("Method not implemented."); + } + resetSchema(uri: string): boolean { + throw new Error("Method not implemented."); + } + doResolve(item: CompletionItem): Thenable { + throw new Error("Method not implemented."); + } + doComplete(document: TextDocument, position: Position, doc: JSONDocument): Thenable { + throw new Error("Method not implemented."); + } + format(document: TextDocument, range: Range, options: FormattingOptions): TextEdit[] { + throw new Error("Method not implemented."); + } + getFoldingRanges(document: TextDocument, context?: { rangeLimit?: number; }): FoldingRange[] { + throw new Error("Method not implemented."); + } + getSelectionRanges(document: TextDocument, positions: Position[], doc: JSONDocument): SelectionRange[] { + throw new Error("Method not implemented."); + } +} diff --git a/src/server/schemas/schemaService.ts b/src/server/schemas/schemaService.ts index 61804cb0d0..682047251b 100644 --- a/src/server/schemas/schemaService.ts +++ b/src/server/schemas/schemaService.ts @@ -1,10 +1,12 @@ import * as path from "path"; import * as fs from "fs"; -import { IncludeReferences, HaFileInfo } from "../haConfig/dto"; +import { HaFileInfo } from "../haConfig/dto"; +import { JSONSchemaService, ISchemaContributions } from "yaml-language-server/out/server/src/languageservice/services/jsonSchemaService"; export class SchemaServiceForIncludes { - private schemaContributions: any; - constructor(private jsonSchemaService: any) { } + private schemaContributions: ISchemaContributions; + + constructor(private jsonSchemaService: JSONSchemaService) { } public onUpdate(haFiles: HaFileInfo[]) { this.schemaContributions = this.getSchemaContributions(haFiles); @@ -19,7 +21,7 @@ export class SchemaServiceForIncludes { return pathToSchemaMappings; } - private getSchemaContributions(haFiles: HaFileInfo[]) { + private getSchemaContributions(haFiles: HaFileInfo[]): ISchemaContributions { var schemas = {}; var schemaAssociations = {}; var pathToSchemaFileMappings = this.getPathToSchemaFileMappings(); diff --git a/src/server/server.ts b/src/server/server.ts index 3984fa0ce6..84a78cdd0e 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -2,14 +2,17 @@ import { createConnection, TextDocuments, ProposedFeatures, ServerCapabilities } import { VsCodeFileAccessor } from "./fileAccessor"; import { HomeAssistantLanguageService } from "./haLanguageService"; import { HaConnection } from "./home-assistant/haConnection"; -import { YamlLanguageServiceWrapper } from "./yamlLanguageServiceWrapper"; +import { JsonLanguageService } from "./jsonLanguageService"; import { EntityIdCompletionContribution } from "./completionHelpers/entityIds"; import { ConfigurationService } from "./configuration"; import { ServicesCompletionContribution } from "./completionHelpers/services"; -import { DefinitionProvider } from "./definition/definition"; import { IncludeDefinitionProvider } from "./definition/includes"; import { ScriptDefinitionProvider } from "./definition/scripts"; import { HomeAssistantConfiguration } from "./haConfig/haConfig"; +import { JSONSchemaService } from "yaml-language-server/out/server/src/languageservice/services/jsonSchemaService"; +import * as path from "path"; +import { YamlLanguageService } from "./yamlLanguageService"; +import { SchemaServiceForIncludes } from "./schemas/schemaService"; let connection = createConnection(ProposedFeatures.all); @@ -35,17 +38,33 @@ connection.onInitialize(async params => { new ScriptDefinitionProvider(haConfig) ]; - var yamlLanguageServiceWrapper = new YamlLanguageServiceWrapper([ + let jsonSchemaService = new JSONSchemaService(null, { + resolveRelativePath: (relativePath: string, resource: string) => { + return path.resolve(resource, relativePath); + } + }, Promise); + + var jsonWorkerContributions = [ new EntityIdCompletionContribution(haConnection), new ServicesCompletionContribution(haConnection) - ]); + ]; + + var jsonLanguageService = new JsonLanguageService(jsonSchemaService, jsonWorkerContributions); + + var yamlLanguageServiceWrapper = new YamlLanguageService( + jsonSchemaService, + jsonLanguageService, + jsonWorkerContributions); + + let schemaServiceForIncludes = new SchemaServiceForIncludes(jsonSchemaService); var homeAsisstantLanguageService = new HomeAssistantLanguageService( documents, yamlLanguageServiceWrapper, haConfig, haConnection, - definitionProviders + definitionProviders, + schemaServiceForIncludes ); documents.onDidChangeContent((e) => homeAsisstantLanguageService.onDocumentChange(e, connection)); diff --git a/src/server/yamlLanguageService.ts b/src/server/yamlLanguageService.ts new file mode 100644 index 0000000000..06ebf4a126 --- /dev/null +++ b/src/server/yamlLanguageService.ts @@ -0,0 +1,81 @@ +import { YAMLDocumentSymbols } from "yaml-language-server/out/server/src/languageservice/services/documentSymbols"; +import { JSONSchemaService } from "yaml-language-server/out/server/src/languageservice/services/jsonSchemaService"; +import { YAMLCompletion } from "yaml-language-server/out/server/src/languageservice/services/yamlCompletion"; +import { YAMLHover } from "yaml-language-server/out/server/src/languageservice/services/yamlHover"; +import { YAMLValidation } from "yaml-language-server/out/server/src/languageservice/services/yamlValidation"; +import { YAMLFormatter } from "yaml-language-server/out/server/src/languageservice/services/yamlFormatter"; +import { TextDocument, TextEdit, Diagnostic } from "vscode-languageserver-types"; +import { JSONWorkerContribution, SymbolInformation, Hover, CompletionItem, CompletionList } from "vscode-json-languageservice"; +import { Includetype } from "./haConfig/dto"; +import { LanguageSettings } from "yaml-language-server/out/server/src/languageservice/yamlLanguageService"; +import { JsonLanguageService } from "./jsonLanguageService"; + + +export class YamlLanguageService { + + private yamlValidation: YAMLValidation; + private yamlDocumentSymbols: YAMLDocumentSymbols; + private yamlCompletion: YAMLCompletion; + private yamlHover: YAMLHover; + private yamlFormatter: YAMLFormatter; + + constructor(jsonSchemaService: JSONSchemaService, jsonLanguageService: JsonLanguageService, completionContributions: JSONWorkerContribution[]) { + + var languageSettings = { + validate: true, + customTags: this.getValidYamlTags(), + completion: true, + format: true, + hover: true, + isKubernetes: false + }; + + this.yamlValidation = new YAMLValidation(Promise, jsonLanguageService); + this.yamlDocumentSymbols = new YAMLDocumentSymbols(jsonLanguageService); + this.yamlCompletion = new YAMLCompletion(jsonSchemaService, completionContributions); + this.yamlHover = new YAMLHover(Promise, jsonLanguageService); + this.yamlFormatter = new YAMLFormatter(); + + this.yamlValidation.configure(languageSettings); + // enables auto completion suggestions for tags like !include () + // commeted because they end up at the top of the list which does not look nice :-) + // this.yamlCompletion.configure(languageSettings, languageSettings.customTags); + this.yamlHover.configure(languageSettings); + this.yamlFormatter.configure(languageSettings); + } + + public async doValidation(document: TextDocument): Promise { + return await this.yamlValidation.doValidation(document); + } + + public findDocumentSymbols(document: TextDocument): SymbolInformation[] { + return this.yamlDocumentSymbols.findDocumentSymbols(document); + } + + public doComplete = async (textDocument: TextDocument, position: any): Promise => { + return await this.yamlCompletion.doComplete(textDocument, position, false); + } + + public doResolve(completionItem: any): Thenable { + return this.yamlCompletion.doResolve(completionItem); + } + + public doHover(document: TextDocument, position: any): Thenable { + return this.yamlHover.doHover(document, position); + } + + public format = (document: TextDocument, options: any): TextEdit[] => { + return this.yamlFormatter.format(document, options); + } + + private getValidYamlTags(): string[] { + var validTags: string[] = []; + for (let item in Includetype) { + if (isNaN(Number(item))) { + validTags.push(`!${item} scalar`); + } + } + validTags.push("!secret scalar"); + return validTags; + } +} \ No newline at end of file diff --git a/src/server/yamlLanguageServiceWrapper.ts b/src/server/yamlLanguageServiceWrapper.ts deleted file mode 100644 index 883f38efdc..0000000000 --- a/src/server/yamlLanguageServiceWrapper.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { SchemaServiceForIncludes } from "./schemas/schemaService"; -import { YAMLDocumentSymbols } from "yaml-language-server/out/server/src/languageservice/services/documentSymbols"; -import { JSONSchemaService } from "yaml-language-server/out/server/src/languageservice/services/jsonSchemaService"; -import { YAMLCompletion } from "yaml-language-server/out/server/src/languageservice/services/yamlCompletion"; -import { YAMLHover } from "yaml-language-server/out/server/src/languageservice/services/yamlHover"; -import { YAMLValidation } from "yaml-language-server/out/server/src/languageservice/services/yamlValidation"; -import { YAMLFormatter } from "yaml-language-server/out/server/src/languageservice/services/yamlFormatter"; -import * as path from "path"; -import { EntityIdCompletionContribution } from "./completionHelpers/entityIds"; -import { TextDocument, TextEdit, Diagnostic } from "vscode-languageserver-types"; -import { JSONWorkerContribution, getLanguageService } from "vscode-json-languageservice"; - -export class YamlLanguageServiceWrapper { - - private yamlValidation: any; - private yamlDocumentSymbols: any; - private yamlCompletion: any; - private yamlHover: any; - private yamlFormatter: any; - public jsonSchemaService: JSONSchemaService; - - constructor(completionContributions: JSONWorkerContribution[]) { - - var jsonLanguageService = getLanguageService(null); - - this.jsonSchemaService = new JSONSchemaService(null, { - resolveRelativePath: (relativePath: string, resource: string) => { - return path.resolve(resource, relativePath); - } - }, null); - - - this.yamlValidation = new YAMLValidation(Promise, jsonLanguageService); - this.yamlValidation.configure({ validate: true }); - this.yamlDocumentSymbols = new YAMLDocumentSymbols(jsonLanguageService); - this.yamlCompletion = new YAMLCompletion(this.jsonSchemaService, completionContributions); - // enables auto completion suggestions for tags like !include () - // commeted because they end up at the top of the list which does not look nice :-) - // this.yamlCompletion.configure(null, this.getValidYamlTags()); - this.yamlHover = new YAMLHover(Promise, jsonLanguageService); - this.yamlFormatter = new YAMLFormatter(); - } - - public doValidation(document: TextDocument, yamlDocument: any): Diagnostic[] { - return this.yamlValidation.doValidation(document, yamlDocument); - } - - public findDocumentSymbols(document: TextDocument, jsonDocument: any): any { - return this.yamlDocumentSymbols.findDocumentSymbols(document, jsonDocument); - } - - public doComplete = async (textDocument: TextDocument, position: any, jsonDocument: any): Promise => { - return await this.yamlCompletion.doComplete(textDocument, position, jsonDocument); - } - - public doResolve(completionItem: any): any { - return this.yamlCompletion.doResolve(completionItem); - } - - public doHover(document: TextDocument, position: any, jsonDocument: any): any { - return this.yamlHover.doHover(document, position, jsonDocument); - } - - public format = (document: TextDocument, options: any): TextEdit[] => { - return this.yamlFormatter.format(document, options); - } -} \ No newline at end of file