From 645aa7d6ec655879a741685aab8dee583462fa51 Mon Sep 17 00:00:00 2001
From: Josh Johnson <josh.johnson@leafyacre.com>
Date: Thu, 1 Mar 2018 21:50:18 -0500
Subject: [PATCH] Add XQuery Completion Provider

---
 .../xquery-completion-item-provider.ts        | 51 +++++++++++++++++++
 src/extension.ts                              |  6 +++
 2 files changed, 57 insertions(+)
 create mode 100644 src/completion/xquery-completion-item-provider.ts

diff --git a/src/completion/xquery-completion-item-provider.ts b/src/completion/xquery-completion-item-provider.ts
new file mode 100644
index 0000000..d9d9941
--- /dev/null
+++ b/src/completion/xquery-completion-item-provider.ts
@@ -0,0 +1,51 @@
+import { CompletionItem, CompletionItemKind, CompletionItemProvider, Position, TextDocument } from "vscode";
+
+const XQLint = require("xqlint").XQLint;
+
+export class XQueryCompletionItemProvider implements CompletionItemProvider {
+
+    provideCompletionItems(document: TextDocument, position: Position): CompletionItem[] {
+        const completionItems = new Array<CompletionItem>();
+        const linter = new XQLint(document.getText());
+
+        linter.getCompletions({ line: position.line, col: position.character }).forEach((x: any) => {
+            completionItems.push(this._getCompletionItem(x));
+        });
+
+        return completionItems;
+    }
+
+    private _getCompletionItem(xqLintCompletionItem: any): CompletionItem {
+        const completionItem = new CompletionItem(xqLintCompletionItem.name);
+        completionItem.insertText = xqLintCompletionItem.value;
+
+        switch (xqLintCompletionItem.meta) {
+            // functions (always qualified with a colon)
+            case "function":
+                completionItem.kind = CompletionItemKind.Function;
+
+                const funcStart = (xqLintCompletionItem.value.indexOf(":") + 1);
+                const funcEnd = xqLintCompletionItem.value.indexOf("(");
+
+                completionItem.insertText = xqLintCompletionItem.value.substring(funcStart, funcEnd);
+            break;
+
+            // variables and parameters (always qualified with a dollar sign)
+            case "Let binding":
+            case "Local variable":
+            case "Window variable":
+            case "Function parameter":
+                completionItem.kind = CompletionItemKind.Variable;
+                completionItem.insertText = xqLintCompletionItem.value.substring(1);
+            break;
+
+            // everything else
+            default:
+                completionItem.kind = CompletionItemKind.Text;
+            break;
+        }
+
+        return completionItem;
+    }
+
+}
\ No newline at end of file
diff --git a/src/extension.ts b/src/extension.ts
index eb4fcb3..834d097 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -1,6 +1,7 @@
 import { languages, window, workspace, commands } from "vscode";
 import { ExtensionContext, TextEditor, TextEditorSelectionChangeEvent, WorkspaceConfiguration } from "vscode";
 
+import { XQueryCompletionItemProvider } from "./completion/xquery-completion-item-provider";
 import { FormatAsXmlCommandName, formatAsXml } from "./formatting/commands/formatAsXml";
 import { MinifyXmlCommandName, minifyXml } from "./formatting/commands/minifyXml";
 import { XmlFormatterFactory } from "./formatting/xml-formatter";
@@ -12,6 +13,11 @@ import * as constants from "./constants";
 export function activate(context: ExtensionContext) {
     const config = workspace.getConfiguration(constants.extensionPrefix);
 
+    /* Completion Features */
+    context.subscriptions.push(
+        languages.registerCompletionItemProvider("xquery", new XQueryCompletionItemProvider(), ":", "$")
+    );
+
     /* Formatting Features */
     const xmlFormattingEditProvider = new XmlFormattingEditProvider(config, XmlFormatterFactory.getXmlFormatter());