src/language/providers/closeElementSlash.ts (158 lines of code) (raw):
/*
* 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 vscode from 'vscode'
import { checkMissingCloseTag } from './closeUtils'
import {
insertSnippet,
checkBraceOpen,
isInXPath,
isNotTriggerChar,
getNsPrefix,
getItemPrefix,
getItemsOnLineCount,
cursorWithinBraces,
cursorWithinQuotes,
cursorAfterEquals,
} from './utils'
export function getCloseElementSlashProvider() {
return vscode.languages.registerCompletionItemProvider(
'dfdl',
{
async provideCompletionItems(
document: vscode.TextDocument,
position: vscode.Position
) {
let backpos = new vscode.Position(position.line, position.character - 1)
const nsPrefix = getNsPrefix(document, position)
const triggerText = document
.lineAt(position)
.text.substring(0, position.character)
let nearestTagNotClosed = checkMissingCloseTag(
document,
position,
nsPrefix
)
const itemsOnLine = getItemsOnLineCount(triggerText)
const triggerChar = '/'
if (
checkBraceOpen(document, position) ||
cursorWithinBraces(document, position) ||
cursorWithinQuotes(document, position) ||
cursorAfterEquals(document, position) ||
isInXPath(document, position) ||
isNotTriggerChar(document, position, triggerChar)
) {
return undefined
}
if (!(nearestTagNotClosed == 'none')) {
let range = new vscode.Range(backpos, position)
await vscode.window.activeTextEditor?.edit((editBuilder) => {
editBuilder.replace(range, '')
})
}
if (triggerText.endsWith('/')) {
checkItemsOnLine(
document,
position,
itemsOnLine,
nearestTagNotClosed,
backpos,
nsPrefix,
triggerText
)
}
//return undefined
},
},
'/'
// triggered whenever a '/' is typed
)
}
export function getTDMLCloseElementSlashProvider() {
return vscode.languages.registerCompletionItemProvider(
'tdml',
{
async provideCompletionItems(
document: vscode.TextDocument,
position: vscode.Position
) {
let backpos = position.with(position.line, position.character - 1)
const nsPrefix = getNsPrefix(document, position)
const triggerText = document
.lineAt(position)
.text.substring(0, position.character)
let nearestTagNotClosed = checkMissingCloseTag(
document,
position,
nsPrefix
)
const itemsOnLine = getItemsOnLineCount(triggerText)
if (
checkBraceOpen(document, position) ||
cursorWithinBraces(document, position) ||
cursorWithinQuotes(document, position) ||
cursorAfterEquals(document, position) ||
isInXPath(document, position)
) {
return undefined
}
if (triggerText.endsWith('/')) {
checkItemsOnLine(
document,
position,
itemsOnLine,
nearestTagNotClosed,
backpos,
nsPrefix,
triggerText
)
}
return undefined
},
},
'/'
// triggered whenever a '/' is typed
)
}
function checkItemsOnLine(
document: vscode.TextDocument,
position: vscode.Position,
itemsOnLine: number,
nearestTagNotClosed: string,
backpos: vscode.Position,
nsPrefix: string,
triggerText: string
) {
nsPrefix = getItemPrefix(nearestTagNotClosed, nsPrefix)
if (
!(nearestTagNotClosed == 'none') &&
(itemsOnLine == 1 || itemsOnLine == 0)
) {
if (
nearestTagNotClosed.includes('defineVariable') ||
nearestTagNotClosed.includes('setVariable')
) {
insertSnippet('/>\n', backpos)
} else {
insertSnippet('/>$0', backpos)
}
}
if (itemsOnLine > 1) {
if (
triggerText.endsWith('/') &&
triggerText.includes('<' + nsPrefix + nearestTagNotClosed)
) {
let tagPos = triggerText.lastIndexOf('<' + nsPrefix + nearestTagNotClosed)
let tagEndPos = triggerText.indexOf('>', tagPos)
if (
tagPos != -1 &&
!triggerText.substring(tagEndPos - 1, 2).includes('/>') &&
triggerText
.substring(backpos.character - 1, backpos.character)
.includes('>') &&
!triggerText
.substring(tagEndPos)
.includes('</' + nsPrefix + nearestTagNotClosed)
) {
insertSnippet('</' + nsPrefix + nearestTagNotClosed + '>$0', backpos)
} else {
insertSnippet('/>$0', backpos)
}
}
}
}