This is an automated email from the ASF dual-hosted git repository.
rthomas320 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil-vscode.git
The following commit(s) were added to refs/heads/main by this push:
new c262b6b Fixes problems with space and slash truncating attribute
values without default values when typng a space or slash in the quoted text
Fixes a problem where typing a slash almost anywhere inserts '/>' a self
closing tag Prevents hover popups for non-attribute items Fixes intellisense
suggesting incorrect attributes for elements that spread across multiple lines
c262b6b is described below
commit c262b6b71d0401fc71dd2ded5b0d48443555ea8e
Author: rthomas320 <[email protected]>
AuthorDate: Thu Sep 19 07:39:30 2024 -0400
Fixes problems with space and slash truncating attribute values
without default values when typng a space or slash in the quoted
text
Fixes a problem where typing a slash almost anywhere inserts '/>'
a self closing tag
Prevents hover popups for non-attribute items
Fixes intellisense suggesting incorrect attributes for elements
that spread across multiple lines
closes #1065
---
src/language/providers/attributeCompletion.ts | 20 ++++
src/language/providers/attributeValueCompletion.ts | 12 +-
src/language/providers/closeElement.ts | 19 +++-
src/language/providers/closeElementSlash.ts | 42 +++----
src/language/providers/closeUtils.ts | 1 +
src/language/providers/elementCompletion.ts | 125 ++++++++++++---------
.../providers/intellisense/attributeHoverItems.ts | 4 +
.../providers/intellisense/attributeItems.ts | 10 ++
.../providers/intellisense/attributeValueItems.ts | 1 +
.../providers/intellisense/elementItems.ts | 4 +-
src/language/providers/utils.ts | 86 ++++++++++----
src/tests/suite/language/items.test.ts | 2 +
12 files changed, 214 insertions(+), 112 deletions(-)
diff --git a/src/language/providers/attributeCompletion.ts
b/src/language/providers/attributeCompletion.ts
index 3d51644..8369327 100644
--- a/src/language/providers/attributeCompletion.ts
+++ b/src/language/providers/attributeCompletion.ts
@@ -326,6 +326,26 @@ function checkNearestOpenItem(
spacingChar,
afterChar
)
+ case 'include':
+ return getCompletionItems(
+ ['schemaLocation'],
+ '',
+ '',
+ nsPrefix,
+ '',
+ spacingChar,
+ afterChar
+ )
+ case 'import':
+ return getCompletionItems(
+ ['schemaLocation', 'namespace'],
+ '',
+ '',
+ nsPrefix,
+ '',
+ spacingChar,
+ afterChar
+ )
case 'assert':
return getCompletionItems(
['testKind', 'test', 'testPattern', 'message', 'failureType'],
diff --git a/src/language/providers/attributeValueCompletion.ts
b/src/language/providers/attributeValueCompletion.ts
index 741f5d5..c59c984 100644
--- a/src/language/providers/attributeValueCompletion.ts
+++ b/src/language/providers/attributeValueCompletion.ts
@@ -45,25 +45,19 @@ export function getAttributeValueCompletionProvider() {
position
)
- if (attributeName !== 'none') {
+ if (attributeName !== 'none' && !attributeName.includes('xmlns:')) {
let replaceValue = ''
if (startPos === endPos) {
replaceValue = ' '
}
- if (
- attributeName.includes(':') &&
- !attributeName.includes('xmlns:')
- ) {
+ if (attributeName.includes(':')) {
attributeName = attributeName.substring(
attributeName.indexOf(':') + 1
)
}
- if (
- noChoiceAttributes.includes(attributeName) ||
- attributeName.includes('xmlns:')
- ) {
+ if (noChoiceAttributes.includes(attributeName)) {
return undefined
}
diff --git a/src/language/providers/closeElement.ts
b/src/language/providers/closeElement.ts
index ffd1438..42d0b6f 100644
--- a/src/language/providers/closeElement.ts
+++ b/src/language/providers/closeElement.ts
@@ -27,6 +27,7 @@ import {
getXsdNsPrefix,
insertSnippet,
isInXPath,
+ isNotTriggerChar,
getItemsOnLineCount,
getItemPrefix,
} from './utils'
@@ -39,12 +40,14 @@ export function getCloseElementProvider() {
document: vscode.TextDocument,
position: vscode.Position
) {
+ let triggerChar = '>'
if (
checkBraceOpen(document, position) ||
cursorWithinBraces(document, position) ||
cursorWithinQuotes(document, position) ||
cursorAfterEquals(document, position) ||
- isInXPath(document, position)
+ isInXPath(document, position) ||
+ isNotTriggerChar(document, position, triggerChar)
) {
return undefined
}
@@ -184,7 +187,7 @@ export function getTDMLCloseElementProvider() {
backpos3
)
}
- return undefined
+ //return undefined
},
},
'>' // triggered whenever a '>' is typed
@@ -202,7 +205,11 @@ function checkItemsOnLine(
backpos: vscode.Position,
backpos3: vscode.Position
) {
- if (itemsOnLine == 0 && !triggerText.includes('</')) {
+ if (
+ itemsOnLine == 0 &&
+ !triggerText.includes('</') &&
+ !triggerText.includes('/>')
+ ) {
if (triggerText.trim() === '>') {
insertSnippet('</' + nsPrefix + nearestTagNotClosed + '>', backpos)
} else {
@@ -237,7 +244,11 @@ function checkItemsOnLine(
}
}
- if (itemsOnLine === 1 && !triggerText.includes('</')) {
+ if (
+ itemsOnLine === 1 &&
+ !triggerText.includes('</') &&
+ !triggerText.includes('/>')
+ ) {
checkNearestTagNotClosed(
document,
position,
diff --git a/src/language/providers/closeElementSlash.ts
b/src/language/providers/closeElementSlash.ts
index 7021c86..cc06f03 100644
--- a/src/language/providers/closeElementSlash.ts
+++ b/src/language/providers/closeElementSlash.ts
@@ -21,6 +21,7 @@ import {
insertSnippet,
checkBraceOpen,
isInXPath,
+ isNotTriggerChar,
getXsdNsPrefix,
getItemPrefix,
getItemsOnLineCount,
@@ -47,28 +48,28 @@ export function getCloseElementSlashProvider() {
position,
nsPrefix
)
- if (nearestTagNotClosed === 'none') {
- return undefined
- }
const itemsOnLine = getItemsOnLineCount(triggerText)
-
+ const triggerChar = '/'
if (
checkBraceOpen(document, position) ||
cursorWithinBraces(document, position) ||
cursorWithinQuotes(document, position) ||
cursorAfterEquals(document, position) ||
- isInXPath(document, position)
+ isInXPath(document, position) ||
+ isNotTriggerChar(document, position, triggerChar)
) {
return undefined
}
- if (triggerText.endsWith('/')) {
+ 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,
@@ -80,7 +81,7 @@ export function getCloseElementSlashProvider() {
)
}
- return undefined
+ //return undefined
},
},
'/'
@@ -119,12 +120,6 @@ export function getTDMLCloseElementSlashProvider() {
}
if (triggerText.endsWith('/')) {
- let range = new vscode.Range(backpos, position)
-
- await vscode.window.activeTextEditor?.edit((editBuilder) => {
- editBuilder.replace(range, '')
- })
-
checkItemsOnLine(
document,
position,
@@ -155,19 +150,22 @@ function checkItemsOnLine(
) {
nsPrefix = getItemPrefix(nearestTagNotClosed, nsPrefix)
- if (itemsOnLine == 1 || itemsOnLine == 0) {
- insertSnippet('/>$0', backpos)
+ if (
+ !(nearestTagNotClosed == 'none') &&
+ (itemsOnLine == 1 || itemsOnLine == 0)
+ ) {
+ // let range = new vscode.Range(backpos, position)
+ // await vscode.window.activeTextEditor?.edit((editBuilder) => {
+ // editBuilder.replace(range, '')
+ // })
if (
nearestTagNotClosed.includes('defineVariable') ||
nearestTagNotClosed.includes('setVariable')
) {
- let range = new vscode.Range(backpos, position)
- vscode.window.activeTextEditor?.edit((editBuilder) => {
- editBuilder.replace(range, '')
- })
-
insertSnippet('/>\n', backpos)
+ } else {
+ insertSnippet('/>$0', backpos)
}
}
@@ -178,6 +176,10 @@ function checkItemsOnLine(
) {
let tagPos = triggerText.lastIndexOf('<' + nsPrefix +
nearestTagNotClosed)
let tagEndPos = triggerText.indexOf('>', tagPos)
+ // let range = new vscode.Range(backpos, position)
+ // await vscode.window.activeTextEditor?.edit((editBuilder) => {
+ // editBuilder.replace(range, '')
+ // })
if (
tagPos != -1 &&
diff --git a/src/language/providers/closeUtils.ts
b/src/language/providers/closeUtils.ts
index 1b931cf..65f238b 100644
--- a/src/language/providers/closeUtils.ts
+++ b/src/language/providers/closeUtils.ts
@@ -336,6 +336,7 @@ export function getItemsForLineLT2(
testLine = lineBefore
while (!testText.includes('>')) {
testText = document.lineAt(++testLine).text
+ if (testText.indexOf('<') > -1) [openTagArray.push(testLine)]
}
}
diff --git a/src/language/providers/elementCompletion.ts
b/src/language/providers/elementCompletion.ts
index f4eed6f..63669eb 100644
--- a/src/language/providers/elementCompletion.ts
+++ b/src/language/providers/elementCompletion.ts
@@ -21,6 +21,7 @@ import {
checkBraceOpen,
getXsdNsPrefix,
isInXPath,
+ isTagEndTrigger,
nearestOpen,
createCompletionItem,
getCommonItems,
@@ -33,68 +34,74 @@ import {
import { elementCompletion } from './intellisense/elementItems'
export function getElementCompletionProvider(dfdlFormatString: string) {
- return vscode.languages.registerCompletionItemProvider('dfdl', {
- provideCompletionItems(
- document: vscode.TextDocument,
- position: vscode.Position,
- token: vscode.CancellationToken,
- context: vscode.CompletionContext
- ) {
- if (
- checkBraceOpen(document, position) ||
- cursorWithinBraces(document, position) ||
- cursorWithinQuotes(document, position) ||
- cursorAfterEquals(document, position) ||
- isInXPath(document, position)
+ return vscode.languages.registerCompletionItemProvider(
+ 'dfdl',
+ {
+ provideCompletionItems(
+ document: vscode.TextDocument,
+ position: vscode.Position,
+ token: vscode.CancellationToken,
+ context: vscode.CompletionContext
) {
- return undefined
- }
-
- let nsPrefix = getXsdNsPrefix(document, position)
- let [triggerLine, triggerPos] = [position.line, position.character]
- let triggerText = document.lineAt(triggerLine).text
- let itemsOnLine = getItemsOnLineCount(triggerText)
- let nearestOpenItem = nearestOpen(document, position)
- let lastCloseSymbol = triggerText.lastIndexOf('>')
- let firstOpenSymbol = triggerText.indexOf('<')
-
- let missingCloseTag = checkMissingCloseTag(document, position, nsPrefix)
-
- if (nearestOpenItem.includes('none')) {
- if (missingCloseTag !== 'none') {
- return undefined
- }
if (
- missingCloseTag === 'none' &&
- itemsOnLine > 1 &&
- (triggerPos === lastCloseSymbol + 1 || triggerPos ===
firstOpenSymbol)
+ !checkBraceOpen(document, position) &&
+ !cursorWithinBraces(document, position) &&
+ !cursorWithinQuotes(document, position) &&
+ !cursorAfterEquals(document, position) &&
+ !isInXPath(document, position) &&
+ !isTagEndTrigger(document, position)
) {
- return undefined
- }
-
- let definedVariables = getDefinedVariables(document)
+ let nsPrefix = getXsdNsPrefix(document, position)
+ let [triggerLine, triggerPos] = [position.line, position.character]
+ let triggerText = document.lineAt(triggerLine).text
+ let itemsOnLine = getItemsOnLineCount(triggerText)
+ let nearestOpenItem = nearestOpen(document, position)
+ let lastCloseSymbol = triggerText.lastIndexOf('>')
+ let firstOpenSymbol = triggerText.indexOf('<')
+
+ let missingCloseTag = checkMissingCloseTag(
+ document,
+ position,
+ nsPrefix
+ )
- let [tagNearestTrigger, tagPosition] = getTagNearestTrigger(
- document,
- position,
- triggerText,
- triggerLine,
- triggerPos,
- itemsOnLine,
- nsPrefix
- )
+ if (!nearestOpenItem.includes('none') && missingCloseTag == 'none') {
+ return undefined
+ }
+ if (
+ missingCloseTag === 'none' &&
+ itemsOnLine > 1 &&
+ (triggerPos === lastCloseSymbol + 1 ||
+ triggerPos === firstOpenSymbol)
+ ) {
+ return undefined
+ }
+
+ let definedVariables = getDefinedVariables(document)
+
+ let [tagNearestTrigger, tagPosition] = getTagNearestTrigger(
+ document,
+ position,
+ triggerText,
+ triggerLine,
+ triggerPos,
+ itemsOnLine,
+ nsPrefix
+ )
- return nearestOpenTagChildElements(
- document,
- position,
- tagNearestTrigger,
- tagPosition,
- definedVariables,
- nsPrefix
- )
- }
+ return nearestOpenTagChildElements(
+ document,
+ position,
+ tagNearestTrigger,
+ tagPosition,
+ definedVariables,
+ nsPrefix
+ )
+ }
+ },
},
- })
+ '\n'
+ )
}
export function getTDMLElementCompletionProvider(tdmlFormatString: string) {
@@ -386,6 +393,10 @@ function nearestOpenTagChildElements(
return getElementCompletionItems(['dfdl:escapeScheme'], '', '', nsPrefix)
case 'format':
return getElementCompletionItems(['dfdl:property'], '', '', nsPrefix)
+ case 'include':
+ return getElementCompletionItems([''], '', '', nsPrefix)
+ case 'import':
+ return getElementCompletionItems([''], '', '', nsPrefix)
case 'schema':
return getElementCompletionItems(
[
@@ -396,6 +407,8 @@ function nearestOpenTagChildElements(
'complexType',
'simpleType',
'annotation',
+ 'include',
+ 'import',
],
'',
'',
diff --git a/src/language/providers/intellisense/attributeHoverItems.ts
b/src/language/providers/intellisense/attributeHoverItems.ts
index 4395c67..baf4dfd 100644
--- a/src/language/providers/intellisense/attributeHoverItems.ts
+++ b/src/language/providers/intellisense/attributeHoverItems.ts
@@ -225,6 +225,10 @@ export function attributeHoverValues(attributeName:
string): string {
return 'Defines text for use in an error message'
case 'failureType':
return 'Specifies the type of failure that occurs when the dfdl:assert
is unsuccessful'
+ case 'schemaLocation':
+ return 'Specifies the location of the schema'
+ case 'namespace':
+ return 'User defined identifier for the namespace defined by
schemaLocation value'
default:
return 'No definition available'
}
diff --git a/src/language/providers/intellisense/attributeItems.ts
b/src/language/providers/intellisense/attributeItems.ts
index b999a41..be54936 100644
--- a/src/language/providers/intellisense/attributeItems.ts
+++ b/src/language/providers/intellisense/attributeItems.ts
@@ -545,6 +545,16 @@ export const attributeCompletion = (
snippetString: spacingChar +
'failureType="${1|processingError,recoverableError|}"$0' + afterChar,
markdownString: 'Specifies the type of failure that occurs when the
dfdl:assert is unsuccessful',
},
+ {
+ item: 'schemaLocation',
+ snippetString: spacingChar + 'schemaLocation="$1"$0' + afterChar,
+ markdownString: 'Specifies the location of the schema'
+ },
+ {
+ item: 'namespace',
+ snippetString: spacingChar + 'namespace="$1"$0' + afterChar,
+ markdownString: 'User defined identifier for the imported
schemaLocation'
+ }
],
}
}
diff --git a/src/language/providers/intellisense/attributeValueItems.ts
b/src/language/providers/intellisense/attributeValueItems.ts
index 8e757f2..30ca943 100644
--- a/src/language/providers/intellisense/attributeValueItems.ts
+++ b/src/language/providers/intellisense/attributeValueItems.ts
@@ -65,6 +65,7 @@ export const noChoiceAttributes = [
'source',
'schemaLocation',
'targetNamespace',
+ 'namespace',
]
export function attributeValues(
diff --git a/src/language/providers/intellisense/elementItems.ts
b/src/language/providers/intellisense/elementItems.ts
index cf13b6e..3eb281f 100644
--- a/src/language/providers/intellisense/elementItems.ts
+++ b/src/language/providers/intellisense/elementItems.ts
@@ -207,7 +207,7 @@ export const elementCompletion = (definedVariables,
nsPrefix) => {
markdownString: 'Used to restrict a datatype to a finite set of values'
},
{
- item: 'include',
+ item: nsPrefix + 'include',
snippetString: '<' + nsPrefix + 'include "$1"/>$0',
markdownString: 'Used to add all the components of an included schema'
},
@@ -216,7 +216,7 @@ export const elementCompletion = (definedVariables,
nsPrefix) => {
snippetString: '<' + nsPrefix +
'documentation>\n\t$1\n</documentation>$0'
},
{
- item: 'import',
+ item: nsPrefix + 'import',
snippetString: '<' + nsPrefix + 'import "$1"/>$0',
markdownString: 'Used to add all the components of an included schema'
},
diff --git a/src/language/providers/utils.ts b/src/language/providers/utils.ts
index f083d61..88118d9 100644
--- a/src/language/providers/utils.ts
+++ b/src/language/providers/utils.ts
@@ -45,6 +45,8 @@ const items = [
'restriction',
'schema',
'xml version',
+ 'include',
+ 'import',
]
export function getItems() {
@@ -202,24 +204,16 @@ export function checkTagOpen(
let triggerText = document.lineAt(triggerLine).text
let itemsOnLine = getItemsOnLineCount(triggerText)
let isMultiLineTag = false
- let origTriggerText = triggerText
let origTriggerLine = triggerLine
+ let compareText = triggerText
+ let compareLine = triggerLine
const triggerPos = position.character
const textBeforeTrigger = triggerText.substring(0, triggerPos)
- while (
- itemsOnLine < 2 &&
- !triggerText.trim().startsWith('<') &&
- !triggerText.includes('/>') &&
- !triggerText.includes('<')
- ) {
+ while (itemsOnLine < 2 && !triggerText.trim().startsWith('<')) {
triggerText = document.lineAt(--triggerLine).text
}
- if (triggerText.includes('/>') || triggerText.includes('</')) {
- return false
- }
-
if (!(triggerText.endsWith('>') && triggerText.includes('<'))) {
isMultiLineTag = true
}
@@ -239,21 +233,21 @@ export function checkTagOpen(
}
}
- while (origTriggerText.trim() === '') {
- origTriggerText = document.lineAt(--origTriggerLine).text
+ while (compareText.trim() === '') {
+ compareText = document.lineAt(--compareLine).text
}
tagPos = triggerText.indexOf('<' + nsPrefix + tag)
if (itemsOnLine < 2 && tagPos > -1) {
- if (triggerText !== origTriggerText) {
- tagEndPos = origTriggerText.indexOf('>')
+ if (triggerText !== compareText) {
+ tagEndPos = compareText.indexOf('>')
}
if (
(triggerPos > tagPos &&
triggerPos <= tagEndPos &&
triggerLine === position.line) ||
- (origTriggerLine == position.line &&
+ (compareLine == position.line &&
triggerPos <= tagEndPos &&
triggerPos > tagPos) ||
position.line < origTriggerLine
@@ -315,21 +309,27 @@ export function checkMultiLineTag(
return false
}
let currentLine = position.line
+ let openTagLine = position.line
+ let closeTagLine = position.line
const origText = document.lineAt(currentLine).text
let currentText = origText
//the current line doesn't have the self close symbol
if (!currentText.endsWith('/>')) {
while (currentText.trim() === '' || !currentText.includes('<')) {
- --currentLine
- currentText = document.lineAt(currentLine).text
+ --openTagLine
+ currentText = document.lineAt(openTagLine).text
+ if (currentText.includes('/>')) {
+ closeTagLine = openTagLine
+ }
}
if (
currentText.indexOf('<' + nsPrefix + tag) !== -1 &&
currentText.indexOf('>') === -1 &&
currentText.indexOf('<' + nsPrefix + tag) &&
- currentLine <= position.line &&
+ openTagLine <= position.line &&
+ closeTagLine >= position.line &&
(origText.indexOf('>') > position.character ||
origText.indexOf('>') === -1)
) {
@@ -380,7 +380,10 @@ export function getItemsOnLineCount(triggerText: String) {
let nextPos = 0
let result = 0
- if (triggerText.includes('schema')) {
+ if (
+ triggerText.includes('schema') &&
+ !triggerText.includes('schemaLocation')
+ ) {
itemsOnLine = 1
return itemsOnLine
}
@@ -419,6 +422,40 @@ export function isInXPath(
return isXPath(position)
}
+export function isNotTriggerChar(
+ document: vscode.TextDocument,
+ position: vscode.Position,
+ triggerChar: string
+) {
+ const triggerText = document.lineAt(position.line).text
+ const triggerPos = position.character
+ const trigChar = triggerText.substring(triggerPos - 1, triggerPos)
+ if (trigChar != triggerChar) {
+ return true
+ } else {
+ return false
+ }
+}
+
+export function isTagEndTrigger(
+ document: vscode.TextDocument,
+ position: vscode.Position
+) {
+ const triggerText = document.lineAt(position.line).text
+ const triggerPos = position.character
+ const trigChar = triggerText.substring(triggerPos - 1, triggerPos)
+ if (
+ trigChar == '/' ||
+ (trigChar == '>' &&
+ !triggerText.includes('/>') &&
+ !triggerText.includes('</'))
+ ) {
+ return true
+ } else {
+ return false
+ }
+}
+
export function cursorAfterEquals(
document: vscode.TextDocument,
position: vscode.Position
@@ -457,7 +494,14 @@ export function cursorWithinQuotes(
if (currentText.includes(quoteChar[i])) {
let textBeforeTrigger = currentText.substring(0, position.character)
- //let tagStartPos = -1
+
+ if (
+ currentText.indexOf('=' + quoteChar[i]) > position.character &&
+ textBeforeTrigger.trim() == ''
+ ) {
+ return false
+ }
+
let quoteStartLine = startLine
let quoteStartPos = -1
let equalStartPos = -1
diff --git a/src/tests/suite/language/items.test.ts
b/src/tests/suite/language/items.test.ts
index c771404..d4053bb 100644
--- a/src/tests/suite/language/items.test.ts
+++ b/src/tests/suite/language/items.test.ts
@@ -172,6 +172,8 @@ suite('Items Test Suite', () => {
'testPattern',
'message',
'failureType',
+ 'schemaLocation',
+ 'namespace',
]
test('all commonItems available', async () => {