Add CodeMirror addons - search, code folding, match brackets, lint
This commit is contained in:
parent
51a9c5c016
commit
b4173d68f6
32
codemirror/addon/dialog/dialog.css
vendored
Normal file
32
codemirror/addon/dialog/dialog.css
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
.CodeMirror-dialog {
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
background: white;
|
||||
z-index: 15;
|
||||
padding: .1em .8em;
|
||||
overflow: hidden;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog-top {
|
||||
border-bottom: 1px solid #eee;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog-bottom {
|
||||
border-top: 1px solid #eee;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog input {
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
width: 20em;
|
||||
color: inherit;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog button {
|
||||
font-size: 70%;
|
||||
}
|
155
codemirror/addon/dialog/dialog.js
vendored
Normal file
155
codemirror/addon/dialog/dialog.js
vendored
Normal file
|
@ -0,0 +1,155 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// Open simple dialogs on top of an editor. Relies on dialog.css.
|
||||
|
||||
(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) {
|
||||
function dialogDiv(cm, template, bottom) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
var dialog;
|
||||
dialog = wrap.appendChild(document.createElement("div"));
|
||||
if (bottom)
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
|
||||
else
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
|
||||
|
||||
if (typeof template == "string") {
|
||||
dialog.innerHTML = template;
|
||||
} else { // Assuming it's a detached DOM element.
|
||||
dialog.appendChild(template);
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
function closeNotification(cm, newVal) {
|
||||
if (cm.state.currentNotificationClose)
|
||||
cm.state.currentNotificationClose();
|
||||
cm.state.currentNotificationClose = newVal;
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("openDialog", function(template, callback, options) {
|
||||
if (!options) options = {};
|
||||
|
||||
closeNotification(this, null);
|
||||
|
||||
var dialog = dialogDiv(this, template, options.bottom);
|
||||
var closed = false, me = this;
|
||||
function close(newVal) {
|
||||
if (typeof newVal == 'string') {
|
||||
inp.value = newVal;
|
||||
} else {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
|
||||
if (options.onClose) options.onClose(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
var inp = dialog.getElementsByTagName("input")[0], button;
|
||||
if (inp) {
|
||||
if (options.value) {
|
||||
inp.value = options.value;
|
||||
inp.select();
|
||||
}
|
||||
|
||||
if (options.onInput)
|
||||
CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
|
||||
if (options.onKeyUp)
|
||||
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
|
||||
|
||||
CodeMirror.on(inp, "keydown", function(e) {
|
||||
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
|
||||
if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
|
||||
inp.blur();
|
||||
CodeMirror.e_stop(e);
|
||||
close();
|
||||
}
|
||||
if (e.keyCode == 13) callback(inp.value, e);
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
|
||||
|
||||
inp.focus();
|
||||
} else if (button = dialog.getElementsByTagName("button")[0]) {
|
||||
CodeMirror.on(button, "click", function() {
|
||||
close();
|
||||
me.focus();
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
|
||||
|
||||
button.focus();
|
||||
}
|
||||
return close;
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
|
||||
closeNotification(this, null);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var buttons = dialog.getElementsByTagName("button");
|
||||
var closed = false, me = this, blurring = 1;
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
}
|
||||
buttons[0].focus();
|
||||
for (var i = 0; i < buttons.length; ++i) {
|
||||
var b = buttons[i];
|
||||
(function(callback) {
|
||||
CodeMirror.on(b, "click", function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
if (callback) callback(me);
|
||||
});
|
||||
})(callbacks[i]);
|
||||
CodeMirror.on(b, "blur", function() {
|
||||
--blurring;
|
||||
setTimeout(function() { if (blurring <= 0) close(); }, 200);
|
||||
});
|
||||
CodeMirror.on(b, "focus", function() { ++blurring; });
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* openNotification
|
||||
* Opens a notification, that can be closed with an optional timer
|
||||
* (default 5000ms timer) and always closes on click.
|
||||
*
|
||||
* If a notification is opened while another is opened, it will close the
|
||||
* currently opened one and open the new one immediately.
|
||||
*/
|
||||
CodeMirror.defineExtension("openNotification", function(template, options) {
|
||||
closeNotification(this, close);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var closed = false, doneTimer;
|
||||
var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000;
|
||||
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
clearTimeout(doneTimer);
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
}
|
||||
|
||||
CodeMirror.on(dialog, 'click', function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
});
|
||||
|
||||
if (duration)
|
||||
doneTimer = setTimeout(close, duration);
|
||||
|
||||
return close;
|
||||
});
|
||||
});
|
120
codemirror/addon/edit/matchbrackets.js
vendored
Normal file
120
codemirror/addon/edit/matchbrackets.js
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
// 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) {
|
||||
var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
|
||||
(document.documentMode == null || document.documentMode < 8);
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
|
||||
|
||||
function findMatchingBracket(cm, where, strict, config) {
|
||||
var line = cm.getLineHandle(where.line), pos = where.ch - 1;
|
||||
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
|
||||
if (!match) return null;
|
||||
var dir = match.charAt(1) == ">" ? 1 : -1;
|
||||
if (strict && (dir > 0) != (pos == where.ch)) return null;
|
||||
var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
|
||||
|
||||
var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
|
||||
if (found == null) return null;
|
||||
return {from: Pos(where.line, pos), to: found && found.pos,
|
||||
match: found && found.ch == match.charAt(0), forward: dir > 0};
|
||||
}
|
||||
|
||||
// bracketRegex is used to specify which type of bracket to scan
|
||||
// should be a regexp, e.g. /[[\]]/
|
||||
//
|
||||
// Note: If "where" is on an open bracket, then this bracket is ignored.
|
||||
//
|
||||
// Returns false when no bracket was found, null when it reached
|
||||
// maxScanLines and gave up
|
||||
function scanForBracket(cm, where, dir, style, config) {
|
||||
var maxScanLen = (config && config.maxScanLineLength) || 10000;
|
||||
var maxScanLines = (config && config.maxScanLines) || 1000;
|
||||
|
||||
var stack = [];
|
||||
var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/;
|
||||
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
|
||||
: Math.max(cm.firstLine() - 1, where.line - maxScanLines);
|
||||
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
|
||||
var line = cm.getLine(lineNo);
|
||||
if (!line) continue;
|
||||
var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
|
||||
if (line.length > maxScanLen) continue;
|
||||
if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
|
||||
for (; pos != end; pos += dir) {
|
||||
var ch = line.charAt(pos);
|
||||
if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
|
||||
var match = matching[ch];
|
||||
if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
|
||||
else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
|
||||
else stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
|
||||
}
|
||||
|
||||
function matchBrackets(cm, autoclear, config) {
|
||||
// Disable brace matching in long lines, since it'll cause hugely slow updates
|
||||
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
|
||||
var marks = [], ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config);
|
||||
if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
|
||||
var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
|
||||
marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
|
||||
if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
|
||||
marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
|
||||
}
|
||||
}
|
||||
|
||||
if (marks.length) {
|
||||
// Kludge to work around the IE bug from issue #1193, where text
|
||||
// input stops going to the textare whever this fires.
|
||||
if (ie_lt8 && cm.state.focused) cm.focus();
|
||||
|
||||
var clear = function() {
|
||||
cm.operation(function() {
|
||||
for (var i = 0; i < marks.length; i++) marks[i].clear();
|
||||
});
|
||||
};
|
||||
if (autoclear) setTimeout(clear, 800);
|
||||
else return clear;
|
||||
}
|
||||
}
|
||||
|
||||
var currentlyHighlighted = null;
|
||||
function doMatchBrackets(cm) {
|
||||
cm.operation(function() {
|
||||
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
|
||||
currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
|
||||
});
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init)
|
||||
cm.off("cursorActivity", doMatchBrackets);
|
||||
if (val) {
|
||||
cm.state.matchBrackets = typeof val == "object" ? val : {};
|
||||
cm.on("cursorActivity", doMatchBrackets);
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
|
||||
CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){
|
||||
return findMatchingBracket(this, pos, strict, config);
|
||||
});
|
||||
CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
|
||||
return scanForBracket(this, pos, dir, style, config);
|
||||
});
|
||||
});
|
105
codemirror/addon/fold/brace-fold.js
vendored
Normal file
105
codemirror/addon/fold/brace-fold.js
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
// 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";
|
||||
|
||||
CodeMirror.registerHelper("fold", "brace", function(cm, start) {
|
||||
var line = start.line, lineText = cm.getLine(line);
|
||||
var startCh, tokenType;
|
||||
|
||||
function findOpening(openCh) {
|
||||
for (var at = start.ch, pass = 0;;) {
|
||||
var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);
|
||||
if (found == -1) {
|
||||
if (pass == 1) break;
|
||||
pass = 1;
|
||||
at = lineText.length;
|
||||
continue;
|
||||
}
|
||||
if (pass == 1 && found < start.ch) break;
|
||||
tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
|
||||
if (!/^(comment|string)/.test(tokenType)) return found + 1;
|
||||
at = found - 1;
|
||||
}
|
||||
}
|
||||
|
||||
var startToken = "{", endToken = "}", startCh = findOpening("{");
|
||||
if (startCh == null) {
|
||||
startToken = "[", endToken = "]";
|
||||
startCh = findOpening("[");
|
||||
}
|
||||
|
||||
if (startCh == null) return;
|
||||
var count = 1, lastLine = cm.lastLine(), end, endCh;
|
||||
outer: for (var i = line; i <= lastLine; ++i) {
|
||||
var text = cm.getLine(i), pos = i == line ? startCh : 0;
|
||||
for (;;) {
|
||||
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, 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.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {
|
||||
if (pos == nextOpen) ++count;
|
||||
else if (!--count) { end = i; endCh = pos; break outer; }
|
||||
}
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
if (end == null || line == end && endCh == startCh) return;
|
||||
return {from: CodeMirror.Pos(line, startCh),
|
||||
to: CodeMirror.Pos(end, endCh)};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("fold", "import", function(cm, start) {
|
||||
function hasImport(line) {
|
||||
if (line < cm.firstLine() || line > cm.lastLine()) return null;
|
||||
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
|
||||
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
|
||||
if (start.type != "keyword" || start.string != "import") return null;
|
||||
// Now find closing semicolon, return its position
|
||||
for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
|
||||
var text = cm.getLine(i), semi = text.indexOf(";");
|
||||
if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
|
||||
}
|
||||
}
|
||||
|
||||
var start = start.line, has = hasImport(start), prev;
|
||||
if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1))
|
||||
return null;
|
||||
for (var end = has.end;;) {
|
||||
var next = hasImport(end.line + 1);
|
||||
if (next == null) break;
|
||||
end = next.end;
|
||||
}
|
||||
return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("fold", "include", function(cm, start) {
|
||||
function hasInclude(line) {
|
||||
if (line < cm.firstLine() || line > cm.lastLine()) return null;
|
||||
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
|
||||
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
|
||||
if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
|
||||
}
|
||||
|
||||
var start = start.line, has = hasInclude(start);
|
||||
if (has == null || hasInclude(start - 1) != null) return null;
|
||||
for (var end = start;;) {
|
||||
var next = hasInclude(end + 1);
|
||||
if (next == null) break;
|
||||
++end;
|
||||
}
|
||||
return {from: CodeMirror.Pos(start, has + 1),
|
||||
to: cm.clipPos(CodeMirror.Pos(end))};
|
||||
});
|
||||
|
||||
});
|
57
codemirror/addon/fold/comment-fold.js
vendored
Normal file
57
codemirror/addon/fold/comment-fold.js
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
// 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";
|
||||
|
||||
CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
|
||||
return mode.blockCommentStart && mode.blockCommentEnd;
|
||||
}, function(cm, start) {
|
||||
var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
|
||||
if (!startToken || !endToken) return;
|
||||
var line = start.line, lineText = cm.getLine(line);
|
||||
|
||||
var startCh;
|
||||
for (var at = start.ch, pass = 0;;) {
|
||||
var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
|
||||
if (found == -1) {
|
||||
if (pass == 1) return;
|
||||
pass = 1;
|
||||
at = lineText.length;
|
||||
continue;
|
||||
}
|
||||
if (pass == 1 && found < start.ch) return;
|
||||
if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)))) {
|
||||
startCh = found + startToken.length;
|
||||
break;
|
||||
}
|
||||
at = found - 1;
|
||||
}
|
||||
|
||||
var depth = 1, lastLine = cm.lastLine(), end, endCh;
|
||||
outer: for (var i = line; i <= lastLine; ++i) {
|
||||
var text = cm.getLine(i), pos = i == line ? startCh : 0;
|
||||
for (;;) {
|
||||
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
|
||||
if (nextOpen < 0) nextOpen = text.length;
|
||||
if (nextClose < 0) nextClose = text.length;
|
||||
pos = Math.min(nextOpen, nextClose);
|
||||
if (pos == text.length) break;
|
||||
if (pos == nextOpen) ++depth;
|
||||
else if (!--depth) { end = i; endCh = pos; break outer; }
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
if (end == null || line == end && endCh == startCh) return;
|
||||
return {from: CodeMirror.Pos(line, startCh),
|
||||
to: CodeMirror.Pos(end, endCh)};
|
||||
});
|
||||
|
||||
});
|
149
codemirror/addon/fold/foldcode.js
vendored
Normal file
149
codemirror/addon/fold/foldcode.js
vendored
Normal file
|
@ -0,0 +1,149 @@
|
|||
// 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";
|
||||
|
||||
function doFold(cm, pos, options, force) {
|
||||
if (options && options.call) {
|
||||
var finder = options;
|
||||
options = null;
|
||||
} else {
|
||||
var finder = getOption(cm, options, "rangeFinder");
|
||||
}
|
||||
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
|
||||
var minSize = getOption(cm, options, "minFoldSize");
|
||||
|
||||
function getRange(allowFolded) {
|
||||
var range = finder(cm, pos);
|
||||
if (!range || range.to.line - range.from.line < minSize) return null;
|
||||
var marks = cm.findMarksAt(range.from);
|
||||
for (var i = 0; i < marks.length; ++i) {
|
||||
if (marks[i].__isFold && force !== "fold") {
|
||||
if (!allowFolded) return null;
|
||||
range.cleared = true;
|
||||
marks[i].clear();
|
||||
}
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
var range = getRange(true);
|
||||
if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) {
|
||||
pos = CodeMirror.Pos(pos.line - 1, 0);
|
||||
range = getRange(false);
|
||||
}
|
||||
if (!range || range.cleared || force === "unfold") return;
|
||||
|
||||
var myWidget = makeWidget(cm, options);
|
||||
CodeMirror.on(myWidget, "mousedown", function(e) {
|
||||
myRange.clear();
|
||||
CodeMirror.e_preventDefault(e);
|
||||
});
|
||||
var myRange = cm.markText(range.from, range.to, {
|
||||
replacedWith: myWidget,
|
||||
clearOnEnter: true,
|
||||
__isFold: true
|
||||
});
|
||||
myRange.on("clear", function(from, to) {
|
||||
CodeMirror.signal(cm, "unfold", cm, from, to);
|
||||
});
|
||||
CodeMirror.signal(cm, "fold", cm, range.from, range.to);
|
||||
}
|
||||
|
||||
function makeWidget(cm, options) {
|
||||
var widget = getOption(cm, options, "widget");
|
||||
if (typeof widget == "string") {
|
||||
var text = document.createTextNode(widget);
|
||||
widget = document.createElement("span");
|
||||
widget.appendChild(text);
|
||||
widget.className = "CodeMirror-foldmarker";
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
// Clumsy backwards-compatible interface
|
||||
CodeMirror.newFoldFunction = function(rangeFinder, widget) {
|
||||
return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
|
||||
};
|
||||
|
||||
// New-style interface
|
||||
CodeMirror.defineExtension("foldCode", function(pos, options, force) {
|
||||
doFold(this, pos, options, force);
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("isFolded", function(pos) {
|
||||
var marks = this.findMarksAt(pos);
|
||||
for (var i = 0; i < marks.length; ++i)
|
||||
if (marks[i].__isFold) return true;
|
||||
});
|
||||
|
||||
CodeMirror.commands.toggleFold = function(cm) {
|
||||
cm.foldCode(cm.getCursor());
|
||||
};
|
||||
CodeMirror.commands.fold = function(cm) {
|
||||
cm.foldCode(cm.getCursor(), null, "fold");
|
||||
};
|
||||
CodeMirror.commands.unfold = function(cm) {
|
||||
cm.foldCode(cm.getCursor(), null, "unfold");
|
||||
};
|
||||
CodeMirror.commands.foldAll = function(cm) {
|
||||
cm.operation(function() {
|
||||
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
|
||||
cm.foldCode(CodeMirror.Pos(i, 0), null, "fold");
|
||||
});
|
||||
};
|
||||
CodeMirror.commands.unfoldAll = function(cm) {
|
||||
cm.operation(function() {
|
||||
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
|
||||
cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold");
|
||||
});
|
||||
};
|
||||
|
||||
CodeMirror.registerHelper("fold", "combine", function() {
|
||||
var funcs = Array.prototype.slice.call(arguments, 0);
|
||||
return function(cm, start) {
|
||||
for (var i = 0; i < funcs.length; ++i) {
|
||||
var found = funcs[i](cm, start);
|
||||
if (found) return found;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("fold", "auto", function(cm, start) {
|
||||
var helpers = cm.getHelpers(start, "fold");
|
||||
for (var i = 0; i < helpers.length; i++) {
|
||||
var cur = helpers[i](cm, start);
|
||||
if (cur) return cur;
|
||||
}
|
||||
});
|
||||
|
||||
var defaultOptions = {
|
||||
rangeFinder: CodeMirror.fold.auto,
|
||||
widget: "\u2194",
|
||||
minFoldSize: 0,
|
||||
scanUp: false
|
||||
};
|
||||
|
||||
CodeMirror.defineOption("foldOptions", null);
|
||||
|
||||
function getOption(cm, options, name) {
|
||||
if (options && options[name] !== undefined)
|
||||
return options[name];
|
||||
var editorOptions = cm.options.foldOptions;
|
||||
if (editorOptions && editorOptions[name] !== undefined)
|
||||
return editorOptions[name];
|
||||
return defaultOptions[name];
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("foldOption", function(options, name) {
|
||||
return getOption(this, options, name);
|
||||
});
|
||||
});
|
20
codemirror/addon/fold/foldgutter.css
vendored
Normal file
20
codemirror/addon/fold/foldgutter.css
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
.CodeMirror-foldmarker {
|
||||
color: blue;
|
||||
text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
|
||||
font-family: arial;
|
||||
line-height: .3;
|
||||
cursor: pointer;
|
||||
}
|
||||
.CodeMirror-foldgutter {
|
||||
width: .7em;
|
||||
}
|
||||
.CodeMirror-foldgutter-open,
|
||||
.CodeMirror-foldgutter-folded {
|
||||
cursor: pointer;
|
||||
}
|
||||
.CodeMirror-foldgutter-open:after {
|
||||
content: "\25BE";
|
||||
}
|
||||
.CodeMirror-foldgutter-folded:after {
|
||||
content: "\25B8";
|
||||
}
|
144
codemirror/addon/fold/foldgutter.js
vendored
Normal file
144
codemirror/addon/fold/foldgutter.js
vendored
Normal file
|
@ -0,0 +1,144 @@
|
|||
// 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"), require("./foldcode"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "./foldcode"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
cm.clearGutter(cm.state.foldGutter.options.gutter);
|
||||
cm.state.foldGutter = null;
|
||||
cm.off("gutterClick", onGutterClick);
|
||||
cm.off("change", onChange);
|
||||
cm.off("viewportChange", onViewportChange);
|
||||
cm.off("fold", onFold);
|
||||
cm.off("unfold", onFold);
|
||||
cm.off("swapDoc", updateInViewport);
|
||||
}
|
||||
if (val) {
|
||||
cm.state.foldGutter = new State(parseOptions(val));
|
||||
updateInViewport(cm);
|
||||
cm.on("gutterClick", onGutterClick);
|
||||
cm.on("change", onChange);
|
||||
cm.on("viewportChange", onViewportChange);
|
||||
cm.on("fold", onFold);
|
||||
cm.on("unfold", onFold);
|
||||
cm.on("swapDoc", updateInViewport);
|
||||
}
|
||||
});
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
function State(options) {
|
||||
this.options = options;
|
||||
this.from = this.to = 0;
|
||||
}
|
||||
|
||||
function parseOptions(opts) {
|
||||
if (opts === true) opts = {};
|
||||
if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
|
||||
if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
|
||||
if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
|
||||
return opts;
|
||||
}
|
||||
|
||||
function isFolded(cm, line) {
|
||||
var marks = cm.findMarksAt(Pos(line));
|
||||
for (var i = 0; i < marks.length; ++i)
|
||||
if (marks[i].__isFold && marks[i].find().from.line == line) return true;
|
||||
}
|
||||
|
||||
function marker(spec) {
|
||||
if (typeof spec == "string") {
|
||||
var elt = document.createElement("div");
|
||||
elt.className = spec + " CodeMirror-guttermarker-subtle";
|
||||
return elt;
|
||||
} else {
|
||||
return spec.cloneNode(true);
|
||||
}
|
||||
}
|
||||
|
||||
function updateFoldInfo(cm, from, to) {
|
||||
var opts = cm.state.foldGutter.options, cur = from;
|
||||
var minSize = cm.foldOption(opts, "minFoldSize");
|
||||
var func = cm.foldOption(opts, "rangeFinder");
|
||||
cm.eachLine(from, to, function(line) {
|
||||
var mark = null;
|
||||
if (isFolded(cm, cur)) {
|
||||
mark = marker(opts.indicatorFolded);
|
||||
} else {
|
||||
var pos = Pos(cur, 0);
|
||||
var range = func && func(cm, pos);
|
||||
if (range && range.to.line - range.from.line >= minSize)
|
||||
mark = marker(opts.indicatorOpen);
|
||||
}
|
||||
cm.setGutterMarker(line, opts.gutter, mark);
|
||||
++cur;
|
||||
});
|
||||
}
|
||||
|
||||
function updateInViewport(cm) {
|
||||
var vp = cm.getViewport(), state = cm.state.foldGutter;
|
||||
if (!state) return;
|
||||
cm.operation(function() {
|
||||
updateFoldInfo(cm, vp.from, vp.to);
|
||||
});
|
||||
state.from = vp.from; state.to = vp.to;
|
||||
}
|
||||
|
||||
function onGutterClick(cm, line, gutter) {
|
||||
var state = cm.state.foldGutter;
|
||||
if (!state) return;
|
||||
var opts = state.options;
|
||||
if (gutter != opts.gutter) return;
|
||||
cm.foldCode(Pos(line, 0), opts.rangeFinder);
|
||||
}
|
||||
|
||||
function onChange(cm) {
|
||||
var state = cm.state.foldGutter;
|
||||
if (!state) return;
|
||||
var opts = state.options;
|
||||
state.from = state.to = 0;
|
||||
clearTimeout(state.changeUpdate);
|
||||
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
|
||||
}
|
||||
|
||||
function onViewportChange(cm) {
|
||||
var state = cm.state.foldGutter;
|
||||
if (!state) return;
|
||||
var opts = state.options;
|
||||
clearTimeout(state.changeUpdate);
|
||||
state.changeUpdate = setTimeout(function() {
|
||||
var vp = cm.getViewport();
|
||||
if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
|
||||
updateInViewport(cm);
|
||||
} else {
|
||||
cm.operation(function() {
|
||||
if (vp.from < state.from) {
|
||||
updateFoldInfo(cm, vp.from, state.from);
|
||||
state.from = vp.from;
|
||||
}
|
||||
if (vp.to > state.to) {
|
||||
updateFoldInfo(cm, state.to, vp.to);
|
||||
state.to = vp.to;
|
||||
}
|
||||
});
|
||||
}
|
||||
}, opts.updateViewportTimeSpan || 400);
|
||||
}
|
||||
|
||||
function onFold(cm, from) {
|
||||
var state = cm.state.foldGutter;
|
||||
if (!state) return;
|
||||
var line = from.line;
|
||||
if (line >= state.from && line < state.to)
|
||||
updateFoldInfo(cm, line, line + 1);
|
||||
}
|
||||
});
|
35
codemirror/addon/lint/css-lint.js
vendored
Normal file
35
codemirror/addon/lint/css-lint.js
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// Depends on csslint.js from https://github.com/stubbornella/csslint
|
||||
|
||||
// declare global: CSSLint
|
||||
|
||||
(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";
|
||||
|
||||
CodeMirror.registerHelper("lint", "css", function(text) {
|
||||
var found = [];
|
||||
if (!window.CSSLint) return found;
|
||||
var results = CSSLint.verify(text), messages = results.messages, message = null;
|
||||
for ( var i = 0; i < messages.length; i++) {
|
||||
message = messages[i];
|
||||
var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col;
|
||||
found.push({
|
||||
from: CodeMirror.Pos(startLine, startCol),
|
||||
to: CodeMirror.Pos(endLine, endCol),
|
||||
message: message.message,
|
||||
severity : message.type
|
||||
});
|
||||
}
|
||||
return found;
|
||||
});
|
||||
|
||||
});
|
73
codemirror/addon/lint/lint.css
vendored
Normal file
73
codemirror/addon/lint/lint.css
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
/* The lint marker gutter */
|
||||
.CodeMirror-lint-markers {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-tooltip {
|
||||
background-color: infobackground;
|
||||
border: 1px solid black;
|
||||
border-radius: 4px 4px 4px 4px;
|
||||
color: infotext;
|
||||
font-family: monospace;
|
||||
font-size: 10pt;
|
||||
overflow: hidden;
|
||||
padding: 2px 5px;
|
||||
position: fixed;
|
||||
white-space: pre;
|
||||
white-space: pre-wrap;
|
||||
z-index: 100;
|
||||
max-width: 600px;
|
||||
opacity: 0;
|
||||
transition: opacity .4s;
|
||||
-moz-transition: opacity .4s;
|
||||
-webkit-transition: opacity .4s;
|
||||
-o-transition: opacity .4s;
|
||||
-ms-transition: opacity .4s;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning {
|
||||
background-position: left bottom;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-mark-error {
|
||||
background-image:
|
||||
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==")
|
||||
;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-mark-warning {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning {
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning {
|
||||
padding-left: 18px;
|
||||
background-position: top left;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
.CodeMirror-lint-marker-multiple {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right bottom;
|
||||
width: 100%; height: 100%;
|
||||
}
|
205
codemirror/addon/lint/lint.js
vendored
Normal file
205
codemirror/addon/lint/lint.js
vendored
Normal file
|
@ -0,0 +1,205 @@
|
|||
// 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 GUTTER_ID = "CodeMirror-lint-markers";
|
||||
|
||||
function showTooltip(e, content) {
|
||||
var tt = document.createElement("div");
|
||||
tt.className = "CodeMirror-lint-tooltip";
|
||||
tt.appendChild(content.cloneNode(true));
|
||||
document.body.appendChild(tt);
|
||||
|
||||
function position(e) {
|
||||
if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
|
||||
tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px";
|
||||
tt.style.left = (e.clientX + 5) + "px";
|
||||
}
|
||||
CodeMirror.on(document, "mousemove", position);
|
||||
position(e);
|
||||
if (tt.style.opacity != null) tt.style.opacity = 1;
|
||||
return tt;
|
||||
}
|
||||
function rm(elt) {
|
||||
if (elt.parentNode) elt.parentNode.removeChild(elt);
|
||||
}
|
||||
function hideTooltip(tt) {
|
||||
if (!tt.parentNode) return;
|
||||
if (tt.style.opacity == null) rm(tt);
|
||||
tt.style.opacity = 0;
|
||||
setTimeout(function() { rm(tt); }, 600);
|
||||
}
|
||||
|
||||
function showTooltipFor(e, content, node) {
|
||||
var tooltip = showTooltip(e, content);
|
||||
function hide() {
|
||||
CodeMirror.off(node, "mouseout", hide);
|
||||
if (tooltip) { hideTooltip(tooltip); tooltip = null; }
|
||||
}
|
||||
var poll = setInterval(function() {
|
||||
if (tooltip) for (var n = node;; n = n.parentNode) {
|
||||
if (n && n.nodeType == 11) n = n.host;
|
||||
if (n == document.body) return;
|
||||
if (!n) { hide(); break; }
|
||||
}
|
||||
if (!tooltip) return clearInterval(poll);
|
||||
}, 400);
|
||||
CodeMirror.on(node, "mouseout", hide);
|
||||
}
|
||||
|
||||
function LintState(cm, options, hasGutter) {
|
||||
this.marked = [];
|
||||
this.options = options;
|
||||
this.timeout = null;
|
||||
this.hasGutter = hasGutter;
|
||||
this.onMouseOver = function(e) { onMouseOver(cm, e); };
|
||||
}
|
||||
|
||||
function parseOptions(cm, options) {
|
||||
if (options instanceof Function) return {getAnnotations: options};
|
||||
if (!options || options === true) options = {};
|
||||
if (!options.getAnnotations) options.getAnnotations = cm.getHelper(CodeMirror.Pos(0, 0), "lint");
|
||||
if (!options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)");
|
||||
return options;
|
||||
}
|
||||
|
||||
function clearMarks(cm) {
|
||||
var state = cm.state.lint;
|
||||
if (state.hasGutter) cm.clearGutter(GUTTER_ID);
|
||||
for (var i = 0; i < state.marked.length; ++i)
|
||||
state.marked[i].clear();
|
||||
state.marked.length = 0;
|
||||
}
|
||||
|
||||
function makeMarker(labels, severity, multiple, tooltips) {
|
||||
var marker = document.createElement("div"), inner = marker;
|
||||
marker.className = "CodeMirror-lint-marker-" + severity;
|
||||
if (multiple) {
|
||||
inner = marker.appendChild(document.createElement("div"));
|
||||
inner.className = "CodeMirror-lint-marker-multiple";
|
||||
}
|
||||
|
||||
if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
|
||||
showTooltipFor(e, labels, inner);
|
||||
});
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
function getMaxSeverity(a, b) {
|
||||
if (a == "error") return a;
|
||||
else return b;
|
||||
}
|
||||
|
||||
function groupByLine(annotations) {
|
||||
var lines = [];
|
||||
for (var i = 0; i < annotations.length; ++i) {
|
||||
var ann = annotations[i], line = ann.from.line;
|
||||
(lines[line] || (lines[line] = [])).push(ann);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
function annotationTooltip(ann) {
|
||||
var severity = ann.severity;
|
||||
if (!severity) severity = "error";
|
||||
var tip = document.createElement("div");
|
||||
tip.className = "CodeMirror-lint-message-" + severity;
|
||||
tip.appendChild(document.createTextNode(ann.message));
|
||||
return tip;
|
||||
}
|
||||
|
||||
function startLinting(cm) {
|
||||
var state = cm.state.lint, options = state.options;
|
||||
var passOptions = options.options || options; // Support deprecated passing of `options` property in options
|
||||
if (options.async || options.getAnnotations.async)
|
||||
options.getAnnotations(cm.getValue(), updateLinting, passOptions, cm);
|
||||
else
|
||||
updateLinting(cm, options.getAnnotations(cm.getValue(), passOptions, cm));
|
||||
}
|
||||
|
||||
function updateLinting(cm, annotationsNotSorted) {
|
||||
clearMarks(cm);
|
||||
var state = cm.state.lint, options = state.options;
|
||||
|
||||
var annotations = groupByLine(annotationsNotSorted);
|
||||
|
||||
for (var line = 0; line < annotations.length; ++line) {
|
||||
var anns = annotations[line];
|
||||
if (!anns) continue;
|
||||
|
||||
var maxSeverity = null;
|
||||
var tipLabel = state.hasGutter && document.createDocumentFragment();
|
||||
|
||||
for (var i = 0; i < anns.length; ++i) {
|
||||
var ann = anns[i];
|
||||
var severity = ann.severity;
|
||||
if (!severity) severity = "error";
|
||||
maxSeverity = getMaxSeverity(maxSeverity, severity);
|
||||
|
||||
if (options.formatAnnotation) ann = options.formatAnnotation(ann);
|
||||
if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
|
||||
|
||||
if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
|
||||
className: "CodeMirror-lint-mark-" + severity,
|
||||
__annotation: ann
|
||||
}));
|
||||
}
|
||||
|
||||
if (state.hasGutter)
|
||||
cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1,
|
||||
state.options.tooltips));
|
||||
}
|
||||
if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
|
||||
}
|
||||
|
||||
function onChange(cm) {
|
||||
var state = cm.state.lint;
|
||||
clearTimeout(state.timeout);
|
||||
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
|
||||
}
|
||||
|
||||
function popupSpanTooltip(ann, e) {
|
||||
var target = e.target || e.srcElement;
|
||||
showTooltipFor(e, annotationTooltip(ann), target);
|
||||
}
|
||||
|
||||
function onMouseOver(cm, e) {
|
||||
var target = e.target || e.srcElement;
|
||||
if (!/\bCodeMirror-lint-mark-/.test(target.className)) return;
|
||||
var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2;
|
||||
var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client"));
|
||||
for (var i = 0; i < spans.length; ++i) {
|
||||
var ann = spans[i].__annotation;
|
||||
if (ann) return popupSpanTooltip(ann, e);
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("lint", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
clearMarks(cm);
|
||||
cm.off("change", onChange);
|
||||
CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
|
||||
delete cm.state.lint;
|
||||
}
|
||||
|
||||
if (val) {
|
||||
var gutters = cm.getOption("gutters"), hasLintGutter = false;
|
||||
for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
|
||||
var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter);
|
||||
cm.on("change", onChange);
|
||||
if (state.options.tooltips != false)
|
||||
CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
|
||||
|
||||
startLinting(cm);
|
||||
}
|
||||
});
|
||||
});
|
100
codemirror/addon/scroll/annotatescrollbar.js
vendored
Normal file
100
codemirror/addon/scroll/annotatescrollbar.js
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
// 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";
|
||||
|
||||
CodeMirror.defineExtension("annotateScrollbar", function(options) {
|
||||
if (typeof options == "string") options = {className: options};
|
||||
return new Annotation(this, options);
|
||||
});
|
||||
|
||||
CodeMirror.defineOption("scrollButtonHeight", 0);
|
||||
|
||||
function Annotation(cm, options) {
|
||||
this.cm = cm;
|
||||
this.options = options;
|
||||
this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight");
|
||||
this.annotations = [];
|
||||
this.doRedraw = this.doUpdate = null;
|
||||
this.div = cm.getWrapperElement().appendChild(document.createElement("div"));
|
||||
this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none";
|
||||
this.computeScale();
|
||||
|
||||
function scheduleRedraw(delay) {
|
||||
clearTimeout(self.doRedraw);
|
||||
self.doRedraw = setTimeout(function() { self.redraw(); }, delay);
|
||||
}
|
||||
|
||||
var self = this;
|
||||
cm.on("refresh", this.resizeHandler = function() {
|
||||
clearTimeout(self.doUpdate);
|
||||
self.doUpdate = setTimeout(function() {
|
||||
if (self.computeScale()) scheduleRedraw(20);
|
||||
}, 100);
|
||||
});
|
||||
cm.on("markerAdded", this.resizeHandler);
|
||||
cm.on("markerCleared", this.resizeHandler);
|
||||
if (options.listenForChanges !== false)
|
||||
cm.on("change", this.changeHandler = function() {
|
||||
scheduleRedraw(250);
|
||||
});
|
||||
}
|
||||
|
||||
Annotation.prototype.computeScale = function() {
|
||||
var cm = this.cm;
|
||||
var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) /
|
||||
cm.heightAtLine(cm.lastLine() + 1, "local");
|
||||
if (hScale != this.hScale) {
|
||||
this.hScale = hScale;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Annotation.prototype.update = function(annotations) {
|
||||
this.annotations = annotations;
|
||||
this.redraw();
|
||||
};
|
||||
|
||||
Annotation.prototype.redraw = function(compute) {
|
||||
if (compute !== false) this.computeScale();
|
||||
var cm = this.cm, hScale = this.hScale;
|
||||
|
||||
var frag = document.createDocumentFragment(), anns = this.annotations;
|
||||
if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) {
|
||||
var ann = anns[i];
|
||||
var top = nextTop || cm.charCoords(ann.from, "local").top * hScale;
|
||||
var bottom = cm.charCoords(ann.to, "local").bottom * hScale;
|
||||
while (i < anns.length - 1) {
|
||||
nextTop = cm.charCoords(anns[i + 1].from, "local").top * hScale;
|
||||
if (nextTop > bottom + .9) break;
|
||||
ann = anns[++i];
|
||||
bottom = cm.charCoords(ann.to, "local").bottom * hScale;
|
||||
}
|
||||
if (bottom == top) continue;
|
||||
var height = Math.max(bottom - top, 3);
|
||||
|
||||
var elt = frag.appendChild(document.createElement("div"));
|
||||
elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: "
|
||||
+ (top + this.buttonHeight) + "px; height: " + height + "px";
|
||||
elt.className = this.options.className;
|
||||
}
|
||||
this.div.textContent = "";
|
||||
this.div.appendChild(frag);
|
||||
};
|
||||
|
||||
Annotation.prototype.clear = function() {
|
||||
this.cm.off("refresh", this.resizeHandler);
|
||||
this.cm.off("markerAdded", this.resizeHandler);
|
||||
this.cm.off("markerCleared", this.resizeHandler);
|
||||
if (this.changeHandler) this.cm.off("change", this.changeHandler);
|
||||
this.div.parentNode.removeChild(this.div);
|
||||
};
|
||||
});
|
8
codemirror/addon/search/matchesonscrollbar.css
vendored
Normal file
8
codemirror/addon/search/matchesonscrollbar.css
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
.CodeMirror-search-match {
|
||||
background: gold;
|
||||
border-top: 1px solid orange;
|
||||
border-bottom: 1px solid orange;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
opacity: .5;
|
||||
}
|
95
codemirror/addon/search/matchesonscrollbar.js
vendored
Normal file
95
codemirror/addon/search/matchesonscrollbar.js
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
// 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"), require("./searchcursor"), require("../scroll/annotatescrollbar"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) {
|
||||
if (typeof options == "string") options = {className: options};
|
||||
if (!options) options = {};
|
||||
return new SearchAnnotation(this, query, caseFold, options);
|
||||
});
|
||||
|
||||
function SearchAnnotation(cm, query, caseFold, options) {
|
||||
this.cm = cm;
|
||||
var annotateOptions = {listenForChanges: false};
|
||||
for (var prop in options) annotateOptions[prop] = options[prop];
|
||||
if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match";
|
||||
this.annotation = cm.annotateScrollbar(annotateOptions);
|
||||
this.query = query;
|
||||
this.caseFold = caseFold;
|
||||
this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1};
|
||||
this.matches = [];
|
||||
this.update = null;
|
||||
|
||||
this.findMatches();
|
||||
this.annotation.update(this.matches);
|
||||
|
||||
var self = this;
|
||||
cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); });
|
||||
}
|
||||
|
||||
var MAX_MATCHES = 1000;
|
||||
|
||||
SearchAnnotation.prototype.findMatches = function() {
|
||||
if (!this.gap) return;
|
||||
for (var i = 0; i < this.matches.length; i++) {
|
||||
var match = this.matches[i];
|
||||
if (match.from.line >= this.gap.to) break;
|
||||
if (match.to.line >= this.gap.from) this.matches.splice(i--, 1);
|
||||
}
|
||||
var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), this.caseFold);
|
||||
while (cursor.findNext()) {
|
||||
var match = {from: cursor.from(), to: cursor.to()};
|
||||
if (match.from.line >= this.gap.to) break;
|
||||
this.matches.splice(i++, 0, match);
|
||||
if (this.matches.length > MAX_MATCHES) break;
|
||||
}
|
||||
this.gap = null;
|
||||
};
|
||||
|
||||
function offsetLine(line, changeStart, sizeChange) {
|
||||
if (line <= changeStart) return line;
|
||||
return Math.max(changeStart, line + sizeChange);
|
||||
}
|
||||
|
||||
SearchAnnotation.prototype.onChange = function(change) {
|
||||
var startLine = change.from.line;
|
||||
var endLine = CodeMirror.changeEnd(change).line;
|
||||
var sizeChange = endLine - change.to.line;
|
||||
if (this.gap) {
|
||||
this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line);
|
||||
this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line);
|
||||
} else {
|
||||
this.gap = {from: change.from.line, to: endLine + 1};
|
||||
}
|
||||
|
||||
if (sizeChange) for (var i = 0; i < this.matches.length; i++) {
|
||||
var match = this.matches[i];
|
||||
var newFrom = offsetLine(match.from.line, startLine, sizeChange);
|
||||
if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch);
|
||||
var newTo = offsetLine(match.to.line, startLine, sizeChange);
|
||||
if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch);
|
||||
}
|
||||
clearTimeout(this.update);
|
||||
var self = this;
|
||||
this.update = setTimeout(function() { self.updateAfterChange(); }, 250);
|
||||
};
|
||||
|
||||
SearchAnnotation.prototype.updateAfterChange = function() {
|
||||
this.findMatches();
|
||||
this.annotation.update(this.matches);
|
||||
};
|
||||
|
||||
SearchAnnotation.prototype.clear = function() {
|
||||
this.cm.off("change", this.changeHandler);
|
||||
this.annotation.clear();
|
||||
};
|
||||
});
|
164
codemirror/addon/search/search.js
vendored
Normal file
164
codemirror/addon/search/search.js
vendored
Normal file
|
@ -0,0 +1,164 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// Define search commands. Depends on dialog.js or another
|
||||
// implementation of the openDialog method.
|
||||
|
||||
// Replace works a little oddly -- it will do the replace on the next
|
||||
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
|
||||
// replace by making sure the match is no longer selected when hitting
|
||||
// Ctrl-G.
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
function searchOverlay(query, caseInsensitive) {
|
||||
if (typeof query == "string")
|
||||
query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
|
||||
else if (!query.global)
|
||||
query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");
|
||||
|
||||
return {token: function(stream) {
|
||||
query.lastIndex = stream.pos;
|
||||
var match = query.exec(stream.string);
|
||||
if (match && match.index == stream.pos) {
|
||||
stream.pos += match[0].length;
|
||||
return "searching";
|
||||
} else if (match) {
|
||||
stream.pos = match.index;
|
||||
} else {
|
||||
stream.skipToEnd();
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
function SearchState() {
|
||||
this.posFrom = this.posTo = this.query = null;
|
||||
this.overlay = null;
|
||||
}
|
||||
function getSearchState(cm) {
|
||||
return cm.state.search || (cm.state.search = new SearchState());
|
||||
}
|
||||
function queryCaseInsensitive(query) {
|
||||
return typeof query == "string" && query == query.toLowerCase();
|
||||
}
|
||||
function getSearchCursor(cm, query, pos) {
|
||||
// Heuristic: if the query string is all lowercase, do a case insensitive search.
|
||||
return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
|
||||
}
|
||||
function dialog(cm, text, shortText, deflt, f) {
|
||||
if (cm.openDialog) cm.openDialog(text, f, {value: deflt});
|
||||
else f(prompt(shortText, deflt));
|
||||
}
|
||||
function confirmDialog(cm, text, shortText, fs) {
|
||||
if (cm.openConfirm) cm.openConfirm(text, fs);
|
||||
else if (confirm(shortText)) fs[0]();
|
||||
}
|
||||
function parseQuery(query) {
|
||||
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
|
||||
if (isRE) {
|
||||
try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
|
||||
catch(e) {} // Not a regular expression after all, do a string search
|
||||
}
|
||||
if (typeof query == "string" ? query == "" : query.test(""))
|
||||
query = /x^/;
|
||||
return query;
|
||||
}
|
||||
var queryDialog =
|
||||
'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
|
||||
function doSearch(cm, rev) {
|
||||
var state = getSearchState(cm);
|
||||
if (state.query) return findNext(cm, rev);
|
||||
dialog(cm, queryDialog, "Search for:", cm.getSelection(), function(query) {
|
||||
cm.operation(function() {
|
||||
if (!query || state.query) return;
|
||||
state.query = parseQuery(query);
|
||||
cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
|
||||
state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
|
||||
cm.addOverlay(state.overlay);
|
||||
if (cm.showMatchesOnScrollbar) {
|
||||
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
|
||||
state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
|
||||
}
|
||||
state.posFrom = state.posTo = cm.getCursor();
|
||||
findNext(cm, rev);
|
||||
});
|
||||
});
|
||||
}
|
||||
function findNext(cm, rev) {cm.operation(function() {
|
||||
var state = getSearchState(cm);
|
||||
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
|
||||
if (!cursor.find(rev)) {
|
||||
cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
|
||||
if (!cursor.find(rev)) return;
|
||||
}
|
||||
cm.setSelection(cursor.from(), cursor.to());
|
||||
cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
|
||||
state.posFrom = cursor.from(); state.posTo = cursor.to();
|
||||
});}
|
||||
function clearSearch(cm) {cm.operation(function() {
|
||||
var state = getSearchState(cm);
|
||||
if (!state.query) return;
|
||||
state.query = null;
|
||||
cm.removeOverlay(state.overlay);
|
||||
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
|
||||
});}
|
||||
|
||||
var replaceQueryDialog =
|
||||
'Replace: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
|
||||
var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
|
||||
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
|
||||
function replace(cm, all) {
|
||||
if (cm.getOption("readOnly")) return;
|
||||
dialog(cm, replaceQueryDialog, "Replace:", cm.getSelection(), function(query) {
|
||||
if (!query) return;
|
||||
query = parseQuery(query);
|
||||
dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
|
||||
if (all) {
|
||||
cm.operation(function() {
|
||||
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
|
||||
if (typeof query != "string") {
|
||||
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
|
||||
cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
|
||||
} else cursor.replace(text);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
clearSearch(cm);
|
||||
var cursor = getSearchCursor(cm, query, cm.getCursor());
|
||||
var advance = function() {
|
||||
var start = cursor.from(), match;
|
||||
if (!(match = cursor.findNext())) {
|
||||
cursor = getSearchCursor(cm, query);
|
||||
if (!(match = cursor.findNext()) ||
|
||||
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
|
||||
}
|
||||
cm.setSelection(cursor.from(), cursor.to());
|
||||
cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
|
||||
confirmDialog(cm, doReplaceConfirm, "Replace?",
|
||||
[function() {doReplace(match);}, advance]);
|
||||
};
|
||||
var doReplace = function(match) {
|
||||
cursor.replace(typeof query == "string" ? text :
|
||||
text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
|
||||
advance();
|
||||
};
|
||||
advance();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
|
||||
CodeMirror.commands.findNext = doSearch;
|
||||
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
|
||||
CodeMirror.commands.clearSearch = clearSearch;
|
||||
CodeMirror.commands.replace = replace;
|
||||
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
|
||||
});
|
189
codemirror/addon/search/searchcursor.js
vendored
Normal file
189
codemirror/addon/search/searchcursor.js
vendored
Normal file
|
@ -0,0 +1,189 @@
|
|||
// 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);
|
||||
});
|
||||
});
|
9259
csslint/csslint.js
Normal file
9259
csslint/csslint.js
Normal file
File diff suppressed because it is too large
Load Diff
27
edit.html
27
edit.html
|
@ -3,7 +3,30 @@
|
|||
<script src="codemirror/lib/codemirror.js"></script>
|
||||
<link rel="stylesheet" href="codemirror/lib/codemirror.css">
|
||||
<script src="codemirror/mode/css/css.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="codemirror/addon/dialog/dialog.css">
|
||||
<link rel="stylesheet" href="codemirror/addon/search/matchesonscrollbar.css">
|
||||
<script src="codemirror/addon/scroll/annotatescrollbar.js"></script>
|
||||
<script src="codemirror/addon/search/matchesonscrollbar.js"></script>
|
||||
<script src="codemirror/addon/dialog/dialog.js"></script>
|
||||
<script src="codemirror/addon/search/searchcursor.js"></script>
|
||||
<script src="codemirror/addon/search/search.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="codemirror/addon/fold/foldgutter.css" />
|
||||
<script src="codemirror/addon/fold/foldcode.js"></script>
|
||||
<script src="codemirror/addon/fold/foldgutter.js"></script>
|
||||
<script src="codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script src="codemirror/addon/fold/comment-fold.js"></script>
|
||||
|
||||
<script src="codemirror/addon/edit/matchbrackets.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="codemirror/addon/lint/lint.css" />
|
||||
<script src="csslint/csslint.js"></script>
|
||||
<script src="codemirror/addon/lint/lint.js"></script>
|
||||
<script src="codemirror/addon/lint/css-lint.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
margin: 0px;
|
||||
font: 12px arial,sans-serif;
|
||||
|
@ -85,6 +108,9 @@
|
|||
.applies-to img {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.CodeMirror-lint-marker-warning {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media(max-width:737px) {
|
||||
#header {
|
||||
|
@ -110,6 +136,7 @@
|
|||
body > section > *:not(h2) {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
<script src="storage.js"></script>
|
||||
|
|
4
edit.js
4
edit.js
|
@ -19,6 +19,10 @@ function setupCodeMirror(textarea) {
|
|||
mode: 'css',
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
foldGutter: true,
|
||||
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"],
|
||||
matchBrackets: true,
|
||||
lint: CodeMirror.lint.css,
|
||||
smartIndent: (typeof localStorage["smart-indent"] == "undefined") || localStorage["smart-indent"] == "true"
|
||||
});
|
||||
editors.push(cm);
|
||||
|
|
Loading…
Reference in New Issue
Block a user