Skip to content

Commit

Permalink
Merge pull request #157 from Stuart-Wilcox/main
Browse files Browse the repository at this point in the history
Feat: Add "Definition" Support for for template Entries
  • Loading branch information
winstliu authored Jan 2, 2024
2 parents e11a31a + 527f7e5 commit 237abd3
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 4 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
* Hovering over a node shows description *if available*
5. Document outlining:
* Shows a complete document outline of all nodes in the document
6. Go to definition for Templates
* Referenced templates can be resolved to a local file (if it exists)

## Developer Support

Expand Down
16 changes: 14 additions & 2 deletions language-server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import {
createConnection, Connection,
TextDocuments, InitializeParams, InitializeResult, NotificationType, RequestType,
DocumentFormattingRequest, Disposable, ProposedFeatures, CompletionList, TextDocumentSyncKind, ClientCapabilities
DocumentFormattingRequest, Disposable, ProposedFeatures, CompletionList, TextDocumentSyncKind, ClientCapabilities, DefinitionParams,
} from "vscode-languageserver/node";
import { TextDocument } from 'vscode-languageserver-textdocument';

Expand Down Expand Up @@ -87,7 +87,7 @@ let workspaceRoot: URI;
connection.onInitialize((params: InitializeParams): InitializeResult => {
capabilities = params.capabilities;
workspaceFolders = params["workspaceFolders"];
workspaceRoot = URI.parse(params.rootPath);
workspaceRoot = URI.parse(params.rootUri, true);

function hasClientCapability(...keys: string[]) {
let c = params.capabilities;
Expand All @@ -104,6 +104,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
textDocumentSync: TextDocumentSyncKind.Full,
completionProvider: { resolveProvider: true },
hoverProvider: true,
definitionProvider: true,
documentSymbolProvider: true,
documentFormattingProvider: false
}
Expand Down Expand Up @@ -495,4 +496,15 @@ connection.onDocumentFormatting(formatParams => {
return customLanguageService.doFormat(document, formatParams.options, customTags);
});

connection.onDefinition((definitionParams: DefinitionParams) => {
let document = documents.get(definitionParams.textDocument.uri);

if(!document){
return;
}

let jsonDocument = parseYAML(document.getText());
return customLanguageService.doDefinition(document, definitionParams.position, jsonDocument, workspaceRoot);
})

connection.listen();
81 changes: 81 additions & 0 deletions language-service/src/services/yamlDefinition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';

import * as path from "path";
import { PromiseConstructor, Thenable } from "vscode-json-languageservice";
import { TextDocument, Position, Definition, Location, Range } from "vscode-languageserver-types";
import { URI, Utils } from "vscode-uri";

import { StringASTNode } from "../parser/jsonParser";
import { YAMLDocument } from "../parser/yamlParser";

export class YAMLDefinition {

private promise: PromiseConstructor;

constructor(promiseConstructor: PromiseConstructor) {
this.promise = promiseConstructor || Promise;
}

public doDefinition(document: TextDocument, position: Position, yamlDocument: YAMLDocument, workspaceRoot: URI): Thenable<Definition> {
const offset = document.offsetAt(position);

const jsonDocument = yamlDocument.documents.length > 0 ? yamlDocument.documents[0] : null;
if(jsonDocument === null){
return this.promise.resolve(void 0);
}

const node = jsonDocument.getNodeFromOffset(offset);

// can only jump to definition for template declaration, which means:
// * we must be on a string node that is acting as a value (vs a key)
// * the key (location) must be "template"
//
// In other words...
// - template: my_cool_template.yml
// ^^^^^^^^^^^^^^^^^^^^ this part
if (!(node instanceof StringASTNode) || node.location !== 'template' || node.isKey) {
return this.promise.resolve(void 0);
}

let [location, resource] = node
.value
.split('@');

// cannot jump to external resources
if (resource && resource !== 'self') {
return this.promise.resolve(void 0);
}

// Azure Pipelines accepts both forward and back slashes as path separators,
// even when running on non-Windows.
// To make things easier, normalize all path separators into this platform's path separator.
// That way, vscode-uri will operate on the separators as expected.
location = location
.replaceAll(path.posix.sep, path.sep)
.replaceAll(path.win32.sep, path.sep);

// determine if abs path (from root) or relative path
// NOTE: Location.create takes in a string, even though the parameter is called 'uri'.
// So create an actual URI, then .toString() it and skip the unnecessary encoding.
let definitionUri = '';
if (location.startsWith(path.sep)) {
// Substring to strip the leading separator.
definitionUri = Utils.joinPath(workspaceRoot, location.substring(1)).toString(true);
}
else {
definitionUri = Utils.resolvePath(
Utils.dirname(URI.parse(document.uri, true)),
location
).toString(true);
}

const definition = Location.create(definitionUri, Range.create(0, 0, 0, 0));

return this.promise.resolve(definition);
}
}
7 changes: 6 additions & 1 deletion language-service/src/yamlLanguageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
*--------------------------------------------------------------------------------------------*/
import { JSONSchemaService, CustomSchemaProvider } from './services/jsonSchemaService'
import { TextDocument, Position, CompletionList, FormattingOptions, Diagnostic,
CompletionItem, TextEdit, Hover, SymbolInformation
CompletionItem, TextEdit, Hover, SymbolInformation, Definition
} from 'vscode-languageserver-types';
import { URI } from "vscode-uri";
import { JSONSchema } from './jsonSchema';
import { YAMLDocumentSymbols } from './services/documentSymbols';
import { YAMLCompletion } from "./services/yamlCompletion";
import { YAMLHover } from "./services/yamlHover";
import { YAMLDefinition } from "./services/yamlDefinition";
import { YAMLValidation } from "./services/yamlValidation";
import { format } from './services/yamlFormatter';
import { JSONWorkerContribution } from './jsonContributions';
Expand Down Expand Up @@ -99,6 +101,7 @@ export interface LanguageService {
doComplete(document: TextDocument, position: Position, yamlDocument: YAMLDocument): Thenable<CompletionList>;
doValidation(document: TextDocument, yamlDocument: YAMLDocument): Thenable<Diagnostic[]>;
doHover(document: TextDocument, position: Position, doc: YAMLDocument): Thenable<Hover>;
doDefinition(document: TextDocument, position: Position, doc: YAMLDocument, workspaceRoot: URI): Thenable<Definition>;
findDocumentSymbols(document: TextDocument, doc: YAMLDocument): SymbolInformation[];
doResolve(completionItem: CompletionItem): Thenable<CompletionItem>;
resetSchema(uri: string): boolean;
Expand All @@ -120,6 +123,7 @@ export function getLanguageService(

let completer = new YAMLCompletion(schemaService, contributions, promise);
let hover = new YAMLHover(schemaService, contributions, promise);
let definition = new YAMLDefinition(promise);
let yamlDocumentSymbols = new YAMLDocumentSymbols();
let yamlValidation = new YAMLValidation(schemaService, promise);
let yamlTraversal = new YAMLTraversal(promise);
Expand All @@ -140,6 +144,7 @@ export function getLanguageService(
doResolve: completer.doResolve.bind(completer),
doValidation: yamlValidation.doValidation.bind(yamlValidation),
doHover: hover.doHover.bind(hover),
doDefinition: definition.doDefinition.bind(definition),
findDocumentSymbols: yamlDocumentSymbols.findDocumentSymbols.bind(yamlDocumentSymbols),
resetSchema: (uri: string) => schemaService.onResourceChange(uri),
doFormat: format,
Expand Down
5 changes: 4 additions & 1 deletion language-service/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
"moduleResolution": "node",
"sourceMap": true,
"declaration": true,
"lib" : [ "es2015", "dom" ],
"lib": [
"es2021",
"dom"
],
"outDir": "./lib",
"noUnusedLocals": true
},
Expand Down

0 comments on commit 237abd3

Please sign in to comment.