make multi-section search instantaneous

This commit is contained in:
tophf 2017-12-14 10:35:59 +03:00
parent 49a995afae
commit cc5a254e01

View File

@ -307,7 +307,8 @@ onDOMscriptReady('/codemirror.js').then(() => {
function updateState(cm, newState) { function updateState(cm, newState) {
if (!newState) { if (!newState) {
if (cm.state.search) { const query = (cm.state.search || {}).query;
if (query !== null && query !== undefined) {
return cm.state.search; return cm.state.search;
} }
if (!searchState) { if (!searchState) {
@ -343,23 +344,26 @@ onDOMscriptReady('/codemirror.js').then(() => {
return cm; return cm;
} }
function propagateSearchState(cm) {
if ((cm.state.search || {}).clearSearch) {
cm.execCommand('clearSearch');
}
updateState(cm);
}
function find(activeCM) { function find(activeCM) {
activeCM = focusClosestCM(activeCM); activeCM = focusClosestCM(activeCM);
customizeOpenDialog(activeCM, template.find, function (query) { customizeOpenDialog(activeCM, template.find, function (query) {
this(query); this(query);
searchState = activeCM.state.search; searchState = activeCM.state.search;
const searchOthers = editors.length > 1 && searchState.query; if (!searchState.query ||
editors.forEach(cm => { editors.length === 1 ||
if (cm !== activeCM) { CodeMirror.cmpPos(searchState.posFrom, searchState.posTo)) {
cm.execCommand('clearSearch'); return;
if (searchOthers) {
updateState(cm, searchState);
}
}
});
if (searchOthers && CodeMirror.cmpPos(searchState.posFrom, searchState.posTo) === 0) {
findNext(activeCM);
} }
editors.forEach(cm => ((cm.state.search || {}).clearSearch = cm !== activeCM));
editors.forEach((cm, i) => setTimeout(propagateSearchState, i + 100, cm));
findNext(activeCM);
}); });
ORIGINAL_COMMAND.find(activeCM); ORIGINAL_COMMAND.find(activeCM);
} }
@ -372,67 +376,73 @@ onDOMscriptReady('/codemirror.js').then(() => {
} }
let pos = activeCM.getCursor(reverse ? 'from' : 'to'); let pos = activeCM.getCursor(reverse ? 'from' : 'to');
// clear the selection, don't move the cursor // clear the selection, don't move the cursor
activeCM.setSelection(activeCM.getCursor()); if (activeCM.somethingSelected()) {
activeCM.setSelection(activeCM.getCursor());
}
const rxQuery = typeof state.query === 'object' const icase = shouldIgnoreCase(state.query);
? state.query : stringAsRegExp(state.query, shouldIgnoreCase(state.query) ? 'i' : ''); const query = searchState.query;
const rxQuery = typeof query === 'object'
? query : stringAsRegExp(query, icase ? 'i' : '');
if ( const total = editors.length;
document.activeElement && if ((!reverse || total === 1 ||
document.activeElement.name === 'applies-value' && (document.activeElement || {}).name === 'applies-value') &&
searchAppliesTo(activeCM) findAppliesTo(activeCM, reverse, rxQuery)) {
) {
return; return;
} }
let cm = activeCM; let cm = activeCM;
for (let i = 0; i < editors.length; i++) { const startIndex = editors.indexOf(cm);
state = updateState(cm); for (let i = 1; i < total; i++) {
if (!cm.hasFocus()) { cm = editors[(startIndex + i * (reverse ? -1 : 1) + total) % total];
pos = reverse ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(0, 0); pos = reverse ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(0, 0);
} const searchCursor = cm.getSearchCursor(query, pos, icase);
const searchCursor = cm.getSearchCursor(state.query, pos, shouldIgnoreCase(state.query));
if (searchCursor.find(reverse)) { if (searchCursor.find(reverse)) {
if (editors.length > 1) { if (total > 1) {
makeSectionVisible(cm); makeSectionVisible(cm);
cm.focus(); cm.focus();
} }
if ((cm.state.search || {}).clearSearch) {
cm.execCommand('clearSearch');
}
state = updateState(cm);
// speedup the original findNext // speedup the original findNext
state.posFrom = reverse ? searchCursor.to() : searchCursor.from(); state.posFrom = reverse ? searchCursor.to() : searchCursor.from();
state.posTo = CodeMirror.Pos(state.posFrom.line, state.posFrom.ch); state.posTo = Object.assign({}, state.posFrom);
ORIGINAL_COMMAND[reverse ? 'findPrev' : 'findNext'](cm); setTimeout(ORIGINAL_COMMAND[reverse ? 'findPrev' : 'findNext'], 0, cm);
return; return;
} else if (!reverse && searchAppliesTo(cm)) { } else if (!reverse && findAppliesTo(cm, reverse, rxQuery)) {
return; return;
} }
cm = editors[(editors.indexOf(cm) + (reverse ? -1 + editors.length : 1)) % editors.length]; cm = editors[(startIndex + (i + 1) * (reverse ? -1 : 1) + total) % total];
if (reverse && searchAppliesTo(cm)) { if (reverse && findAppliesTo(cm, reverse, rxQuery)) {
return; return;
} }
} }
// nothing found so far, so call the original search with wrap-around // nothing found so far, so call the original search with wrap-around
ORIGINAL_COMMAND[reverse ? 'findPrev' : 'findNext'](activeCM); ORIGINAL_COMMAND[reverse ? 'findPrev' : 'findNext'](activeCM);
}
function searchAppliesTo(cm) { function findAppliesTo(cm, reverse, rxQuery) {
let inputs = $$('.applies-value', cm.getSection()); let inputs = $$('.applies-value', cm.getSection());
if (reverse) { if (reverse) {
inputs = inputs.reverse(); inputs = inputs.reverse();
}
inputs.splice(0, inputs.indexOf(document.activeElement) + 1);
return inputs.some(input => {
const match = rxQuery.exec(input.value);
if (match) {
input.focus();
const end = match.index + match[0].length;
// scroll selected part into view in long inputs,
// works only outside of current event handlers chain, hence timeout=0
setTimeout(() => {
input.setSelectionRange(end, end);
input.setSelectionRange(match.index, end);
}, 0);
return true;
}
});
} }
inputs.splice(0, inputs.indexOf(document.activeElement) + 1);
return inputs.some(input => {
const match = rxQuery.exec(input.value);
if (match) {
input.focus();
const end = match.index + match[0].length;
// scroll selected part into view in long inputs,
// works only outside of current event handlers chain, hence timeout=0
setTimeout(() => {
input.setSelectionRange(end, end);
input.setSelectionRange(match.index, end);
}, 0);
return true;
}
});
} }
function findPrev(cm) { function findPrev(cm) {