Add Format As XML Command

This commit is contained in:
Josh Johnson 2018-03-01 21:22:53 -05:00
parent 33535163c1
commit d37a8b70fd
5 changed files with 104 additions and 21 deletions

View File

@ -1,10 +1,9 @@
import { languages, window, workspace } from "vscode"; import { languages, window, workspace, commands } from "vscode";
import { ExtensionContext, TextEditor, TextEditorSelectionChangeEvent, WorkspaceConfiguration } from "vscode"; import { ExtensionContext, TextEditor, TextEditorSelectionChangeEvent, WorkspaceConfiguration } from "vscode";
import { XmlFormatter } from "./formatting/xml-formatter"; import { FormatAsXmlCommandName, formatAsXml } from "./formatting/commands/formatAsXml";
import { XmlFormatterFactory } from "./formatting/xml-formatter";
import { XmlFormattingEditProvider } from "./formatting/xml-formatting-edit-provider"; import { XmlFormattingEditProvider } from "./formatting/xml-formatting-edit-provider";
import { ClassicXmlFormatter } from "./formatting/formatters/classic-xml-formatter";
import { V2XmlFormatter } from "./formatting/formatters/v2-xml-formatter";
import { XQueryLinter } from "./linting/xquery-linter"; import { XQueryLinter } from "./linting/xquery-linter";
import * as constants from "./constants"; import * as constants from "./constants";
@ -13,17 +12,10 @@ export function activate(context: ExtensionContext) {
const config = workspace.getConfiguration(constants.extensionPrefix); const config = workspace.getConfiguration(constants.extensionPrefix);
/* Formatting Features */ /* Formatting Features */
const xmlFormatterImplementationSetting = config.get<string>("xmlFormatterImplementation"); const xmlFormattingEditProvider = new XmlFormattingEditProvider(config, XmlFormatterFactory.getXmlFormatter());
let xmlFormatterImplementation: XmlFormatter;
switch (xmlFormatterImplementationSetting) {
case "v2": xmlFormatterImplementation = new V2XmlFormatter(); break;
case "classic": default: xmlFormatterImplementation = new ClassicXmlFormatter(); break;
}
const xmlFormattingEditProvider = new XmlFormattingEditProvider(config, xmlFormatterImplementation);
context.subscriptions.push( context.subscriptions.push(
commands.registerTextEditorCommand(FormatAsXmlCommandName, formatAsXml),
languages.registerDocumentFormattingEditProvider("xml", xmlFormattingEditProvider), languages.registerDocumentFormattingEditProvider("xml", xmlFormattingEditProvider),
languages.registerDocumentRangeFormattingEditProvider("xml", xmlFormattingEditProvider) languages.registerDocumentRangeFormattingEditProvider("xml", xmlFormattingEditProvider)
); );

View File

@ -0,0 +1,53 @@
import { commands, workspace } from "vscode";
import { ProviderResult, Range, TextEdit, TextEditor, TextEditorEdit } from "vscode";
import * as constants from "../../constants";
import { XmlFormatterFactory } from "../xml-formatter";
import { XmlFormattingEditProvider } from "../xml-formatting-edit-provider";
import { XmlFormattingOptionsFactory } from "../xml-formatting-options";
export const FormatAsXmlCommandName = "formatAsXml";
export function formatAsXml(editor: TextEditor, edit: TextEditorEdit): void {
const xmlFormattingEditProvider = new XmlFormattingEditProvider(workspace.getConfiguration(constants.extensionPrefix), XmlFormatterFactory.getXmlFormatter());
const formattingOptions = {
insertSpaces: <boolean>editor.options.insertSpaces,
tabSize: <number>editor.options.tabSize
};
let edits: ProviderResult<TextEdit[]>;
if (!editor.selection.isEmpty) {
edits = xmlFormattingEditProvider.provideDocumentRangeFormattingEdits(
editor.document,
new Range(editor.selection.start, editor.selection.end),
formattingOptions,
null);
}
else {
edits = xmlFormattingEditProvider.provideDocumentFormattingEdits(
editor.document,
formattingOptions,
null);
}
for (let i = 0; i < (edits as TextEdit[]).length; i++) {
const textEdit = (edits as TextEdit[])[i];
editor.edit(async (editBuilder) => {
editBuilder.replace(textEdit.range, textEdit.newText);
// wiggle the cursor to deselect the formatted XML (is there a non-hacky way to go about this?)
await commands.executeCommand("cursorMove", {
to: "left",
by: "character"
});
await commands.executeCommand("cursorMove", {
to: "right",
by: "character"
});
});
}
}

View File

@ -1,6 +1,32 @@
import { workspace } from "vscode";
import * as constants from "../constants";
import { ClassicXmlFormatter } from "./formatters/classic-xml-formatter";
import { V2XmlFormatter } from "./formatters/v2-xml-formatter";
import { XmlFormattingOptions } from "./xml-formatting-options"; import { XmlFormattingOptions } from "./xml-formatting-options";
export interface XmlFormatter { export interface XmlFormatter {
formatXml(xml: string, options: XmlFormattingOptions): string; formatXml(xml: string, options: XmlFormattingOptions): string;
minifyXml(xml: string, options: XmlFormattingOptions): string; minifyXml(xml: string, options: XmlFormattingOptions): string;
} }
export class XmlFormatterFactory {
private static _xmlFormatter: XmlFormatter;
static getXmlFormatter(): XmlFormatter {
if (XmlFormatterFactory._xmlFormatter) {
return XmlFormatterFactory._xmlFormatter;
}
const xmlFormatterImplementationSetting = workspace.getConfiguration(constants.extensionPrefix).get<string>("xmlFormatterImplementation");
let xmlFormatterImplementation: XmlFormatter;
switch (xmlFormatterImplementationSetting) {
case "classic": xmlFormatterImplementation = new ClassicXmlFormatter(); break;
case "v2": default: xmlFormatterImplementation = new V2XmlFormatter(); break;
}
return (XmlFormatterFactory._xmlFormatter = xmlFormatterImplementation);
}
}

View File

@ -6,6 +6,7 @@ import {
import * as constants from "../constants"; import * as constants from "../constants";
import { XmlFormatter } from "./xml-formatter"; import { XmlFormatter } from "./xml-formatter";
import { XmlFormattingOptionsFactory } from "./xml-formatting-options";
export class XmlFormattingEditProvider implements DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider { export class XmlFormattingEditProvider implements DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider {
@ -27,13 +28,7 @@ export class XmlFormattingEditProvider implements DocumentFormattingEditProvider
let xml = document.getText(range); let xml = document.getText(range);
xml = this.xmlFormatter.formatXml(xml, { xml = this.xmlFormatter.formatXml(xml, XmlFormattingOptionsFactory.getXmlFormattingOptions(options, document.eol));
editorOptions: options,
newLine: (document.eol === EndOfLine.CRLF) ? "\r\n" : "\n",
removeCommentsOnMinify: this.workspaceConfiguration.get<boolean>("removeCommentsOnMinify"),
splitAttributesOnFormat: this.workspaceConfiguration.get<boolean>("splitAttributesOnFormat"),
splitXmlnsOnFormat: this.workspaceConfiguration.get<boolean>("splitXmlnsOnFormat")
});
return [ TextEdit.replace(range, xml) ]; return [ TextEdit.replace(range, xml) ];
} }

View File

@ -1,4 +1,7 @@
import { FormattingOptions } from "vscode"; import { workspace } from "vscode";
import { EndOfLine, FormattingOptions } from "vscode";
import * as constants from "../constants";
export interface XmlFormattingOptions { export interface XmlFormattingOptions {
editorOptions: FormattingOptions; editorOptions: FormattingOptions;
@ -7,3 +10,17 @@ export interface XmlFormattingOptions {
splitAttributesOnFormat: boolean; splitAttributesOnFormat: boolean;
splitXmlnsOnFormat: boolean; splitXmlnsOnFormat: boolean;
} }
export class XmlFormattingOptionsFactory {
static getXmlFormattingOptions(formattingOptions: FormattingOptions, eol: EndOfLine): XmlFormattingOptions {
const config = workspace.getConfiguration(constants.extensionPrefix);
return {
editorOptions: formattingOptions,
newLine: (eol === EndOfLine.CRLF) ? "\r\n" : "\n",
removeCommentsOnMinify: config.get<boolean>("removeCommentsOnMinify"),
splitAttributesOnFormat: config.get<boolean>("splitAttributesOnFormat"),
splitXmlnsOnFormat: config.get<boolean>("splitXmlnsOnFormat")
};
}
}