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

0001 var katescript = {
0002     "author": "Dominik Haumann <dhdev@gmx.de>, Milian Wolff <mail@milianw.de>, Gerald Senarclens de Grancy <oss@senarclens.eu>, Alex Turbov <i.zaufi@gmail.com>, Pablo Rauzy <r_NOSPAM_@uzy.me>, Henri Kaustinen <heka1@protonmail.com>",
0003     "license": "LGPL-2.1+",
0004     "revision": 12,
0005     "kate-version": "5.1",
0006     "functions": ["sort", "sortuniq", "moveLinesDown", "moveLinesUp", "natsort", "uniq", "rtrim", "ltrim", "trim", "join", "rmblank", "alignon", "unwrap", "each", "filter", "map", "duplicateLinesUp", "duplicateLinesDown", "duplicateSelection", "rewrap", "encodeURISelection", "decodeURISelection", "fsel", "bsel"],
0007     "actions": [
0008         {   "function": "sort",
0009             "name": "Sort Selected Text Alphabetically",
0010             "category": "Editing"
0011         },
0012         {   "function": "sortuniq",
0013             "name": "Remove Duplicates and Sort Selected Text Alphabetically",
0014             "category": "Editing"
0015         },
0016         {   "function": "uniq",
0017             "name": "Remove Duplicate Lines",
0018             "category": "Editing"
0019         },
0020         {   "function": "rtrim",
0021             "name": "Remove Trailing Spaces",
0022             "category": "Editing"
0023         },
0024         {   "function": "ltrim",
0025             "name": "Remove Leading Spaces",
0026             "category": "Editing"
0027         },
0028         {   "function": "trim",
0029             "name": "Remove Trailing and Leading Spaces",
0030             "category": "Editing"
0031         },
0032         {   "function": "join",
0033             "name": "Join Lines",
0034             "category": "Editing"
0035         },
0036         {   "function": "moveLinesDown",
0037             "name": "Move Lines Down",
0038             "shortcut": "Ctrl+Shift+Down",
0039             "category": "Editing"
0040         },
0041         {   "function": "moveLinesUp",
0042             "name": "Move Lines Up",
0043             "shortcut": "Ctrl+Shift+Up",
0044             "category": "Editing"
0045         },
0046         {   "function": "duplicateLinesDown",
0047             "name": "Duplicate Selected Lines Down",
0048             "category": "Editing"
0049         },
0050         {   "function": "duplicateLinesUp",
0051             "name": "Duplicate Selected Lines Up",
0052             "category": "Editing"
0053         },
0054         {   "function": "duplicateSelection",
0055             "name": "Duplicate selected text",
0056             "category": "Editing"
0057         },
0058         {   "function": "encodeURISelection",
0059             "name": "URI-encode Selected Text",
0060             "category": "Editing"
0061         },
0062         {   "function": "decodeURISelection",
0063             "name": "URI-decode Selected Text",
0064             "category": "Editing"
0065         },
0066         {   "function": "rmblank",
0067             "name": "Remove Empty Lines",
0068             "category": "Editing"
0069         }
0070     ]
0071 }; // kate-script-header, must be at the start of the file without comments, pure json
0072 
0073 // required katepart js libraries
0074 require ("range.js");
0075 
0076 function sort()
0077 {
0078     each(function(lines){return lines.sort()});
0079 }
0080 
0081 function uniq()
0082 {
0083     each(function(lines) {
0084         var uniq_lines = [];
0085         var seen = new Set();
0086         for ( var i = 0; i < lines.length; ++i ) {
0087             if (!seen.has(lines[i])) {
0088                 seen.add(lines[i]);
0089                 uniq_lines.push(lines[i]);
0090             }
0091         }
0092         return uniq_lines;
0093     });
0094 }
0095 
0096 function sortuniq()
0097 {
0098     each(function(lines) {
0099         var uniq_lines = [];
0100         var seen = new Set();
0101         for ( var i = 0; i < lines.length; ++i ) {
0102             if (!seen.has(lines[i])) {
0103                 seen.add(lines[i]);
0104                 uniq_lines.push(lines[i]);
0105             }
0106         }
0107         return uniq_lines.sort();
0108     });
0109 }
0110 
0111 function natsort()
0112 {
0113     each(function(lines){return lines.sort(natcompare);});
0114 }
0115 
0116 function rtrim()
0117 {
0118     map(function(l){ return l.replace(/\s+$/, ''); });
0119 }
0120 
0121 function ltrim()
0122 {
0123     map(function(l){ return l.replace(/^\s+/, ''); });
0124 }
0125 
0126 function trim()
0127 {
0128     map(function(l){ return l.replace(/^\s+|\s+$/, ''); });
0129 }
0130 
0131 function rmblank()
0132 {
0133     filter(function(l) { return l.length > 0; });
0134 }
0135 
0136 function alignon(pattern)
0137 {
0138     if (typeof pattern == "undefined") {
0139         pattern = "";
0140     }
0141     var selection = view.selection();
0142     if (!selection.isValid()) {
0143         selection = document.documentRange();
0144     }
0145     view.alignOn(selection, pattern);
0146 }
0147 
0148 function join(separator)
0149 {
0150     if (typeof(separator) != "string") {
0151         separator = "";
0152     }
0153     each(function(lines){
0154         return [lines.join(separator)];
0155     });
0156 }
0157 
0158 // unwrap does the opposite of the script word wrap
0159 function unwrap ()
0160 {
0161     var selectionRange = view.selection();
0162     if (selectionRange.isValid()) {
0163         // unwrap all paragraphs in the selection range
0164         var currentLine = selectionRange.start.line;
0165         var count = selectionRange.end.line - selectionRange.start.line;
0166 
0167         document.editBegin();
0168         while (count >= 0) {
0169             // skip empty lines
0170             while (count >= 0 && document.firstColumn(currentLine) == -1) {
0171                 --count;
0172                 ++currentLine;
0173             }
0174 
0175             // find block of text lines to join
0176             var anchorLine = currentLine;
0177             while (count >= 0 && document.firstColumn(currentLine) != -1) {
0178                 --count;
0179                 ++currentLine;
0180             }
0181 
0182             if (currentLine != anchorLine) {
0183                 document.joinLines(anchorLine, currentLine - 1);
0184                 currentLine -= currentLine - anchorLine - 1;
0185             }
0186         }
0187         document.editEnd();
0188     } else {
0189         // unwrap paragraph under the cursor
0190         var cursorPosition = view.cursorPosition();
0191         if (document.firstColumn(cursorPosition.line) != -1) {
0192             var startLine = cursorPosition.line;
0193             while (startLine > 0) {
0194                 if (document.firstColumn(startLine - 1) == -1) {
0195                     break;
0196                 }
0197                 --startLine;
0198             }
0199 
0200             var endLine = cursorPosition.line;
0201             var lineCount = document.lines();
0202             while (endLine < lineCount) {
0203                 if (document.firstColumn(endLine + 1) == -1) {
0204                     break;
0205                 }
0206                 ++endLine;
0207             }
0208 
0209             if (startLine != endLine) {
0210                 document.editBegin();
0211                 document.joinLines(startLine, endLine);
0212                 document.editEnd();
0213             }
0214         }
0215     }
0216 }
0217 
0218 /// \note Range contains a block selected by lines (\b ONLY)!
0219 /// And it is an open range! I.e. <em>[start, end)</em> (like in STL).
0220 function _getBlockForAction()
0221 {
0222     // Check if selection present in a view...
0223     var blockRange = Range(view.selection());
0224     var cursorPosition = view.cursorPosition();
0225     if (blockRange.isValid()) {
0226         blockRange.start.column = 0;
0227         if (blockRange.end.column != 0)
0228             blockRange.end.line++;
0229         blockRange.end.column = 0;
0230     } else {
0231         // No, it doesn't! Ok, lets select the current line only
0232         // from current position to the end
0233         blockRange = new Range(cursorPosition.line, 0, cursorPosition.line + 1, 0);
0234     }
0235     return blockRange;
0236 }
0237 
0238 // Adjusts ("moves") the current selection by offset.
0239 // Positive offsets move down, negatives up.
0240 function _adjustSelection(selection, offset)
0241 {
0242     if (selection.end.line + offset < document.lines()) {
0243         selection = new Range(selection.start.line + offset, selection.start.column,
0244                               selection.end.line + offset, selection.end.column);
0245     } else {
0246         selection = new Range(selection.start.line + offset, selection.start.column,
0247                               selection.end.line + offset - 1,
0248                               document.lineLength(selection.end.line + offset - 1));
0249     }
0250     view.setSelection(selection);
0251 }
0252 
0253 function moveLinesDown()
0254 {
0255     var selection = view.selection();
0256     var blockRange = _getBlockForAction();
0257     // Check is there a space to move?
0258     if (blockRange.end.line < document.lines()) {
0259         document.editBegin();
0260         // Move a block to one line down:
0261         // 0) take one line after the block
0262         var text = document.line(blockRange.end.line);
0263         // 1) remove the line after the block
0264         document.removeLine(blockRange.end.line);
0265         // 2) insert a line before the block
0266         document.insertLine(blockRange.start.line, text);
0267         document.editEnd();
0268         if (view.hasSelection())
0269             _adjustSelection(selection, 1);
0270     }
0271 }
0272 
0273 function moveLinesUp()
0274 {
0275     var cursor = view.cursorPosition();
0276     var selection = view.selection();
0277     var blockRange = _getBlockForAction();
0278     // Check is there a space to move?
0279     if (0 < blockRange.start.line) {
0280         document.editBegin();
0281         // Move a block to one line up:
0282         // 0) take one line before the block,
0283         var text = document.line(blockRange.start.line - 1);
0284         // 1) and insert it after the block
0285         document.insertLine(blockRange.end.line, text);
0286         // 2) remove the original line
0287         document.removeLine(blockRange.start.line - 1);
0288         view.setCursorPosition(cursor.line - 1, cursor.column);
0289         if (view.hasSelection())
0290             _adjustSelection(selection, -1);
0291         document.editEnd();
0292     }
0293 }
0294 
0295 function duplicateLinesDown()
0296 {
0297     var selection = view.selection();
0298     var blockRange = _getBlockForAction();
0299     document.editBegin();
0300     document.insertText(blockRange.start, document.text(blockRange));
0301     _adjustSelection(selection, blockRange.end.line - blockRange.start.line);
0302     document.editEnd();
0303 }
0304 
0305 function duplicateLinesUp()
0306 {
0307     var cursor = view.cursorPosition();
0308     var selection = view.selection();
0309     var blockRange = _getBlockForAction();
0310     document.editBegin();
0311     if (blockRange.end.line == document.lines()) {
0312         var lastLine = document.lines() - 1;
0313         var lastCol = document.lineLength(document.lines() - 1);
0314         blockRange.end.line = lastLine;
0315         blockRange.end.column = lastCol;
0316         document.insertText(lastLine, lastCol, document.text(blockRange));
0317         document.wrapLine(lastLine, lastCol);
0318     } else {
0319         document.insertText(blockRange.end, document.text(blockRange));
0320     }
0321     view.setCursorPosition(cursor.line, cursor.column);
0322     _adjustSelection(selection, 0);
0323     document.editEnd();
0324 }
0325 
0326 
0327 // Duplicate selected text at start of selection. Place cursor after selection.
0328 function duplicateSelection()
0329 {
0330     var selection = view.selectedText();
0331 
0332     if (!selection) {
0333         return
0334     }
0335 
0336     var range = view.selection();
0337     document.insertText(range.start, selection);
0338     range = view.selection();
0339     view.setCursorPosition(range.end.line, range.end.column);
0340 }
0341 
0342 function rewrap()
0343 {
0344     // initialize line span
0345     var fromLine = view.cursorPosition().line;
0346     var toLine = fromLine;
0347     var hasSelection = view.hasSelection();
0348 
0349     // if a text selection is present, use it to reformat the paragraph
0350     if (hasSelection) {
0351         var range = view.selection();
0352         fromLine = range.start.line;
0353         toLine = range.end.line;
0354     } else {
0355         // abort, if the cursor is in an empty line
0356         if (document.firstColumn(fromLine) == -1)
0357             return;
0358 
0359         // no text selection present: search for start & end of paragraph
0360         while (fromLine > 0 &&
0361             document.prevNonEmptyLine(fromLine-1) == fromLine - 1) --fromLine;
0362         while (toLine < document.lines() - 1 &&
0363             document.nextNonEmptyLine(toLine+1) == toLine + 1) ++toLine;
0364     }
0365 
0366     // initialize wrap columns
0367     var wrapColumn = 80;
0368     var softWrapColumn = 82;
0369     var exceptionColumn = 70;
0370 
0371     document.editBegin();
0372 
0373     if (fromLine < toLine) {
0374         document.joinLines(fromLine, toLine);
0375     }
0376 
0377     var line = fromLine;
0378     // as long as the line is too long...
0379     while (document.lastColumn(line) > wrapColumn) {
0380         // ...search for current word boundaries...
0381         var range = document.wordRangeAt(line, wrapColumn);
0382         if (!range.isValid()) {
0383             break;
0384         }
0385 
0386         // ...and wrap at a 'smart' position
0387         var wrapCursor = range.start;
0388         if (range.start.column < exceptionColumn && range.end.column <= softWrapColumn) {
0389             wrapCursor = range.end;
0390         }
0391         if (!document.wrapLine(wrapCursor))
0392             break;
0393         ++line;
0394     }
0395 
0396     document.editEnd();
0397 }
0398 
0399 function _uri_transform_selection(transformer)
0400 {
0401     var selection = view.selection();
0402     var cursor = view.cursorPosition();
0403     // TODO Multiline conversions are meaningless!?
0404     if (selection.isValid() && selection.onSingleLine()) {
0405         var text = document.text(selection);
0406         var coded_text = transformer(text);
0407         document.editBegin();
0408         document.removeText(selection);
0409         document.insertText(selection.start, coded_text);
0410         document.editEnd();
0411         var size_diff = coded_text.length - text.length;
0412         selection.end.column += size_diff;
0413         view.setSelection(selection);
0414         if (selection.start.column < cursor.column) {
0415             cursor.column += size_diff;
0416         }
0417         view.setCursorPosition(cursor);
0418     }
0419 }
0420 
0421 function encodeURISelection()
0422 {
0423     _uri_transform_selection(encodeURIComponent);
0424 }
0425 
0426 function decodeURISelection()
0427 {
0428     _uri_transform_selection(decodeURIComponent);
0429 }
0430 
0431 function fsel(target) // forward select
0432 {
0433     startSel = view.cursorPosition();
0434     if (typeof target == "undefined") { // by default, select til the end of the current line
0435         endSel = new Cursor(startSel.line, document.lastColumn(startSel.line) + 1);
0436     } else { // otherwise, select to the first occurrence of the given target (including it)
0437         match = view.searchText(new Range(startSel, document.documentRange().end), target);
0438         if (!match.isValid()) return false;
0439         else endSel = match.end;
0440     }
0441     view.setCursorPosition(endSel);
0442     view.setSelection(new Range(startSel, endSel));
0443 }
0444 
0445 function bsel(target) // backward select
0446 {
0447     endSel = view.cursorPosition();
0448     if (typeof target == "undefined") { // by default, select from the beginning of the current line
0449         startSel = new Cursor(endSel.line, 0);
0450     } else { // otherwise, select from the last occurrence of the given target (including it)
0451         match = view.searchText(new Range(document.documentRange().start, endSel), target, true);
0452         if (!match.isValid()) return false;
0453         else startSel = match.start;
0454     }
0455     view.setCursorPosition(startSel);
0456     view.setSelection(new Range(startSel, endSel));
0457 }
0458 
0459 function help(cmd)
0460 {
0461     if (cmd == "sort") {
0462         return i18n("Sort the selected text or whole document.");
0463     } else if (cmd == "moveLinesDown") {
0464         return i18n("Move selected lines down.");
0465     } else if (cmd == "moveLinesUp") {
0466         return i18n("Move selected lines up.");
0467     } else if (cmd == "uniq") {
0468         return i18n("Remove duplicate lines from the selected text or whole document.");
0469     } else if (cmd == "natsort") {
0470         return i18n("Sort the selected text or whole document in natural order.<br>Here is an example to show the difference to the normal sort method:<br>sort(a10, a1, a2) => a1, a10, a2<br>natsort(a10, a1, a2) => a1, a2, a10");
0471     } else if (cmd == "rtrim") {
0472         return i18n("Trims trailing whitespace from selection or whole document.");
0473     } else if (cmd == "ltrim") {
0474         return i18n("Trims leading whitespace from selection or whole document.");
0475     } else if (cmd == "trim") {
0476         return i18n("Trims leading and trailing whitespace from selection or whole document.");
0477     } else if (cmd == "join") {
0478         return i18n("Joins selected lines or whole document. Optionally pass a separator to put between each line:<br><code>join ', '</code> will e.g. join lines and separate them by a comma.");
0479     } else if (cmd == "rmblank") {
0480         return i18n("Removes empty lines from selection or whole document.");
0481     } else if (cmd == "alignon") {
0482         return i18n("This command aligns lines in the selected block or whole document on the column given by a regular expression given as an argument.<br><br>If you give an empty pattern it will align on the first non-blank character by default.<br>If the pattern has a capture it will indent on the captured match.<br><br><i>Examples</i>:<br>'<code>alignon -</code>' will insert spaces before the first '-' of each lines to align them all on the same column.<br>'<code>alignon :\\s+(.)</code>' will insert spaces before the first non-blank character that occurs after a colon to align them all on the same column.");
0483     } else if (cmd == "unwrap") {
0484         return "Unwraps all paragraphs in the text selection, or the paragraph under the text cursor if there is no selected text.";
0485     } else if (cmd == "each") {
0486         return i18n("Given a JavaScript function as argument, call that for the list of (selected) lines and replace them with the return value of that callback.<br>Example (join selected lines):<br><code>each 'function(lines){return lines.join(\", \");}'</code><br>To save you some typing, you can also do this to achieve the same:<br><code>each 'lines.join(\", \")'</code>");
0487     } else if (cmd == "filter") {
0488         return i18n("Given a JavaScript function as argument, call that for the list of (selected) lines and remove those where the callback returns false.<br>Example (see also <code>rmblank</code>):<br><code>filter 'function(l){return l.length > 0;}'</code><br>To save you some typing, you can also do this to achieve the same:<br><code>filter 'line.length > 0'</code>");
0489     } else if (cmd == "map") {
0490         return i18n("Given a JavaScript function as argument, call that for the list of (selected) lines and replace the line with the return value of the callback.<br>Example (see also <code>ltrim</code>):<br><code>map 'function(line){return line.replace(/^\\s+/, \"\");}'</code><br>To save you some typing, you can also do this to achieve the same:<br><code>map 'line.replace(/^\\s+/, \"\")'</code>");
0491     } else if (cmd == "duplicateLinesUp") {
0492         return i18n("Duplicates the selected lines up.");
0493     } else if (cmd == "duplicateLinesDown") {
0494         return i18n("Duplicates the selected lines down.");
0495     } else if (cmd == 'duplicateSelection') {
0496         return i18n('Duplicate the selected text. Place cursor after selection.');
0497     } else if (cmd == "encodeURISelection") {
0498         return i18n("Encode special chars in a single line selection, so the result text can be used as URI.");
0499     } else if (cmd == "decodeURISelection") {
0500         return i18n("Reverse action of URI encode.");
0501     } else if (cmd == "fsel") {
0502         return i18n("Select text forward from current cursor position to the first occurrence of the given argument after it (or the end of the current line by default).");
0503     } else if (cmd == "bsel") {
0504         return i18n("Select text backward from current cursor position to the last occurrence of the given argument before it (or the beginning of the current line by default).");
0505     }
0506 }
0507 
0508 /// helper code below:
0509 
0510 function __toFunc(func, defaultArgName)
0511 {
0512     if ( typeof(func) != "function" ) {
0513         try {
0514             func = eval("(" + func + ")");
0515         } catch(e) {}
0516         debug(func, typeof(func))
0517         if ( typeof(func) != "function" ) {
0518             try {
0519                 // one more try to support e.g.:
0520                 // map 'l+l'
0521                 // or:
0522                 // each 'lines.join("\n")'
0523                 func = eval("(function(" + defaultArgName + "){ return " + func + ";})");
0524                 debug(func, typeof(func))
0525             } catch(e) {}
0526             if ( typeof(func) != "function" ) {
0527                 throw "parameter is not a valid JavaScript callback function: " + typeof(func);
0528             }
0529         }
0530     }
0531     return func;
0532 }
0533 
0534 function each(func)
0535 {
0536     func = __toFunc(func, 'lines');
0537 
0538     var cursor = view.cursorPosition();
0539     var selection = view.selection();
0540     var hasSelection = selection.isValid();
0541     if (!hasSelection) {
0542         // use whole range
0543         selection = document.documentRange();
0544     } else {
0545         selection.start.column = 0;
0546         selection.end.column = document.lineLength(selection.end.line);
0547     }
0548 
0549     var text = document.text(selection);
0550 
0551     var lines = text.split("\n");
0552     oldLineCount = lines.length;
0553     oldCurrentLineLength = document.lineLength(cursor.line);
0554     lines = func(lines);
0555     if ( typeof(lines) == "object" ) {
0556       text = lines.join("\n");
0557       newLineCount = lines.length;
0558     } else if ( typeof(lines) == "string" ) {
0559       text = lines
0560       newLineCount = (lines.match('\n') || []).length;
0561     } else {
0562       throw "callback function for each has to return object or array of lines";
0563     }
0564 
0565     view.clearSelection();
0566 
0567     document.editBegin();
0568     if (!hasSelection) {
0569         document.setText(text);
0570     } else {
0571         document.removeText(selection);
0572         document.insertText(selection.start, text);
0573     }
0574     document.editEnd();
0575     if (newLineCount == oldLineCount) {
0576         if (document.lineLength(cursor.line) != oldCurrentLineLength) {
0577             cursor.column = document.lastColumn(cursor.line) + 1;
0578         }
0579         view.setCursorPosition(cursor);
0580     }
0581 }
0582 
0583 function filter(func)
0584 {
0585     each(function(lines) { return lines.filter(__toFunc(func, 'line')); });
0586 }
0587 
0588 function map(func)
0589 {
0590     each(function(lines) { return lines.map(__toFunc(func, 'line')); });
0591 }
0592 
0593 /*
0594 natcompare.js -- Perform 'natural order' comparisons of strings in JavaScript.
0595 Copyright (C) 2005 by SCK-CEN (Belgian Nucleair Research Centre)
0596 Written by Kristof Coomans <kristof[dot]coomans[at]sckcen[dot]be>
0597 
0598 Based on the Java version by Pierre-Luc Paour, of which this is more or less a straight conversion.
0599 Copyright (C) 2003 by Pierre-Luc Paour <natorder@paour.com>
0600 
0601 The Java version was based on the C version by Martin Pool.
0602 Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au>
0603 
0604 This software is provided 'as-is', without any express or implied
0605 warranty.  In no event will the authors be held liable for any damages
0606 arising from the use of this software.
0607 
0608 Permission is granted to anyone to use this software for any purpose,
0609 including commercial applications, and to alter it and redistribute it
0610 freely, subject to the following restrictions:
0611 
0612 1. The origin of this software must not be misrepresented; you must not
0613 claim that you wrote the original software. If you use this software
0614 in a product, an acknowledgment in the product documentation would be
0615 appreciated but is not required.
0616 2. Altered source versions must be plainly marked as such, and must not be
0617 misrepresented as being the original software.
0618 3. This notice may not be removed or altered from any source distribution.
0619 */
0620 
0621 
0622 function isWhitespaceChar(a)
0623 {
0624     var charCode;
0625     charCode = a.charCodeAt(0);
0626 
0627     if ( charCode <= 32 )
0628     {
0629         return true;
0630     }
0631     else
0632     {
0633         return false;
0634     }
0635 }
0636 
0637 function isDigitChar(a)
0638 {
0639     var charCode;
0640     charCode = a.charCodeAt(0);
0641 
0642     if ( charCode >= 48  && charCode <= 57 )
0643     {
0644         return true;
0645     }
0646     else
0647     {
0648         return false;
0649     }
0650 }
0651 
0652 function compareRight(a,b)
0653 {
0654     var bias = 0;
0655     var ia = 0;
0656     var ib = 0;
0657 
0658     var ca;
0659     var cb;
0660 
0661     // The longest run of digits wins.  That aside, the greatest
0662     // value wins, but we can't know that it will until we've scanned
0663     // both numbers to know that they have the same magnitude, so we
0664     // remember it in BIAS.
0665     for (;; ia++, ib++) {
0666         ca = a.charAt(ia);
0667         cb = b.charAt(ib);
0668 
0669         if (!isDigitChar(ca)
0670                 && !isDigitChar(cb)) {
0671             return bias;
0672         } else if (!isDigitChar(ca)) {
0673             return -1;
0674         } else if (!isDigitChar(cb)) {
0675             return +1;
0676         } else if (ca < cb) {
0677             if (bias == 0) {
0678                 bias = -1;
0679             }
0680         } else if (ca > cb) {
0681             if (bias == 0)
0682                 bias = +1;
0683         } else if (ca == 0 && cb == 0) {
0684             return bias;
0685         }
0686     }
0687 }
0688 
0689 function natcompare(a,b) {
0690 
0691     var ia = 0, ib = 0;
0692         var nza = 0, nzb = 0;
0693         var ca, cb;
0694         var result;
0695 
0696     while (true)
0697     {
0698         // only count the number of zeroes leading the last number compared
0699         nza = nzb = 0;
0700 
0701         ca = a.charAt(ia);
0702         cb = b.charAt(ib);
0703 
0704         // skip over leading spaces or zeros
0705         while ( isWhitespaceChar( ca ) || ca =='0' ) {
0706             if (ca == '0') {
0707                 nza++;
0708             } else {
0709                 // only count consecutive zeroes
0710                 nza = 0;
0711             }
0712 
0713             ca = a.charAt(++ia);
0714         }
0715 
0716         while ( isWhitespaceChar( cb ) || cb == '0') {
0717             if (cb == '0') {
0718                 nzb++;
0719             } else {
0720                 // only count consecutive zeroes
0721                 nzb = 0;
0722             }
0723 
0724             cb = b.charAt(++ib);
0725         }
0726 
0727         // process run of digits
0728         if (isDigitChar(ca) && isDigitChar(cb)) {
0729             if ((result = compareRight(a.substring(ia), b.substring(ib))) != 0) {
0730                 return result;
0731             }
0732         }
0733 
0734         if (ca == 0 && cb == 0) {
0735             // The strings compare the same.  Perhaps the caller
0736             // will want to call strcmp to break the tie.
0737             return nza - nzb;
0738         }
0739 
0740         if (ca < cb) {
0741             return -1;
0742         } else if (ca > cb) {
0743             return +1;
0744         }
0745 
0746         ++ia; ++ib;
0747     }
0748 }
0749 
0750 // kate: space-indent on; indent-width 4; replace-tabs on;