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

0001 var katescript = {
0002     "name": "Julia",
0003     "author": "Ilia Kats <ilia-kats@gmx.net>, Paul Giannaros <paul@giannaros.org>, Gerald Senarclens de Grancy <oss@senarclens.eu>",
0004     "license": "LGPL",
0005     "revision": 1,
0006     "kate-version": "5.1",
0007     "indent-languages": ["Julia"]
0008 }; // kate-script-header, must be at the start of the file without comments, pure json
0009 
0010 // required katepart js libraries
0011 require("range.js");
0012 require("string.js");
0013 
0014 openings = ['(', '[', '{'];
0015 closings = [')', ']', '}'];  // requires same order as in openings
0016 imports = ["using", "import"]
0017 linestart_block_start = ["function", "if", "try", "for", "while", "let", "quote", "mutable struct", "struct"];
0018 linemid_block_start = ["do", "begin"];
0019 block_continue = ["else", "elseif", "catch", "finally"];
0020 block_continue_lineend = ["else", "finally", "catch"];
0021 block_continue_linemid = ["elseif", "catch"];
0022 unindenter = "end";
0023 
0024 triggerCharacters = "efhyd ";
0025 
0026 immediate_unindenters = new Set(block_continue.concat([unindenter]));
0027 all_block_expr = new RegExp(
0028         "\\b(" +
0029         [
0030             linestart_block_start.join("|"),
0031             linemid_block_start.join("|"),
0032             block_continue.join("|") + "|" +
0033             unindenter
0034         ].join("|") +
0035         ")\\b"
0036 , "g");
0037 full_block_expr = new RegExp(
0038         "\\b(" +
0039         linestart_block_start.join("|") + "|" +
0040         linemid_block_start.join("|") + "|" +
0041         unindenter +
0042         ")\\b"
0043 , "g");
0044 linestart_block_start_expr = new RegExp("\\b(" + linestart_block_start.join("|") + ")\\b");
0045 linemid_block_start_expr = new RegExp("\\b(" + linemid_block_start.join("|") + ")\\b");
0046 unindenters_newline_expr = new RegExp(
0047         "\\b((" +
0048         block_continue_lineend.join("$|") + "$|" +
0049         unindenter + "$)|((" +
0050         block_continue_linemid.join("|") +
0051         ")(?!.*" + all_block_expr.source + ")))\\b"
0052 );
0053 
0054 block_starts = new Set(linestart_block_start.concat(linemid_block_start));
0055 
0056 var imports_expr = new RegExp("((\\s*\\w+\\s*:)(\\s*\\w+\\s*,)*|(\\s*\\w+\\s*,)+)$");
0057 var imports_end_expr = new RegExp("(\\s*(\\w+\\s*:?)\\s*,\\s*)*\\s*(\\w+)\\s*$");
0058 
0059 // Return the given line without comments and leading or trailing whitespace.
0060 // Eg.
0061 // getCode(x) -> "for i in range(3):"
0062 //     if document.line(x) == "  for i in range(3):"
0063 // getCode(x) -> "for i in range(3):"
0064 //     if document.line(x) == "for i in range(3):  "
0065 // getCode(x) -> "for i in range(3):"
0066 //     if document.line(x) == "for i in range(3):  # grand"
0067 function getCode(lineNr, virtcol=-1) {
0068     var line = document.line(lineNr);
0069     var code = '';
0070     virtcol = virtcol >= 0 ? virtcol : document.firstVirtualColumn(lineNr);
0071     if (virtcol < 0)
0072         return code;
0073     for (;virtcol < line.length; ++virtcol) {
0074         if (!document.isComment(lineNr, virtcol)) {
0075             code += line[virtcol];
0076         }
0077     }
0078     return code.trim();
0079 }
0080 
0081 function getLastCodePosition(lineNr, lastVirtCol=-1) {
0082     var line = document.line(lineNr);
0083     virtcol = lastVirtCol >= 0 ? lastVirtCol : document.lastVirtualColumn(lineNr);
0084     if (virtcol < 0)
0085         return -1
0086     for (; virtcol >= 0; --virtcol) {
0087         if (!document.isComment(lineNr, virtcol) && !document.isSpace(lineNr, virtcol))
0088             break;
0089     }
0090     return virtcol;
0091 }
0092 
0093 // Return the indent if a opening bracket is not closed (incomplete sequence).
0094 // The calculated intent is the innermost opening bracket's position plus 1.
0095 // `lineNr`: the number of the line on which the brackets should be counted
0096 function _calcOpeningIndent(lineNr) {
0097     var line = document.line(lineNr);
0098     var countClosing = new Array();
0099     closings.forEach(function(elem) {
0100         countClosing[elem] = 0;
0101     });
0102     for (i = line.length - 1; i >= 0; --i) {
0103         if (document.isComment(lineNr, i) || document.isString(lineNr, i))
0104             continue;
0105         if (closings.indexOf(line[i]) > -1)
0106             countClosing[line[i]]++;
0107         var index = openings.indexOf(line[i]);
0108         if (index > -1) {
0109             if (countClosing[closings[index]] == 0) {
0110                 return i + 1;
0111             }
0112             countClosing[closings[index]]--;
0113         }
0114     }
0115     return -1;
0116 }
0117 
0118 
0119 // Return the indent if a closing bracket not opened (incomplete sequence).
0120 // The intent is the same as on the line with the unmatched opening bracket.
0121 // `lineNr`: the number of the line on which the brackets should be counted
0122 function _calcClosingIndent(lineNr, indentWidth) {
0123     var line = document.line(lineNr);
0124     var countClosing = new Array();
0125     closings.forEach(function(elem) {
0126         countClosing[elem] = 0;
0127     });
0128     for (i = line.length - 1; i >= 0; --i) {
0129         if (document.isComment(lineNr, i) || document.isString(lineNr, i))
0130             continue;
0131         if (closings.indexOf(line[i]) > -1)
0132             countClosing[line[i]]++;
0133         var index = openings.indexOf(line[i]);
0134         if (index > -1)
0135             countClosing[closings[index]]--;
0136     }
0137     for (var key in countClosing) {
0138         if (countClosing[key] > 0) {  // unmatched closing bracket
0139             for (--lineNr; lineNr >= 0; --lineNr) {
0140                 if (_calcOpeningIndent(lineNr) > -1) {
0141                     var indent = document.firstVirtualColumn(lineNr);
0142                     if (shouldUnindent(lineNr + 1))
0143                         return Math.max(0, indent - indentWidth);
0144                     return indent;
0145                 }
0146             }
0147         }
0148     }
0149     return -1;
0150 }
0151 
0152 // Returns the indent for mismatched (opening or closing) brackets.
0153 // If there are no mismatched brackets, -1 is returned.
0154 // `lineNr`: number of the line for which the indent is calculated
0155 function calcBracketIndent(lineNr, indentWidth) {
0156     var indent = _calcOpeningIndent(lineNr);
0157     if (indent > -1)
0158         return indent
0159     indent = _calcClosingIndent(lineNr);
0160     if (indent > -1)
0161         return indent
0162     return -1;
0163 }
0164 
0165 function findMatchingParenthesis(lineNr, charNr) {
0166     var nests = 1;
0167     charNr = charNr + document.firstVirtualColumn(lineNr);
0168     while (lineNr >= 0) {
0169         var line = document.line(lineNr);
0170         for (i = Math.min(charNr - 1, line.length - 1); i >= 0; --i) {
0171             if (document.isComment(lineNr, i) || document.isString(lineNr, i))
0172                 continue;
0173             if (line[i] == '(')
0174                 nests -= 1;
0175             else if (line[i] == ')')
0176                 nests += 1;
0177             if (nests == 0)
0178                 return [lineNr, i - document.firstVirtualColumn(lineNr)];
0179         }
0180         --lineNr;
0181         charNr = Infinity;
0182     }
0183     return [-1, -1]
0184 }
0185 
0186 // Return true if a single unindent should occur.
0187 function shouldUnindent(LineNr, bracketOnly=true) {
0188     // unindent if the last line was indented b/c of an operator
0189     if (LineNr >= 1) {
0190         var lastcodepos = getLastCodePosition(LineNr - 1);
0191         if (lastcodepos > 0 && document.defStyleNum(LineNr - 1, lastcodepos) == dsOperator)
0192             return 1;
0193         if (!bracketOnly && document.line(LineNr)[lastcodepos] != ',') {
0194             var cline = getCode(LineNr);
0195             if (!imports.some(imp => cline.startsWith(imp)) && imports_end_expr.test(cline)) {
0196                 --LineNr;
0197                 for (; LineNr >= 0; --LineNr) {
0198                     cline = getCode(LineNr);
0199                     if (!cline.length)
0200                         continue;
0201                     if (imports_expr.test(cline)) {
0202                         if (imports.some(imp => cline.startsWith(imp)))
0203                             return 1;
0204                     } else
0205                         break;
0206                 }
0207             }
0208         }
0209     }
0210     return 0;
0211 }
0212 
0213 // finds the indentation level of a matching block start for a block end
0214 function findMatchingBlock(lineNr, trigger) {
0215     var nested_threshold = trigger == unindenter ? 1 : 0;
0216     var nestedBlocks = 0;
0217     var found = false;
0218     for (var linenr = lineNr; linenr >= 0; --linenr) {
0219         var lline = getCode(linenr);
0220         var matches = [];
0221         while (match = full_block_expr.exec(lline)) {
0222             matches.push(match);
0223         }
0224         if (matches.length > 0) {
0225             for (match of matches.reverse()) {
0226                 if (match[0] == unindenter) {
0227                     var lastclosingbracket = lline.lastIndexOf("]", match.index);
0228                     var lastopeningbracket = lline.lastIndexOf("[", match.index);
0229                     // end is also used in subsetting to get the last element, ignore this
0230                     // for block calculation
0231                     if (lastopeningbracket == -1 || lastclosingbracket > lastopeningbracket)
0232                         ++nestedBlocks;
0233                 } else if (nestedBlocks == nested_threshold) {
0234                     found = block_starts.has(match[0]);
0235                     if (found)
0236                         break;
0237                 } else {
0238                     --nestedBlocks;
0239                 }
0240             }
0241         }
0242         if (found)
0243             break;
0244     }
0245     return found && linenr < lineNr ? document.firstVirtualColumn(linenr) : -1;
0246 }
0247 
0248 // Return the amount of characters (in spaces) to be indented.
0249 // Special indent() return values:
0250 //   -2 = no indent
0251 //   -1 = keep last indent
0252 // Follow PEP8 for unfinished sequences and argument lists.
0253 // Nested sequences are not implemented. (neither by Emacs' python-mode)
0254 function indent(line, indentWidth, character) {
0255     if (line == 0)  // don't ever act on document's first line
0256         return -2;
0257 
0258     var alignOnly = character == "";
0259 
0260     if (alignOnly || character != '\n') {
0261         var lline = getCode(line);
0262         if (immediate_unindenters.has(lline))
0263             return findMatchingBlock(lline == unindenter ? line : line - 1, lline);
0264         else if (!alignOnly)
0265             return -2
0266     }
0267 
0268     while (line > 0 && !document.line(line - 1).length) // ignore empty lines
0269         --line;
0270     --line;
0271 
0272     var virtcol = document.firstVirtualColumn(line);
0273     var lastLine = getCode(line, virtcol);
0274     var lastChar = lastLine.substr(-1);
0275 
0276     // indent when opening bracket or an operator is at the end the previous line
0277     if (openings.indexOf(lastChar) >= 0 || document.defStyleNum(line, getLastCodePosition(line)) == dsOperator) {
0278         return virtcol + indentWidth;
0279     }
0280     var indent = calcBracketIndent(line, indentWidth);
0281     if (lastChar == ')') {
0282         // could be a function definition with multi-line argument list
0283         var matching = findMatchingParenthesis(line, lastLine.length - 1);
0284         if (matching[0] > -1) {
0285             line = matching[0];
0286             virtcol = document.firstVirtualColumn(line);
0287             lastLine = getCode(line, virtcol);
0288         }
0289         else
0290             return -1;
0291     } else if (lastChar == ',' || lastChar == ':') {
0292         var is_import = false;
0293         for (const imp of imports) {
0294             if (lastLine.startsWith(imp))
0295                 return virtcol + indentWidth;
0296         }
0297     }
0298 
0299     // this also covers single-line blocks
0300     var match = lastLine.match(unindenters_newline_expr);
0301     if (match) {
0302         var mblock = findMatchingBlock(line, match[0]);
0303         if (mblock > -1) {
0304             return match[0] == unindenter ? mblock : mblock + indentWidth;
0305         } else
0306             return -1;
0307     }
0308 
0309     startblock = lastLine.search(linestart_block_start_expr);
0310     if (startblock == 0) {
0311         if (indent > virtcol)
0312             return indent; // unmatched open bracket in proper block start
0313         else
0314             return virtcol + indentWidth;
0315     } else if (startblock > 0 || lastLine.search(linemid_block_start_expr) > -1) { // single-line blocks
0316         var endpos = lastLine.lastIndexOf(unindenter);
0317         var lastkeyword = unindenter;
0318         block_continue.forEach(function(keyw) {
0319             var pos = lastLine.lastIndexOf(keyw);
0320             if (pos >= 0 && pos > endpos) {
0321                 lastkeyword = keyw;
0322                 endpos = pos;
0323             }
0324         });
0325         if (endpos >= 0)
0326             return findMatchingBlock(line, lastkeyword);
0327         else {
0328             if (indent > -1)
0329                 indent += indentWidth; // unmatched open bracket in possibly nested blocks
0330             else
0331                 indent = virtcol + indentWidth;
0332         }
0333     }
0334     if (shouldUnindent(line, false) && (indent == -1)) {
0335         indent = Math.max(0, virtcol - indentWidth);
0336     }
0337     return indent;
0338 }
0339 
0340 // kate: space-indent on; indent-width 4; replace-tabs on;