blob: bb18fd0355d32026b7dd00d1a8baf2f4f23fa952 [file]
/*
* 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.
*/
import * as fs from 'fs'
import * as vscode from 'vscode'
import { XMLParser } from 'fast-xml-parser'
// Method to create simple completion item given provided value and position
export function getSimpleCompletionItem(
document: vscode.TextDocument,
position: vscode.Position,
value: string
): vscode.CompletionItem {
let item = new vscode.CompletionItem(
`${value}`,
vscode.CompletionItemKind.Value
)
const text = item.label.toString()
const before =
position.character > 0
? document.getText(new vscode.Range(position.translate(0, -1), position))
: ''
const after = document.getText(
new vscode.Range(position, position.translate(0, 1))
)
// Check if already wrapped in quotes
const alreadyWrapped = before === '"' && after === '"'
// If not wrapped in quotes add double quotes to before and after text
item.insertText = !alreadyWrapped ? `"${text}"` : text
item.range = new vscode.Range(position, position)
return item
}
/* Method to get previous lines based on i.
*
* The reason for going 4 lines back is because the schema object only has
* 3 sub properties. So, this mean the schema object should technically
* not be anymore than 3 or 4 lines back from where the path attribute is set.
*/
function getPrevLines(
document: vscode.TextDocument,
i: number
): vscode.TextLine[] {
let prevLines: vscode.TextLine[] = []
for (var j = 0; j < 4; j++) {
if (i > j) {
prevLines.push(document.lineAt(i - (j + 1)))
}
}
return prevLines
}
/* Method to get the schema path from the configuration file being edited.
*
* The reason for going 4 lines back is because the schema object only has
* 3 sub properties. So, this mean the schema object should technically
* not be anymore than 3 or 4 lines back from where the path attribute is set.
*/
export function getSchemaPathFromLaunchJSON(
document: vscode.TextDocument,
position: vscode.Position
): string {
let schemaPath = ''
for (var i = position.line - 4; i < position.line; i++) {
if (i <= 0) continue
let currLine = document.lineAt(i)
if (!currLine.text.includes('path')) continue
const prevLines = getPrevLines(document, i)
let isUnderSchema =
prevLines
.map((prevLines) => prevLines.text.includes('schema'))
.filter((b) => b == true).length > 0
if (isUnderSchema) {
const regex = /(["'])path\1\s*:\s*(["'])(.*?)\2/
const match = currLine.text.match(regex)
schemaPath = match ? JSON.parse(`{${match[0]}}`).path : ''
}
}
return schemaPath.includes('${workspaceFolder}') &&
vscode.workspace.workspaceFolders
? schemaPath.replace(
'${workspaceFolder}',
vscode.workspace.workspaceFolders[0].uri.fsPath
)
: schemaPath
}
// Method to get the possible items
export function getPossibleItems(
document: vscode.TextDocument,
position: vscode.Position,
findRootNamespace: boolean
): string[] {
const schemaPath = getSchemaPathFromLaunchJSON(document, position)
const parser = new XMLParser({
ignoreAttributes: false,
removeNSPrefix: true,
isArray: (name) => name == 'element',
})
const fileData = schemaPath === '' ? '' : fs.readFileSync(schemaPath)
if (fileData === '') return []
const obj = parser.parse(fileData)
if (obj && typeof obj === 'object') {
return findRootNamespace
? [obj['schema']['@_targetNamespace']]
: obj['schema']['element'].map((e) => e['@_name'])
}
return []
}
export function checkForItems(
document: vscode.TextDocument,
position: vscode.Position,
includeText: string
): vscode.CompletionItem[] {
if (
!document.fileName.includes('launch.json') ||
!document.lineAt(position).text.includes(`"${includeText}"`)
)
return []
const possibleItems: string[] = getPossibleItems(
document,
position,
includeText.includes('rootNamespace')
)
return possibleItems.map((prn) =>
getSimpleCompletionItem(document, position, prn)
)
}
export function getCompletionProviders(includeText: string) {
return [
vscode.languages.registerCompletionItemProvider(
{ language: 'jsonc' },
{
provideCompletionItems(
document: vscode.TextDocument,
position: vscode.Position
) {
return checkForItems(document, position, includeText)
},
},
'"' // trigger
),
vscode.languages.registerCompletionItemProvider(
{ language: 'json' },
{
provideCompletionItems(
document: vscode.TextDocument,
position: vscode.Position
) {
return checkForItems(document, position, includeText)
},
},
'"' // trigger
),
]
}