diff options
Diffstat (limited to 'public/vendor/codemirror/addon/search')
-rw-r--r-- | public/vendor/codemirror/addon/search/jump-to-line.js | 49 | ||||
-rw-r--r--[-rwxr-xr-x] | public/vendor/codemirror/addon/search/match-highlighter.js | 43 | ||||
-rw-r--r--[-rwxr-xr-x] | public/vendor/codemirror/addon/search/matchesonscrollbar.js | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | public/vendor/codemirror/addon/search/search.js | 125 | ||||
-rw-r--r--[-rwxr-xr-x] | public/vendor/codemirror/addon/search/searchcursor.js | 0 |
5 files changed, 174 insertions, 43 deletions
diff --git a/public/vendor/codemirror/addon/search/jump-to-line.js b/public/vendor/codemirror/addon/search/jump-to-line.js new file mode 100644 index 00000000..8b599cbc --- /dev/null +++ b/public/vendor/codemirror/addon/search/jump-to-line.js @@ -0,0 +1,49 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Defines jumpToLine command. Uses dialog.js if present. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../dialog/dialog")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../dialog/dialog"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function dialog(cm, text, shortText, deflt, f) { + if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true}); + else f(prompt(shortText, deflt)); + } + + var jumpDialog = + 'Jump to line: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use line:column or scroll% syntax)</span>'; + + function interpretLine(cm, string) { + var num = Number(string) + if (/^[-+]/.test(string)) return cm.getCursor().line + num + else return num - 1 + } + + CodeMirror.commands.jumpToLine = function(cm) { + var cur = cm.getCursor(); + dialog(cm, jumpDialog, "Jump to line:", (cur.line + 1) + ":" + cur.ch, function(posStr) { + if (!posStr) return; + + var match; + if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) { + cm.setCursor(interpretLine(cm, match[1]), Number(match[2])) + } else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) { + var line = Math.round(cm.lineCount() * Number(match[1]) / 100); + if (/^[-+]/.test(match[1])) line = cur.line + line + 1; + cm.setCursor(line - 1, cur.ch); + } else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) { + cm.setCursor(interpretLine(cm, match[1]), cur.ch); + } + }); + }; + + CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine"; +}); diff --git a/public/vendor/codemirror/addon/search/match-highlighter.js b/public/vendor/codemirror/addon/search/match-highlighter.js index e9a22721..8f02f01c 100755..100644 --- a/public/vendor/codemirror/addon/search/match-highlighter.js +++ b/public/vendor/codemirror/addon/search/match-highlighter.js @@ -16,13 +16,14 @@ // highlighted only if the selected text is a word. showToken, when enabled, // will cause the current token to be highlighted when nothing is selected. // delay is used to specify how much time to wait, in milliseconds, before -// highlighting the matches. +// highlighting the matches. If annotateScrollbar is enabled, the occurances +// will be highlighted on the scrollbar via the matchesonscrollbar addon. (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); + mod(require("../../lib/codemirror"), require("./matchesonscrollbar")); else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); + define(["../../lib/codemirror", "./matchesonscrollbar"], mod); else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { @@ -40,18 +41,19 @@ this.showToken = options.showToken; this.delay = options.delay; this.wordsOnly = options.wordsOnly; + this.annotateScrollbar = options.annotateScrollbar; } if (this.style == null) this.style = DEFAULT_TOKEN_STYLE; if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS; if (this.delay == null) this.delay = DEFAULT_DELAY; if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY; this.overlay = this.timeout = null; + this.matchesonscroll = null; } CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { if (old && old != CodeMirror.Init) { - var over = cm.state.matchHighlighter.overlay; - if (over) cm.removeOverlay(over); + removeOverlay(cm); clearTimeout(cm.state.matchHighlighter.timeout); cm.state.matchHighlighter = null; cm.off("cursorActivity", cursorActivity); @@ -69,20 +71,39 @@ state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay); } + function addOverlay(cm, query, hasBoundary, style) { + var state = cm.state.matchHighlighter; + cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style)); + if (state.annotateScrollbar) { + var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query; + state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, true, + {className: "CodeMirror-selection-highlight-scrollbar"}); + } + } + + function removeOverlay(cm) { + var state = cm.state.matchHighlighter; + if (state.overlay) { + cm.removeOverlay(state.overlay); + state.overlay = null; + if (state.annotateScrollbar) { + state.matchesonscroll.clear(); + state.matchesonscroll = null; + } + } + } + function highlightMatches(cm) { cm.operation(function() { var state = cm.state.matchHighlighter; - if (state.overlay) { - cm.removeOverlay(state.overlay); - state.overlay = null; - } + removeOverlay(cm); if (!cm.somethingSelected() && state.showToken) { var re = state.showToken === true ? /[\w$]/ : state.showToken; var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; while (start && re.test(line.charAt(start - 1))) --start; while (end < line.length && re.test(line.charAt(end))) ++end; if (start < end) - cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style)); + addOverlay(cm, line.slice(start, end), re, state.style); return; } var from = cm.getCursor("from"), to = cm.getCursor("to"); @@ -90,7 +111,7 @@ if (state.wordsOnly && !isWord(cm, from, to)) return; var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, ""); if (selection.length >= state.minChars) - cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style)); + addOverlay(cm, selection, false, state.style); }); } diff --git a/public/vendor/codemirror/addon/search/matchesonscrollbar.js b/public/vendor/codemirror/addon/search/matchesonscrollbar.js index 8d192289..8d192289 100755..100644 --- a/public/vendor/codemirror/addon/search/matchesonscrollbar.js +++ b/public/vendor/codemirror/addon/search/matchesonscrollbar.js diff --git a/public/vendor/codemirror/addon/search/search.js b/public/vendor/codemirror/addon/search/search.js index afa85ebe..93e90b36 100755..100644 --- a/public/vendor/codemirror/addon/search/search.js +++ b/public/vendor/codemirror/addon/search/search.js @@ -18,6 +18,7 @@ mod(CodeMirror); })(function(CodeMirror) { "use strict"; + function searchOverlay(query, caseInsensitive) { if (typeof query == "string") query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g"); @@ -28,7 +29,7 @@ query.lastIndex = stream.pos; var match = query.exec(stream.string); if (match && match.index == stream.pos) { - stream.pos += match[0].length; + stream.pos += match[0].length || 1; return "searching"; } else if (match) { stream.pos = match.index; @@ -42,57 +43,106 @@ this.posFrom = this.posTo = this.lastQuery = 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 persistentDialog(cm, text, deflt, f) { + cm.openDialog(text, f, { + value: deflt, + selectValueOnOpen: true, + closeOnEnter: false, + onClose: function() { clearSearch(cm); } + }); + } + function dialog(cm, text, shortText, deflt, f) { if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true}); 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 parseString(string) { + return string.replace(/\\(.)/g, function(_, ch) { + if (ch == "n") return "\n" + if (ch == "r") return "\r" + return ch + }) + } + 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 + } else { + query = parseString(query) } 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) { + + function startSearch(cm, state, query) { + state.queryText = query; + 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)); + } + } + + function doSearch(cm, rev, persistent) { var state = getSearchState(cm); if (state.query) return findNext(cm, rev); var q = cm.getSelection() || state.lastQuery; - dialog(cm, queryDialog, "Search for:", q, 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); + if (persistent && cm.openDialog) { + var hiding = null + persistentDialog(cm, queryDialog, q, function(query, event) { + CodeMirror.e_stop(event); + if (!query) return; + if (query != state.queryText) startSearch(cm, state, query); + if (hiding) hiding.style.opacity = 1 + findNext(cm, event.shiftKey, function(_, to) { + var dialog + if (to.line < 3 && document.querySelector && + (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) && + dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top) + (hiding = dialog).style.opacity = .4 + }) }); - }); + } else { + dialog(cm, queryDialog, "Search for:", q, function(query) { + if (query && !state.query) cm.operation(function() { + startSearch(cm, state, query); + state.posFrom = state.posTo = cm.getCursor(); + findNext(cm, rev); + }); + }); + } } - function findNext(cm, rev) {cm.operation(function() { + + function findNext(cm, rev, callback) {cm.operation(function() { var state = getSearchState(cm); var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); if (!cursor.find(rev)) { @@ -100,38 +150,47 @@ if (!cursor.find(rev)) return; } cm.setSelection(cursor.from(), cursor.to()); - cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); + cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20); state.posFrom = cursor.from(); state.posTo = cursor.to(); + if (callback) callback(cursor.from(), cursor.to()) });} + function clearSearch(cm) {cm.operation(function() { var state = getSearchState(cm); state.lastQuery = state.query; if (!state.query) return; - state.query = null; + state.query = state.queryText = 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>'; + ' <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>"; + var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>"; + + function replaceAll(cm, query, text) { + 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); + } + }); + } + function replace(cm, all) { if (cm.getOption("readOnly")) return; var query = cm.getSelection() || getSearchState(cm).lastQuery; - dialog(cm, replaceQueryDialog, "Replace:", query, function(query) { + var dialogText = all ? "Replace all:" : "Replace:" + dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) { if (!query) return; query = parseQuery(query); dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) { + text = parseString(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];}), "+input"); - } else cursor.replace(text, "+input"); - } - }); + replaceAll(cm, query, text) } else { clearSearch(cm); var cursor = getSearchCursor(cm, query, cm.getCursor()); @@ -145,11 +204,12 @@ cm.setSelection(cursor.from(), cursor.to()); cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); confirmDialog(cm, doReplaceConfirm, "Replace?", - [function() {doReplace(match);}, advance]); + [function() {doReplace(match);}, advance, + function() {replaceAll(cm, query, text)}]); }; var doReplace = function(match) { cursor.replace(typeof query == "string" ? text : - text.replace(/\$(\d)/g, function(_, i) {return match[i];}), "+input"); + text.replace(/\$(\d)/g, function(_, i) {return match[i];})); advance(); }; advance(); @@ -159,6 +219,7 @@ } CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; + CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);}; CodeMirror.commands.findNext = doSearch; CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; CodeMirror.commands.clearSearch = clearSearch; diff --git a/public/vendor/codemirror/addon/search/searchcursor.js b/public/vendor/codemirror/addon/search/searchcursor.js index b70242ee..b70242ee 100755..100644 --- a/public/vendor/codemirror/addon/search/searchcursor.js +++ b/public/vendor/codemirror/addon/search/searchcursor.js |