| /* |
| * 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 + ','; |
| } |
| } |
| } |
| } |
| } |
| |