Spaces:
Running
Running
| // 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: CodeMirror.Pos(start.line, gtPos + 1), | |
| to: CodeMirror.Pos(l, 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(CodeMirror.Pos(line, found + 1)).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(CodeMirror.Pos(i, 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: CodeMirror.Pos(line, startChar + 1), | |
| to: CodeMirror.Pos(end, 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 && | |
| CodeMirror.countColumn(cm.getLine(i-1), null, tabSize) > myIndent) | |
| return {from: CodeMirror.Pos(start.line, firstLine.length), | |
| to: CodeMirror.Pos(i, 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 = CodeMirror.Pos(pos, 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 | |
| }); | |
| }; | |
| }; | |