feat: some adjustment to auto completion

This commit is contained in:
Peng Xiao 2018-12-13 18:26:58 +08:00
parent 56dda31a03
commit a478bef722
7 changed files with 153 additions and 93 deletions

View file

@ -40,7 +40,7 @@ export abstract class ASTNodeImpl {
constructor(parent: ASTNode, offset: number, length?: number) {
this.offset = offset;
this.length = length;
this.length = length || 0;
this.parent = parent;
}
@ -290,6 +290,30 @@ export function contains(node: ASTNode, offset: number, includeRightBound = fals
return offset >= node.offset && offset < (node.offset + node.length) || includeRightBound && offset === (node.offset + node.length);
}
// export function contains(node: ASTNode, offset: number, includeRightBound = false): boolean {
// let flag = offset >= node.offset && offset <= (node.offset + node.length);
// if (!flag && includeRightBound) {
// if (node.parent && node.parent.children && )
// const nextSibling = node.parent
// }
// return flag;
// }
// export function findNodeAtOffset(node: ASTNode, offset: number, includeRightBound = false): ASTNode | undefined {
// if (contains(node, offset, includeRightBound)) {
// const children = node.children;
// if (Array.isArray(children)) {
// for (var i = 0; i < children.length && children[i].offset <= offset; i++) {
// const item = findNodeAtOffset(children[i], offset, includeRightBound);
// if (item) {
// return item;
// }
// }
// }
// return node;
// }
// }
export class JSONDocument {
constructor(public root: ASTNode, public readonly syntaxErrors: Diagnostic[] = [], public readonly comments: Range[] = []) {
@ -298,6 +322,7 @@ export class JSONDocument {
public getNodeFromOffset(offset: number, includeRightBound = false): ASTNode | undefined {
if (this.root) {
return <ASTNode>Json.findNodeAtOffset(this.root, offset, includeRightBound);
//return findNodeAtOffset(this.root, offset, includeRightBound);
}
return void 0;
}

View file

@ -9,13 +9,14 @@ import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
import * as Yaml from '../../yaml-ast-parser/index'
import { Schema, Type } from 'js-yaml';
import { getLineStartPositions } from '../utils/documentPositionCalculator'
import { parseYamlBoolean } from './scalar-type';
import { ObjectASTNodeImpl, StringASTNodeImpl, PropertyASTNodeImpl, NullASTNodeImpl, ArrayASTNodeImpl, BooleanASTNodeImpl, NumberASTNodeImpl } from './jsonParser';
import { ASTNode, PropertyASTNode, ErrorCode } from '../jsonLanguageTypes';
import { SingleYAMLDocument, YAMLDocument } from '../yamlLanguageTypes';
import { Schema } from '../../yaml-ast-parser/schema';
import { Type } from '../../yaml-ast-parser/type';
function recursivelyBuildAst(parent: ASTNode, node: Yaml.YAMLNode): ASTNode {
@ -47,7 +48,8 @@ function recursivelyBuildAst(parent: ASTNode, node: Yaml.YAMLNode): ASTNode {
const keyNode = new StringASTNodeImpl(result, key.startPosition, key.endPosition - key.startPosition);
keyNode.value = key.value;
const valueNode = (instance.value) ? recursivelyBuildAst(result, instance.value) : new NullASTNodeImpl(parent, instance.startPosition)
// TODO: calculate the correct NULL range.
const valueNode = (instance.value) ? recursivelyBuildAst(result, instance.value) : new NullASTNodeImpl(parent, instance.endPosition);
result.keyNode = keyNode;
result.valueNode = valueNode;

View file

@ -58,11 +58,13 @@ export class YAMLCompletion {
let currentDoc = matchOffsetToDocument(offset, doc);
if(currentDoc === null){
return Promise.resolve(result);
}
const currentDocIndex = doc.documents.indexOf(currentDoc);
let node = currentDoc.getNodeFromOffset(offset, true);
if (currentDoc === null) {
return Promise.resolve(result);
}
let node = currentDoc.getNodeFromOffsetEndInclusive(offset);
if (this.isInComment(document, node ? node.offset : 0, offset)) {
return Promise.resolve(result);
}
@ -131,12 +133,13 @@ export class YAMLCompletion {
}
}
// Support multiple doc per YAML
if (schema && schema.schema && schema.schema.schemaSequence && schema.schema.schemaSequence[currentDocIndex]) {
schema = new SchemaService.ResolvedSchema(schema.schema.schemaSequence[currentDocIndex]);
}
// proposals for properties
if (node && node.type === 'object') {
// don't suggest keys when the cursor is just before the opening curly brace
if (node.offset === offset) {
return result;
}
// don't suggest properties that are already present
let properties = node.properties;
properties.forEach(p => {
@ -362,7 +365,6 @@ export class YAMLCompletion {
}
}
private getValueCompletions(schema: SchemaService.ResolvedSchema, doc: Parser.JSONDocument, node: ASTNode, offset: number, document: TextDocument, collector: CompletionsCollector, types: { [type: string]: boolean }): void {
let offsetForSeparator = offset;
let parentKey: string = null;
@ -679,11 +681,11 @@ export class YAMLCompletion {
}
private getInsertTextForValue(value: any, separatorAfter: string): string {
var text = JSON.stringify(value, null, '\t');
const text = value;
if (text === '{}') {
return '{$1}' + separatorAfter;
return '{\n\t$1\n}' + separatorAfter;
} else if (text === '[]') {
return '[$1]' + separatorAfter;
return '[\n\t$1\n]' + separatorAfter;
}
return this.getInsertTextForPlainText(text + separatorAfter);
}
@ -767,7 +769,7 @@ export class YAMLCompletion {
if (!addValue) {
return propertyText;
}
let resultText = propertyText + ': ';
let resultText = propertyText + ':';
let value;
let nValueProposals = 0;
@ -804,23 +806,23 @@ export class YAMLCompletion {
}
switch (type) {
case 'boolean':
value = '$1';
value = ' $1';
break;
case 'string':
value = '"$1"';
value = ' $1';
break;
case 'object':
value = '{$1}';
value = '\n\t';
break;
case 'array':
value = '[$1]';
value = '\n\t- ';
break;
case 'number':
case 'integer':
value = '${1:0}';
value = ' ${1:0}';
break;
case 'null':
value = '${1:null}';
value = ' ${1:null}';
break;
default:
return propertyText;
@ -834,8 +836,8 @@ export class YAMLCompletion {
}
private getCurrentWord(document: TextDocument, offset: number) {
var i = offset - 1;
var text = document.getText();
let i = offset - 1;
const text = document.getText();
while (i >= 0 && ' \t\n\r\v":{[,]}'.indexOf(text.charAt(i)) === -1) {
i--;
}
@ -853,7 +855,7 @@ export class YAMLCompletion {
case Json.SyntaxKind.EOF:
return '';
default:
return ',';
return '';
}
}

View file

@ -2,36 +2,65 @@ import { JSONDocument } from './parser/jsonParser';
import { ASTNode } from './jsonLanguageTypes';
export class SingleYAMLDocument extends JSONDocument {
public lines;
public errors;
public warnings;
public lines;
public errors;
public warnings;
constructor(lines: number[]) {
super(null, []);
this.lines = lines;
this.errors = [];
this.warnings = [];
}
constructor(lines: number[]) {
super(null, []);
this.lines = lines;
this.errors = [];
this.warnings = [];
}
public getSchemas(schema, doc, node) {
let matchingSchemas = [];
doc.validate(schema, matchingSchemas, node.start);
return matchingSchemas;
}
public getSchemas(schema, doc, node) {
let matchingSchemas = [];
doc.validate(schema, matchingSchemas, node.start);
return matchingSchemas;
}
public getNodeFromOffset(offset: number, includeRightBound = false): ASTNode {
return super.getNodeFromOffset(offset, includeRightBound);
public getNodeFromOffset(offset: number): ASTNode {
return super.getNodeFromOffset(offset, true);
}
public getNodeFromOffsetEndInclusive(offset: number): ASTNode {
let collector: ASTNode[] = [];
let findNode = (node: ASTNode): ASTNode => {
if (offset >= node.offset && offset <= node.offset + node.length) {
let children = node.children;
for (let i = 0; i < children.length && children[i].offset <= offset; i++) {
let item = findNode(children[i]);
if (item) {
collector.push(item);
}
}
return node;
}
return null;
};
let foundNode = findNode(this.root);
let currMinDist = Number.MAX_VALUE;
let currMinNode = null;
for (let possibleNode in collector) {
let currNode = collector[possibleNode];
let minDist = (currNode.offset + currNode.length - offset) + (offset - currNode.offset);
if (minDist < currMinDist) {
currMinNode = currNode;
currMinDist = minDist;
}
}
return currMinNode || foundNode;
}
}
export class YAMLDocument {
public documents: SingleYAMLDocument[]
public errors;
public warnings;
public documents: SingleYAMLDocument[]
public errors;
public warnings;
constructor(documents: SingleYAMLDocument[]) {
this.documents = documents;
this.errors = [];
this.warnings = [];
}
constructor(documents: SingleYAMLDocument[]) {
this.documents = documents;
this.errors = [];
this.warnings = [];
}
}

View file

@ -75,18 +75,19 @@ export class Schema {
}
static DEFAULT = null;
static create = function createSchema() {
var schemas, types;
static create = function createSchema(...args: [Schema | Schema[], Type[]] | [Type[]]) {
let schemas: Schema | Schema[];
let types: Type[];
switch (arguments.length) {
switch (args.length) {
case 1:
schemas = Schema.DEFAULT;
types = arguments[0];
types = args[0];
break;
case 2:
schemas = arguments[0];
types = arguments[1];
schemas = args[0];
types = args[1];
break;
default:
@ -109,4 +110,4 @@ export class Schema {
explicit: types
});
}
}
}

View file

@ -26,15 +26,16 @@ export function setupMode(defaults: LanguageServiceDefaultsImpl): void {
let languageId = defaults.languageId;
// TODO:
// disposables.push(monaco.languages.registerCompletionItemProvider(languageId, new languageFeatures.CompletionAdapter(worker)));
disposables.push(monaco.languages.registerCompletionItemProvider(languageId, new languageFeatures.CompletionAdapter(worker)));
disposables.push(monaco.languages.registerHoverProvider(languageId, new languageFeatures.HoverAdapter(worker)));
disposables.push(monaco.languages.registerDocumentSymbolProvider(languageId, new languageFeatures.DocumentSymbolAdapter(worker)));
disposables.push(monaco.languages.registerColorProvider(languageId, new languageFeatures.DocumentColorAdapter(worker)));
disposables.push(monaco.languages.registerDocumentFormattingEditProvider(languageId, new languageFeatures.DocumentFormattingEditProvider(worker)));
disposables.push(monaco.languages.registerDocumentRangeFormattingEditProvider(languageId, new languageFeatures.DocumentRangeFormattingEditProvider(worker)));
disposables.push(new languageFeatures.DiagnosticsAdapter(languageId, worker, defaults));
disposables.push(monaco.languages.setLanguageConfiguration(languageId, richEditConfiguration));
disposables.push(monaco.languages.setLanguageConfiguration(languageId, richEditConfiguration));
// Color adapter should be necessary most of the time:
// disposables.push(monaco.languages.registerColorProvider(languageId, new languageFeatures.DocumentColorAdapter(worker)));
}

View file

@ -47,41 +47,42 @@
'vs/basic-languages/monaco.contribution',
'vs/language/yaml/monaco.contribution'
], function () {
const yaml = `apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
apps.deployment: nginx
template:
metadata:
labels:
apps.deployment: nginx
spec:
containers:
- name: nginx
image: nginx:alpine`;
var editor = monaco.editor.create(document.getElementById('container'), {
value: yaml,
language: 'yaml'
const yaml = `p1: `;
const modelUri = monaco.Uri.parse("a://b/foo.json");
const editor = monaco.editor.create(document.getElementById('container'), {
language: 'yaml',
showFoldingControls: 'always',
model: monaco.editor.createModel(yaml, "yaml", modelUri),
});
monaco.languages.yaml.yamlDefaults.setDiagnosticsOptions({
enableSchemaRequest: true,
validate: true,
schemas: [
{
uri: 'https://raw.githubusercontent.com/garethr/kubernetes-json-schema/master/master/deployment.json',
fileMatch: ['*'],
},
],
schemas: [{
uri: "http://myserver/foo-schema.json", // id of the first schema
fileMatch: [modelUri.toString()], // associate with our model
schema: {
type: "object",
properties: {
p1: {
enum: ["v1", "v2"]
},
p2: {
$ref: "http://myserver/bar-schema.json" // reference the second schema
}
}
}
}, {
uri: "http://myserver/bar-schema.json", // id of the first schema
schema: {
type: "object",
properties: {
q1: {
enum: ["x1", "x2"]
}
}
}
}]
});
require(["vs/editor/contrib/quickOpen/quickOpen"], async quickOpen => {
@ -117,7 +118,8 @@ spec:
const position = selection.getPosition();
const symbol = await _getSymbolForPosition(model, position);
if (symbol) {
console.log(`${symbol.name}: ${symbol.range}`);
if (symbol && symbol.range) {
const decoration = {
range: symbol.range,
options: {
@ -130,8 +132,6 @@ spec:
oldDecorations,
decoration ? [decoration] : [],
)
console.log(`${symbol.name}: ${symbol.range}`);
}
});