Skip to content
Snippets Groups Projects
Commit ef896f95 authored by Marijn Haverbeke's avatar Marijn Haverbeke
Browse files

[folding addon] Rewrite tagRangeFinder

Closes #1360
parent 804e62ba
No related branches found
No related tags found
No related merge requests found
// the tagRangeFinder function is
// Copyright (C) 2011 by Daniel Glazman <daniel@glazman.org>
// released under the MIT license (../../LICENSE) like the rest of CodeMirror
CodeMirror.tagRangeFinder = function(cm, start) {
CodeMirror.tagRangeFinder = (function() {
var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*");
var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
var lineText = cm.getLine(start.line);
var found = false;
var tag = null;
var pos = start.ch;
while (!found) {
pos = lineText.indexOf("<", pos);
if (-1 == pos) // no tag on line
return;
if (pos + 1 < lineText.length && lineText[pos + 1] == "/") { // closing tag
pos++;
continue;
}
// ok we seem to have a start tag
if (!lineText.substr(pos + 1).match(xmlNAMERegExp)) { // not a tag name...
pos++;
continue;
return function(cm, start) {
var line = start.line, ch = start.ch, lineText = cm.getLine(line);
function nextLine() {
if (line >= cm.lastLine()) return;
ch = 0;
lineText = cm.getLine(++line);
return true;
}
var gtPos = lineText.indexOf(">", pos + 1);
if (-1 == gtPos) { // end of start tag not in line
var l = start.line + 1;
var foundGt = false;
var lastLine = cm.lineCount();
while (l < lastLine && !foundGt) {
var lt = cm.getLine(l);
gtPos = lt.indexOf(">");
if (-1 != gtPos) { // found a >
foundGt = true;
var slash = lt.lastIndexOf("/", gtPos);
if (-1 != slash && slash < gtPos) {
var str = lineText.substr(slash, gtPos - slash + 1);
if (!str.match( /\/\s*\>/ )) // yep, that's the end of empty tag
return;
}
}
l++;
function toTagEnd() {
for (;;) {
var gt = lineText.indexOf(">", ch);
if (gt == -1) { if (nextLine()) continue; else return; }
var lastSlash = lineText.lastIndexOf("/", gt);
var selfClose = lastSlash > -1 && /^\s*$/.test(lineText.slice(lastSlash + 1, gt));
ch = gt + 1;
return selfClose ? "selfClose" : "regular";
}
found = true;
}
else {
var slashPos = lineText.lastIndexOf("/", gtPos);
if (-1 == slashPos) { // cannot be empty tag
found = true;
// don't continue
}
else { // empty tag?
// check if really empty tag
var str = lineText.substr(slashPos, gtPos - slashPos + 1);
if (!str.match( /\/\s*\>/ )) { // finally not empty
found = true;
// don't continue
}
function toNextTag() {
for (;;) {
xmlTagStart.lastIndex = ch;
var found = xmlTagStart.exec(lineText);
if (!found) { if (nextLine()) continue; else return; }
ch = found.index + found[0].length;
return found;
}
}
if (found) {
var subLine = lineText.substr(pos + 1);
tag = subLine.match(xmlNAMERegExp);
if (tag) {
// we have an element name, wooohooo !
tag = tag[0];
// do we have the close tag on same line ???
if (-1 != lineText.indexOf("</" + tag + ">", pos)) // yep
{
found = false;
}
// we don't, so we have a candidate...
var stack = [], startCh;
for (;;) {
var openTag = toNextTag(), end;
if (!openTag || line != start.line || !(end = toTagEnd())) return;
if (!openTag[1] && end != "selfClose") {
stack.push(openTag[2]);
startCh = ch;
break;
}
else
found = false;
}
if (!found)
pos++;
}
if (found) {
var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\\s)|(\\<" + tag + "$)";
var startTagRegExp = new RegExp(startTag);
var endTag = "</" + tag + ">";
var depth = 1;
var l = start.line + 1;
var lastLine = cm.lineCount();
while (l < lastLine) {
lineText = cm.getLine(l);
var match = lineText.match(startTagRegExp);
if (match) {
for (var i = 0; i < match.length; i++) {
if (match[i] == endTag)
depth--;
else
depth++;
if (!depth) return {from: CodeMirror.Pos(start.line, gtPos + 1),
to: CodeMirror.Pos(l, match.index)};
for (;;) {
var next = toNextTag(), end, tagLine = line, tagCh = ch - (next ? next[0].length : 0);
if (!next || !(end = toTagEnd())) return;
if (end == "selfClose") continue;
if (next[1]) { // closing tag
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
stack.length = i;
break;
}
if (!stack.length) return {
from: CodeMirror.Pos(start.line, startCh),
to: CodeMirror.Pos(tagLine, tagCh)
};
} else { // opening tag
stack.push(next[2]);
}
l++;
}
return;
}
};
};
})();
CodeMirror.braceRangeFinder = function(cm, start) {
var line = start.line, lineText = cm.getLine(line);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment