diff --git a/package.json b/package.json index 2a1e4336..2fb0e135 100755 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "js-yaml": "^3.13.1", "jsonc-parser": "^2.2.1", "request-light": "^0.2.4", - "vscode-json-languageservice": "^3.5.2", + "vscode-json-languageservice": "^3.6.0", "vscode-languageserver": "^5.2.1", "vscode-languageserver-types": "^3.15.1", "vscode-nls": "^4.1.2", diff --git a/src/languageservice/services/yamlDefinition.ts b/src/languageservice/services/yamlDefinition.ts new file mode 100644 index 00000000..32e089bd --- /dev/null +++ b/src/languageservice/services/yamlDefinition.ts @@ -0,0 +1,18 @@ +import { JSONSchemaRef, JSONSchema } from '../jsonSchema'; +import { TextDocument, Position, DefinitionLink } from 'vscode-languageserver-types'; +import { parse as parseYAML } from '../parser/yamlParser07'; +import { matchOffsetToDocument } from '../utils/arrUtils'; +import { findDefinition as JSONFindDefinition } from 'vscode-json-languageservice/lib/umd/services/jsonDefinition'; + +export function findDefinition(document: TextDocument, position: Position): Thenable { + const doc = parseYAML(document.getText()); + const offset = document.offsetAt(position); + const currentDoc = matchOffsetToDocument(offset, doc); + if (currentDoc === null) { + return Promise.resolve([]); + } + + const currentDocIndex = doc.documents.indexOf(currentDoc); + currentDoc.currentDocIndex = currentDocIndex; + return JSONFindDefinition(document, position, currentDoc); +} diff --git a/src/languageservice/yamlLanguageService.ts b/src/languageservice/yamlLanguageService.ts index 64dbd008..3296c396 100644 --- a/src/languageservice/yamlLanguageService.ts +++ b/src/languageservice/yamlLanguageService.ts @@ -5,7 +5,7 @@ *--------------------------------------------------------------------------------------------*/ import { YAMLSchemaService, CustomSchemaProvider, SchemaAdditions, SchemaDeletions } from './services/yamlSchemaService'; -import { TextDocument, Position, CompletionList, Diagnostic, Hover, SymbolInformation, DocumentSymbol, CompletionItem, TextEdit } from 'vscode-languageserver-types'; +import { TextDocument, Position, CompletionList, Diagnostic, Hover, SymbolInformation, DocumentSymbol, CompletionItem, TextEdit, DefinitionLink } from 'vscode-languageserver-types'; import { JSONSchema } from './jsonSchema'; import { YAMLDocumentSymbols } from './services/documentSymbols'; import { YAMLCompletion } from './services/yamlCompletion'; @@ -13,6 +13,7 @@ import { YAMLHover } from './services/yamlHover'; import { YAMLValidation } from './services/yamlValidation'; import { YAMLFormatter } from './services/yamlFormatter'; import { getLanguageService as getJSONLanguageService, JSONWorkerContribution } from 'vscode-json-languageservice'; +import { findDefinition } from './services/yamlDefinition'; export interface LanguageSettings { validate?: boolean; //Setting for whether we want to validate the schema @@ -116,6 +117,7 @@ export interface LanguageService { findDocumentSymbols(document: TextDocument): SymbolInformation[]; findDocumentSymbols2(document: TextDocument): DocumentSymbol[]; doResolve(completionItem): Thenable; + findDefinition(document: TextDocument, position: Position): Thenable; resetSchema(uri: string): boolean; doFormat(document: TextDocument, options: CustomFormatterOptions): TextEdit[]; addSchema(schemaID: string, schema: JSONSchema): void; @@ -154,6 +156,7 @@ export function getLanguageService(schemaRequestService: SchemaRequestService, registerCustomSchemaProvider: (schemaProvider: CustomSchemaProvider) => { schemaService.registerCustomSchemaProvider(schemaProvider); }, + findDefinition, doComplete: completer.doComplete.bind(completer), doResolve: completer.doResolve.bind(completer), doValidation: yamlValidation.doValidation.bind(yamlValidation), diff --git a/src/server.ts b/src/server.ts index e4b0d0ea..2f5b7a41 100755 --- a/src/server.ts +++ b/src/server.ts @@ -104,6 +104,7 @@ let workspaceRoot: URI = null; let workspaceFolders: WorkspaceFolder[] = []; let clientDynamicRegisterSupport = false; let hierarchicalDocumentSymbolSupport = false; +let clientDefinitionLinkSupport = false; /**************************** * Reusable helper functions @@ -353,6 +354,11 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { capabilities.textDocument.rangeFormatting && capabilities.textDocument.rangeFormatting.dynamicRegistration ); + clientDefinitionLinkSupport = !!( + capabilities.textDocument && + capabilities.textDocument.definition && + capabilities.textDocument.definition.linkSupport + ); return { capabilities: { @@ -361,7 +367,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { hoverProvider: true, documentSymbolProvider: true, documentFormattingProvider: false, - documentRangeFormattingProvider: false + documentRangeFormattingProvider: false, + definitionProvider: true } }; }); @@ -564,6 +571,20 @@ connection.onDocumentFormatting(formatParams => { return customLanguageService.doFormat(document, customFormatterSettings); }); +connection.onDefinition(params => { + const document = documents.get(params.textDocument.uri); + if (!document) { + return Promise.resolve([]); + } + + const definitionLinksPromise = customLanguageService.findDefinition(document, params.position); + if (clientDefinitionLinkSupport) { + return definitionLinksPromise; + } else { + return definitionLinksPromise.then(definitionLinks => definitionLinks.map(definitionLink => ({uri: definitionLink.targetUri, range: definitionLink.targetRange}))); + } +}); + connection.onRequest(SchemaModificationNotification.type, (modifications: SchemaAdditions | SchemaDeletions) => { if (modifications.action === MODIFICATION_ACTIONS.add) { customLanguageService.modifySchemaContent(modifications); diff --git a/test/findDefintion.test.ts b/test/findDefintion.test.ts new file mode 100644 index 00000000..d3a938d7 --- /dev/null +++ b/test/findDefintion.test.ts @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Red Hat. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { getLanguageService } from '../src/languageservice/yamlLanguageService'; +import { schemaRequestService, setupTextDocument, workspaceContext } from './utils/testHelper'; +import assert = require('assert'); + +const languageService = getLanguageService(schemaRequestService, workspaceContext, [], null); + +suite('FindDefintion Tests', () => { + + describe('Jump to defintion', function () { + + function findDefinitions(content: string, position: number) { + const testTextDocument = setupTextDocument(content); + return languageService.findDefinition(testTextDocument, testTextDocument.positionAt(position)); + } + + it('Find source defintion', done => { + const content = "definitions:\n link:\n type: string\ntype: object\nproperties:\n uri:\n $ref: '#/definitions/link'\n"; + const definitions = findDefinitions(content, content.lastIndexOf('/li')); + definitions.then(function (results) { + assert.equal(results.length, 1); + assert.deepEqual(results[0].originSelectionRange, { + start: { + line: 6, + character: 10 + }, + end: { + line: 6, + character: 30 + } + }); + assert.deepEqual(results[0].targetRange, { + start: { + line: 2, + character: 4 + }, + end: { + line: 2, + character: 16 + } + }); + }).then(done, done); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 802bc32e..7a554b08 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1490,15 +1490,15 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vscode-json-languageservice@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.5.2.tgz#4b898140a8e581359c10660845a4cae15dcbb4f9" - integrity sha512-9cUvBq00O08lpWVVOx6tQ1yLxCHss79nsUdEAVYGomRyMbnPBmc0AkYPcXI9WK1EM6HBo0R9Zo3NjFhcICpy4A== +vscode-json-languageservice@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.6.0.tgz#133a1e2c3a3dffe38564a1ba948516805c3c1869" + integrity sha512-dXzFywypUZ9T0tjr4fREZiknXDz6vAGx1zsxbQY1+9DOpjMfbz0VLP873KmcbuvL4K3nseKTxc4TKHu8kLXRMw== dependencies: jsonc-parser "^2.2.1" vscode-languageserver-textdocument "^1.0.1" vscode-languageserver-types "^3.15.1" - vscode-nls "^4.1.1" + vscode-nls "^4.1.2" vscode-uri "^2.1.1" vscode-jsonrpc@^4.0.0: