File indexing completed on 2024-05-19 04:00:10

0001 var katescript = {
0002     "name": "XML Style",
0003     "author": "Milian Wolff <mail@milianw.de>, Gerald Senarclens de Grancy <oss@senarclens.eu>",
0004     "license": "LGPL",
0005     "revision": 3,
0006     "kate-version": "5.1"
0007 }; // kate-script-header, must be at the start of the file without comments, pure json
0008 
0009 /*
0010     This file is part of the Kate Project.
0011 
0012     SPDX-License-Identifier: LGPL-2.0-only
0013 */
0014 
0015 
0016 // required katepart js libraries
0017 require ("range.js");
0018 require ("string.js");
0019 
0020 var DEBUG = false;  // disable before checking in!
0021 
0022 function dbg(s) {
0023     if (DEBUG)
0024         debug(s);
0025 }
0026 
0027 // specifies the characters which should trigger indent, beside the default '\n'
0028 triggerCharacters = ">";
0029 
0030 // used regular expressions
0031 // dear reader, please forgive me for using regular expressions in relation
0032 // with xml/html
0033 
0034 // match the beginning of any opening tag; special tags (<?..., <[... and <!...)
0035 // are ignored
0036 opening = /<[^\/?\[!]/g;
0037 // matches the beginning of any closing tag
0038 closing = /<\//g;
0039 // matches if there is nothing but a single closing tag
0040 single_closing_tag = /^<\/[^<>]*>$/;
0041 open_tag = /<[^\[]/;  // starting of a non-CDATA tag
0042 close_tag = /[^\]]>|^>/;  // end of a non-CDATA tag
0043 // ignore indenting if a line is started with one of the following tags
0044 ignore_tags = [/^<html/, /^<body/];
0045 
0046 
0047 // Return the code string of the given lineNr (no comments or strings etc).
0048 // Also strips self-closing tags.
0049 // Eg.
0050 // if document.line(x) is "  <p id="go">test</p> "
0051 //   getCode(x) -> "<p>test</p>"
0052 // if document.line(x) == "  <p id="go">test<br /></p> "
0053 //   getCode(x) -> "<p>test</p>"
0054 // if document.line(x) == "<p>test<!-- <em>comment</em> --></p>"
0055 //   getCode(x) -> "<p>test</p>"
0056 function getCode(lineNr) {
0057     var line = document.line(lineNr);
0058     var code = '';
0059     // // Skip any spaces at the front
0060     var col = document.firstVirtualColumn(lineNr);
0061     if (col == -1)
0062         return code;
0063     for (; col < line.length; ++col) {
0064         if (document.isCode(lineNr, col))
0065             code += line[col];
0066     }
0067     code = replaceSelfClosing(code);
0068     return code.trim();
0069 }
0070 
0071 
0072 // Return given code with all self-closing tags removed.
0073 function replaceSelfClosing(code) {
0074     return code.replace(/<[^<>]*\/>/g, '<tag></tag>');
0075 }
0076 
0077 
0078 // Check if the last line was endet inside a tag and return appropriate indent.
0079 // If the last line wasn't endet inside a tag, return -1.
0080 // Otherwise, return appropriate indent so that attributes are aligned.
0081 function _calcAttributeIndent(lineNr, indentWidth) {
0082     var text = document.line(lineNr);
0083     var num_open_tag = text.countMatches(open_tag);
0084     var num_close_tag = text.countMatches(close_tag);
0085     if (num_open_tag > num_close_tag) {
0086         dbg("unfinished tag");
0087         for (col = text.lastIndexOf("<"); col < text.length; ++col) {
0088             if (document.isOthers(lineNr, col) &&
0089                 document.isSpace(lineNr, col))
0090                 return col + 1;
0091         }
0092     } else if (num_open_tag < num_close_tag) {
0093         dbg("closing unfinished tag");
0094         code = getCode(lineNr);
0095         do {
0096             lineNr--;
0097             var line = document.line(lineNr);
0098             code = getCode(lineNr) + code;
0099         } while ((line.countMatches(open_tag) <= line.countMatches(close_tag)) &&
0100                  (lineNr > 0));
0101         var prevIndent = Math.max(document.firstVirtualColumn(lineNr), 0);
0102         code = replaceSelfClosing(code);
0103         var steps = calcSteps(code);
0104         return prevIndent + indentWidth * steps;
0105     }
0106     return -1;  // by default, keep last line's indent (-1)
0107 }
0108 
0109 
0110 // Return the number of steps to indent/ un-indent.
0111 // If the code is matched by any element of ignore_tags, 0 is returned.
0112 function calcSteps(code) {
0113     for (var key in ignore_tags) {
0114         if (code.match(ignore_tags[key]))
0115             return 0;
0116     }
0117     var num_opening = code.match(opening) ? code.match(opening).length : 0;
0118     var num_closing = code.match(closing) ? code.match(closing).length : 0;
0119     return num_opening - num_closing;
0120 }
0121 
0122 
0123 // Return the amount of characters (in spaces) to be indented.
0124 // Called for each newline (ch == '\n') and all characters specified in
0125 // the global variable triggerCharacters. When calling Tools → Align
0126 // the variable ch is empty, i.e. ch == ''.
0127 // Special indent() return values:
0128 //   -1: keep last indent
0129 //   -2: do nothing
0130 function indent(lineNr, indentWidth, char) {
0131     dbg("lineNr: " + lineNr + " indentWidth: " + indentWidth + " char: " + char);
0132     if (lineNr == 0)  // don't ever act on document's first line
0133         return -2;
0134 
0135     var lastLineNr = lineNr - 1;
0136     var lastLine = getCode(lastLineNr);
0137     dbg("lastLine1: " + lastLine);
0138     while (lastLine == "") {
0139         lastLineNr--;
0140         if (lastLineNr <= 0) {
0141             return -1;
0142         }
0143         lastLine = getCode(lastLineNr);
0144     }
0145     dbg("lastLine2: " + lastLine);
0146 
0147     // default action (for char == '\n' or char == '')
0148     var indent = _calcAttributeIndent(lastLineNr, indentWidth);
0149     if (indent != -1) {
0150         return indent;
0151     }
0152     dbg("indent: " + indent);
0153 
0154     indent = Math.max(document.firstVirtualColumn(lastLineNr), 0);
0155     dbg("indent: " + indent);
0156 
0157 
0158     var steps = calcSteps(lastLine);
0159     // unindenting separate closing tags are dealt with by last line
0160     if (steps && !lastLine.match(single_closing_tag))
0161         indent += indentWidth * steps;
0162 
0163     // set char if required (eg. in case of align or copy and paste)
0164     if (char == ">" || !char) {  // ok b/c of inner if
0165         // if there is nothing but a separate closing tag, unindent
0166         var curLine = getCode(lineNr);
0167         dbg("curLine: " + curLine);
0168         if (curLine.match(single_closing_tag)) {
0169             return Math.max(indent - indentWidth, 0);
0170         }
0171     }
0172     return Math.max(indent, -1);
0173 }
0174 
0175 // kate: space-indent on; indent-width 4; replace-tabs on;