(function (mod){ if (typeof exports == "object" && typeof module == "object") mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog")); else if (typeof define == "function" && define.amd) define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"] , mod); else mod(CodeMirror); } )(function (CodeMirror){ "use strict"; function searchOverlay(query, caseInsensitive){ if (typeof query == "string") query = new RegExp((_AN_Call_replace("replace", query, /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/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 += _AN_Read_length("length", match[0]) || 1; return "searching"; } else if (match) { stream.pos = match.index; } else { stream.skipToEnd(); } } } ; } function SearchState(){ this.posFrom = this.posTo = this.lastQuery = this.query = null ; this.overlay = null ; } function getSearchState(cm){ return _AN_Read_search("search", cm.state) || (_AN_Write_search("search", cm.state, false , new SearchState())); } function queryCaseInsensitive(query){ return typeof query == "string" && query == query.toLowerCase(); } function getSearchCursor(cm, query, pos){ 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 _AN_Call_replace("replace", string, /\\(.)/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) { } } else { query = parseString(query); } if (typeof query == "string"? query == "": query.test("")) query = /x^/; return query; } var queryDialog = 'Search: (Use /re/ syntax for regexp search)'; 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) { _AN_Call_clear('clear', state.annotate); 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; 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 = 0.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, callback){ 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()} , 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 = state.queryText = null ; cm.removeOverlay(state.overlay); if (state.annotate) { _AN_Call_clear("clear", state.annotate); state.annotate = null ; } } ); } var replaceQueryDialog = ' (Use /re/ syntax for regexp search)'; var replacementQueryDialog = 'With: '; var doReplaceConfirm = "Replace? "; 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); _AN_Call_replace("replace", cursor, _AN_Call_replace("replace", text, /\$(\d)/g, function (_, i){ return match[i]; } )); } else _AN_Call_replace("replace", cursor, text); } } ); } function replace(cm, all){ if (cm.getOption("readOnly")) return ; var query = cm.getSelection() || getSearchState(cm).lastQuery; 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) { replaceAll(cm, query, 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, function (){ replaceAll(cm, query, text); } ] ); } ; var doReplace = function (match){ _AN_Call_replace("replace", cursor, typeof query == "string"? text: _AN_Call_replace("replace", text, /\$(\d)/g, function (_, i){ return match[i]; } )); advance(); } ; advance(); } } ); } ); } 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; CodeMirror.commands.replace = replace; CodeMirror.commands.replaceAll = function (cm){ replace(cm, true ); } ; } );