Skip to content

Commit

Permalink
axml and style format
Browse files Browse the repository at this point in the history
  • Loading branch information
木农 committed Sep 28, 2017
1 parent d8469f7 commit ae82182
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 14 deletions.
180 changes: 180 additions & 0 deletions extensions/axml/out/format.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// Based on pretty-data (https://github.com/vkiryukhin/pretty-data)
module.exports = class XmlFormatter {
constructor(options) {
options = options || {};

if (typeof options.preferSpaces === "undefined") {
options.preferSpaces = false;
}

if (typeof options.splitNamespaces === "undefined") {
options.splitNamespaces = true;
}

options.tabSize = options.tabSize || 4;
options.newLine = options.newLine || "\n";

this.newLine = options.newLine || "\n";
this.indentPattern = (options.preferSpaces) ? " ".repeat(options.tabSize) : "\t";
this.splitNamespaces = options.splitNamespaces;
}

format(xml) {
xml = this.minify(xml, false);
xml = xml.replace(/</g, "~::~<");

if (this.splitNamespaces) {
xml = xml
.replace(/xmlns\:/g, "~::~xmlns:")
.replace(/xmlns\=/g, "~::~xmlns=");
}

let parts = xml.split("~::~");
let inComment = false;
let level = 0;
let output = "";

for (let i = 0; i < parts.length; i++) {
// <!
if (parts[i].search(/<!/) > -1) {
output += this._getIndent(level, parts[i]);
inComment = true;

// end <!
if (parts[i].search(/-->/) > -1 || parts[i].search(/\]>/) > -1 || parts[i].search(/!DOCTYPE/) > -1) {
inComment = false;
}
}

// end <!
else if (parts[i].search(/-->/) > -1 || parts[i].search(/\]>/) > -1) {
output += parts[i];
inComment = false;
}

// <elm></elm>
else if (/^<(\w|:)/.test(parts[i - 1]) && /^<\/(\w|:)/.test(parts[i])
&& /^<[\w:\-\.\,\/]+/.exec(parts[i - 1])[0] == /^<\/[\w:\-\.\,]+/.exec(parts[i])[0].replace("/", "")) {

output += parts[i];
if (!inComment) level--;
}

// <elm>
else if (parts[i].search(/<(\w|:)/) > -1 && parts[i].search(/<\//) == -1 && parts[i].search(/\/>/) == -1) {
output = (!inComment) ? output += this._getIndent(level++, parts[i]) : output += parts[i];
}

// <elm>...</elm>
else if (parts[i].search(/<(\w|:)/) > -1 && parts[i].search(/<\//) > -1) {
output = (!inComment) ? output += this._getIndent(level, parts[i]) : output += parts[i];
}

// </elm>
else if (parts[i].search(/<\//) > -1) {
output = (!inComment) ? output += this._getIndent(--level, parts[i]) : output += parts[i];
}

// <elm />
else if (parts[i].search(/\/>/) > -1 && (!this.splitNamespaces || parts[i].search(/xmlns(:|=)/) == -1)) {
output = (!inComment) ? output += this._getIndent(level, parts[i]) : output += parts[i];
}

// xmlns />
else if (parts[i].search(/\/>/) > -1 && parts[i].search(/xmlns(:|=)/) > -1 && this.splitNamespaces) {
output = (!inComment) ? output += this._getIndent(level--, parts[i]) : output += parts[i];
}

// <?xml ... ?>
else if (parts[i].search(/<\?/) > -1) {
output += this._getIndent(level, parts[i]);
}

// xmlns
else if (this.splitNamespaces && (parts[i].search(/xmlns\:/) > -1 || parts[i].search(/xmlns\=/) > -1)) {
output += this._getIndent(level, parts[i]);
}

else {
output += parts[i];
}
}

// remove leading newline
if (output[0] == this.newLine) {
output = output.slice(1);
}

else if (output.substring(0, 1) == this.newLine) {
output = output.slice(2);
}

return output;
}

minify(xml, removeComments) {
if (typeof removeComments === "undefined") {
removeComments = false;
}

xml = this._stripLineBreaks(xml); // all line breaks outside of CDATA elements
xml = (removeComments) ? xml.replace(/\<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)\>/g, "") : xml;
xml = xml.replace(/>\s{0,}</g, "><"); // insignificant whitespace between tags
xml = xml.replace(/"\s+(?=[^\s]+=)/g, "\" "); // spaces between attributes
xml = xml.replace(/"\s+(?=>)/g, "\""); // spaces between the last attribute and tag close (>)
xml = xml.replace(/"\s+(?=\/>)/g, "\" "); // spaces between the last attribute and tag close (/>)
xml = xml.replace(/[^ <>="]\s+[^ <>="]+=/g, (match) => { // spaces between the node name and the first attribute
return match.replace(/\s+/g, " ");
});

return xml;
}

_getIndent(level, trailingValue) {
trailingValue = trailingValue || "";

return `${this.newLine}${this.indentPattern.repeat(level)}${trailingValue}`;
}

_stripLineBreaks(xml) {
let output = "";
let inTag = false;
let inTagName = false;
let inCdata = false;
let inAttribute = false;

for (let i = 0; i < xml.length; i++) {
let char = xml.charAt(i);
let prev = xml.charAt(i - 1);
let next = xml.charAt(i + 1);

if (char == "!" && (xml.substr(i, 8) == "![CDATA[" || xml.substr(i, 3) == "!--")) {
inCdata = true;
}

else if (char == "]" && (xml.substr(i, 3) == "]]>")) {
inCdata = false;
}

else if (char == "-" && (xml.substr(i, 3) == "-->")) {
inCdata = false;
}

else if (char.search(/[\r\n]/g) > -1 && !inCdata) {
if (/\r/.test(char) && /\S|\r|\n/.test(prev) && /\S|\r|\n/.test(xml.charAt(i + this.newLine.length))) {
output += char;
}

else if (/\n/.test(char) && /\S|\r|\n/.test(xml.charAt(i - this.newLine.length)) && /\S|\r|\n/.test(next)) {
output += char;
}

continue;
}

output += char;
}

return output;
}
}
30 changes: 29 additions & 1 deletion extensions/axml/out/main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { languages, SnippetString, Position, IndentAction } = require('vscode');
const { languages, SnippetString, Position, IndentAction, TextEdit } = require('vscode');
const Formatter = require('./format');
const snippets = require('../snippets/axml');
const completions = require('./completions/axml.json');

Expand Down Expand Up @@ -54,6 +55,7 @@ function activate(context) {
})

languages.registerCompletionItemProvider('axml', new CompletionsProvider(), '.', ':', '<', '"', '=', '/', '\s');
languages.registerDocumentRangeFormattingEditProvider('axml', new AxmlFormatter());
}

const tagRex = /<[a-zA-Z\-\:\"\'\=\{\}\s]*\/?>?/;
Expand Down Expand Up @@ -106,5 +108,31 @@ class CompletionsProvider {
}
}

class AxmlFormatter {
provideDocumentFormattingEdits(document, options) {
let range = RangeUtil.getRangeForDocument(document);

return this._provideFormattingEdits(document, range, options);
}

provideDocumentRangeFormattingEdits(document, range, options) {
return this._provideFormattingEdits(document, range, options);
}

_provideFormattingEdits(document, range, options) {

let formatterOptions = {
preferSpaces: options.insertSpaces,
tabSize: options.tabSize,
};

let formatter = new Formatter(formatterOptions);
let xml = formatter.format(document.getText(range));

return [TextEdit.replace(range, xml)];

}
}

exports.activate = activate;
module.exports['default'] = activate;
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ant-editor",
"version": "0.1.17",
"version": "0.2.0",
"description": "Ant monaco with vscode-textmate. This module can only run under node runtime",
"main": "lib/editor",
"scripts": {
Expand Down Expand Up @@ -51,7 +51,7 @@
"bluebird": "^3.5.0",
"chalk": "^1.1.3",
"copy-webpack-plugin": "^4.0.1",
"electron": "1.7.5",
"electron": "^1.7.x",
"electron-rebuild-ln": "^0.0.7",
"fs-extra": "^3.0.1",
"glob": "^7.1.2",
Expand Down
4 changes: 4 additions & 0 deletions src/ant/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ export function executeCommand() {
export function getCommands() {
return commandsMap.keys();
}

export function registerTextEditorCommand() {
// noop
}
23 changes: 13 additions & 10 deletions src/ant/languages.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ async function delay(ms) {
}

function handleLanguageId(ids) {
if (typeof ids === 'string')
return ids;
return ids.map((id) => {
switch (typeof id) {
case 'object':
Expand Down Expand Up @@ -62,7 +64,7 @@ export default {
return result;
},
registerCompletionItemProvider: (id, provider, ...trigger) => {
monaco.languages.registerCompletionItemProvider(id, {
monaco.languages.registerCompletionItemProvider(handleLanguageId(id), {
triggerCharacters: trigger,
provideCompletionItems: async (model, position, token) => {
// For bufferSupport to sync textDocuments (typescript & javascript).
Expand Down Expand Up @@ -103,7 +105,7 @@ export default {
*/
},
registerDocumentFormattingEditProvider: (id, provider) => {
return monaco.languages.registerDocumentFormattingEditProvider(id, {
return monaco.languages.registerDocumentFormattingEditProvider(handleLanguageId(id), {
provideDocumentFormattingEdits: async (model, options, token) => {
const textDocument = uriToDocument.get(model.uri);
const args = await wireCancellationToken(token, provider.provideDocumentFormattingEdits(textDocument, options, token));
Expand All @@ -112,7 +114,8 @@ export default {
});
},
registerDocumentRangeFormattingEditProvider: (id, provider) => {
return monaco.languages.registerDocumentRangeFormattingEditProvider(id, {
console.log(id);
return monaco.languages.registerDocumentRangeFormattingEditProvider(handleLanguageId(id), {
provideDocumentRangeFormattingEdits: async (model, range, options, token) => {
const textDocument = uriToDocument.get(model.uri);
const args = await wireCancellationToken(token, provider.provideDocumentRangeFormattingEdits(textDocument, convert.toRange(range), options, token));
Expand All @@ -121,7 +124,7 @@ export default {
});
},
registerHoverProvider: (id, provider) => {
return monaco.languages.registerHoverProvider(id, {
return monaco.languages.registerHoverProvider(handleLanguageId(id), {
provideHover: async (model, position, token) => {
const textDocument = uriToDocument.get(model.uri);
const args = await wireCancellationToken(token, provider.provideHover(textDocument, convert.toPosition(position), token));
Expand All @@ -130,7 +133,7 @@ export default {
});
},
registerDefinitionProvider: (id, provider) => {
return monaco.languages.registerDefinitionProvider(id, {
return monaco.languages.registerDefinitionProvider(handleLanguageId(id), {
provideDefinition: async (model, position, token) => {
const textDocument = uriToDocument.get(model.uri);
const args = await wireCancellationToken(token, provider.provideDefinition(textDocument, convert.toPosition(position), token));
Expand All @@ -153,7 +156,7 @@ export default {
},
registerReferenceProvider: (id, provider) => {
if (!provider.provideReferences) return;
return monaco.languages.registerReferenceProvider(id, {
return monaco.languages.registerReferenceProvider(handleLanguageId(id), {
provideReferences: async (model, position, context, token) => {
const textDocument = uriToDocument.get(model.uri);
const args = await wireCancellationToken(token, provider.provideReferences(textDocument, convert.toPosition(position), context, token));
Expand All @@ -163,7 +166,7 @@ export default {
},
registerDocumentSymbolProvider: (id, provider) => {
if (!provider.provideDocumentSymbols) return;
return monaco.languages.registerDocumentSymbolProvider(id, {
return monaco.languages.registerDocumentSymbolProvider(handleLanguageId(id), {
provideDocumentSymbols: async (model, token) => {
const textDocument = uriToDocument.get(model.uri);
const args = await wireCancellationToken(token, provider.provideDocumentSymbols(textDocument, token));
Expand All @@ -172,7 +175,7 @@ export default {
});
},
registerSignatureHelpProvider: (id, provider, ...trigger) => {
return monaco.languages.registerSignatureHelpProvider(id, {
return monaco.languages.registerSignatureHelpProvider(handleLanguageId(id), {
signatureHelpTriggerCharacters: trigger,
provideSignatureHelp: (model, position, token) => {
const textDocument = uriToDocument.get(model.uri);
Expand Down Expand Up @@ -202,7 +205,7 @@ export default {
// return monaco.languages.registerImplementationProvider(id, provider);
},
registerTypeDefinitionProvider: (id, provider) => {
return monaco.languages.registerTypeDefinitionProvider(id, {
return monaco.languages.registerTypeDefinitionProvider(handleLanguageId(id), {
provideTypeDefinition: async (model, position, token) => {
const textDocument = uriToDocument.get(model.uri);
const args = await wireCancellationToken(token, provider.provideTypeDefinition(textDocument, convert.toPosition(position), token));
Expand All @@ -211,7 +214,7 @@ export default {
});
},
registerCodeLensProvider: (id, provider) => {
return monaco.languages.registerCodeLensProvider(id, {
return monaco.languages.registerCodeLensProvider(handleLanguageId(id), {
provideCodeLenses: async (model, token) => {
const textDocument = uriToDocument.get(model.uri);
const args = await wireCancellationToken(token, provider.provideCodeLenses(textDocument, token));
Expand Down
2 changes: 1 addition & 1 deletion src/editor/textDocument.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default class TextDocument extends MirrorModel {
* used in this document.
*/
this._eol = eol || (os.platform() === 'win32' ? '\r\n' : '\n');

/**
* Mutiple lines content.
*/
Expand Down

0 comments on commit ae82182

Please sign in to comment.