diff --git a/package.json b/package.json index 86f6c6a..857bf4b 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "url": "https://github.com/TrueCommerce/vscode-xml/wiki" }, "engines": { - "vscode": "^0.10.6", + "vscode": "^0.10.7", "node": "*" }, "categories": [ @@ -44,6 +44,10 @@ { "command": "xmlTools.executeXQuery", "title": "XML Tools: Execute XQuery" + }, + { + "command": "xmlTools.viewXmlTree", + "title": "XML Tools: View XML Tree" } ], "configuration": { @@ -113,10 +117,11 @@ "onLanguage:xquery", "onCommand:xmlTools.minifyXml", "onCommand:xmlTools.evaluateXPath", - "onCommand:xmlTools.executeXQuery" + "onCommand:xmlTools.executeXQuery", + "onCommand:xmlTools.viewXmlTree" ], "devDependencies": { - "vscode": "^0.10.7", + "vscode": "^0.11.x", "typescript": "^1.6.2", "gulp": "^3.9.0", "gulp-shell": "^0.5.1" @@ -127,6 +132,7 @@ "xqlint": "^0.2.9" }, "scripts": { - "vscode:prepublish": "tsc" + "vscode:prepublish": "tsc", + "postinstall": "node ./node_modules/vscode/bin/install" } } diff --git a/src/Commands.ts b/src/Commands.ts index 44980af..0941d26 100644 --- a/src/Commands.ts +++ b/src/Commands.ts @@ -7,6 +7,7 @@ import { RangeUtil } from './utils/RangeUtil'; import { XmlFormatter } from './services/XmlFormatter'; import { XPathFeatureProvider } from './providers/XPath'; import { XQueryExecutionProvider } from './providers/Execution'; +import { XmlTreeDocumentContentProvider } from './providers/Content'; const CFG_SECTION: string = 'xmlTools'; const CFG_REMOVE_COMMENTS: string = 'removeCommentsOnMinify'; @@ -30,4 +31,17 @@ export class TextEditorCommands { static executeXQuery(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): void { XQueryExecutionProvider.executeXQueryAsync(editor); } + + static async viewXmlTree(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): Promise { + try { + await vsc.commands.executeCommand( + 'vscode.previewHtml', + XmlTreeDocumentContentProvider.buildUri(editor.document.uri), + vsc.ViewColumn.Three); + } + + catch (error) { + vsc.window.showErrorMessage(`The XML Tree could not be created: ${error}`); + } + } } \ No newline at end of file diff --git a/src/Extension.ts b/src/Extension.ts index 582a4ce..9d4c562 100644 --- a/src/Extension.ts +++ b/src/Extension.ts @@ -5,6 +5,7 @@ import { TextEditorCommands } from './Commands'; import { XmlFormattingEditProvider } from './providers/Formatting'; import { XQueryLintingFeatureProvider } from './providers/Linting'; import { XQueryCompletionItemProvider } from './providers/Completion'; +import { XmlTreeDocumentContentProvider } from './providers/Content'; export var GlobalState: vsc.Memento; export var WorkspaceState: vsc.Memento; @@ -23,8 +24,8 @@ export function activate(ctx: vsc.ExtensionContext) { ctx.subscriptions.push( vsc.commands.registerTextEditorCommand('xmlTools.minifyXml', TextEditorCommands.minifyXml), vsc.commands.registerTextEditorCommand('xmlTools.evaluateXPath', TextEditorCommands.evaluateXPath), - - vsc.commands.registerTextEditorCommand('xmlTools.executeXQuery', TextEditorCommands.executeXQuery) + vsc.commands.registerTextEditorCommand('xmlTools.executeXQuery', TextEditorCommands.executeXQuery), + vsc.commands.registerTextEditorCommand('xmlTools.viewXmlTree', TextEditorCommands.viewXmlTree) ); // register language feature providers @@ -35,6 +36,11 @@ export function activate(ctx: vsc.ExtensionContext) { vsc.languages.registerCompletionItemProvider(LANG_XQUERY, new XQueryCompletionItemProvider(), ':', '$') ); + // register workspace feature providers + ctx.subscriptions.push( + vsc.workspace.registerTextDocumentContentProvider(XmlTreeDocumentContentProvider.SCHEME, new XmlTreeDocumentContentProvider()) + ); + // listen to editor events (for linting) ctx.subscriptions.push( vsc.window.onDidChangeActiveTextEditor(_handleChangeActiveTextEditor), diff --git a/src/providers/Content.ts b/src/providers/Content.ts new file mode 100644 index 0000000..b6a094b --- /dev/null +++ b/src/providers/Content.ts @@ -0,0 +1,28 @@ +'use strict'; + +import * as vsc from 'vscode'; +import { XmlTreeService } from '../services/XmlTreeService'; + +export class XmlTreeDocumentContentProvider implements vsc.TextDocumentContentProvider { + + static get SCHEME(): string { + return "xmltree"; + } + + static buildUri(sourceUri: vsc.Uri): vsc.Uri { + let uriStr: string = `xmltree://${encodeURIComponent(sourceUri.toString())}`; + + let uri: vsc.Uri = vsc.Uri.parse(uriStr); + + return uri; + } + + async provideTextDocumentContent(uri: vsc.Uri): Promise { + let sourceUri: vsc.Uri = vsc.Uri.parse(decodeURIComponent(uri.toString().substr(10))); + let document: vsc.TextDocument = await vsc.workspace.openTextDocument(sourceUri); + + let html: string = XmlTreeService.getXmlTreeHtml(document.getText()); + + return Promise.resolve(html); + } +} \ No newline at end of file diff --git a/src/services/XmlTreeService.ts b/src/services/XmlTreeService.ts new file mode 100644 index 0000000..343753b --- /dev/null +++ b/src/services/XmlTreeService.ts @@ -0,0 +1,186 @@ +'use strict'; + +let DOMParser = require('xmldom').DOMParser; + +export class XmlTreeService { + static getXmlTreeHtml(xml: string): string { + let xdoc: Document = new DOMParser().parseFromString(xml, 'text/xml'); + let html: string = + ` + + + + XML Tree View + + + + `; + + html += `
    `; + html += XmlTreeService._processXmlNode(xdoc.lastChild); + html += `
`; + + html += + ` + + + `; + + return html; + } + + private static _processXmlNode(node: Node): string { + let html: string = ''; + + if (node.childNodes) { + html += `
    1. `; + } + + if (node.attributes) { + for (let i = 0; i < node.attributes.length; i++) { + html += `
    2. ${node.attributes.item(i).localName} = '${node.attributes.item(i).value}'
    3. `; + } + } + + if (!node.childNodes && node.textContent) { + html += `
    4. ${node.textContent}
    5. `; + } + + if (node.childNodes) { + for (let i = 0; i < node.childNodes.length; i++) { + html += XmlTreeService._processXmlNode(node.childNodes.item(i)); + } + + html += `
  • `; + } + + return html; + } +} \ No newline at end of file