diff --git a/src/features/xmlFormatting.ts b/src/features/xmlFormatting.ts
index e3bf197..5c2fe3e 100644
--- a/src/features/xmlFormatting.ts
+++ b/src/features/xmlFormatting.ts
@@ -1,22 +1,132 @@
'use strict';
-import { TextEditor, TextEditorEdit } from 'vscode';
+import {
+Range,
+TextEdit,
+TextEditor,
+TextDocument,
+TextEditorEdit,
+CancellationToken,
+FormattingOptions,
+DocumentFormattingEditProvider,
+DocumentRangeFormattingEditProvider
+} from 'vscode';
+
import { getRangeForDocument } from '../utils/RangeUtils';
-let pd = require('pretty-data').pd;
-
-export function formatXml(editor: TextEditor, edit: TextEditorEdit): void {
- let current = editor.document.getText();
- let pretty = pd.xml(current);
- let range = getRangeForDocument(editor.document);
-
- edit.replace(range, pretty);
-}
-
export function linearizeXml(editor: TextEditor, edit: TextEditorEdit): void {
let current = editor.document.getText();
- let linear = pd.xmlmin(current);
let range = getRangeForDocument(editor.document);
+
+ edit.replace(range, _linearizeXml(current));
+}
+
+export class XmlDocumentFormattingProvider implements DocumentFormattingEditProvider {
+ provideDocumentFormattingEdits(document: TextDocument, options: FormattingOptions, token: CancellationToken): TextEdit[] {
+ let current = document.getText();
+ let range = getRangeForDocument(document);
+
+ return [TextEdit.replace(range, _formatXml(current, options))];
+ }
+}
+
+export class XmlRangeFormattingProvider implements DocumentRangeFormattingEditProvider {
+ provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): TextEdit[] {
+ let current = document.getText(range);
+
+ return [TextEdit.replace(range, _formatXml(current, options))];
+ }
+}
+
+function _strRepeat(source: string, count: number): string {
+ let output = '';
- edit.replace(range, linear);
+ for (let i = 0; i < count; i++) {
+ output += source;
+ }
+
+ return output;
+}
+
+function _linearizeXml(xml: string): string {
+ return xml.replace(/>\s{0,}<');
+}
+
+function _formatXml(xml: string, options: FormattingOptions): string {
+ /* This code was taken from https://github.com/vkiryukhin/pretty-data/blob/master/pretty-data.js
+ * and refactored to fit our needs for this extension. pretty-data is dual-licensed (MIT/GPL).
+ */
+
+ let parts = _linearizeXml(xml)
+ .replace(/ -1) {
+ output += _strRepeat(tab, deep) + parts[i];
+ formatted = true;
+
+ // end comment, CDATA, or DOCTYPE
+ if (parts[i].search(/-->/) > -1 || parts[i].search(/\]>/) > -1 || parts[i].search(/!DOCTYPE/) > -1) {
+ formatted = false;
+ }
+ }
+
+ // end comment or CDATA
+ else if (parts[i].search(/-->/) > -1 || parts[i].search(/\]>/) > -1) {
+ output += parts[i];
+ formatted = false;
+ }
+
+ //
+ else if (/^<\w/.exec(parts[i - 1]) && /^<\/\w/.exec(parts[i]) && (/^<[\w:\-\.\,]+/.exec(parts[i - 1])[0] == /^<\/[\w:\-\.\,]+/.exec(parts[i])[0].replace('/','')) {
+ output += parts[i];
+ if (!formatted) deep--;
+ }
+
+ //
+ else if (parts[i].search(/<\w/) > -1 && parts[i].search(/<\//) == -1 && parts[i].search(/\/>/) == -1 ) {
+ output = !formatted ? output += _strRepeat(tab, deep++) + parts[i] : output += parts[i];
+ }
+
+ // ...
+ else if (parts[i].search(/<\w/) > -1 && parts[i].search(/<\//) > -1) {
+ output = !formatted ? output += _strRepeat(tab, deep) + parts[i] : output += parts[i];
+ }
+
+ //
+ else if (parts[i].search(/<\//) > -1) {
+ output = !formatted ? output += _strRepeat(tab, --deep) + parts[i] : output += parts[i];
+ }
+
+ //
+ else if (parts[i].search(/\/>/) > -1) {
+ output = !formatted ? output += _strRepeat(tab, deep) + parts[i] : output += parts[i];
+ }
+
+ //
+ else if (parts[i].search(/<\?/) > -1) {
+ output += _strRepeat(tab, deep) + parts[i];
+ }
+
+ // xmlns
+ else if (parts[i].search(/xmlns\:/) > -1 || parts[i].search(/xmlns\=/) > -1) {
+ output += _strRepeat(tab, deep) + parts[i];
+ }
+
+ else {
+ output += parts[i];
+ }
+ }
+
+ return output;
}
\ No newline at end of file
diff --git a/src/main.ts b/src/main.ts
index 9d7473f..c9ff199 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,7 +1,7 @@
'use strict';
-import { commands, ExtensionContext } from 'vscode';
-import { formatXml, linearizeXml } from './features/xmlFormatting';
+import { commands, languages, ExtensionContext } from 'vscode';
+import { linearizeXml, XmlDocumentFormattingProvider, XmlRangeFormattingProvider } from './features/xmlFormatting';
import { evaluateXPath } from './features/xmlXPathEngine';
import { checkForUpdates } from './utils/UpdateNotifier';
@@ -10,7 +10,10 @@ export function activate(ctx: ExtensionContext) {
checkForUpdates();
// register palette commands
- ctx.subscriptions.push(commands.registerTextEditorCommand('xmltools.formatXml', formatXml));
ctx.subscriptions.push(commands.registerTextEditorCommand('xmltools.linearizeXml', linearizeXml));
ctx.subscriptions.push(commands.registerTextEditorCommand('xmltools.evaluateXPath', evaluateXPath));
+
+ // register formatting providers
+ ctx.subscriptions.push(languages.registerDocumentFormattingEditProvider('xml', new XmlDocumentFormattingProvider()));
+ ctx.subscriptions.push(languages.registerDocumentRangeFormattingEditProvider('xml', new XmlRangeFormattingProvider()));
}
\ No newline at end of file