dianping/cat · error · Error
Search feature not available. Requires searchcursor.js or an
Error message
Search feature not available. Requires searchcursor.js or any other getSearchCursor implementation.
What it means
Thrown by the vim keybinding's `:substitute` (`:s`) implementation when `cm.getSearchCursor` is not defined on the CodeMirror instance. The substitute command needs to iterate matches line by line, and CodeMirror ships that capability in a separate addon (`search/searchcursor.js`); without it the core editor has no search API. The code checks for the capability up front and fails fast instead of silently doing nothing.
Source
Thrown at cat-home/src/main/webapp/assets/js/editor/keybinding-vim.js:4677
if (!cmd) {
showConfirm(cm, content);
return;
}
var index = 0;
var nextCommand = function() {
if (index < matchedLines.length) {
var command = matchedLines[index] + cmd;
exCommandDispatcher.processCommand(cm, command, {
callback: nextCommand
});
}
index++;
};
nextCommand();
},
substitute: function(cm, params) {
if (!cm.getSearchCursor) {
throw new Error('Search feature not available. Requires searchcursor.js or ' +
'any other getSearchCursor implementation.');
}
var argString = params.argString;
var tokens = argString ? splitBySlash(argString) : [];
var regexPart, replacePart = '', trailing, flagsPart, count;
var confirm = false; // Whether to confirm each replace.
var global = false; // True to replace all instances on a line, false to replace only 1.
if (tokens.length) {
regexPart = tokens[0];
replacePart = tokens[1];
if (replacePart !== undefined) {
if (getOption('pcre')) {
replacePart = unescapeRegexReplace(replacePart);
} else {
replacePart = translateRegexReplace(replacePart);
}
vimGlobalState.lastSubstituteReplacePart = replacePart;
}View on GitHub (pinned to e815e74d4c)
Solutions
- Include the searchcursor addon before the vim keybinding: `<script src="codemirror/addon/search/searchcursor.js">` (or `import 'codemirror/addon/search/searchcursor'`).
- If importing modules, ensure the addon import happens in the same bundle/page where the vim keymap is active.
- Alternatively provide any `getSearchCursor(query, pos, caseFold)` implementation on the CodeMirror prototype before vim commands run.
- As a last resort, disable `:substitute`/`:g` in your command handling if search is intentionally excluded.
Example fix
// before import CodeMirror from 'codemirror'; import 'codemirror/keymap/vim.js'; // :%s/.../ throws 'Search feature not available' // after import CodeMirror from 'codemirror'; import 'codemirror/addon/search/searchcursor.js'; // provides cm.getSearchCursor import 'codemirror/keymap/vim.js';
Defensive patterns
Strategy: type-guard
Validate before calling
function searchAvailable(cm) {
return typeof cm.getSearchCursor === 'function';
}
if (!searchAvailable(cm)) {
document.querySelector('script#searchcursor') || warn(':s/:g disabled — load searchcursor.js');
} Type guard
function hasSearchCursor(cm) {
return typeof cm.getSearchCursor === 'function';
} Try / catch
try {
CodeMirror.Vim.handleEx(cm, ':%s/old/new/g');
} catch (e) {
if (/searchcursor/.test(e.message)) { loadScript('addon/search/searchcursor.js').then(retry); return; }
throw e;
} Prevention
- Always load the searchcursor addon in the same page/bundle as keybinding-vim.js.
- In bundler setups, import 'codemirror/addon/search/searchcursor' explicitly so tree-shaking cannot drop it.
- Feature-detect cm.getSearchCursor before enabling :substitute/:global UI affordances.
- Keep addons and the vim keymap from the same CodeMirror version.
When it happens
Trigger: Loading `keybinding-vim.js` without first (or ever) loading the `searchcursor.js` addon, then running `:%s/foo/bar/g`, `:s/x/y`, or `:g/pat/cmd` (global also drives substitute); building a custom CodeMirror bundle that omits the search addon; using a third-party editor wrapper that only includes the vim keymap.
Common situations: Custom bundlers (webpack/esbuild tree-shaking) stripping the addon; pages that copy keybinding-vim.js alone out of the CodeMirror distribution; upgrading CodeMirror where addons moved to separate module paths and the import was not migrated.
Related errors
AI-assisted analysis of dianping/cat@e815e74d4c (2026-08-14).
Data as JSON: /api/errors/48360a99e49a98ec.
Report an issue: GitHub.