Add Configuration Service

This commit is contained in:
Josh Johnson 2018-05-03 22:36:54 -04:00
parent 907fa71394
commit a4366a5061
13 changed files with 103 additions and 64 deletions

View File

@ -85,13 +85,13 @@
"type": "boolean",
"default": true,
"description": "Ignore default xmlns attributes when evaluating XPath.",
"scope": "resource"
"scope": "window"
},
"xmlTools.persistXPathQuery": {
"type": "boolean",
"default": true,
"description": "Remember the last XPath query used.",
"scope": "resource"
"scope": "window"
},
"xmlTools.removeCommentsOnMinify": {
"type": "boolean",
@ -115,7 +115,7 @@
"type": "string",
"default": "v2",
"description": "Supported XML Formatters: classic",
"scope": "resource"
"scope": "window"
},
"xmlTools.xqueryExecutionArguments": {
"type": "array",
@ -128,25 +128,25 @@
"$(input.output.xml"
],
"description": "Arguments to be passed to the XQuery execution engine.",
"scope": "resource"
"scope": "window"
},
"xmlTools.xqueryExecutionEngine": {
"type": "string",
"default": "",
"description": "The full path to the executable to run when executing XQuery scripts.",
"scope": "resource"
"scope": "window"
},
"xmlTools.xqueryExecutionInputLimit": {
"type": "integer",
"default": 100,
"description": "The maximum number of input files to enumerate when executing XQuery scripts.",
"scope": "resource"
"scope": "window"
},
"xmlTools.xqueryExecutionInputSearchPattern": {
"type": "string",
"default": "**/*.xml",
"description": "The pattern used to search for input XML files when executing XQuery scripts.",
"scope": "resource"
"scope": "window"
}
}
},

View File

@ -0,0 +1,65 @@
import { workspace, Uri } from "vscode";
const ExtensionTopLevelSection = "xmlTools";
export class Configuration {
static get enableXmlTreeView(): boolean {
return this._getForWindow<boolean>("enableXmlTreeView");
}
static get enableXmlTreeViewMetadata(): boolean {
return this._getForWindow<boolean>("enableXmlTreeViewMetadata");
}
static get enableXmlTreeViewCursorSync(): boolean {
return this._getForWindow<boolean>("enableXmlTreeViewCursorSync");
}
static get ignoreDefaultNamespace(): boolean {
return this._getForWindow<boolean>("ignoreDefaultNamespace");
}
static get persistXPathQuery(): boolean {
return this._getForWindow<boolean>("persistXPathQuery");
}
static get xmlFormatterImplementation(): string {
return this._getForWindow<string>("xmlFormatterImplementation");
}
static get xqueryExecutionArguments(): string[] {
return this._getForWindow<string[]>("xqueryExecutionArguments");
}
static get xqueryExecutionEngine(): string {
return this._getForWindow<string>("xqueryExecutionEngine");
}
static get xqueryExecutionInputLimit(): number {
return this._getForWindow<number>("xqueryExecutionInputLimit");
}
static get xqueryExecutionInputSearchPattern(): string {
return this._getForWindow<string>("xqueryExecutionInputSearchPattern");
}
static removeCommentsOnMinify(resource: Uri): boolean {
return this._getForResource<boolean>("removeCommentsOnMinify", resource);
}
static splitAttributesOnFormat(resource: Uri): boolean {
return this._getForResource<boolean>("splitAttributesOnFormat", resource);
}
static splitXmlnsOnFormat(resource: Uri): boolean {
return this._getForResource<boolean>("splitXmlnsOnFormat", resource);
}
private static _getForResource<T>(section: string, resource: Uri): T {
return workspace.getConfiguration(ExtensionTopLevelSection, resource).get<T>(section);
}
private static _getForWindow<T>(section: string): T {
return workspace.getConfiguration(ExtensionTopLevelSection).get<T>(section);
}
}

View File

@ -1,2 +1,3 @@
export * from "./configuration";
export * from "./create-document-selector";
export * from "./extension-state";

View File

@ -11,21 +11,6 @@ export namespace contextKeys {
export const xmlTreeViewEnabled = "xmlTreeViewEnabled";
}
export namespace configKeys {
export const enableXmlTreeView = "enableXmlTreeView";
export const enableXmlTreeViewMetadata = "enableXmlTreeViewMetadata";
export const enableXmlTreeViewCursorSync = "enableXmlTreeViewCursorSync";
export const ignoreDefaultNamespace = "ignoreDefaultNamespace";
export const persistXPathQuery = "persistXPathQuery";
export const removeCommentsOnMinify = "removeCommentsOnMinify";
export const splitAttributesOnFormat = "splitAttributesOnFormat";
export const splitXmlnsOnFormat = "splitXmlnsOnFormat";
export const xqueryExecutionArguments = "xqueryExecutionArguments";
export const xqueryExecutionEngine = "xqueryExecutionEngine";
export const xqueryExecutionInputLimit = "xqueryExecutionInputLimit";
export const xqueryExecutionInputSearchPattern = "xqueryExecutionInputSearchPattern";
}
export namespace diagnosticCollections {
export const xquery = "XQueryDiagnostics";
}

View File

@ -3,7 +3,7 @@ import {
TextEditor, TextEditorSelectionChangeEvent, TextEditorSelectionChangeKind
} from "vscode";
import { createDocumentSelector, ExtensionState } from "./common";
import { createDocumentSelector, ExtensionState, Configuration } from "./common";
import { XQueryCompletionItemProvider } from "./completion";
import { XmlFormatterFactory, XmlFormattingEditProvider } from "./formatting";
import { formatAsXml, minifyXml } from "./formatting/commands";
@ -17,8 +17,6 @@ import * as constants from "./constants";
export function activate(context: ExtensionContext) {
ExtensionState.configure(context);
const config = workspace.getConfiguration(constants.extensionPrefix);
const xmlXsdDocSelector = [...createDocumentSelector(constants.languageIds.xml), ...createDocumentSelector(constants.languageIds.xsd)];
const xqueryDocSelector = createDocumentSelector(constants.languageIds.xquery);
@ -28,7 +26,7 @@ export function activate(context: ExtensionContext) {
);
/* Formatting Features */
const xmlFormattingEditProvider = new XmlFormattingEditProvider(config, XmlFormatterFactory.getXmlFormatter());
const xmlFormattingEditProvider = new XmlFormattingEditProvider(XmlFormatterFactory.getXmlFormatter());
context.subscriptions.push(
commands.registerTextEditorCommand(constants.commands.formatAsXml, formatAsXml),
@ -49,7 +47,7 @@ export function activate(context: ExtensionContext) {
treeDataProvider: treeViewDataProvider
});
if (config.get<boolean>(constants.configKeys.enableXmlTreeViewCursorSync)) {
if (Configuration.enableXmlTreeViewCursorSync) {
window.onDidChangeTextEditorSelection(x => {
if (x.kind === TextEditorSelectionChangeKind.Mouse && x.selections.length > 0) {
treeView.reveal(treeViewDataProvider.getNodeAtPosition(x.selections[0].start));

View File

@ -8,7 +8,7 @@ import { XmlFormattingEditProvider } from "../xml-formatting-edit-provider";
import { XmlFormattingOptionsFactory } from "../xml-formatting-options";
export function formatAsXml(editor: TextEditor, edit: TextEditorEdit): void {
const xmlFormattingEditProvider = new XmlFormattingEditProvider(workspace.getConfiguration(constants.extensionPrefix), XmlFormatterFactory.getXmlFormatter());
const xmlFormattingEditProvider = new XmlFormattingEditProvider(XmlFormatterFactory.getXmlFormatter());
const formattingOptions = {
insertSpaces: <boolean>editor.options.insertSpaces,
tabSize: <number>editor.options.tabSize

View File

@ -12,7 +12,7 @@ export function minifyXml(editor: TextEditor, edit: TextEditorEdit): void {
const xmlFormattingOptions = XmlFormattingOptionsFactory.getXmlFormattingOptions({
insertSpaces: <boolean>editor.options.insertSpaces,
tabSize: <number>editor.options.tabSize
}, editor.document.eol);
}, editor.document);
const endPosition = editor.document.lineAt(editor.document.lineCount - 1).rangeIncludingLineBreak.end;
const range = new Range(editor.document.positionAt(0), endPosition);

View File

@ -1,5 +1,6 @@
import { workspace } from "vscode";
import { Configuration } from "../common";
import * as constants from "../constants";
import { ClassicXmlFormatter } from "./formatters/classic-xml-formatter";
import { V2XmlFormatter } from "./formatters/v2-xml-formatter";
@ -19,7 +20,7 @@ export class XmlFormatterFactory {
return XmlFormatterFactory._xmlFormatter;
}
const xmlFormatterImplementationSetting = workspace.getConfiguration(constants.extensionPrefix).get<string>("xmlFormatterImplementation");
const xmlFormatterImplementationSetting = Configuration.xmlFormatterImplementation;
let xmlFormatterImplementation: XmlFormatter;
switch (xmlFormatterImplementationSetting) {

View File

@ -1,7 +1,7 @@
import { workspace } from "vscode";
import {
CancellationToken, DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider, EndOfLine,
FormattingOptions, ProviderResult, Range, TextDocument, TextEdit, WorkspaceConfiguration
FormattingOptions, ProviderResult, Range, TextDocument, TextEdit
} from "vscode";
import * as constants from "../constants";
@ -11,7 +11,6 @@ import { XmlFormattingOptionsFactory } from "./xml-formatting-options";
export class XmlFormattingEditProvider implements DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider {
constructor(
public workspaceConfiguration: WorkspaceConfiguration,
public xmlFormatter: XmlFormatter
) { }
@ -23,12 +22,9 @@ export class XmlFormattingEditProvider implements DocumentFormattingEditProvider
}
provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult<TextEdit[]> {
// override global configuration (issue #128)
this.workspaceConfiguration = workspace.getConfiguration(constants.extensionPrefix, document.uri);
let xml = document.getText(range);
xml = this.xmlFormatter.formatXml(xml, XmlFormattingOptionsFactory.getXmlFormattingOptions(options, document.eol));
xml = this.xmlFormatter.formatXml(xml, XmlFormattingOptionsFactory.getXmlFormattingOptions(options, document));
return [ TextEdit.replace(range, xml) ];
}

View File

@ -1,6 +1,6 @@
import { workspace } from "vscode";
import { EndOfLine, FormattingOptions } from "vscode";
import { EndOfLine, FormattingOptions, TextDocument } from "vscode";
import { Configuration } from "../common";
import * as constants from "../constants";
export interface XmlFormattingOptions {
@ -12,15 +12,13 @@ export interface XmlFormattingOptions {
}
export class XmlFormattingOptionsFactory {
static getXmlFormattingOptions(formattingOptions: FormattingOptions, eol: EndOfLine): XmlFormattingOptions {
const config = workspace.getConfiguration(constants.extensionPrefix);
static getXmlFormattingOptions(formattingOptions: FormattingOptions, document: TextDocument): XmlFormattingOptions {
return {
editorOptions: formattingOptions,
newLine: (eol === EndOfLine.CRLF) ? "\r\n" : "\n",
removeCommentsOnMinify: config.get<boolean>(constants.configKeys.removeCommentsOnMinify),
splitAttributesOnFormat: config.get<boolean>(constants.configKeys.splitAttributesOnFormat),
splitXmlnsOnFormat: config.get<boolean>(constants.configKeys.splitXmlnsOnFormat)
newLine: (document.eol === EndOfLine.CRLF) ? "\r\n" : "\n",
removeCommentsOnMinify: Configuration.removeCommentsOnMinify(document.uri),
splitAttributesOnFormat: Configuration.splitAttributesOnFormat(document.uri),
splitXmlnsOnFormat: Configuration.splitXmlnsOnFormat(document.uri)
};
}
}

View File

@ -1,22 +1,20 @@
import { commands, window, workspace } from "vscode";
import {
Event, EventEmitter, ExtensionContext, Position, TextEditor, TreeDataProvider,
TreeItem, TreeItemCollapsibleState, WorkspaceConfiguration
TreeItem, TreeItemCollapsibleState
} from "vscode";
import * as path from "path";
import { DOMParser } from "xmldom";
import { Configuration } from "../common";
import * as constants from "../constants";
export class XmlTreeDataProvider implements TreeDataProvider<any> {
private _config: WorkspaceConfiguration;
private _onDidChangeTreeData: EventEmitter<any> = new EventEmitter<any>();
private _xmlDocument: Document;
constructor(private _context: ExtensionContext) {
this._config = workspace.getConfiguration(constants.extensionPrefix);
window.onDidChangeActiveTextEditor(() => {
this._refreshTree();
});
@ -33,8 +31,8 @@ export class XmlTreeDataProvider implements TreeDataProvider<any> {
}
getTreeItem(element: Node): TreeItem | Thenable<TreeItem> {
const enableMetadata = this._config.get<boolean>(constants.configKeys.enableXmlTreeViewMetadata);
const enableSync = this._config.get<boolean>(constants.configKeys.enableXmlTreeViewCursorSync);
const enableMetadata = Configuration.enableXmlTreeViewMetadata;
const enableSync = Configuration.enableXmlTreeViewCursorSync;
const treeItem = new TreeItem(element.localName);
@ -208,7 +206,7 @@ export class XmlTreeDataProvider implements TreeDataProvider<any> {
return;
}
const enableTreeView = this._config.get<boolean>(constants.configKeys.enableXmlTreeView, true);
const enableTreeView = Configuration.enableXmlTreeView;
commands.executeCommand(constants.nativeCommands.setContext, constants.contextKeys.xmlTreeViewEnabled, enableTreeView);

View File

@ -1,7 +1,7 @@
import { window, workspace } from "vscode";
import { window } from "vscode";
import { TextEditor, TextEditorEdit, ViewColumn } from "vscode";
import { ExtensionState } from "../../common";
import { Configuration, ExtensionState } from "../../common";
import * as constants from "../../constants";
import { EvaluatorResult, EvaluatorResultType, XPathEvaluator } from "../xpath-evaluator";
@ -17,13 +17,11 @@ class HistoricQuery {
}
export async function evaluateXPath(editor: TextEditor, edit: TextEditorEdit): Promise<void> {
const config = workspace.getConfiguration(constants.extensionPrefix);
// if there is no workspace, we will track queries in the global Memento
const memento = ExtensionState.workspace || ExtensionState.global;
// get the xpath persistence setting
const persistQueries = config.get<boolean>(constants.configKeys.persistXPathQuery, true);
const persistQueries = Configuration.persistXPathQuery;
// get the last query if there is one for this document
// if not, try pulling the last query ran, regardless of document
@ -49,7 +47,7 @@ export async function evaluateXPath(editor: TextEditor, edit: TextEditorEdit): P
return;
}
const ignoreDefaultNamespace = config.get<boolean>(constants.configKeys.ignoreDefaultNamespace, true);
const ignoreDefaultNamespace = Configuration.ignoreDefaultNamespace;
// run the query
const xml = editor.document.getText();

View File

@ -4,10 +4,9 @@ import { Disposable, Range, TextEditor, TextEditorEdit, Uri } from "vscode";
import * as constants from "../../constants";
import { ChildProcess } from "../child-process";
import { Configuration } from "../../common";
export async function executeXQuery(editor: TextEditor, edit: TextEditorEdit): Promise<void> {
const config = workspace.getConfiguration(constants.extensionPrefix);
// this disposable will be used for creating status bar messages
let disposable: Disposable;
@ -16,8 +15,8 @@ export async function executeXQuery(editor: TextEditor, edit: TextEditorEdit): P
return;
}
const executable = config.get<string>(constants.configKeys.xqueryExecutionEngine, null);
let args = config.get<string[]>(constants.configKeys.xqueryExecutionArguments, []);
const executable = Configuration.xqueryExecutionEngine;
let args = Configuration.xqueryExecutionArguments || [];
if (!executable || executable === "") {
const action = await window.showWarningMessage("An XQuery execution engine has not been defined.", "Define Now");
@ -32,8 +31,8 @@ export async function executeXQuery(editor: TextEditor, edit: TextEditorEdit): P
let inputFile: Uri;
disposable = window.setStatusBarMessage("Searching for XML files in folder...");
const searchPattern = config.get<string>(constants.configKeys.xqueryExecutionInputSearchPattern);
const inputLimit = config.get<number>(constants.configKeys.xqueryExecutionInputLimit);
const searchPattern = Configuration.xqueryExecutionInputSearchPattern;
const inputLimit = Configuration.xqueryExecutionInputLimit;
const files = await workspace.findFiles(searchPattern, "", inputLimit);