var katescript = { "name": "XML Style", "author": "Milian Wolff , Gerald Senarclens de Grancy ", "license": "LGPL", "revision": 3, "kate-version": "5.1" }; // kate-script-header, must be at the start of the file without comments, pure json /* This file is part of the Kate Project. SPDX-License-Identifier: LGPL-2.0-only */ // required katepart js libraries require ("range.js"); require ("string.js"); var DEBUG = false; // disable before checking in! function dbg(s) { if (DEBUG) debug(s); } // specifies the characters which should trigger indent, beside the default '\n' triggerCharacters = ">"; // used regular expressions // dear reader, please forgive me for using regular expressions in relation // with xml/html // match the beginning of any opening tag; special tags (]*>$/; open_tag = /<[^\[]/; // starting of a non-CDATA tag close_tag = /[^\]]>|^>/; // end of a non-CDATA tag // ignore indenting if a line is started with one of the following tags ignore_tags = [/^test

" // getCode(x) -> "

test

" // if document.line(x) == "

test

" // getCode(x) -> "

test

" // if document.line(x) == "

test

" // getCode(x) -> "

test

" function getCode(lineNr) { var line = document.line(lineNr); var code = ''; // // Skip any spaces at the front var col = document.firstVirtualColumn(lineNr); if (col == -1) return code; for (; col < line.length; ++col) { if (document.isCode(lineNr, col)) code += line[col]; } code = replaceSelfClosing(code); return code.trim(); } // Return given code with all self-closing tags removed. function replaceSelfClosing(code) { return code.replace(/<[^<>]*\/>/g, ''); } // Check if the last line was endet inside a tag and return appropriate indent. // If the last line wasn't endet inside a tag, return -1. // Otherwise, return appropriate indent so that attributes are aligned. function _calcAttributeIndent(lineNr, indentWidth) { var text = document.line(lineNr); var num_open_tag = text.countMatches(open_tag); var num_close_tag = text.countMatches(close_tag); if (num_open_tag > num_close_tag) { dbg("unfinished tag"); for (col = text.lastIndexOf("<"); col < text.length; ++col) { if (document.isOthers(lineNr, col) && document.isSpace(lineNr, col)) return col + 1; } } else if (num_open_tag < num_close_tag) { dbg("closing unfinished tag"); code = getCode(lineNr); do { lineNr--; var line = document.line(lineNr); code = getCode(lineNr) + code; } while ((line.countMatches(open_tag) <= line.countMatches(close_tag)) && (lineNr > 0)); var prevIndent = Math.max(document.firstVirtualColumn(lineNr), 0); code = replaceSelfClosing(code); var steps = calcSteps(code); return prevIndent + indentWidth * steps; } return -1; // by default, keep last line's indent (-1) } // Return the number of steps to indent/ un-indent. // If the code is matched by any element of ignore_tags, 0 is returned. function calcSteps(code) { for (var key in ignore_tags) { if (code.match(ignore_tags[key])) return 0; } var num_opening = code.match(opening) ? code.match(opening).length : 0; var num_closing = code.match(closing) ? code.match(closing).length : 0; return num_opening - num_closing; } // Return the amount of characters (in spaces) to be indented. // Called for each newline (ch == '\n') and all characters specified in // the global variable triggerCharacters. When calling Tools → Align // the variable ch is empty, i.e. ch == ''. // Special indent() return values: // -1: keep last indent // -2: do nothing function indent(lineNr, indentWidth, char) { dbg("lineNr: " + lineNr + " indentWidth: " + indentWidth + " char: " + char); if (lineNr == 0) // don't ever act on document's first line return -2; var lastLineNr = lineNr - 1; var lastLine = getCode(lastLineNr); dbg("lastLine1: " + lastLine); while (lastLine == "") { lastLineNr--; if (lastLineNr <= 0) { return -1; } lastLine = getCode(lastLineNr); } dbg("lastLine2: " + lastLine); // default action (for char == '\n' or char == '') var indent = _calcAttributeIndent(lastLineNr, indentWidth); if (indent != -1) { return indent; } dbg("indent: " + indent); indent = Math.max(document.firstVirtualColumn(lastLineNr), 0); dbg("indent: " + indent); var steps = calcSteps(lastLine); // unindenting separate closing tags are dealt with by last line if (steps && !lastLine.match(single_closing_tag)) indent += indentWidth * steps; // set char if required (eg. in case of align or copy and paste) if (char == ">" || !char) { // ok b/c of inner if // if there is nothing but a separate closing tag, unindent var curLine = getCode(lineNr); dbg("curLine: " + curLine); if (curLine.match(single_closing_tag)) { return Math.max(indent - indentWidth, 0); } } return Math.max(indent, -1); } // kate: space-indent on; indent-width 4; replace-tabs on;