You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by da...@apache.org on 2023/03/28 16:29:49 UTC

[daffodil-vscode] branch main updated: - Added logic to handle tag attributes split on multiple lines - Fixed the logic for determining self-closing tags when '/>' is on a separate line - Added missing assert attribute choices - Corrected a problem with incorrect intellisense suggestions at the schema closing tag - Fixed suggestions before and after a multi-line self-close tag - Fixed suggestions inside a multi-line self-close tag - Removed commented code - Fixed issue with ctrl+spa [...]

This is an automated email from the ASF dual-hosted git repository.

davin 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 a572b9c      - Added logic to handle tag attributes split on multiple lines     - Fixed the logic for determining self-closing tags when '/>' is         on a separate line     - Added missing assert attribute choices     - Corrected a problem with incorrect intellisense suggestions at       the schema closing tag     - Fixed suggestions before and after a multi-line self-close tag     - Fixed suggestions inside a multi-line self-close tag     - Removed commented code     - Fixed  [...]
a572b9c is described below

commit a572b9c840722388b1774789fdedeedac63d790e
Author: rt320 <98...@users.noreply.github.com>
AuthorDate: Tue Mar 21 16:25:44 2023 -0400

        - Added logic to handle tag attributes split on multiple lines
        - Fixed the logic for determining self-closing tags when '/>' is
            on a separate line
        - Added missing assert attribute choices
        - Corrected a problem with incorrect intellisense suggestions at
          the schema closing tag
        - Fixed suggestions before and after a multi-line self-close tag
        - Fixed suggestions inside a multi-line self-close tag
        - Removed commented code
        - Fixed issue with ctrl+space inside a closing tag
        - Fix spelling errors in attributesItems
        - Add missing attributes in attributeCompletion items and attributeItems
          the case list includes the dfdl prefix
    
        Closes #461
        Closes #473
        Closes #474
        Closes #493
        Closes #527
---
 src/language/dfdl.ts                               |   4 +-
 src/language/providers/attributeCompletion.ts      |  79 ++++----
 src/language/providers/closeElement.ts             |  84 ++++++--
 src/language/providers/closeElementSlash.ts        |  22 +--
 src/language/providers/closeUtils.ts               |  89 ++++++++-
 src/language/providers/elementCompletion.ts        |  53 ++++--
 src/language/providers/endSingleBrace.ts           |  43 -----
 .../providers/intellisense/attributeItems.ts       | 212 +++++++++++++--------
 .../providers/intellisense/elementItems.ts         |  75 ++++++--
 src/language/providers/utils.ts                    | 178 +++++++++++------
 src/tests/suite/language/items.test.ts             |  24 ++-
 11 files changed, 564 insertions(+), 299 deletions(-)

diff --git a/src/language/dfdl.ts b/src/language/dfdl.ts
index a52d682..a60dd6b 100644
--- a/src/language/dfdl.ts
+++ b/src/language/dfdl.ts
@@ -21,7 +21,6 @@ import { getElementCompletionProvider } from './providers/elementCompletion'
 import { getAttributeCompletionProvider } from './providers/attributeCompletion'
 import { getCloseElementProvider } from './providers/closeElement'
 import { getCloseElementSlashProvider } from './providers/closeElementSlash'
-import { getEndSingleBraceProvider } from './providers/endSingleBrace'
 
 export function activate(context: vscode.ExtensionContext) {
   let dfdlFormat = fs
@@ -36,7 +35,6 @@ export function activate(context: vscode.ExtensionContext) {
     getElementCompletionProvider(dfdlFormat),
     getAttributeCompletionProvider(),
     getCloseElementProvider(),
-    getCloseElementSlashProvider(),
-    getEndSingleBraceProvider()
+    getCloseElementSlashProvider()
   )
 }
diff --git a/src/language/providers/attributeCompletion.ts b/src/language/providers/attributeCompletion.ts
index 45383e5..57b45a1 100644
--- a/src/language/providers/attributeCompletion.ts
+++ b/src/language/providers/attributeCompletion.ts
@@ -25,6 +25,7 @@ import {
   getCommonItems,
   getXsdNsPrefix,
   getItemsOnLineCount,
+  cursorWithinBraces,
 } from './utils'
 
 import { attributeCompletion } from './intellisense/attributeItems'
@@ -69,25 +70,26 @@ export function getAttributeCompletionProvider() {
         let additionalItems = getDefinedTypes(document, nsPrefix)
 
         if (
-          !checkBraceOpen(document, position) &&
-          !triggerText.includes('assert') &&
-          !nearestOpenItem.includes('none')
+          checkBraceOpen(document, position) ||
+          cursorWithinBraces(document, position) ||
+          nearestOpenItem.includes('none')
         ) {
-          let preVal =
-            !triggerText.includes('<' + nsPrefix + nearestOpenItem) &&
-            lineCount(document, position, nearestOpenItem) === 1 &&
-            itemsOnLine < 2
-              ? '\t'
-              : ''
-
-          return checkNearestOpenItem(
-            nearestOpenItem,
-            triggerText,
-            nsPrefix,
-            preVal,
-            additionalItems
-          )
+          return undefined
         }
+        let preVal =
+          !triggerText.includes('<' + nsPrefix + nearestOpenItem) &&
+          lineCount(document, position, nearestOpenItem) === 1 &&
+          itemsOnLine < 2
+            ? '\t'
+            : ''
+
+        return checkNearestOpenItem(
+          nearestOpenItem,
+          triggerText,
+          nsPrefix,
+          preVal,
+          additionalItems
+        )
       },
     },
     ' ',
@@ -106,8 +108,8 @@ function getDefinedTypes(document: vscode.TextDocument, nsPrefix: string) {
       .text.substring(0, document.lineAt(lineNum).range.end.character)
 
     if (
-      triggerText.includes(nsPrefix + 'simpleType Name=') ||
-      triggerText.includes(nsPrefix + 'complexType Name=')
+      triggerText.includes(nsPrefix + 'simpleType name=') ||
+      triggerText.includes(nsPrefix + 'complexType name=')
     ) {
       let startPos = triggerText.indexOf('"', 0)
       let endPos = triggerText.indexOf('"', startPos + 1)
@@ -155,6 +157,8 @@ function checkNearestOpenItem(
           'dfdl:terminator',
           'dfdl:outputNewLine',
           'dfdl:choiceBranchKey',
+          'dfdl:prefixIncludesPrefixLength',
+          'dfdl:prefixLengthType',
           'dfdl:representation',
         ],
         preVal,
@@ -193,31 +197,40 @@ function checkNearestOpenItem(
     case 'simpleType':
       return getCompletionItems(
         [
+          'dfdl:binaryNumberRep',
           'dfdl:length',
           'dfdl:lengthKind',
-          'dfdl:simpleType',
-          'dfdl:simpleType',
-          nsPrefix + 'restriction',
+          'dfdl:representation',
         ],
         '',
         '',
         nsPrefix
       )
+    case 'assert':
+      return getCompletionItems(
+        ['testKind', 'test', 'testPattern', 'message', 'failureType'],
+        '',
+        '',
+        nsPrefix
+      )
+    case 'discriminator':
+      return getCompletionItems(['message'], '', '', nsPrefix)
     case 'format':
       return getCompletionItems(
         [
           'dfdl:byteOrder',
           'dfdl:bitOrder',
           'dfdl:binaryNumberRep',
-          'dfdl:binaryFloatingRep',
+          'dfdl:binaryFloatRep',
           'dfdl:encoding',
-          'dfdl:errorEndcodingPolicy',
+          'dfdl:encodingErrorPolicy',
           'dfdl:initiator',
           'dfdl:length',
           'dfdl:lengthKind',
           'dfdl:lengthUnits',
           'dfdl:utf16Width',
-          'dfdl:nillKind',
+          'dfdl:nilKind',
+          'dfdl:nilValue',
           'dfdl:nilValueDelimiterPolicy',
           'dfdl:lengthPattern',
           'dfdl:outputNewLine',
@@ -226,21 +239,25 @@ function checkNearestOpenItem(
           'dfdl:separatorSuppressionPolicy',
           'dfdl:terminator',
           'dfdl:occursCountKind',
-          'dfdl:textStandRdZeroRep',
-          'dfdl:textStandardInifinityRep',
+          'dfdl:textStandardZeroRep',
+          'dfdl:textStandardInfinityRep',
           'dfdl:textStandardExponentRep',
           'dfdl:textStandardNaNRep',
           'dfdl:textNumberPattern',
           'dfdl:textNumberRep',
+          'dfdl:textNumberRoundingIncrement',
           'dfdl:textNumberRoundingMode',
           'dfdl:textStandardRoundingIncrement',
           'dfdl:textNumberRounding',
           'dfdl:textNumberCheckPolicy',
+          'dfdl:textOutputMinLength',
           'dfdl:textPolicyOutputMinLength',
-          'dfdl:textStandardGroupingSeporator',
+          'dfdl:textStandardGroupingSeparator',
+          'dfdl:textStringJustification',
           'dfdl:textPadKind',
-          'dfdl:textstandardBase',
+          'dfdl:textStandardBase',
           'dfdl:textTrimKind',
+          'dfdl:leadingSkip',
           'dfdl:trailingSkip',
           'dfdl:truncateSpecifiedLengthString',
           'dfdl:sequenceKind',
@@ -259,17 +276,15 @@ function checkNearestOpenItem(
           'dfdl:terminator',
           'dfdl:outputNewLine',
           'dfdl:representation',
-          'dfdl:defineEscapeScheme',
+          'dfdl:escapeSchemeRef',
           'dfdl:calendarPatternKind',
           'dfdl:documentFinalTerminatorCanBeMissing',
           'dfdl:emptyValueDelimiterPolicy',
-          //nsPrefix + 'restriction',
         ],
         '',
         '',
         nsPrefix
       )
-
     case 'defineVariable':
       return getDefineVariableCompletionItems(preVal, additionalItems, nsPrefix)
     case 'setVariable':
diff --git a/src/language/providers/closeElement.ts b/src/language/providers/closeElement.ts
index 02a6bc4..4450fe5 100644
--- a/src/language/providers/closeElement.ts
+++ b/src/language/providers/closeElement.ts
@@ -17,6 +17,7 @@
 
 import * as vscode from 'vscode'
 import { checkMissingCloseTag } from './closeUtils'
+import { checkBraceOpen, cursorWithinBraces } from './utils'
 import {
   getXsdNsPrefix,
   insertSnippet,
@@ -32,6 +33,12 @@ export function getCloseElementProvider() {
         document: vscode.TextDocument,
         position: vscode.Position
       ) {
+        if (
+          checkBraceOpen(document, position) ||
+          cursorWithinBraces(document, position)
+        ) {
+          return undefined
+        }
         let backpos = position.with(position.line, position.character)
         let backpos3 = position.with(position.line, position.character)
 
@@ -102,18 +109,42 @@ function checkItemsOnLine(
   backpos: vscode.Position,
   backpos3: vscode.Position
 ) {
-  if (
-    itemsOnLine == 0 &&
-    !triggerText.includes('</') &&
-    nearestTagNotClosed !== 'schema'
-  ) {
-    insertSnippet('</' + nsPrefix + nearestTagNotClosed + '>$0', backpos3)
+  if (itemsOnLine == 0 && !triggerText.includes('</')) {
+    if (triggerText.trim() === '>') {
+      insertSnippet('</' + nsPrefix + nearestTagNotClosed + '>', backpos)
+    } else {
+      switch (nearestTagNotClosed) {
+        case 'schema':
+          if (triggerText.endsWith('>>')) {
+            insertSnippet(
+              '\n\t$0\n</' + nsPrefix + nearestTagNotClosed + '>',
+              backpos
+            )
+          } else {
+            insertSnippet(
+              '>\n\t$0\n</' + nsPrefix + nearestTagNotClosed + '>',
+              backpos
+            )
+          }
+          break
+        default:
+          if (triggerText.endsWith('>>')) {
+            insertSnippet(
+              '</' + nsPrefix + nearestTagNotClosed + '>$0',
+              backpos
+            )
+          } else {
+            insertSnippet(
+              '>$1</' + nsPrefix + nearestTagNotClosed + '>',
+              backpos
+            )
+          }
+          break
+      }
+    }
   }
 
-  if (
-    (itemsOnLine === 1 && !triggerText.includes('</')) ||
-    nearestTagNotClosed === 'schema'
-  ) {
+  if (itemsOnLine === 1 && !triggerText.includes('</')) {
     checkNearestTagNotClosed(
       document,
       position,
@@ -137,15 +168,30 @@ function checkNearestTagNotClosed(
   backpos: vscode.Position,
   nsPrefix: string
 ) {
-  if (
-    nearestTagNotClosed.includes('defineVariable') ||
-    nearestTagNotClosed.includes('setVariable')
-  ) {
-    insertSnippet('>\n</' + nsPrefix + nearestTagNotClosed + '>$0', backpos)
-  }
-
-  if (!nearestTagNotClosed.includes('Variable')) {
-    insertSnippet('>\n\t$0\n</' + nsPrefix + nearestTagNotClosed + '>', backpos)
+  const triggerText = document.lineAt(position.line).text
+  switch (nearestTagNotClosed) {
+    case 'defineVariable':
+    case 'setVariable':
+      insertSnippet('>\n</' + nsPrefix + nearestTagNotClosed + '>$0', backpos)
+      break
+    case 'assert':
+    case 'discriminator':
+      if (triggerText.endsWith('>')) {
+        insertSnippet('</' + nsPrefix + nearestTagNotClosed + '>', backpos)
+      } else {
+        insertSnippet('></' + nsPrefix + nearestTagNotClosed + '>$0', backpos)
+      }
+      break
+    default:
+      if (triggerText.trim() === '') {
+        insertSnippet('</' + nsPrefix + nearestTagNotClosed + '>', backpos)
+      } else {
+        insertSnippet(
+          '>\n\t$0\n</' + nsPrefix + nearestTagNotClosed + '>',
+          backpos
+        )
+      }
+      break
   }
 }
 
diff --git a/src/language/providers/closeElementSlash.ts b/src/language/providers/closeElementSlash.ts
index d417900..49d47bd 100644
--- a/src/language/providers/closeElementSlash.ts
+++ b/src/language/providers/closeElementSlash.ts
@@ -23,6 +23,7 @@ import {
   getXsdNsPrefix,
   getItemPrefix,
   getItemsOnLineCount,
+  cursorWithinBraces,
 } from './utils'
 
 export function getCloseElementSlashProvider() {
@@ -45,7 +46,10 @@ export function getCloseElementSlashProvider() {
         )
         const itemsOnLine = getItemsOnLineCount(triggerText)
 
-        if (checkBraceOpen(document, position)) {
+        if (
+          checkBraceOpen(document, position) ||
+          cursorWithinBraces(document, position)
+        ) {
           return undefined
         }
 
@@ -86,31 +90,17 @@ function checkItemsOnLine(
 ) {
   nsPrefix = getItemPrefix(nearestTagNotClosed, nsPrefix)
   if (itemsOnLine == 1 || itemsOnLine == 0) {
-    if (itemsOnLine == 1) {
-      insertSnippet('/>$0', backpos)
-    }
-    if (itemsOnLine == 0) {
-      const backpos3 = position.with(position.line, position.character - 3)
-      insertSnippet('</' + nsPrefix + nearestTagNotClosed + '>$0', backpos3)
-    }
-
+    insertSnippet('/>$0', backpos)
     if (
       nearestTagNotClosed.includes('defineVariable') ||
       nearestTagNotClosed.includes('setVariable')
     ) {
-      let startPos = document.lineAt(position).text.indexOf('<', 0)
       let range = new vscode.Range(backpos, position)
       vscode.window.activeTextEditor?.edit((editBuilder) => {
         editBuilder.replace(range, '')
       })
 
       insertSnippet('/>\n', backpos)
-
-      let backpos2 = position.with(position.line + 1, startPos - 2)
-      insertSnippet('</' + nsPrefix + 'appinfo>\n', backpos2)
-
-      let backpos3 = position.with(position.line + 2, startPos - 4)
-      insertSnippet('</' + nsPrefix + 'annotation>$0', backpos3)
     }
   }
 
diff --git a/src/language/providers/closeUtils.ts b/src/language/providers/closeUtils.ts
index aa7211e..12d1378 100644
--- a/src/language/providers/closeUtils.ts
+++ b/src/language/providers/closeUtils.ts
@@ -61,7 +61,7 @@ export function checkMissingCloseTag(
         i
       )
 
-      if (lt2res != undefined) {
+      if (lt2res != 'none') {
         return lt2res
       }
     }
@@ -70,6 +70,24 @@ export function checkMissingCloseTag(
   return 'none'
 }
 
+export function cursorInsideCloseTag(
+  document: vscode.TextDocument,
+  position: vscode.Position
+) {
+  const triggerText = document.lineAt(position.line).text
+  const triggerPos = position.character
+  const closeTagStart = triggerText.lastIndexOf('</')
+  const closeTagEnd = triggerText.lastIndexOf('>')
+  if (
+    triggerPos > closeTagStart &&
+    triggerPos <= closeTagEnd &&
+    closeTagStart !== -1
+  ) {
+    return true
+  }
+  return false
+}
+
 export function getCloseTag(
   document: vscode.TextDocument,
   position: vscode.Position,
@@ -87,6 +105,11 @@ export function getCloseTag(
   let endPos = triggerText.lastIndexOf('>')
   nsPrefix = getItemPrefix(tag, nsPrefix)
 
+  if (itemsOnLine === 1) {
+    if (cursorInsideCloseTag(document, position))
+      return ['none', lineNum, startPos]
+  }
+
   if (itemsOnLine > 1 && startPos < endPos) {
     while (tagOpen > -1 && tagOpen <= triggerPos) {
       tagOpen = triggerText.indexOf('<', tagOpen)
@@ -118,14 +141,23 @@ export function getCloseTag(
 
     while (lineNum > -1 && lineNum < document.lineCount) {
       let currentText = document.lineAt(lineNum).text
+      let isMultiLineTag = false
+
+      //skip any comment lines
+      if (currentText.includes('<!--')) {
+        while (!currentText.includes('-->')) {
+          currentText = document.lineAt(++lineNum).text
+        }
+        currentText = document.lineAt(++lineNum).text
+      }
+
       startPos = currentText.indexOf('<')
 
       if (getItemsOnLineCount(currentText) < 2) {
         //skip lines until the close tag for this item
         if (
           currentText.includes('<' + nsPrefix + tag) &&
-          (currentText.includes('>') || tag === 'schema') &&
-          !currentText.includes('/>')
+          currentText.endsWith('>')
         ) {
           //skipping to closing tag
           while (!currentText.includes('</' + nsPrefix + tag)) {
@@ -136,7 +168,31 @@ export function getCloseTag(
           }
         }
 
-        if (currentText.includes('</' + nsPrefix + tag)) {
+        //if end tag symbol is on a different line
+        if (
+          currentText.includes('<' + nsPrefix + tag) &&
+          !currentText.includes('>')
+        ) {
+          isMultiLineTag = true
+          //skip to the end tag symbol
+          while (!currentText.includes('>')) {
+            currentText = document.lineAt(++lineNum).text
+          }
+          //if the tag isn't self closing, skip to the closing tag
+          if (!currentText.includes('/>')) {
+            while (!currentText.includes('</' + nsPrefix + tag)) {
+              currentText = document.lineAt(++lineNum).text
+            }
+          }
+        }
+
+        if (
+          currentText.includes('</' + nsPrefix + tag) ||
+          (currentText.includes('/>') && isMultiLineTag)
+        ) {
+          if (isMultiLineTag) {
+            startPos = triggerPos
+          }
           //if the cursor is after the closing tag
           if (
             lineNum == triggerLine &&
@@ -213,10 +269,15 @@ export function getItemsForLineLT2(
   i: number
 ) {
   let [currentText, currentLine] = [triggerText, triggerLine]
-  let [lineBefore, lineAfter] = [triggerLine, triggerLine]
+  let [lineBefore, lineAfter, testLine] = [
+    triggerLine,
+    triggerLine,
+    triggerLine,
+  ]
   let openTagArray: number[] = []
   let closeTagArray: number[] = []
 
+  nsPrefix = getItemPrefix(items[i], nsPrefix)
   while (
     currentText.indexOf('<' + nsPrefix + items[i]) === -1 &&
     currentLine > -1
@@ -239,8 +300,17 @@ export function getItemsForLineLT2(
         if (currentText.indexOf('<' + nsPrefix + items[i]) > -1) {
           openTagArray.push(lineBefore)
 
+          //if multi line tag
+          let testText = currentText
+          if (!testText.includes('>')) {
+            testLine = lineBefore
+            while (!testText.includes('>')) {
+              testText = document.lineAt(++testLine).text
+            }
+          }
+
           //if selfclosing remove from the array
-          if (currentText.indexOf('/>') > -1) {
+          if (testText.indexOf('/>') > -1 || testText.includes('xml version')) {
             openTagArray.splice(openTagArray.length - 1, 1)
           }
         }
@@ -262,6 +332,11 @@ export function getItemsForLineLT2(
         if (currentText.indexOf('<' + nsPrefix + items[i]) > -1) {
           openTagArray.push(lineAfter)
 
+          //if multi line tag
+          while (!currentText.includes('>')) {
+            currentText = document.lineAt(++lineAfter).text
+          }
+
           //if selfclosing remove from the array
           if (currentText.indexOf('/>') > -1) {
             openTagArray.splice(openTagArray.length - 1, 1)
@@ -281,5 +356,5 @@ export function getItemsForLineLT2(
     }
   }
 
-  return undefined
+  return 'none'
 }
diff --git a/src/language/providers/elementCompletion.ts b/src/language/providers/elementCompletion.ts
index b74ea77..fb28848 100644
--- a/src/language/providers/elementCompletion.ts
+++ b/src/language/providers/elementCompletion.ts
@@ -25,6 +25,7 @@ import {
   getCommonItems,
   nearestTag,
   getItemsOnLineCount,
+  cursorWithinBraces,
 } from './utils'
 import { elementCompletion } from './intellisense/elementItems'
 
@@ -36,7 +37,10 @@ export function getElementCompletionProvider(dfdlFormatString: string) {
       token: vscode.CancellationToken,
       context: vscode.CompletionContext
     ) {
-      if (checkBraceOpen(document, position)) {
+      if (
+        checkBraceOpen(document, position) ||
+        cursorWithinBraces(document, position)
+      ) {
         return undefined
       }
 
@@ -93,8 +97,13 @@ function getElementCompletionItems(
     (e) => {
       for (let i = 0; i < itemsToUse.length; ++i) {
         if (e.item.includes(itemsToUse[i])) {
-          const completionItem = createCompletionItem(e, preVal, nsPrefix)
-          compItems.push(completionItem)
+          if (
+            (e.item.includes('dfdl:') && itemsToUse[i].includes('dfdl:')) ||
+            !e.item.includes('dfdl')
+          ) {
+            const completionItem = createCompletionItem(e, preVal, nsPrefix)
+            compItems.push(completionItem)
+          }
         }
       }
     }
@@ -180,17 +189,27 @@ function checkTagNearestOpen(
         '',
         nsPrefix
       )
+    case 'restriction':
+      return getElementCompletionItems(
+        ['maxInclusive', 'maxExclusive', 'minInclusive', 'minExclusive'],
+        '',
+        '',
+        nsPrefix
+      )
     case 'annotation':
       return getElementCompletionItems(['appinfo'], '', '', nsPrefix)
     case 'appinfo':
       return getElementCompletionItems(
         [
-          'assert',
-          'discriminator',
-          'defineFormat',
-          'format',
-          'defineVariable',
-          'setVariable',
+          'dfdl:assert',
+          'dfdl:discriminator',
+          'dfdl:defineFormat',
+          'dfdl:format',
+          'dfdl:defineVariable',
+          'dfdl:setVariable',
+          'dfdl:defineEscapeScheme',
+          'dfdl:element',
+          'dfdl:simpleType',
         ],
         '',
         '',
@@ -242,13 +261,6 @@ export function getTagNearestTrigger(
     return 'emptySchema'
   }
 
-  if (
-    itemsOnLine > 1 &&
-    (triggerPos === triggerText.indexOf('<') ||
-      triggerPos === triggerText.lastIndexOf('>') + 1)
-  ) {
-    return tagNearestTrigger
-  }
   while (true) {
     let [foundTag, foundLine, foundPos] = nearestTag(
       document,
@@ -258,6 +270,15 @@ export function getTagNearestTrigger(
       startPos
     )
 
+    if (itemsOnLine > 1) {
+      let afterTrigger =
+        triggerText.substring(triggerPos).indexOf('<') + triggerPos
+      let beforeTrigger = triggerText.substring(0, triggerPos).lastIndexOf('>')
+      if (triggerPos === afterTrigger && triggerPos === beforeTrigger + 1)
+        tagNearestTrigger = foundTag
+      return tagNearestTrigger
+    }
+
     startLine = foundLine
 
     let [endTag, endTagLine, endTagPos] = getCloseTag(
diff --git a/src/language/providers/endSingleBrace.ts b/src/language/providers/endSingleBrace.ts
deleted file mode 100644
index fbdddd9..0000000
--- a/src/language/providers/endSingleBrace.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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 { insertSnippet } from './utils'
-
-export function getEndSingleBraceProvider() {
-  return vscode.languages.registerCompletionItemProvider(
-    'dfdl',
-    {
-      provideCompletionItems(
-        document: vscode.TextDocument,
-        position: vscode.Position
-      ) {
-        const triggerText = document
-          .lineAt(position)
-          .text.substring(0, position.character)
-        if (
-          triggerText.includes('dfdl:length="{') ||
-          triggerText.includes('dfdl:choiceDispatchKey="{')
-        ) {
-          insertSnippet('$1}$0', position)
-        }
-        return undefined
-      },
-    },
-    '{'
-  )
-}
diff --git a/src/language/providers/intellisense/attributeItems.ts b/src/language/providers/intellisense/attributeItems.ts
index b06f559..2861324 100644
--- a/src/language/providers/intellisense/attributeItems.ts
+++ b/src/language/providers/intellisense/attributeItems.ts
@@ -32,12 +32,12 @@ export const attributeCompletion = (additionalItems, nsPrefix: string) => {
       {
         item: 'minOccurs',
         snippetString: 'minOccurs="${1|0,1|}"$0',
-        markdownString: 'minimum number of times element will occur',
+        markdownString: 'Minimum number of times element will occur',
       },
       {
         item: 'maxOccurs',
         snippetString: 'maxOccurs="${1|0,1,unbounded|}"$0',
-        markdownString: 'maximum number of times element will occur',
+        markdownString: 'Maximum number of times element will occur',
       },
       {
         item: 'dfdl:occursCount',
@@ -47,17 +47,17 @@ export const attributeCompletion = (additionalItems, nsPrefix: string) => {
       {
         item: 'dfdl:byteOrder',
         snippetString: 'dfdl:byteOrder="${1|bigEndian,littleEndian|}"$0',
-        markdownString: 'bigEndian or littleEndian',
+        markdownString: 'This property applies to all Number, Calendar (date and time), and Boolean types with representation binary',
       },
       {
         item: 'dfdl:bitOrder',
-        snippetString: 'dfdl:bitOrder=${1|"mostSignificantBitFirst","leastSignificantBitFirst"|}$0',
-        markdownString: 'mostSignificantBitFirst or leastSignificantBitFirst',
+        snippetString: 'dfdl:bitOrder="${1|mostSignificantBitFirst,leastSignificantBitFirst|}"$0',
+        markdownString: 'Determines the specific bits of any grammar region',
       },
       {
         item: 'dfdl:occursCountKind',
         snippetString: 'dfdl:occursCountKind="${1|expression,fixed,implicit,parsed,stopValue|}"$0',
-        markdownString: 'occursCountKind can be expression, fixed, implicit, parsed, stopValue',
+        markdownString: 'Specifies how the actual number of occurrences is to be established',
       },
       {
         item: 'dfdl:length',
@@ -69,30 +69,45 @@ export const attributeCompletion = (additionalItems, nsPrefix: string) => {
         snippetString: 'dfdl:lengthKind="${1|delimited,fixed,explicit,implicit,prefixed,pattern,endOfParent|}"$0',
         markdownString: 'lengthKind can be delimited, fixed, explicit, implicit, prefixed,pattern, or endOfParent',
       },
+      {
+        item: 'dfdl:prefixIncludesPrefixLength',
+        snippetString: 'dfdl:prefixIncludesPrefixLength="${1|yes,no|}"$0',
+        markdownString: 'Specifies whether the length given by a prefix includes the length of the prefix as well as the length of the content region',
+      },
+      {
+        item: 'dfdl:prefixLengthType',
+        snippetString: 'dfdl:prefixLengthType="$1"$0',
+        markdownString: 'Name of a simple type derived from xs:integer or any subtype of it.',
+      },
       {
         item: 'dfdl:utf16Width',
-        snippetString: 'dfdl:utf16Width=${1|"fixed","variable"|}$0',
-        markdownString: 'fixed or variable',
+        snippetString: 'dfdl:utf16Width="${1|fixed,variable|}"$0',
+        markdownString: 'Specifies whether the encoding UTF-16 is treated as a fixed or variable width encoding',
       },
       {
         item: 'dfdl:encoding',
         snippetString: 'dfdl:encoding="${1|US-ASCII,ASCII,UTF-8,UTF-16,UTF-16BE,UTF-16LE,ISO-8859-1|}"$0',
-        markdownString: 'encoding can be US-ASCII, ASCII, UTF-8, UTF-16, UTF-16BE UTF-16LE, or ISO-8859-1',
+        markdownString: 'This property can be computed by way of an expression which returns an appropriate string value',
       },
       {
         item: 'dfdl:encodingErrorPolicy',
-        snippetString: 'dfdl:encodingErrorPolicy=${1|"error","replace"|}$0',
-        markdownString: 'error or replace',
+        snippetString: 'dfdl:encodingErrorPolicy="${1|error,replace|}"$0',
+        markdownString: 'This property provides control of how decoding and encoding errors are handled when converting the data to text, or text to data',
       },
       {
         item: 'dfdl:nilKind',
-        snippetString: 'dfdl:nilKind=${1|"literalCharacter","literalValue","logicalValue"|}$0',
-        markdownString: 'literalCharacter,literalValue,or logicalValue'
+        snippetString: 'dfdl:nilKind="${1|literalCharacter,literalValue,logicalValue|}"$0',
+        markdownString: 'Specifies how dfdl:<nilValue> is interpreted to represent the nil value in the data stream'
+      },
+      {
+        item: 'dfdl:nilValue',
+        snippetString: 'dfdl:nilValue="$1"$0',
+        markdownString: 'Used to provide a logical value that is used to indicate the data is nilled'
       },
       {
         item: 'dfdl:nilValueDelimiterPolicy',
-        snippetString: 'dfdl:nilValueDelimiterPolicy=${1|"initiator","terminator","both","none"|}$0',
-        markdownString: 'initiator,terminator,both,or none',
+        snippetString: 'dfdl:nilValueDelimiterPolicy="${1|initiator,terminator,both,none|}"$0',
+        markdownString: 'Controls whether matching one of the nil values also involves matching the initiator or terminator specified by the element',
       },
       {
         item: 'dfdl:alignment',
@@ -126,7 +141,7 @@ export const attributeCompletion = (additionalItems, nsPrefix: string) => {
       },
       {
         item: 'dfdl:outputNewLine',
-        snippetString: 'dfdl:outputNewLine="${1|%CR,%LF,%CR%LF,%NEL,%LS|}"$0',
+        snippetString: 'dfdl:outputNewLine="${1|%CR;,%LF;,%CR;%LF;,%NEL;,%LS;|}"$0',
         markdownString: 'Specifies the character or characters that are used to replace the %NL; character class entity during unparse',
       },
       {
@@ -137,117 +152,122 @@ export const attributeCompletion = (additionalItems, nsPrefix: string) => {
       {
         item: 'dfdl:representation',
         snippetString: 'dfdl:representation="${1|binary,text|}"$0',
-        markdownString: 'binary or text',
+        markdownString: 'Identifies the physical representation of the element as text or binary',
       },
       {
-        item: 'dfdl:hiddenGroupRef',
-        snippetString: 'dfdl:hiddenGroupRef="$1"$0',
-        markdownString: 'Specifies ',
+        item: 'dfdl:textStringJustification',
+        snippetString: 'dfdl:textStringJustification="${1|left,right,center|}"$0',
+        markdownString: 'Specifies the string justification',
       },
       {
         item: 'dfdl:textStandardZeroRep',
         snippetString: 'dfdl:textStandardZeroRep="0"$0',
-        markdownString: 'Specifies ',
+        markdownString: 'Specifies the whitespace separated list of alternative DFDL String Literals that are equivalent to zero ',
       },
       {
         item: 'dfdl:textStandardInfinityRep',
         snippetString: 'dfdl:textStandardInfinityRep="Inf"$0',
-        markdownString: 'Specifies ',
+        markdownString: 'The value used to represent infinity.',
       },
       {
         item: 'dfdl:textStandardExponentRep',
         snippetString: 'dfdl:textStandardExponentRep="E"$0',
-        markdownString: 'Specifies ',
+        markdownString: 'Defines the actual character(s) that appear in the data as the exponent indicator',
       },
       {
         item: 'dfdl:textStandardNaNRep',
         snippetString: 'dfdl:textStandardNaNRep="NaN"$0',
-        markdownString: 'Specifies ',
+        markdownString: 'Specifies the value used to represent NaN ',
       },
       {
         item: 'dfdl:textNumberPattern',
         snippetString: 'dfdl:textNumberPattern="#,##0.###;-#,##0.###"$0',
-        markdownString: 'Specifies ',
+        markdownString: 'Defines the ICU-like pattern that describes the format of the text number',
       },
       {
         item: 'dfdl:textNumberRep',
-        snippetString: 'dfdl:textNumberRep=${1|"standard","zoned"|}$0',
-        markdownString: 'Specifies ',
+        snippetString: 'dfdl:textNumberRep="${1|standard,zoned|}"$0',
+        markdownString: 'Represented as standard characters in the character set encoding or represented as a zoned decimal in the character set encoding',
       },
       {
         item: 'dfdl:textNumberRoundingMode',
-        snippetString: 'dfdl:textNumberRoundingMode=${1|"roundCeiling","roundFloor","roundDown","roundUp","roundHalfEven","roundHalfDown","roundHalfUp","roundUnnecessary"|}$0',
-        markdownString: 'roundCeiling,roundFloor,roundDown,roundUp,/nroundHalfEven,roundHalfDown,roundHalfUp, or roundUnnecessary',
+        snippetString: 'dfdl:textNumberRoundingMode="${1|roundCeiling,roundFloor,roundDown,roundUp,roundHalfEven,roundHalfDown,roundHalfUp,roundUnnecessary|}"$0',
+        markdownString: 'Specifies how rounding occurs during unparsing',
       },
       {
         item: 'dfdl:textNumberRoundingIncrement',
-        snippetString: 'dfdl:textNumberRoundingIncrement="0$"$0',
-        markdownString: 'specify ',
+        snippetString: 'dfdl:textNumberRoundingIncrement="0"$0',
+        markdownString: 'Specifies the rounding increment to use during unparsing',
       },
       {
         item: 'dfdl:textNumberRounding',
-        snippetString: 'dfdl:textNumberRounding=${1|"explicit","pattern"|}$0',
-        markdownString: 'explicit or pattern',
+        snippetString: 'dfdl:textNumberRounding="${1|explicit,pattern|}"$0',
+        markdownString: 'Specifies how rounding is controlled during unparsing',
       },
       {
         item: 'dfdl:textNumberCheckPolicy',
-        snippetString: 'dfdl:textNumberCheckPolicy=${1|"lax","strict"|}$0',
-        markdownString: 'lax, strict',
+        snippetString: 'dfdl:textNumberCheckPolicy="${1|lax,strict|}"$0',
+        markdownString: 'Indicates how lenient to be when parsing against the dfdl:textNumberPattern',
       },
       {
         item: 'dfdl:textOutputMinLength',
         snippetString: 'dfdl:textOutputMinLength="0"$0',
-        markdownString: 'Specif ',
+        markdownString: 'Specifies the minimum content length during unparsing for simple types that do not allow the XSD minLength facet to be specified',
       },
       {
         item: 'dfdl:textStandardGroupingSeparator',
         snippetString: 'ddl:textStandardGroupingSeparator=","$0',
-        markdownString: 'Speicify',
+        markdownString: 'Specifies the single character that can appear in the data as the grouping separator',
       },
       {
         item: 'dfdl:textPadKind',
-        snippetString: 'dfdl:textPadKind=${1|"none","padChar"|}$0',
-        markdownString: 'none or padChar',
+        snippetString: 'dfdl:textPadKind="${1|none,padChar|}"$0',
+        markdownString: 'Indicates whether to pad the data value on unparsing',
       },
       {
         item: 'dfdl:textStandardBase',
-        snippetString: 'dfdl:textStandardBase="10"$0',
-        markdownString: 'specify ',
+        snippetString: 'dfdl:textStandardBase="${1|2,8,10,16|}"$0',
+        markdownString: 'Indicates the number base',
       },
       {
         item: 'dfdl:textTrimKind',
-        snippetString: 'dfdl:textTrimKind=${1|"none","padChar"|}$0',
-        markdownString: 'none or padChar',
+        snippetString: 'dfdl:textTrimKind="${1|none,padChar|}"$0',
+        markdownString: 'Indicates whether to trim data on parsing',
+      },
+      {
+        item: 'dfdl:leadingSkip',
+        snippetString: 'dfdl:trailingSkip="0$1"$0',
+        markdownString: 'A non-negative number of bytes or bits to skip before alignment is applied',
       },
       {
         item: 'dfdl:trailingSkip',
-        snippetString: 'dfdl:trailingSkip="0"$0',
-        markdownString: 'specify ',
+        snippetString: 'dfdl:trailingSkip="0$1"$0',
+        markdownString: 'A non-negative number of bytes or bits to skip after the element,',
       },
       {
         item: 'dfdl:truncateSpecifiedLengthString',
-        snippetString: 'dfdl:truncateSpecifiedLengthString=${1|"no","yes"|}$0',
-        markdownString: 'yes or no',
+        snippetString: 'dfdl:truncateSpecifiedLengthString="${1|no,yes|}"$0',
+        markdownString: 'This property provides the means to express an error, or the strings can be truncated to fit when the strings in an Infoset being unparsed do not fit within those specified lengths',
       },
       {
         item: 'dfdl:sequenceKind',
         snippetString: 'dfdl:SequenceKind ="${1|ordered,unordered|}"$0',
-        markdownString: 'order or unordered',
+        markdownString: 'Defines whether the items are expected in the same order that they appear in the schema or in any order',
       },
       {
         item: 'dfdl:separator',
         snippetString: 'dfdl:separator="$1"$0',
-        markdownString: 'specify ',
+        markdownString: 'Specifies a whitespace separated list of alternative DFDL String Literals that are the possible separators for the sequence',
       },
       {
         item: 'dfdl:separatorPosition',
-        snippetString: 'dfdl:separatorPosition="${1|infix,postfix.prefix|}$0',
-        markdownString: '',
+        snippetString: 'dfdl:separatorPosition="${1|infix,postfix,prefix|}"$0',
+        markdownString: 'specifies where the separator occurs between the elements',
       },
       {
         item: 'dfdl:separatorSuppressionPolicy',
         snippetString: 'dfdl:separatorSuppressionPolicy="${1|anyEmpty,never,trailingEmpty,trailingEmptyStrict|}"$0',
-        markdownString: 'anyEmpty,never,trailingEmpty, or trailingEmptyStrict',
+        markdownString: 'Controls the circumstances when separators are expected in the data when parsing, or generated when unparsing',
       },
       {
         item: 'dfdl:terminator',
@@ -256,84 +276,108 @@ export const attributeCompletion = (additionalItems, nsPrefix: string) => {
       },
       {
         item: 'dfdl:textBidi',
-        snippetString: 'dfdl:textBidi=${36|"no","yes"|}$0',
-        markdownString: 'yes or no',
+        snippetString: 'dfdl:textBidi="${1|no,yes|}"$0',
+        markdownString: 'This property exists in anticipation of future DFDL features that enable bidirectional text processing',
+      },
+      {
+        item: 'dfdl:hiddenGroupRef',
+        snippetString: '<' + nsPrefix + 'dfdl:hiddenGroupRef="$1"\n$0',
+        markdownString: 'Reference to a global model group definition',
       },
       {
         item: 'dfdl:choiceLengthKind',
-        snippetString: 'dfdl:choiceLengthKind="${1|explicit,Implicit|}"$0',
-        markdownString: 'Valid values are implicit and explicit',
+        snippetString: 'dfdl:choiceLengthKind="${1|explicit,implicit|}"$0',
+        markdownString: 'Determines whether the branches of the choice are always filled (explicit) to the fixed-length specified by dfdl:choiceLength or not filled (implicit)',
       },
       {
         item: 'dfdl:choiceLength',
         snippetString: 'dfdl:choiceLength="$1"$0',
-        markdownString: 'Only used when dfdl:choiceLengthKind is explicit',
+        markdownString: 'Specifies the length of the choice in bytes, only used when dfdl:choiceLengthKind is explicit',
       },
       {
         item: 'dfdl:fillByte',
         snippetString: 'dfdl:fillByte="$1"$0',
-        markdownString: 'specify ',
+        markdownString: 'A single byte specified as a DFDL byte value entity or a single character, used on unparsing to fill empty space',
       },
       {
         item: 'dfdl:ignoreCase',
-        snippetString: 'dfdl:ignoreCase=${1|"no","yes"|}$0',
-        markdownString: 'specify ',
+        snippetString: 'dfdl:ignoreCase="${1|no,yes|}"$0',
+        markdownString: 'Whether mixed case data is accepted when matching delimiters and data values on input',
       },
        {
         item: 'dfdl:initiatedContent',
-        snippetString: 'dfdl:initiatedContent="${1|yes,no}"$0',
-        markdownString: 'yes indicates all branches of a choice are initiated\no indicates the branch dfdl:initator property may be ste to empty string',
+        snippetString: 'dfdl:initiatedContent="${1|yes,no|}"$0',
+        markdownString: 'yes indicates all branches of a choice are initiated\nno indicates the branch dfdl:initator property may be ste to empty string',
       },
       {
         item: 'dfdl:initiator',
         snippetString: 'dfdl:initiator="$1"$0',
-        markdownString: 'specify ',
+        markdownString: 'Specifies an ordered whitespace separated list of alternative DFDL String Literals one of which marks the beginning of the element or group of elements ',
       },
       {
         item: 'dfdl:choiceDispatchKey',
         snippetString: 'dfdl:choiceDispatchKey="$1"$0',
-        markdownString: 'The expression must evaluate to a string',
-      },
-      {
-        item: 'dfdl:simpleType',
-        snippetString: '<' + nsPrefix + 'annotation>\n\t<' + nsPrefix + 'appinfo source="http://www.ogf.org/dfdl/">\n\t\trepresentation="${1|binary,|"\n\t</' + nsPrefix + 'appinfo>\n</' + nsPrefix + 'annotation>$0',
-        markdownString: 'Creates a simpleType definition',
+        markdownString: 'The expression must evaluate to a string, the string must match one of the dfdl:choiceBranchKey property values of one of the branches of the choice',
       },
       {
         item: 'dfdl:binaryNumberRep',
-        snippetString: 'dfdl:binaryNumberRep=${1|"binary","packed","bcd","ibm4690Packed"|}$0',
-        markdownString: 'binary,packed,bcd, oribm4690Packed',
+        snippetString: 'dfdl:binaryNumberRep="${1|binary,packed,bcd,ibm4690Packed|}"$0',
+        markdownString: 'binary,packed,bcd, or ibm4690Packed',
       },
       {
         item: 'dfdl:floating',
-        snippetString: 'dfdl:floating=${1|"no","yes"|}$0',
+        snippetString: 'dfdl:floating="${1|no,yes|}"$0',
         markdownString: 'yes or no',
       },
        {
-        item: 'dfdl:binaryFloatingRep',
-        snippetString: 'dfdl:binaryFloatRep=${1|"ieee","ibm390Hex"|}$0',
+        item: 'dfdl:binaryFloatRep',
+        snippetString: 'dfdl:binaryFloatRep="${1|ieee,ibm390Hex|}"$0',
         markdownString: 'ieee or ibm390Hex',
       },
       {
         item: 'dfdl:calendarPatternKind',
-        snippetString: 'dfdl:calendarPatternKind=${1|"explicit","implicit"|}$0',
-        markdownString: 'explicit or implicit',
+        snippetString: 'dfdl:calendarPatternKind="${1|explicit,implicit|}"$0',
+        markdownString: 'The pattern is given by dfdl:calendarPattern explicit or the pattern is derived from the XML schema date/time type (implicit)',
       },
       {
         item: "dfdl:documentFinalTerminatorCanBeMissing",
-        snippetString: 'dfdl:documentFinalTerminatorCanBeMissing=${1|"yes","no"|}$0',
-        markdownString: 'yes or no',
+        snippetString: 'dfdl:documentFinalTerminatorCanBeMissing="${1|yes,no|}"$0',
+        markdownString: 'Specifies whether the final line can be missing',
       },
       {
         item:'dfdl:emptyValueDelimiterPolicy',
-        snippetString: 'dfdl:emptyValueDelimiterPolicy=${1|"initiator","terminator","both","none"|}$0',
-        markdownString: 'initiator,terminator,both, or none',
+        snippetString: 'dfdl:emptyValueDelimiterPolicy="${1|initiator,terminator,both,none|}"$0',
+        markdownString: 'Indicates which of initiator, terminator, both, or neither must be present when an element in the data stream is empty.',
+      },
+      {
+        item: 'dfdl:escapeSchemeRef',
+        snippetString: 'dfdl:escapeSchemeRef="$1"$0',
+        markdownString: "Refers to a named escape scheme definition via its qualified name",
+      },
+      {
+        item: 'testKind',
+        snippetString: 'testKind="${1|expression,pattern|}"$0',
+        markdownString: 'Specifies whether a DFDL expression or DFDL regular expression pattern is used in the dfdl:assert',
+      },
+      {
+        item: 'test',
+        snippetString: 'dfdl:test="{$1}"$0',
+        markdownString: 'A DFDL expression that evaluates to true or false.',
+      },
+      {
+        item: 'testPattern',
+        snippetString: 'testPattern="$1"$0',
+        markdownString: 'A DFDL regular expression that is applied against the data stream',
+      },
+      {
+        item: 'message',
+        snippetString: 'message="$1"$0',
+        markdownString: 'Defines text for use in an error message',
       },
       {
-        item: nsPrefix + 'restriction',
-        // use the "xs:" prefix for primitive types to differentiate them from custom simple types
-        snippetString: '<' + nsPrefix + 'restriction base="${1|xs:string,xs:decimal,xs:float,xs:double,xs:integer,xs:nonNegativeInteger,xs:int,xs:unsignedInt,xs:short,xs:unsignedShort,xs:long,xs:unsignedLong,xs:byte,xs:unsignedByte,xs:hexBinary,xs:boolean|}"/>$0',
-        markdownString: 'specify ',
+        item: 'failureType',
+        snippetString: 'failureType="${1|processingError,recoverableError|}"$0',
+        markdownString: 'Specifies the type of failure that occurs when the dfdl:assert is unsuccessful',
       },
     ],
   }
diff --git a/src/language/providers/intellisense/elementItems.ts b/src/language/providers/intellisense/elementItems.ts
index 2dcb5da..a79f43f 100644
--- a/src/language/providers/intellisense/elementItems.ts
+++ b/src/language/providers/intellisense/elementItems.ts
@@ -34,39 +34,37 @@ export const elementCompletion = (definedVariables, dfdlFormatString, nsPrefix)
       {
         item: nsPrefix + 'element name',
         snippetString: '<' + nsPrefix + 'element name="$1"$0',
-        markdownString: 'A new xs element',
+        markdownString: 'Defines an xs element',
       },
       {
         item: nsPrefix + 'element ref',
         snippetString: '<' + nsPrefix + 'element ref="$1"$0',
-        markdownString: 'A new dfdl reference to an item',
+        markdownString: 'Defines a reference to a declared element',
       },
       {
         item: nsPrefix + 'group name',
         snippetString: '<' + nsPrefix + 'group name = "$1">\n\t$0\n</' + nsPrefix + 'group>',
+        markdownString: 'Defines a named model group to be reused later',
       },
       {
         item: nsPrefix + 'group ref',
         snippetString: '<' + nsPrefix + 'group ref="$1"$0',
-        markdownString: 'A new dfdl reference to an item',
+        markdownString: 'Defines a reference to a group declaration',
       },
       {
         item: 'dfdl:assert',
         snippetString: '<dfdl:assert>$1\n</dfdl:assert>$0',
-        markdownString: 'dfdl assertion test',
+        markdownString: 'Used to assert truths about a DFDL model',
       },
       {
         item: 'dfdl:discriminator',
         snippetString: '<dfdl:discriminator test="{$1}"/>$0',
-        markdownString: 'dfdl discriminator test',
-      },
-      {
-        item: 'dfdl:hiddenGroupRef',
-        snippetString: '<' + nsPrefix + 'sequence dfdl:hiddenGroupRef="$1"/>\n$0',
+        markdownString: 'Used during parsing to resolve points or uncertainity, remove ambiguity during speculative parsing, improve diagnostic behavior',
       },
       {
         item: 'dfdl:format',
         snippetString: '<dfdl:format $0/>',
+        markdownString: 'Defines the physical data format properties for multiple DFDL schema constructs',
       },
       {
         item: nsPrefix + 'annotation',
@@ -79,54 +77,89 @@ export const elementCompletion = (definedVariables, dfdlFormatString, nsPrefix)
       {
         item: nsPrefix + 'complexType',
         snippetString: '<' + nsPrefix + 'complexType>\n\t$0\n</' + nsPrefix + 'complexType>',
-        markdownString: 'Starts a complex type definition',
+        markdownString: 'Defines a complex type definition',
       },
       {
         item: nsPrefix + 'complexType name=',
-        snippetString: '<' + nsPrefix + 'complexType Name="$1">\n\t$0\n</' + nsPrefix + 'complexType>',
-        markdownString: 'Starts a complex type definition',
+        snippetString: '<' + nsPrefix + 'complexType name="$1">\n\t$0\n</' + nsPrefix + 'complexType>',
+        markdownString: 'Defines a complex type definition',
       },
       {
         item: nsPrefix + 'simpleType',
-        snippetString: '<' + nsPrefix + 'simpleType>\n\t$0\n</' + nsPrefix + 'simpleType>',
-        markdownString: 'Starts a simple type definition',
+        snippetString: '<' + nsPrefix + 'simpleType$1>\n\t$0\n</' + nsPrefix + 'simpleType>',
+        markdownString: 'Defines a simple type definition',
       },
       {
         item: nsPrefix + 'simpleType name=',
-        snippetString: '<' + nsPrefix + 'simpleType Name="$1"$0',
-        markdownString: 'Starts a simple type definition',
+        snippetString: '<' + nsPrefix + 'simpleType name="$1"$0',
+        markdownString: 'Defines simple type definition',
       },
       {
         item: nsPrefix + 'sequence',
         snippetString: '<' + nsPrefix + 'sequence',
+        markdownString: 'Specifies that the child elements must appear in a sequence',
       },
       {
         item: nsPrefix + 'choice',
         snippetString: '<' + nsPrefix + 'choice',
+        markdownString: 'Define group of mutually exclusive elements that resolve points of uncertainty that cannot be resolved by speculative parsing',
       },
       {
         item: 'dfdl:defineVariable',
         snippetString: '<dfdl:defineVariable name="$1"$0',
+        markdownString: 'Defines the name, type, and optionally default value for the variable.',
       },
       {
         item: 'dfdl:setVariable',
         snippetString: '<dfdl:setVariable ref="${1|' + definedVariables + '"|}, value="$2"$0',
+        markdownString: 'Sets the value of a variable whose declaration is in scope',
       },
       {
         item: 'dfdl:defineFormat',
         snippetString: '<dfdl:defineFormat name="$1">\n\t$2\n</dfdl:defineFormat>$0',
-        markdownString: 'dfdl format name and configuration',
+        markdownString: 'Defines a named reusable format definition',
       },
       {
         item: 'dfdl:defineEscapeScheme',
         snippetString: '<dfdl:defineEscapeScheme name=$1 >\n\t$0,/dfdl:defineEscapeScheme>',
-        markdownString: 'dfdl escape character definition',
+        markdownString: 'Defines a named, reusable escapeScheme',
+      },
+      {
+        item: 'dfdl:simpleType',
+        snippetString: '<dfdl:simpleType $1/>$0',
+        markdownString: 'Defines the physical data format properties of an xs:simpleType',
       },
-      /*TODO not sure how to make dfdl:element work without braking xs:element 
       {
         item: 'dfdl:element',
-        snippetString: '\t<dfdl:defineVariable name="$1"$0',
-      },*/
+        snippetString: '<dfdl:element $1/>$0',
+        markdownString: 'Defines the physical data format properties of an xs:element and xs:element reference',
+      },
+      {
+        item: 'restriction',
+        // use the "xs:" prefix for primitive types to differentiate them from custom simple types
+        snippetString: '<' + nsPrefix + 'restriction base="${1|xs:string,xs:decimal,xs:float,xs:double,xs:integer,xs:nonNegativeInteger,xs:int,xs:unsignedInt,xs:short,xs:unsignedShort,xs:long,xs:unsignedLong,xs:byte,xs:unsignedByte,xs:hexBinary,xs:boolean|}"$0',
+        markdownString: 'Specify type the element is restricted to',
+      },
+      {
+        item: 'minInclusive',
+        snippetString: '<' + nsPrefix + 'minInclusive value="$1"/>$0',
+        markdownString: 'Used to check the validity of an element'
+      },
+      {
+        item: 'minExclusive',
+        snippetString: '<' + nsPrefix + 'minExclusive value="$1"/>$0',
+        markdownString: 'Used to check the validity of an element'
+      },
+      {
+        item: 'maxInclusive',
+        snippetString: '<' + nsPrefix + 'maxInclusive value="$1"/>$0',
+        markdownString: 'Used to check the validity of an element'
+      },
+      {
+        item: 'maxExclusive',
+        snippetString: '<' + nsPrefix + 'maxExclusive value="$1"/>$0',
+        markdownString: 'Used to check the validity of an element'
+      },
     ],
   }
 }
diff --git a/src/language/providers/utils.ts b/src/language/providers/utils.ts
index d8788bf..205cbe0 100644
--- a/src/language/providers/utils.ts
+++ b/src/language/providers/utils.ts
@@ -36,6 +36,9 @@ const items = [
   'format',
   'defineVariable',
   'setVariable',
+  'dfdl:element',
+  'dfdl:simpleType',
+  'restriction',
   'schema',
   'xml version',
 ]
@@ -134,8 +137,8 @@ export function nearestTag(
     }
   } else {
     if (
-      (startLine === triggerLine && tagPos === startPos) ||
-      triggerText.trim() === ''
+      startLine === triggerLine &&
+      (tagPos === startPos || triggerText.trim() === '')
     ) {
       --lineNum
     }
@@ -171,14 +174,18 @@ export function checkTagOpen(
   let triggerLine = position.line
   let triggerText = document.lineAt(triggerLine).text
   let itemsOnLine = getItemsOnLineCount(triggerText)
-  const origTriggerText = triggerText
+  let isMultiLineTag = false
+  let origTriggerText = triggerText
+  let origTriggerLine = triggerLine
   while (itemsOnLine < 2 && triggerText.indexOf('<') === -1) {
     triggerText = document.lineAt(--triggerLine).text
   }
-
+  if (!(triggerText.endsWith('>') && triggerText.includes('<'))) {
+    isMultiLineTag = true
+  }
   const triggerPos = position.character
   const textBeforeTrigger = triggerText.substring(0, triggerPos)
-  const tagPos = textBeforeTrigger.lastIndexOf('<' + nsPrefix + tag)
+  let tagPos = textBeforeTrigger.lastIndexOf('<' + nsPrefix + tag)
   const nextTagPos = triggerText.indexOf('<', tagPos + 1)
   let tagEndPos = triggerText.indexOf('>', tagPos)
   if (tagPos > -1 && itemsOnLine > 1) {
@@ -191,21 +198,37 @@ export function checkTagOpen(
       return true
     }
   }
-  if (tagPos > -1 && itemsOnLine < 2) {
+
+  while (origTriggerText.trim() === '') {
+    origTriggerText = document.lineAt(--origTriggerLine).text
+  }
+  tagPos = triggerText.indexOf('<' + nsPrefix + tag)
+  if (itemsOnLine < 2 && tagPos > -1) {
     if (triggerText !== origTriggerText) {
       tagEndPos = origTriggerText.indexOf('>')
     }
-    if (triggerPos > tagPos && (triggerPos <= tagEndPos || tagEndPos === -1)) {
+    if (
+      (triggerPos > tagPos &&
+        triggerPos <= tagEndPos &&
+        triggerLine === position.line) ||
+      (origTriggerLine == position.line && triggerPos <= tagEndPos) ||
+      position.line < origTriggerLine
+    ) {
       return true
     }
   }
+  if (!isMultiLineTag) {
+    return false
+  }
   //if this tag is part of a multi line set of annotations return true
   //else this tag is not open return false
-  return checkMultiLineAnnotations(
+  return checkMultiLineTag(
     document,
     position,
     itemsOnLine,
     nsPrefix,
+    tagPos,
+    triggerLine,
     tag
   )
 }
@@ -221,31 +244,57 @@ export function getItemPrefix(item: string, nsPrefix: string) {
   ) {
     itemPrefix = 'dfdl:'
   }
+  if (item === 'xml version') {
+    itemPrefix = '?'
+  }
+  if (item === 'dfdl:element' || item === 'dfdl:simpleType') {
+    itemPrefix = ''
+  }
   return itemPrefix
 }
 
-export function checkMultiLineAnnotations(
+export function checkMultiLineTag(
   document: vscode.TextDocument,
   position: vscode.Position,
   itemsOnLine: number,
   nsPrefix: string,
+  tagPos: number,
+  tagLine: number,
   tag: string
 ) {
-  if (itemsOnLine > 1 || tag === 'schema') {
+  if (itemsOnLine > 1) {
     return false
   }
   let currentLine = position.line
   let currentText = document.lineAt(currentLine).text
 
-  while (currentText.trim() === '' || !currentText.includes('<')) {
-    --currentLine
-    currentText = document.lineAt(currentLine).text
+  //the current line doesn't have the self close symbol
+  if (!currentText.endsWith('/>')) {
+    while (currentText.trim() === '' || !currentText.includes('<')) {
+      --currentLine
+      currentText = document.lineAt(currentLine).text
+      if (!currentText.endsWith('/>')) {
+        break
+      }
+    }
+    if (
+      currentText.indexOf('<' + nsPrefix + tag) !== -1 &&
+      currentText.indexOf('>') === -1 &&
+      currentText.indexOf('<' + nsPrefix + tag) < position.character
+    ) {
+      return true
+    }
   }
-  if (
-    currentText.indexOf('<' + nsPrefix + tag) !== -1 &&
-    currentText.indexOf('>') === -1
-  ) {
-    return true
+  if (currentText.endsWith('/>')) {
+    let triggerPos = position.character
+    let tagEndPos = currentText.indexOf('/>')
+    let triggerLine = position.line
+    if (
+      (triggerLine <= currentLine && triggerPos < tagEndPos) ||
+      (triggerLine === tagLine && triggerPos > tagPos && tagPos !== -1)
+    ) {
+      return true
+    }
   }
   return false
 }
@@ -290,7 +339,9 @@ export function getItemsOnLineCount(triggerText: String) {
       if (
         !testForCloseTag.includes('</') &&
         !testForCloseTag.includes('<!--') &&
-        !testForCloseTag.includes('-->')
+        !testForCloseTag.includes('-->') &&
+        !testForCloseTag.includes('<[') &&
+        !testForCloseTag.includes('<![')
       ) {
         ++itemsOnLine
       }
@@ -301,52 +352,71 @@ export function getItemsOnLineCount(triggerText: String) {
   return itemsOnLine
 }
 
+export function cursorWithinBraces(
+  document: vscode.TextDocument,
+  position: vscode.Position
+) {
+  let startLine = position.line
+  let currentText = document.lineAt(startLine).text
+  let braceStartLine = startLine
+  let braceStartPos = -1
+  while (
+    braceStartLine > 0 &&
+    (braceStartPos = currentText.indexOf('{')) === -1
+  ) {
+    currentText = document.lineAt(--braceStartLine).text
+  }
+  let braceEndLine = braceStartLine
+  let braceEndPos = -1
+  if (braceStartPos > -1) {
+    while (
+      braceEndLine < document.lineCount &&
+      (braceEndPos = currentText.indexOf('}')) === -1
+    ) {
+      currentText = document.lineAt(++braceEndLine).text
+    }
+    if (braceEndPos > -1) {
+      if (
+        (position.line > braceStartLine && position.line < braceEndLine) ||
+        (braceEndLine === braceStartLine &&
+          position.character > braceStartPos &&
+          position.character <= braceEndPos) ||
+        (position.line === braceStartLine &&
+          position.character > braceStartPos &&
+          position.line < braceEndLine) ||
+        (position.line === braceEndLine &&
+          position.character <= braceEndPos &&
+          position.line > braceStartLine)
+      ) {
+        return true
+      }
+    }
+  }
+  return false
+}
+
 export function checkBraceOpen(
   document: vscode.TextDocument,
   position: vscode.Position
 ) {
   let lineNum = position.line
+  let triggerText = document.lineAt(lineNum).text
 
-  while (lineNum !== 0) {
-    const triggerText = document.lineAt(lineNum).text
-    //.text.substring(0, document.lineAt(lineNum).range.end.character)
-
-    if (!triggerText.includes('{')) {
-      return false
+  if (triggerText.includes('{')) {
+    while (!triggerText.includes('}') && lineNum < document.lineCount) {
+      triggerText = document.lineAt(++lineNum).text
     }
-    if (
-      triggerText.includes('"{') &&
-      triggerText.includes('}"') &&
-      (triggerText.includes('..') || triggerText.includes('.')) &&
-      !triggerText.includes('}"/') &&
-      !triggerText.includes('>')
-    ) {
+    if (!triggerText.includes('}')) {
       return true
     }
-    if (
-      triggerText.includes('"{') &&
-      !triggerText.includes('}"') &&
-      !triggerText.includes('}"/') &&
-      !triggerText.includes('>')
-    ) {
-      return true
+  }
+  if (triggerText.includes('}')) {
+    while (!triggerText.includes('{') && lineNum > 0) {
+      triggerText = document.lineAt(--lineNum).text
     }
-    if (
-      triggerText.includes('}"') &&
-      !triggerText.includes('}"/') &&
-      !triggerText.includes('>')
-    ) {
+    if (!triggerText.includes('{')) {
       return true
     }
-    if (
-      triggerText.includes('}"') &&
-      (triggerText.includes('}"/') ||
-        triggerText.includes('>') ||
-        triggerText.includes('/>'))
-    ) {
-      return false
-    }
-    --lineNum
   }
   return false
 }
@@ -373,7 +443,7 @@ export function createCompletionItem(
     'dfdl:representation',
     'dfdl:choiceDispatchKey=',
     'dfdl:simpleType',
-    nsPrefix + 'restriction',
+    'restriction',
   ]
 
   if (preVal !== '' && !noPreVals.includes(e.item)) {
diff --git a/src/tests/suite/language/items.test.ts b/src/tests/suite/language/items.test.ts
index 2292038..49a5a05 100644
--- a/src/tests/suite/language/items.test.ts
+++ b/src/tests/suite/language/items.test.ts
@@ -44,6 +44,13 @@ suite('Items Test Suite', () => {
     'dfdl:setVariable',
     'dfdl:defineFormat',
     'dfdl:defineEscapeScheme',
+    'dfdl:simpleType',
+    'dfdl:element',
+    'restriction',
+    'minInclusive',
+    'minExclusive',
+    'maxInclusive',
+    'maxExclusive',
   ]
   const expectedAttributeItems = [
     'name',
@@ -56,10 +63,13 @@ suite('Items Test Suite', () => {
     'dfdl:occursCountKind',
     'dfdl:length',
     'dfdl:lengthKind',
+    'dfdl:prefixIncludesPrefixLength',
+    'dfdl:prefixLengthType',
     'dfdl:utf16Width',
     'dfdl:encoding',
     'dfdl:encodingErrorPolicy',
     'dfdl:nilKind',
+    'dfdl:nilValue',
     'dfdl:nilValueDelimiterPolicy',
     'dfdl:alignment',
     'dfdl:lengthUnits',
@@ -70,7 +80,7 @@ suite('Items Test Suite', () => {
     'dfdl:outputNewLine',
     'dfdl:choiceBranchKey',
     'dfdl:representation',
-    'dfdl:hiddenGroupRef',
+    'dfdl:textStringJustification',
     'dfdl:textStandardZeroRep',
     'dfdl:textStandardInfinityRep',
     'dfdl:textStandardExponentRep',
@@ -86,6 +96,7 @@ suite('Items Test Suite', () => {
     'dfdl:textPadKind',
     'dfdl:textStandardBase',
     'dfdl:textTrimKind',
+    'dfdl:leadingSkip',
     'dfdl:trailingSkip',
     'dfdl:truncateSpecifiedLengthString',
     'dfdl:sequenceKind',
@@ -94,6 +105,7 @@ suite('Items Test Suite', () => {
     'dfdl:separatorSuppressionPolicy',
     'dfdl:terminator',
     'dfdl:textBidi',
+    'dfdl:hiddenGroupRef',
     'dfdl:choiceLengthKind',
     'dfdl:choiceLength',
     'dfdl:fillByte',
@@ -101,14 +113,18 @@ suite('Items Test Suite', () => {
     'dfdl:initiatedContent',
     'dfdl:initiator',
     'dfdl:choiceDispatchKey',
-    'dfdl:simpleType',
     'dfdl:binaryNumberRep',
     'dfdl:floating',
-    'dfdl:binaryFloatingRep',
+    'dfdl:binaryFloatRep',
     'dfdl:calendarPatternKind',
     'dfdl:documentFinalTerminatorCanBeMissing',
     'dfdl:emptyValueDelimiterPolicy',
-    'restriction',
+    'dfdl:escapeSchemeRef',
+    'testKind',
+    'test',
+    'testPattern',
+    'message',
+    'failureType',
   ]
 
   test('all commonItems available', async () => {