mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-11-30 08:26:20 +00:00
96d4a3ecf7
Due to historical reasons, the code is in subfolder "1". With SVN removal, we place the code back and remove the annoying "1" folder.
183 lines
6.4 KiB
JavaScript
183 lines
6.4 KiB
JavaScript
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
|
|
|
(function(mod) {
|
|
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|
mod(require("../../lib/codemirror"));
|
|
else if (typeof define == "function" && define.amd) // AMD
|
|
define(["../../lib/codemirror"], mod);
|
|
else // Plain browser env
|
|
mod(CodeMirror);
|
|
})(function(CodeMirror) {
|
|
"use strict";
|
|
|
|
var Pos = CodeMirror.Pos;
|
|
function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
|
|
|
|
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 xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
|
|
|
|
function Iter(cm, line, ch, range) {
|
|
this.line = line; this.ch = ch;
|
|
this.cm = cm; this.text = cm.getLine(line);
|
|
this.min = range ? range.from : cm.firstLine();
|
|
this.max = range ? range.to - 1 : cm.lastLine();
|
|
}
|
|
|
|
function tagAt(iter, ch) {
|
|
var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
|
|
return type && /\btag\b/.test(type);
|
|
}
|
|
|
|
function nextLine(iter) {
|
|
if (iter.line >= iter.max) return;
|
|
iter.ch = 0;
|
|
iter.text = iter.cm.getLine(++iter.line);
|
|
return true;
|
|
}
|
|
function prevLine(iter) {
|
|
if (iter.line <= iter.min) return;
|
|
iter.text = iter.cm.getLine(--iter.line);
|
|
iter.ch = iter.text.length;
|
|
return true;
|
|
}
|
|
|
|
function toTagEnd(iter) {
|
|
for (;;) {
|
|
var gt = iter.text.indexOf(">", iter.ch);
|
|
if (gt == -1) { if (nextLine(iter)) continue; else return; }
|
|
if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
|
|
var lastSlash = iter.text.lastIndexOf("/", gt);
|
|
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
|
|
iter.ch = gt + 1;
|
|
return selfClose ? "selfClose" : "regular";
|
|
}
|
|
}
|
|
function toTagStart(iter) {
|
|
for (;;) {
|
|
var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
|
|
if (lt == -1) { if (prevLine(iter)) continue; else return; }
|
|
if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
|
|
xmlTagStart.lastIndex = lt;
|
|
iter.ch = lt;
|
|
var match = xmlTagStart.exec(iter.text);
|
|
if (match && match.index == lt) return match;
|
|
}
|
|
}
|
|
|
|
function toNextTag(iter) {
|
|
for (;;) {
|
|
xmlTagStart.lastIndex = iter.ch;
|
|
var found = xmlTagStart.exec(iter.text);
|
|
if (!found) { if (nextLine(iter)) continue; else return; }
|
|
if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
|
|
iter.ch = found.index + found[0].length;
|
|
return found;
|
|
}
|
|
}
|
|
function toPrevTag(iter) {
|
|
for (;;) {
|
|
var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
|
|
if (gt == -1) { if (prevLine(iter)) continue; else return; }
|
|
if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
|
|
var lastSlash = iter.text.lastIndexOf("/", gt);
|
|
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
|
|
iter.ch = gt + 1;
|
|
return selfClose ? "selfClose" : "regular";
|
|
}
|
|
}
|
|
|
|
function findMatchingClose(iter, tag) {
|
|
var stack = [];
|
|
for (;;) {
|
|
var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
|
|
if (!next || !(end = toTagEnd(iter))) 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 (i < 0 && (!tag || tag == next[2])) return {
|
|
tag: next[2],
|
|
from: Pos(startLine, startCh),
|
|
to: Pos(iter.line, iter.ch)
|
|
};
|
|
} else { // opening tag
|
|
stack.push(next[2]);
|
|
}
|
|
}
|
|
}
|
|
function findMatchingOpen(iter, tag) {
|
|
var stack = [];
|
|
for (;;) {
|
|
var prev = toPrevTag(iter);
|
|
if (!prev) return;
|
|
if (prev == "selfClose") { toTagStart(iter); continue; }
|
|
var endLine = iter.line, endCh = iter.ch;
|
|
var start = toTagStart(iter);
|
|
if (!start) return;
|
|
if (start[1]) { // closing tag
|
|
stack.push(start[2]);
|
|
} else { // opening tag
|
|
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
|
|
stack.length = i;
|
|
break;
|
|
}
|
|
if (i < 0 && (!tag || tag == start[2])) return {
|
|
tag: start[2],
|
|
from: Pos(iter.line, iter.ch),
|
|
to: Pos(endLine, endCh)
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
CodeMirror.registerHelper("fold", "xml", function(cm, start) {
|
|
var iter = new Iter(cm, start.line, 0);
|
|
for (;;) {
|
|
var openTag = toNextTag(iter), end;
|
|
if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
|
|
if (!openTag[1] && end != "selfClose") {
|
|
var start = Pos(iter.line, iter.ch);
|
|
var close = findMatchingClose(iter, openTag[2]);
|
|
return close && {from: start, to: close.from};
|
|
}
|
|
}
|
|
});
|
|
CodeMirror.findMatchingTag = function(cm, pos, range) {
|
|
var iter = new Iter(cm, pos.line, pos.ch, range);
|
|
if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
|
|
var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
|
|
var start = end && toTagStart(iter);
|
|
if (!end || !start || cmp(iter, pos) > 0) return;
|
|
var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
|
|
if (end == "selfClose") return {open: here, close: null, at: "open"};
|
|
|
|
if (start[1]) { // closing tag
|
|
return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
|
|
} else { // opening tag
|
|
iter = new Iter(cm, to.line, to.ch, range);
|
|
return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
|
|
}
|
|
};
|
|
|
|
CodeMirror.findEnclosingTag = function(cm, pos, range) {
|
|
var iter = new Iter(cm, pos.line, pos.ch, range);
|
|
for (;;) {
|
|
var open = findMatchingOpen(iter);
|
|
if (!open) break;
|
|
var forward = new Iter(cm, pos.line, pos.ch, range);
|
|
var close = findMatchingClose(forward, open.tag);
|
|
if (close) return {open: open, close: close};
|
|
}
|
|
};
|
|
|
|
// Used by addon/edit/closetag.js
|
|
CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
|
|
var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
|
|
return findMatchingClose(iter, name);
|
|
};
|
|
});
|