Skip to content

Commit

Permalink
Merge pull request vscode-kubernetes-tools#62 from andxu/andy_dev
Browse files Browse the repository at this point in the history
add yaml schema support
  • Loading branch information
andxu authored Mar 9, 2018
2 parents 4e3eaca + 17516a5 commit 9ecdcf5
Show file tree
Hide file tree
Showing 8 changed files with 16,201 additions and 3 deletions.
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -487,20 +487,25 @@
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "node ./node_modules/vscode/bin/test"
},
"extensionDependencies": [
"redhat.vscode-yaml"
],
"dependencies": {
"compare-versions": "^3.1.0",
"docker-file-parser": "^1.0.3",
"dockerfile-parse": "^0.2.0",
"js-yaml": "^3.8.2",
"k8s": "^0.4.12",
"lodash": ">3",
"node-yaml-parser": "^0.0.6",
"opn": "^5.2.0",
"pluralize": "^4.0.0",
"portfinder": "^1.0.13",
"shelljs": "^0.7.7",
"tmp": "^0.0.31",
"uuid": "^3.1.0",
"vscode-extension-telemetry": "^0.0.6",
"vscode-uri": "^1.0.1",
"yamljs": "0.2.10"
},
"devDependencies": {
Expand Down
15,695 changes: 15,695 additions & 0 deletions schema/swagger.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import { Reporter } from './telemetry';
import * as telemetry from './telemetry-helper';
import {dashboardKubernetes} from './components/kubectl/proxy';

import { registerYamlSchemaSupport } from './yaml-support/yaml-schema';

let explainActive = false;
let swaggerSpecPromise = null;

Expand Down Expand Up @@ -68,7 +70,7 @@ export const HELM_TPL_MODE: vscode.DocumentFilter = { language: "helm", scheme:

// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context) {
export async function activate(context) {
kubectl.checkPresent('activation');

const treeProvider = explorer.create(kubectl, host);
Expand Down Expand Up @@ -191,6 +193,8 @@ export function activate(context) {
subscriptions.forEach((element) => {
context.subscriptions.push(element);
}, this);

await registerYamlSchemaSupport();
}

// this method is called when your extension is deactivated
Expand Down
16 changes: 14 additions & 2 deletions src/helm.hoverProvider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as vscode from 'vscode';
import { FuncMap } from './helm.funcmap';
import { Resources } from './helm.resources';
import { isPositionInKey } from "./yaml-support/yaml-util";


// Provide hover support
export class HelmTemplateHoverProvider implements vscode.HoverProvider {
Expand All @@ -23,8 +25,6 @@ export class HelmTemplateHoverProvider implements vscode.HoverProvider {
return Promise.resolve(null);
}

// FIXME: right now, the line `foo: {{foo}}` may match both the action and the resource def

if (this.inActionVal(doc, pos, word)) {
let found = this.findVal(word);
if (found) {
Expand All @@ -40,6 +40,18 @@ export class HelmTemplateHoverProvider implements vscode.HoverProvider {
}

if (this.notInAction(doc, pos, word)) {
try {
// when the word is in value position, it should not pop up hovers, for example,
// the following yaml should not show pop up window for 'metadata'
// selector:
// app: metadata

if (!isPositionInKey(doc, pos)) {
return;
}
} catch (ex) {
// ignore since the editing yaml may not be able to parse
}
let found = this.findResourceDef(word);
if (found) {
return new vscode.Hover(found, wordRange);
Expand Down
13 changes: 13 additions & 0 deletions src/yaml-support/yaml-constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as path from 'path';

export const KUBERNETES_SCHEMA = 'kubernetes';

export const KUBERNETES_SCHEMA_PREFIX = KUBERNETES_SCHEMA + '://schema/';

export const VSCODE_YAML_EXTENSION_ID = 'redhat.vscode-yaml';

export const KUBERNETES_SCHEMA_FILE = path.join(__dirname, '../../../schema/swagger.json');

export const KUBERNETES_GROUP_VERSION_KIND = 'x-kubernetes-group-version-kind';

export const GROUP_VERSION_KIND_SEPARATOR = '@';
100 changes: 100 additions & 0 deletions src/yaml-support/yaml-locator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import * as vscode from 'vscode';

import { parse, findNodeAtPosition } from 'node-yaml-parser';

export interface YamlNode {
readonly kind: string;
readonly raw: string;
readonly startPosition: number;
readonly endPosition: number;
}

export interface YamlMappingItem extends YamlNode {
readonly key: YamlNode;
readonly value: YamlNode;
}

export interface YamlMap extends YamlNode {
readonly mappings: YamlMappingItem[];
}

export interface YamlDocument {
readonly nodes: YamlNode[];
readonly errors: string[];
}

export interface YamlCachedDocuments {
// the documents represents the yaml text
yamlDocs: YamlDocument[];

// lineLengths contains the converted line length of each lines, it is used for converting from
// vscode position to the inner position in yaml element model.
lineLengths: number[];

// the version of the document to avoid duplicate work on the same text
version: number;
}

export interface YamlMatchedElement {
// the found node at the given position(usually at the edit/hover place)
readonly matchedNode: YamlNode;

// the document which contains the node at given position
readonly matchedDocument: YamlDocument;
}

/**
* A yaml interpreter parse the yaml text and find the matched ast node from vscode location.
*/
export class YamlLocator {
// a mapping of URIs to cached documents
private _cache:{ [key:string]: YamlCachedDocuments; } = {};

/**
* Parse the yaml text and find the best node&document for the given position.
*
* @param {vscode.TextDocument} textDocument vscode text document
* @param {vscode.Position} pos vscode position
* @returns {YamlMatchedElement} the search results of yaml elements at the given position
*/
public getMatchedElement(textDocument: vscode.TextDocument, pos: vscode.Position): YamlMatchedElement {
const key: string = textDocument.uri.toString();
this.ensureCache(key, textDocument);
const cacheEntry = this._cache[key];
// findNodeAtPosition will find the matched node at given position
return findNodeAtPosition(cacheEntry.yamlDocs, cacheEntry.lineLengths, pos.line, pos.character);
}

/**
* Parse the yaml text and find the best node&document for the given position.
*
* @param {vscode.TextDocument} textDocument vscode text document
* @param {vscode.Position} pos vscode position
* @returns {YamlMatchedElement} the search results of yaml elements at the given position
*/
public getYamlDocuments(textDocument: vscode.TextDocument): YamlDocument[] {
const key: string = textDocument.uri.toString();
this.ensureCache(key, textDocument);
return this._cache[key].yamlDocs;
}

private ensureCache(key: string, textDocument: vscode.TextDocument): void {
if (!this._cache[key]) {
this._cache[key] = <YamlCachedDocuments> { version: -1 };
}

if (this._cache[key].version !== textDocument.version) {
// the document and line lengths from parse method is cached into YamlCachedDocuments to avoid duplicate
// parse against the same text.
const { documents, lineLengths } = parse(textDocument.getText());
this._cache[key].yamlDocs = documents;
this._cache[key].lineLengths = lineLengths;
this._cache[key].version = textDocument.version;
}
}
}

// a global instance of yaml locator
const yamlLocator = new YamlLocator();

export { yamlLocator };
Loading

0 comments on commit 9ecdcf5

Please sign in to comment.