diff --git a/languages/xquery/xquery.json b/languages/xquery/xquery.json
index 17f4dc4..1ce9409 100644
--- a/languages/xquery/xquery.json
+++ b/languages/xquery/xquery.json
@@ -1,10 +1,7 @@
{
"comments": {
- "lineComment": "//",
- "blockComment": [
- "/*",
- "*/"
- ]
+ "lineComment": ["(:", ":)"],
+ "blockComment": [ "(:~", "~:)"]
},
"brackets": [
[
@@ -20,4 +17,4 @@
")"
]
]
-}
\ No newline at end of file
+}
diff --git a/languages/xquery/xquery.tmLanguage b/languages/xquery/xquery.tmLanguage
index e4c5a42..24a2f1a 100644
--- a/languages/xquery/xquery.tmLanguage
+++ b/languages/xquery/xquery.tmLanguage
@@ -768,7 +768,7 @@
doublequotedString
begin
- (?<![-_a-zA-Z0-9:]>)\s*"(?!\s*</[-_a-zA-Z0-9:])
+ (?<![-_a-zA-Z0-9:'"]>)\s*"(?![\w\s()']*</[-_a-zA-Z0-9:])
beginCaptures
0
@@ -929,7 +929,7 @@
singlequotedString
begin
- (?<![-_a-zA-Z0-9:]>)\s*'(?!\s*</[-_a-zA-Z0-9:])
+ (?<![-_a-zA-Z0-9:'"]>)\s*'(?![\w\s()"]*</[-_a-zA-Z0-9:])
beginCaptures
0
diff --git a/package-lock.json b/package-lock.json
index d971c4d..fe9ebfa 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "xml",
- "version": "2.0.0-preview.2",
+ "version": "2.3.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 9b5ef17..b9e8013 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,8 @@
"onCommand:xmlTools.evaluateXPath",
"onCommand:xmlTools.executeXQuery",
"onCommand:xmlTools.formatAsXml",
+ "onCommand:xmlTools.textToXml",
+ "onCommand:xmlTools.xmlToText",
"onCommand:xmlTools.minifyXml",
"onLanguage:xml",
"onLanguage:xquery",
@@ -55,6 +57,14 @@
"command": "xmlTools.formatAsXml",
"title": "XML Tools: Format as XML"
},
+ {
+ "command": "xmlTools.textToXml",
+ "title": "XML Tools: Convert text to XML (<> -> <>)"
+ },
+ {
+ "command": "xmlTools.xmlToText",
+ "title": "XML Tools: Convert XML to text (<> -> <>)"
+ },
{
"command": "xmlTools.getCurrentXPath",
"title": "XML Tools: Get Current XPath"
@@ -183,6 +193,16 @@
}
],
"languages": [
+ {
+ "id": "xml",
+ "extensions": [
+ ".config",
+ ".csproj",
+ ".xml",
+ ".xsd",
+ ".xsl"
+ ]
+ },
{
"id": "xquery",
"aliases": [
@@ -257,4 +277,4 @@
"xpath": "0.0.27",
"xqlint": "^0.4.1"
}
-}
+}
\ No newline at end of file
diff --git a/src/constants.ts b/src/constants.ts
index 6261aee..07d969e 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -2,6 +2,8 @@ export namespace commands {
export const evaluateXPath = "xmlTools.evaluateXPath";
export const executeXQuery = "xmlTools.executeXQuery";
export const formatAsXml = "xmlTools.formatAsXml";
+ export const xmlToText = "xmlTools.xmlToText";
+ export const textToXml = "xmlTools.textToXml";
export const getCurrentXPath = "xmlTools.getCurrentXPath";
export const minifyXml = "xmlTools.minifyXml";
}
diff --git a/src/extension.ts b/src/extension.ts
index ee975af..17b41b2 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -1,12 +1,12 @@
import {
commands, languages, window, workspace, ExtensionContext, Memento,
- TextEditor, TextEditorSelectionChangeEvent, TextEditorSelectionChangeKind
+ TextEditor, TextEditorSelectionChangeEvent, TextEditorSelectionChangeKind, DiagnosticCollection
} from "vscode";
import { createDocumentSelector, ExtensionState, Configuration } from "./common";
import { XQueryCompletionItemProvider } from "./completion";
import { XmlFormatterFactory, XmlFormattingEditProvider } from "./formatting";
-import { formatAsXml, minifyXml } from "./formatting/commands";
+import { formatAsXml, minifyXml, xmlToText, textToXml } from "./formatting/commands";
import { XQueryLinter } from "./linting";
import { XmlTreeDataProvider } from "./tree-view";
import { evaluateXPath, getCurrentXPath } from "./xpath/commands";
@@ -14,6 +14,8 @@ import { executeXQuery } from "./xquery-execution/commands";
import * as constants from "./constants";
+let diagnosticCollectionXQuery: DiagnosticCollection;
+
export function activate(context: ExtensionContext) {
ExtensionState.configure(context);
@@ -30,13 +32,17 @@ export function activate(context: ExtensionContext) {
context.subscriptions.push(
commands.registerTextEditorCommand(constants.commands.formatAsXml, formatAsXml),
+ commands.registerTextEditorCommand(constants.commands.xmlToText, xmlToText),
+ commands.registerTextEditorCommand(constants.commands.textToXml, textToXml),
commands.registerTextEditorCommand(constants.commands.minifyXml, minifyXml),
languages.registerDocumentFormattingEditProvider(xmlXsdDocSelector, xmlFormattingEditProvider),
languages.registerDocumentRangeFormattingEditProvider(xmlXsdDocSelector, xmlFormattingEditProvider)
);
/* Linting Features */
+ diagnosticCollectionXQuery = languages.createDiagnosticCollection(constants.diagnosticCollections.xquery);
context.subscriptions.push(
+ diagnosticCollectionXQuery,
window.onDidChangeActiveTextEditor(_handleChangeActiveTextEditor),
window.onDidChangeTextEditorSelection(_handleChangeTextEditorSelection)
);
@@ -85,9 +91,7 @@ function _handleContextChange(editor: TextEditor): void {
switch (editor.document.languageId) {
case constants.languageIds.xquery:
- languages
- .createDiagnosticCollection(constants.diagnosticCollections.xquery)
- .set(editor.document.uri, new XQueryLinter().lint(editor.document.getText()));
+ diagnosticCollectionXQuery.set(editor.document.uri, new XQueryLinter().lint(editor.document.getText()));
break;
}
}
diff --git a/src/formatting/commands/index.ts b/src/formatting/commands/index.ts
index 3e12b40..3dc6ea2 100644
--- a/src/formatting/commands/index.ts
+++ b/src/formatting/commands/index.ts
@@ -1,2 +1,4 @@
export * from "./formatAsXml";
export * from "./minifyXml";
+export * from "./xmlToText";
+export * from "./textToXml";
diff --git a/src/formatting/commands/textToXml.ts b/src/formatting/commands/textToXml.ts
new file mode 100644
index 0000000..de2884f
--- /dev/null
+++ b/src/formatting/commands/textToXml.ts
@@ -0,0 +1,26 @@
+import { workspace } from "vscode";
+import { ProviderResult, Range, TextEdit, TextEditor, Selection } from "vscode";
+
+import { NativeCommands } from "../../common";
+import * as constants from "../../constants";
+
+import { XmlFormatterFactory } from "../xml-formatter";
+import { XmlFormattingEditProvider } from "../xml-formatting-edit-provider";
+import { XmlFormattingOptionsFactory } from "../xml-formatting-options";
+
+export function textToXml(textEditor: TextEditor): void {
+ textEditor.edit(textEdit => {
+ const selections = textEditor.selections;
+ selections.forEach(selection => {
+ if (selection.isEmpty) {
+ selection = new Selection(
+ textEditor.document.positionAt(0),
+ textEditor.document.positionAt(textEditor.document.getText().length)
+ );
+ }
+ const txt = textEditor.document.getText(new Range(selection.start, selection.end));
+ const transformed = txt.replace(/</g, "<").replace(/>/g, ">");
+ textEdit.replace(selection, transformed);
+ });
+ });
+}
diff --git a/src/formatting/commands/xmlToText.ts b/src/formatting/commands/xmlToText.ts
new file mode 100644
index 0000000..f3d63ac
--- /dev/null
+++ b/src/formatting/commands/xmlToText.ts
@@ -0,0 +1,26 @@
+import { workspace } from "vscode";
+import { ProviderResult, Range, TextEdit, TextEditor, Selection } from "vscode";
+
+import { NativeCommands } from "../../common";
+import * as constants from "../../constants";
+
+import { XmlFormatterFactory } from "../xml-formatter";
+import { XmlFormattingEditProvider } from "../xml-formatting-edit-provider";
+import { XmlFormattingOptionsFactory } from "../xml-formatting-options";
+
+export function xmlToText(textEditor: TextEditor): void {
+ textEditor.edit(textEdit => {
+ const selections = textEditor.selections;
+ selections.forEach(selection => {
+ if (selection.isEmpty) {
+ selection = new Selection(
+ textEditor.document.positionAt(0),
+ textEditor.document.positionAt(textEditor.document.getText().length)
+ );
+ }
+ const txt = textEditor.document.getText(new Range(selection.start, selection.end));
+ const transformed = txt.replace(//g, ">");
+ textEdit.replace(selection, transformed);
+ });
+ });
+}
diff --git a/src/formatting/formatters/v2-xml-formatter.ts b/src/formatting/formatters/v2-xml-formatter.ts
index f7934d3..d28a731 100644
--- a/src/formatting/formatters/v2-xml-formatter.ts
+++ b/src/formatting/formatters/v2-xml-formatter.ts
@@ -20,7 +20,7 @@ export class V2XmlFormatter implements XmlFormatter {
xml = xml.replace(/"\s+(?=[^\s]+=)/g, "\" "); // spaces between attributes
xml = xml.replace(/"\s+(?=>)/g, "\""); // spaces between the last attribute and tag close (>)
xml = xml.replace(/"\s+(?=\/>)/g, "\" "); // spaces between the last attribute and tag close (/>)
- xml = xml.replace(/[^ <>="]\s+[^ <>="]+=/g, (match: string) => { // spaces between the node name and the first attribute
+ xml = xml.replace(/(?!="]\s+[^ <>="]+=(?![^<]*?\]\]>)/g, (match: string) => { // spaces between the node name and the first attribute
return match.replace(/\s+/g, " ");
});
@@ -29,7 +29,7 @@ export class V2XmlFormatter implements XmlFormatter {
let output = "";
- let indentLevel = 0;
+ let indentLevel = options.initialIndentLevel || 0;
let attributeQuote = "";
let lineBreakSpree = false;
let lastWordCharacter: string | undefined;
@@ -194,7 +194,7 @@ export class V2XmlFormatter implements XmlFormatter {
&& cc === "/"
&& pc !== " "
&& options.enforcePrettySelfClosingTagOnFormat) {
- output += " /";
+ output += " /";
}
// exiting StartTag or StartTag.StartTagName, entering Text
diff --git a/src/formatting/xml-formatting-edit-provider.ts b/src/formatting/xml-formatting-edit-provider.ts
index 6a7f9f2..a64c05c 100644
--- a/src/formatting/xml-formatting-edit-provider.ts
+++ b/src/formatting/xml-formatting-edit-provider.ts
@@ -22,10 +22,43 @@ export class XmlFormattingEditProvider implements DocumentFormattingEditProvider
}
provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult {
- let xml = document.getText(range);
+ const allXml = document.getText();
+ let selectedXml = document.getText(range);
+ const extFormattingOptions = XmlFormattingOptionsFactory.getXmlFormattingOptions(options, document);
- xml = this.xmlFormatter.formatXml(xml, XmlFormattingOptionsFactory.getXmlFormattingOptions(options, document));
+ const selectionStartOffset = document.offsetAt(range.start);
+ let tabCount = 0;
+ let spaceCount = 0;
- return [ TextEdit.replace(range, xml) ];
+ for (let i = (selectionStartOffset - 1); i >= 0; i--) {
+ const cc = allXml.charAt(i);
+
+ if (/\t/.test(cc)) {
+ tabCount++;
+ }
+
+ else if (/ /.test(cc)) {
+ spaceCount++;
+ }
+
+ else {
+ break;
+ }
+ }
+
+ if (options.insertSpaces) {
+ extFormattingOptions.initialIndentLevel = Math.ceil(spaceCount / (options.tabSize || 1));
+ }
+
+ else {
+ extFormattingOptions.initialIndentLevel = tabCount;
+ }
+
+ selectedXml = this.xmlFormatter.formatXml(selectedXml, extFormattingOptions);
+
+ // we need to remove the leading whitespace because the formatter will add an indent before the first element
+ selectedXml = selectedXml.replace(/^\s+/, "");
+
+ return [TextEdit.replace(range, selectedXml)];
}
}
diff --git a/src/formatting/xml-formatting-options.ts b/src/formatting/xml-formatting-options.ts
index 06782a1..7c5185a 100644
--- a/src/formatting/xml-formatting-options.ts
+++ b/src/formatting/xml-formatting-options.ts
@@ -10,6 +10,7 @@ export interface XmlFormattingOptions {
removeCommentsOnMinify: boolean;
splitAttributesOnFormat: boolean;
splitXmlnsOnFormat: boolean;
+ initialIndentLevel?: number;
}
export class XmlFormattingOptionsFactory {
@@ -20,7 +21,8 @@ export class XmlFormattingOptionsFactory {
newLine: (document.eol === EndOfLine.CRLF) ? "\r\n" : "\n",
removeCommentsOnMinify: Configuration.removeCommentsOnMinify(document.uri),
splitAttributesOnFormat: Configuration.splitAttributesOnFormat(document.uri),
- splitXmlnsOnFormat: Configuration.splitXmlnsOnFormat(document.uri)
+ splitXmlnsOnFormat: Configuration.splitXmlnsOnFormat(document.uri),
+ initialIndentLevel: 0
};
}
}
diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts
index 8c3627b..675aa6b 100644
--- a/src/test/extension.test.ts
+++ b/src/test/extension.test.ts
@@ -92,6 +92,9 @@ describe("V2XmlFormatter", () => {
testFormatter(xmlFormatter, options, "issue-200");
});
+ it("should not remove spaces between the node name and the first attribute within CDATA", () => {
+ testFormatter(xmlFormatter, options, "issue-227");
+ });
});
});
diff --git a/src/test/test-data/issue-227.formatted.xml b/src/test/test-data/issue-227.formatted.xml
new file mode 100644
index 0000000..d4ead94
--- /dev/null
+++ b/src/test/test-data/issue-227.formatted.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/test-data/issue-227.unformatted.xml b/src/test/test-data/issue-227.unformatted.xml
new file mode 100644
index 0000000..b55e3f3
--- /dev/null
+++ b/src/test/test-data/issue-227.unformatted.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file