diff --git a/package.json b/package.json index 9774bfc..723f589 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,11 @@ { "command": "xmlTools.evaluateXPath", "title": "XML Tools: Evaluate XPath" - } + }, + { + "command": "xmlTools.executeXQuery", + "title": "XML Tools: Execute XQuery" + } ], "configuration": { "title": "XML Tools Configuration", @@ -64,6 +68,16 @@ "type": "boolean", "default": true, "description": "Put each xmlns attribute on a new line when fromatting XML." + }, + "xmlTools.xqueryExecutionEngine": { + "type": "string", + "default": "", + "description": "The full path to the execution engine executable." + }, + "xmlTools.xqueryExecutionArguments": { + "type": "array", + "default": ["-xquery", "$(script)", "-in", "$(input)", "-out", "$(input).output.xml"], + "description": "Arguments to be passed to the execution engine. '$(script)' and '$(input)' refer to the XQuery script and input XML file, respectively." } } }, diff --git a/src/Commands.ts b/src/Commands.ts index 15f6fae..d39b08d 100644 --- a/src/Commands.ts +++ b/src/Commands.ts @@ -6,6 +6,7 @@ import * as xpath from 'xpath'; import { RangeUtil } from './utils/RangeUtil'; import { XmlFormatter } from './services/XmlFormatter'; import { XPathFeatureProvider } from './providers/XPath'; +import { XQueryExecutionProvider } from './providers/Execution'; const CFG_SECTION: string = 'xmlTools'; const CFG_REMOVE_COMMENTS: string = 'removeCommentsOnMinify'; @@ -30,4 +31,8 @@ export class TextEditorCommands { static evaluateXPath(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): void { XPathFeatureProvider.evaluateXPathAsync(editor, edit); } + + static executeXQuery(editor: vsc.TextEditor, edit: vsc.TextEditorEdit): void { + XQueryExecutionProvider.executeXQueryAsync(editor); + } } \ No newline at end of file diff --git a/src/Extension.ts b/src/Extension.ts index 85df16d..e54d51e 100644 --- a/src/Extension.ts +++ b/src/Extension.ts @@ -22,7 +22,9 @@ export function activate(ctx: vsc.ExtensionContext) { ctx.subscriptions.push( vsc.commands.registerTextEditorCommand('xmlTools.minifyXml', TextEditorCommands.minifyXml), vsc.commands.registerTextEditorCommand('xmlTools.formatXml', TextEditorCommands.formatXml), - vsc.commands.registerTextEditorCommand('xmlTools.evaluateXPath', TextEditorCommands.evaluateXPath) + vsc.commands.registerTextEditorCommand('xmlTools.evaluateXPath', TextEditorCommands.evaluateXPath), + + vsc.commands.registerTextEditorCommand('xmlTools.executeXQuery', TextEditorCommands.executeXQuery) ); // register language feature providers diff --git a/src/providers/Execution.ts b/src/providers/Execution.ts new file mode 100644 index 0000000..5c81f97 --- /dev/null +++ b/src/providers/Execution.ts @@ -0,0 +1,59 @@ +'use strict'; + +import * as vsc from 'vscode'; +import { ChildProcess } from '../services/ChildProcess'; + +const CFG_SECTION: string = 'xmlTools'; +const CFG_XQEXEC: string = 'xqueryExecutionEngine'; +const CFG_XQARGS: string = 'xqueryExecutionArguments'; + +export class XQueryExecutionProvider { + static async executeXQueryAsync(editor: vsc.TextEditor): Promise { + if (editor.document.languageId !== 'xquery') { + vsc.window.showErrorMessage('This action can only be performed on an XQuery file.'); + return; + } + + let executable = vsc.workspace.getConfiguration(CFG_SECTION).get(CFG_XQEXEC, null); + let args = vsc.workspace.getConfiguration(CFG_SECTION).get(CFG_XQARGS, []); + + if (!executable || executable == '') { + let action = await vsc.window.showWarningMessage('An XQuery execution engine has not been defined.', 'Define Now'); + + if (action == 'Define Now') { + vsc.commands.executeCommand('workbench.action.openGlobalSettings'); + } + + return; + } + + let files: vsc.Uri[] = await vsc.workspace.findFiles('**/*.xml', '', 100); + + let qpItems: any[] = new Array(); + + files.forEach((file) => { + let filename: string = file.fsPath.replace('\\', '/'); + + qpItems.push({ // must implement vscode.QuickPickItem + label: filename.substring(filename.lastIndexOf('/') + 1), + description: file.fsPath, + file: file + }); + }); + + let selection = await vsc.window.showQuickPick(qpItems, { placeHolder: 'Please select an input file.' }); + + if (!selection) { + return; + } + + let disposable: vsc.Disposable = vsc.window.setStatusBarMessage('Executing XQuery Script...'); + args = args.map((value: string) => { + return value + .replace('$(script)', editor.document.uri.fsPath) + .replace('$(input)', selection.file.fsPath); + }); + await ChildProcess.spawnAsync(executable, args); + disposable.dispose(); + } +} \ No newline at end of file diff --git a/src/services/ChildProcess.ts b/src/services/ChildProcess.ts new file mode 100644 index 0000000..6030be0 --- /dev/null +++ b/src/services/ChildProcess.ts @@ -0,0 +1,23 @@ +'use strict'; + +let child_process = require('child_process'); + +export class ChildProcess { + static async spawnAsync(executable: string, args: string[]): Promise { + return new Promise((resolve, reject) => { + + let handle = child_process.spawn(executable, args); + + handle.on('close', (code: string) => { + if (code == '0') { + resolve(); + } + + else { + reject(code); + } + }); + + }); + } +} \ No newline at end of file