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

View File

@ -11,21 +11,6 @@ export namespace contextKeys {
export const xmlTreeViewEnabled = "xmlTreeViewEnabled"; 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 namespace diagnosticCollections {
export const xquery = "XQueryDiagnostics"; export const xquery = "XQueryDiagnostics";
} }

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
import { workspace } from "vscode"; import { workspace } from "vscode";
import { import {
CancellationToken, DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider, EndOfLine, CancellationToken, DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider, EndOfLine,
FormattingOptions, ProviderResult, Range, TextDocument, TextEdit, WorkspaceConfiguration FormattingOptions, ProviderResult, Range, TextDocument, TextEdit
} from "vscode"; } from "vscode";
import * as constants from "../constants"; import * as constants from "../constants";
@ -11,7 +11,6 @@ import { XmlFormattingOptionsFactory } from "./xml-formatting-options";
export class XmlFormattingEditProvider implements DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider { export class XmlFormattingEditProvider implements DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider {
constructor( constructor(
public workspaceConfiguration: WorkspaceConfiguration,
public xmlFormatter: XmlFormatter public xmlFormatter: XmlFormatter
) { } ) { }
@ -23,12 +22,9 @@ export class XmlFormattingEditProvider implements DocumentFormattingEditProvider
} }
provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult<TextEdit[]> { 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); 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) ]; return [ TextEdit.replace(range, xml) ];
} }

View File

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

View File

@ -1,22 +1,20 @@
import { commands, window, workspace } from "vscode"; import { commands, window, workspace } from "vscode";
import { import {
Event, EventEmitter, ExtensionContext, Position, TextEditor, TreeDataProvider, Event, EventEmitter, ExtensionContext, Position, TextEditor, TreeDataProvider,
TreeItem, TreeItemCollapsibleState, WorkspaceConfiguration TreeItem, TreeItemCollapsibleState
} from "vscode"; } from "vscode";
import * as path from "path"; import * as path from "path";
import { DOMParser } from "xmldom"; import { DOMParser } from "xmldom";
import { Configuration } from "../common";
import * as constants from "../constants"; import * as constants from "../constants";
export class XmlTreeDataProvider implements TreeDataProvider<any> { export class XmlTreeDataProvider implements TreeDataProvider<any> {
private _config: WorkspaceConfiguration;
private _onDidChangeTreeData: EventEmitter<any> = new EventEmitter<any>(); private _onDidChangeTreeData: EventEmitter<any> = new EventEmitter<any>();
private _xmlDocument: Document; private _xmlDocument: Document;
constructor(private _context: ExtensionContext) { constructor(private _context: ExtensionContext) {
this._config = workspace.getConfiguration(constants.extensionPrefix);
window.onDidChangeActiveTextEditor(() => { window.onDidChangeActiveTextEditor(() => {
this._refreshTree(); this._refreshTree();
}); });
@ -33,8 +31,8 @@ export class XmlTreeDataProvider implements TreeDataProvider<any> {
} }
getTreeItem(element: Node): TreeItem | Thenable<TreeItem> { getTreeItem(element: Node): TreeItem | Thenable<TreeItem> {
const enableMetadata = this._config.get<boolean>(constants.configKeys.enableXmlTreeViewMetadata); const enableMetadata = Configuration.enableXmlTreeViewMetadata;
const enableSync = this._config.get<boolean>(constants.configKeys.enableXmlTreeViewCursorSync); const enableSync = Configuration.enableXmlTreeViewCursorSync;
const treeItem = new TreeItem(element.localName); const treeItem = new TreeItem(element.localName);
@ -208,7 +206,7 @@ export class XmlTreeDataProvider implements TreeDataProvider<any> {
return; return;
} }
const enableTreeView = this._config.get<boolean>(constants.configKeys.enableXmlTreeView, true); const enableTreeView = Configuration.enableXmlTreeView;
commands.executeCommand(constants.nativeCommands.setContext, constants.contextKeys.xmlTreeViewEnabled, enableTreeView); 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 { TextEditor, TextEditorEdit, ViewColumn } from "vscode";
import { ExtensionState } from "../../common"; import { Configuration, ExtensionState } from "../../common";
import * as constants from "../../constants"; import * as constants from "../../constants";
import { EvaluatorResult, EvaluatorResultType, XPathEvaluator } from "../xpath-evaluator"; import { EvaluatorResult, EvaluatorResultType, XPathEvaluator } from "../xpath-evaluator";
@ -17,13 +17,11 @@ class HistoricQuery {
} }
export async function evaluateXPath(editor: TextEditor, edit: TextEditorEdit): Promise<void> { 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 // if there is no workspace, we will track queries in the global Memento
const memento = ExtensionState.workspace || ExtensionState.global; const memento = ExtensionState.workspace || ExtensionState.global;
// get the xpath persistence setting // 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 // get the last query if there is one for this document
// if not, try pulling the last query ran, regardless of 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; return;
} }
const ignoreDefaultNamespace = config.get<boolean>(constants.configKeys.ignoreDefaultNamespace, true); const ignoreDefaultNamespace = Configuration.ignoreDefaultNamespace;
// run the query // run the query
const xml = editor.document.getText(); 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 * as constants from "../../constants";
import { ChildProcess } from "../child-process"; import { ChildProcess } from "../child-process";
import { Configuration } from "../../common";
export async function executeXQuery(editor: TextEditor, edit: TextEditorEdit): Promise<void> { 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 // this disposable will be used for creating status bar messages
let disposable: Disposable; let disposable: Disposable;
@ -16,8 +15,8 @@ export async function executeXQuery(editor: TextEditor, edit: TextEditorEdit): P
return; return;
} }
const executable = config.get<string>(constants.configKeys.xqueryExecutionEngine, null); const executable = Configuration.xqueryExecutionEngine;
let args = config.get<string[]>(constants.configKeys.xqueryExecutionArguments, []); let args = Configuration.xqueryExecutionArguments || [];
if (!executable || executable === "") { if (!executable || executable === "") {
const action = await window.showWarningMessage("An XQuery execution engine has not been defined.", "Define Now"); 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; let inputFile: Uri;
disposable = window.setStatusBarMessage("Searching for XML files in folder..."); disposable = window.setStatusBarMessage("Searching for XML files in folder...");
const searchPattern = config.get<string>(constants.configKeys.xqueryExecutionInputSearchPattern); const searchPattern = Configuration.xqueryExecutionInputSearchPattern;
const inputLimit = config.get<number>(constants.configKeys.xqueryExecutionInputLimit); const inputLimit = Configuration.xqueryExecutionInputLimit;
const files = await workspace.findFiles(searchPattern, "", inputLimit); const files = await workspace.findFiles(searchPattern, "", inputLimit);