mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-11-27 02:16: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.
190 lines
7.5 KiB
JavaScript
190 lines
7.5 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 SearchCursor(doc, query, pos, caseFold) {
|
|
this.atOccurrence = false; this.doc = doc;
|
|
if (caseFold == null && typeof query == "string") caseFold = false;
|
|
|
|
pos = pos ? doc.clipPos(pos) : Pos(0, 0);
|
|
this.pos = {from: pos, to: pos};
|
|
|
|
// The matches method is filled in based on the type of query.
|
|
// It takes a position and a direction, and returns an object
|
|
// describing the next occurrence of the query, or null if no
|
|
// more matches were found.
|
|
if (typeof query != "string") { // Regexp match
|
|
if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g");
|
|
this.matches = function(reverse, pos) {
|
|
if (reverse) {
|
|
query.lastIndex = 0;
|
|
var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;
|
|
for (;;) {
|
|
query.lastIndex = cutOff;
|
|
var newMatch = query.exec(line);
|
|
if (!newMatch) break;
|
|
match = newMatch;
|
|
start = match.index;
|
|
cutOff = match.index + (match[0].length || 1);
|
|
if (cutOff == line.length) break;
|
|
}
|
|
var matchLen = (match && match[0].length) || 0;
|
|
if (!matchLen) {
|
|
if (start == 0 && line.length == 0) {match = undefined;}
|
|
else if (start != doc.getLine(pos.line).length) {
|
|
matchLen++;
|
|
}
|
|
}
|
|
} else {
|
|
query.lastIndex = pos.ch;
|
|
var line = doc.getLine(pos.line), match = query.exec(line);
|
|
var matchLen = (match && match[0].length) || 0;
|
|
var start = match && match.index;
|
|
if (start + matchLen != line.length && !matchLen) matchLen = 1;
|
|
}
|
|
if (match && matchLen)
|
|
return {from: Pos(pos.line, start),
|
|
to: Pos(pos.line, start + matchLen),
|
|
match: match};
|
|
};
|
|
} else { // String query
|
|
var origQuery = query;
|
|
if (caseFold) query = query.toLowerCase();
|
|
var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
|
|
var target = query.split("\n");
|
|
// Different methods for single-line and multi-line queries
|
|
if (target.length == 1) {
|
|
if (!query.length) {
|
|
// Empty string would match anything and never progress, so
|
|
// we define it to match nothing instead.
|
|
this.matches = function() {};
|
|
} else {
|
|
this.matches = function(reverse, pos) {
|
|
if (reverse) {
|
|
var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig);
|
|
var match = line.lastIndexOf(query);
|
|
if (match > -1) {
|
|
match = adjustPos(orig, line, match);
|
|
return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
|
|
}
|
|
} else {
|
|
var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig);
|
|
var match = line.indexOf(query);
|
|
if (match > -1) {
|
|
match = adjustPos(orig, line, match) + pos.ch;
|
|
return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
|
|
}
|
|
}
|
|
};
|
|
}
|
|
} else {
|
|
var origTarget = origQuery.split("\n");
|
|
this.matches = function(reverse, pos) {
|
|
var last = target.length - 1;
|
|
if (reverse) {
|
|
if (pos.line - (target.length - 1) < doc.firstLine()) return;
|
|
if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return;
|
|
var to = Pos(pos.line, origTarget[last].length);
|
|
for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln)
|
|
if (target[i] != fold(doc.getLine(ln))) return;
|
|
var line = doc.getLine(ln), cut = line.length - origTarget[0].length;
|
|
if (fold(line.slice(cut)) != target[0]) return;
|
|
return {from: Pos(ln, cut), to: to};
|
|
} else {
|
|
if (pos.line + (target.length - 1) > doc.lastLine()) return;
|
|
var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length;
|
|
if (fold(line.slice(cut)) != target[0]) return;
|
|
var from = Pos(pos.line, cut);
|
|
for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln)
|
|
if (target[i] != fold(doc.getLine(ln))) return;
|
|
if (fold(doc.getLine(ln).slice(0, origTarget[last].length)) != target[last]) return;
|
|
return {from: from, to: Pos(ln, origTarget[last].length)};
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
SearchCursor.prototype = {
|
|
findNext: function() {return this.find(false);},
|
|
findPrevious: function() {return this.find(true);},
|
|
|
|
find: function(reverse) {
|
|
var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
|
|
function savePosAndFail(line) {
|
|
var pos = Pos(line, 0);
|
|
self.pos = {from: pos, to: pos};
|
|
self.atOccurrence = false;
|
|
return false;
|
|
}
|
|
|
|
for (;;) {
|
|
if (this.pos = this.matches(reverse, pos)) {
|
|
this.atOccurrence = true;
|
|
return this.pos.match || true;
|
|
}
|
|
if (reverse) {
|
|
if (!pos.line) return savePosAndFail(0);
|
|
pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length);
|
|
}
|
|
else {
|
|
var maxLine = this.doc.lineCount();
|
|
if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
|
|
pos = Pos(pos.line + 1, 0);
|
|
}
|
|
}
|
|
},
|
|
|
|
from: function() {if (this.atOccurrence) return this.pos.from;},
|
|
to: function() {if (this.atOccurrence) return this.pos.to;},
|
|
|
|
replace: function(newText) {
|
|
if (!this.atOccurrence) return;
|
|
var lines = CodeMirror.splitLines(newText);
|
|
this.doc.replaceRange(lines, this.pos.from, this.pos.to);
|
|
this.pos.to = Pos(this.pos.from.line + lines.length - 1,
|
|
lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
|
|
}
|
|
};
|
|
|
|
// Maps a position in a case-folded line back to a position in the original line
|
|
// (compensating for codepoints increasing in number during folding)
|
|
function adjustPos(orig, folded, pos) {
|
|
if (orig.length == folded.length) return pos;
|
|
for (var pos1 = Math.min(pos, orig.length);;) {
|
|
var len1 = orig.slice(0, pos1).toLowerCase().length;
|
|
if (len1 < pos) ++pos1;
|
|
else if (len1 > pos) --pos1;
|
|
else return pos1;
|
|
}
|
|
}
|
|
|
|
CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
|
|
return new SearchCursor(this.doc, query, pos, caseFold);
|
|
});
|
|
CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
|
|
return new SearchCursor(this, query, pos, caseFold);
|
|
});
|
|
|
|
CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
|
|
var ranges = [], next;
|
|
var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold);
|
|
while (next = cur.findNext()) {
|
|
if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break;
|
|
ranges.push({anchor: cur.from(), head: cur.to()});
|
|
}
|
|
if (ranges.length)
|
|
this.setSelections(ranges, 0);
|
|
});
|
|
});
|