ace.define("ace/ext/beautify",["require","exports","module","ace/token_iterator"], function(require, exports, module){// [WIP] "use strict"; var TokenIterator = require("../token_iterator").TokenIterator; function is(token, type) { return token.type.lastIndexOf(type + ".xml") > -1; } exports.singletonTags = ["area", "base", "br", "col", "command", "embed", "hr", "html", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"]; exports.blockTags = ["article", "aside", "blockquote", "body", "div", "dl", "fieldset", "footer", "form", "head", "header", "html", "nav", "ol", "p", "script", "section", "style", "table", "tbody", "tfoot", "thead", "ul"]; exports.formatOptions = { lineBreaksAfterCommasInCurlyBlock: true }; exports.beautify = function (session) { var iterator = new TokenIterator(session, 0, 0); var token = iterator.getCurrentToken(); var tabString = session.getTabString(); var singletonTags = exports.singletonTags; var blockTags = exports.blockTags; var formatOptions = exports.formatOptions || {}; var nextToken; var breakBefore = false; var spaceBefore = false; var spaceAfter = false; var code = ""; var value = ""; var tagName = ""; var depth = 0; var lastDepth = 0; var lastIndent = 0; var indent = 0; var unindent = 0; var roundDepth = 0; var curlyDepth = 0; var row; var curRow = 0; var rowsToAdd = 0; var rowTokens = []; var abort = false; var i; var indentNextLine = false; var inTag = false; var inCSS = false; var inBlock = false; var levels = { 0: 0 }; var parents = []; var caseBody = false; var trimNext = function () { if (nextToken && nextToken.value && nextToken.type !== 'string.regexp') nextToken.value = nextToken.value.replace(/^\s*/, ""); }; var trimLine = function () { var end = code.length - 1; while (true) { if (end == 0) break; if (code[end] !== " ") break; end = end - 1; } code = code.slice(0, end + 1); }; var trimCode = function () { code = code.trimRight(); breakBefore = false; }; while (token !== null) { curRow = iterator.getCurrentTokenRow(); rowTokens = iterator.$rowTokens; nextToken = iterator.stepForward(); if (typeof token !== "undefined") { value = token.value; unindent = 0; inCSS = (tagName === "style" || session.$modeId === "ace/mode/css"); if (is(token, "tag-open")) { inTag = true; if (nextToken) inBlock = (blockTags.indexOf(nextToken.value) !== -1); if (value === "</") { if (inBlock && !breakBefore && rowsToAdd < 1) rowsToAdd++; if (inCSS) rowsToAdd = 1; unindent = 1; inBlock = false; } } else if (is(token, "tag-close")) { inTag = false; } else if (is(token, "comment.start")) { inBlock = true; } else if (is(token, "comment.end")) { inBlock = false; } if (!inTag && !rowsToAdd && token.type === "paren.rparen" && token.value.substr(0, 1) === "}") { rowsToAdd++; } if (curRow !== row) { rowsToAdd = curRow; if (row) rowsToAdd -= row; } if (rowsToAdd) { trimCode(); for (; rowsToAdd > 0; rowsToAdd--) code += "\n"; breakBefore = true; if (!is(token, "comment") && !token.type.match(/^(comment|string)$/)) value = value.trimLeft(); } if (value) { if (token.type === "keyword" && value.match(/^(if|else|elseif|for|foreach|while|switch)$/)) { parents[depth] = value; trimNext(); spaceAfter = true; if (value.match(/^(else|elseif)$/)) { if (code.match(/\}[\s]*$/)) { trimCode(); spaceBefore = true; } } } else if (token.type === "paren.lparen") { trimNext(); if (value.substr(-1) === "{") { spaceAfter = true; indentNextLine = false; if (!inTag) rowsToAdd = 1; } if (value.substr(0, 1) === "{") { spaceBefore = true; if (code.substr(-1) !== '[' && code.trimRight().substr(-1) === '[') { trimCode(); spaceBefore = false; } else if (code.trimRight().substr(-1) === ')') { trimCode(); } else { trimLine(); } } } else if (token.type === "paren.rparen") { unindent = 1; if (value.substr(0, 1) === "}") { if (parents[depth - 1] === 'case') unindent++; if (code.trimRight().substr(-1) === '{') { trimCode(); } else { spaceBefore = true; if (inCSS) rowsToAdd += 2; } } if (value.substr(0, 1) === "]") { if (code.substr(-1) !== '}' && code.trimRight().substr(-1) === '}') { spaceBefore = false; indent++; trimCode(); } } if (value.substr(0, 1) === ")") { if (code.substr(-1) !== '(' && code.trimRight().substr(-1) === '(') { spaceBefore = false; indent++; trimCode(); } } trimLine(); } else if ((token.type === "keyword.operator" || token.type === "keyword") && value.match(/^(=|==|===|!=|!==|&&|\|\||and|or|xor|\+=|.=|>|>=|<|<=|=>)$/)) { trimCode(); trimNext(); spaceBefore = true; spaceAfter = true; } else if (token.type === "punctuation.operator" && value === ';') { trimCode(); trimNext(); spaceAfter = true; if (inCSS) rowsToAdd++; } else if (token.type === "punctuation.operator" && value.match(/^(:|,)$/)) { trimCode(); trimNext(); if (value.match(/^(,)$/) && curlyDepth > 0 && roundDepth === 0 && formatOptions.lineBreaksAfterCommasInCurlyBlock) { rowsToAdd++; } else { spaceAfter = true; breakBefore = false; } } else if (token.type === "support.php_tag" && value === "?>" && !breakBefore) { trimCode(); spaceBefore = true; } else if (is(token, "attribute-name") && code.substr(-1).match(/^\s$/)) { spaceBefore = true; } else if (is(token, "attribute-equals")) { trimLine(); trimNext(); } else if (is(token, "tag-close")) { trimLine(); if (value === "/>") spaceBefore = true; } else if (token.type === "keyword" && value.match(/^(case|default)$/)) { if (caseBody) unindent = 1; } if (breakBefore && !(token.type.match(/^(comment)$/) && !value.substr(0, 1).match(/^[/#]$/)) && !(token.type.match(/^(string)$/) && !value.substr(0, 1).match(/^['"@]$/))) { indent = lastIndent; if (depth > lastDepth) { indent++; for (i = depth; i > lastDepth; i--) levels[i] = indent; } else if (depth < lastDepth) indent = levels[depth]; lastDepth = depth; lastIndent = indent; if (unindent) indent -= unindent; if (indentNextLine && !roundDepth) { indent++; indentNextLine = false; } for (i = 0; i < indent; i++) code += tabString; } if (token.type === "keyword" && value.match(/^(case|default)$/)) { if (caseBody === false) { parents[depth] = value; depth++; caseBody = true; } } else if (token.type === "keyword" && value.match(/^(break)$/)) { if (parents[depth - 1] && parents[depth - 1].match(/^(case|default)$/)) { depth--; caseBody = false; } } if (token.type === "paren.lparen") { roundDepth += (value.match(/\(/g) || []).length; curlyDepth += (value.match(/\{/g) || []).length; depth += value.length; } if (token.type === "keyword" && value.match(/^(if|else|elseif|for|while)$/)) { indentNextLine = true; roundDepth = 0; } else if (!roundDepth && value.trim() && token.type !== "comment") indentNextLine = false; if (token.type === "paren.rparen") { roundDepth -= (value.match(/\)/g) || []).length; curlyDepth -= (value.match(/\}/g) || []).length; for (i = 0; i < value.length; i++) { depth--; if (value.substr(i, 1) === '}' && parents[depth] === 'case') { depth--; } } } if (token.type == "text") value = value.replace(/\s+$/, " "); if (spaceBefore && !breakBefore) { trimLine(); if (code.substr(-1) !== "\n") code += " "; } code += value; if (spaceAfter) code += " "; breakBefore = false; spaceBefore = false; spaceAfter = false; if ((is(token, "tag-close") && (inBlock || blockTags.indexOf(tagName) !== -1)) || (is(token, "doctype") && value === ">")) { if (inBlock && nextToken && nextToken.value === "</") rowsToAdd = -1; else rowsToAdd = 1; } if (nextToken && singletonTags.indexOf(nextToken.value) === -1) { if (is(token, "tag-open") && value === "</") { depth--; } else if (is(token, "tag-open") && value === "<") { depth++; } else if (is(token, "tag-close") && value === "/>") { depth--; } } if (is(token, "tag-name")) { tagName = value; } row = curRow; } } token = nextToken; } code = code.trim(); session.doc.setValue(code); }; exports.commands = [{ name: "beautify", description: "Format selection (Beautify)", exec: function (editor) { exports.beautify(editor.session); }, bindKey: "Ctrl-Shift-B" }]; }); (function() { ace.require(["ace/ext/beautify"], function(m) { if (typeof module == "object" && typeof exports == "object" && module) { module.exports = m; } }); })();