123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- // 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) {
- 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 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;
- }
- 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++;
- }
- 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
- }
- }
- }
- 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...
- }
- 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: {line: start.line, ch: gtPos + 1},
- to: {line: l, ch: match.index}};
- }
- }
- l++;
- }
- return;
- }
- };
- CodeMirror.braceRangeFinder = function(cm, start) {
- var line = start.line, lineText = cm.getLine(line);
- var at = lineText.length, startChar, tokenType;
- for (;;) {
- var found = lineText.lastIndexOf("{", at);
- if (found < start.ch) break;
- tokenType = cm.getTokenAt({line: line, ch: found}).type;
- if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
- at = found - 1;
- }
- if (startChar == null || lineText.lastIndexOf("}") > startChar) return;
- var count = 1, lastLine = cm.lineCount(), end, endCh;
- outer: for (var i = line + 1; i < lastLine; ++i) {
- var text = cm.getLine(i), pos = 0;
- for (;;) {
- var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos);
- if (nextOpen < 0) nextOpen = text.length;
- if (nextClose < 0) nextClose = text.length;
- pos = Math.min(nextOpen, nextClose);
- if (pos == text.length) break;
- if (cm.getTokenAt({line: i, ch: pos + 1}).type == tokenType) {
- if (pos == nextOpen) ++count;
- else if (!--count) { end = i; endCh = pos; break outer; }
- }
- ++pos;
- }
- }
- if (end == null || end == line + 1) return;
- return {from: {line: line, ch: startChar + 1},
- to: {line: end, ch: endCh}};
- };
- CodeMirror.indentRangeFinder = function(cm, start) {
- var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line);
- var myIndent = CodeMirror.countColumn(firstLine, null, tabSize);
- for (var i = start.line + 1, end = cm.lineCount(); i < end; ++i) {
- var curLine = cm.getLine(i);
- if (CodeMirror.countColumn(curLine, null, tabSize) < myIndent)
- return {from: {line: start.line, ch: firstLine.length},
- to: {line: i, ch: curLine.length}};
- }
- };
- CodeMirror.newFoldFunction = function(rangeFinder, widget) {
- if (widget == null) widget = "\u2194";
- if (typeof widget == "string") {
- var text = document.createTextNode(widget);
- widget = document.createElement("span");
- widget.appendChild(text);
- widget.className = "CodeMirror-foldmarker";
- }
- return function(cm, pos) {
- if (typeof pos == "number") pos = {line: pos, ch: 0};
- var range = rangeFinder(cm, pos);
- if (!range) return;
- var present = cm.findMarksAt(range.from), cleared = 0;
- for (var i = 0; i < present.length; ++i) {
- if (present[i].__isFold) {
- ++cleared;
- present[i].clear();
- }
- }
- if (cleared) return;
- var myWidget = widget.cloneNode(true);
- CodeMirror.on(myWidget, "mousedown", function() {myRange.clear();});
- var myRange = cm.markText(range.from, range.to, {
- replacedWith: myWidget,
- clearOnEnter: true,
- __isFold: true
- });
- };
- };
|