blob: 48006b5a2e6e971b7cad20ea203de5a1c8a87bb5 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
'use strict';
import { commands, CompletionItem, CompletionList, ExtensionContext, languages, ProviderResult, SnippetString } from 'vscode';
import { InsertTextFormat } from 'vscode-languageclient';
import * as jsoncp from 'jsonc-parser';
export function registerCompletion(context: ExtensionContext) {
context.subscriptions.push(languages.registerCompletionItemProvider({ language: 'jsonc', pattern: '**/launch.json' }, {
provideCompletionItems(document, position, cancelToken) {
const sourceText = document.getText();
const root = jsoncp.parseTree(sourceText);
if (root) {
const offset = document.offsetAt(position);
const currentNode = jsoncp.findNodeAtOffset(root, offset);
if (currentNode) {
const path = jsoncp.getNodePath(currentNode);
if (path.length >= 1 && 'configurations' == path[0]) {
const uri = document.uri.toString();
let completionItems: ProviderResult<CompletionList<CompletionItem>> | CompletionItem[];
if (path.length == 1) {
// Get all configurations:
completionItems = commands.executeCommand('java.project.configuration.completion', uri);
} else {
let node: jsoncp.Node = currentNode;
if (currentNode.type == 'property' && currentNode.parent) {
let propName = currentNode.children?.[0]?.value;
if (!propName) { // Invalid node?
return new CompletionList();
}
node = currentNode.parent;
let attributesMap = getAttributes(node);
// Get possible values of property 'propName':
completionItems = commands.executeCommand('java.project.configuration.completion', uri, attributesMap, propName);
} else {
let attributesMap = getAttributes(node);
// Get additional possible attributes:
completionItems = commands.executeCommand('java.project.configuration.completion', uri, attributesMap);
}
}
return (completionItems as Thenable<CompletionList<CompletionItem>>).then(itemsList => {
let items = itemsList.items;
if (!items) {
items = ((itemsList as unknown) as CompletionItem[]);
}
addCommas(sourceText, offset, items);
return new CompletionList(items);
});
}
}
}
}
}));
}
function getAttributesMap(node: jsoncp.Node) {
let attributes = new Map<string, object>();
if (node.children) {
for (let index in node.children) {
let ch = node.children[index];
let prop = ch.children;
if (prop) {
attributes.set(prop[0].value, prop[1].value);
}
}
}
return attributes;
}
function getAttributes(node: jsoncp.Node) {
let attributes: any = {};
if (node.children) {
for (let index in node.children) {
let ch = node.children[index];
let prop = ch.children;
if (prop) {
attributes[prop[0].value] = prop[1].value;
}
}
}
return attributes;
}
function addCommas(sourceText: string, offset: number, completionItems: CompletionItem[]) {
if (!completionItems) {
return ;
}
let prepend = false;
let o = offset - 1;
while (o >= 0) {
let c = sourceText.charAt(o);
if (!/\s/.test(c)) {
prepend = c != '[' && c != '{' && c != ',' && c != ':';
break;
}
o--;
}
let append = false;
o = offset + 1;
while (o < sourceText.length) {
let c = sourceText.charAt(o);
if (!/\s/.test(c)) {
append = c != ']' && c != '}' && c != ',';
break;
}
o++;
}
for (let index in completionItems) {
let ci = completionItems[index];
if (ci.insertText) {
if ((<any> ci).insertTextFormat === InsertTextFormat.Snippet) {
let snippet = new SnippetString(<string> ci.insertText);
ci.insertText = snippet;
if (prepend) {
snippet.value = ',' + snippet.value;
}
if (append) {
snippet.value = snippet.value + ',';
}
} else {
if (prepend) {
ci.insertText = ',' + ci.insertText;
}
if (append) {
ci.insertText = ci.insertText + ',';
}
}
}
}
}