in vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimSearchHelperBase.kt [263:338]
override fun findPattern(
editor: VimEditor,
pattern: String?,
startOffset: Int,
count: Int,
searchOptions: EnumSet<SearchOptions>?,
): TextRange? {
if (pattern.isNullOrEmpty()) return null
val dir = if (searchOptions!!.contains(SearchOptions.BACKWARDS)) Direction.BACKWARDS else Direction.FORWARDS
val options = enumSetOf<VimRegexOptions>()
if (injector.globalOptions().smartcase && !searchOptions.contains(SearchOptions.IGNORE_SMARTCASE)) options.add(
VimRegexOptions.SMART_CASE
)
if (injector.globalOptions().ignorecase) options.add(VimRegexOptions.IGNORE_CASE)
if (searchOptions.contains(SearchOptions.WANT_ENDPOS)) {
// When we want to get the end position of a search match, we can match at the current location. Having these as
// separate flags means we can remove CAN_MATCH_START_LOCATION for subsequent matches (i.e., count)
options.add(VimRegexOptions.WANT_END_POSITION)
options.add(VimRegexOptions.CAN_MATCH_START_LOCATION)
}
val wrap = searchOptions.contains(SearchOptions.WRAP)
val showMessages = searchOptions.contains(SearchOptions.SHOW_MESSAGES)
val regex = try {
VimRegex(pattern)
} catch (e: VimRegexException) {
injector.messages.showStatusBarMessage(editor, e.message)
return null
}
var result = if (dir === Direction.FORWARDS) {
findNextWithWrapscan(editor, regex, startOffset, options, wrap, showMessages)
} else {
findPreviousWithWrapscan(editor, regex, startOffset, options, wrap, showMessages)
}
if (result is VimMatchResult.Failure) {
if (wrap) {
injector.messages.showStatusBarMessage(editor, injector.messages.message("E486", pattern))
} else if (dir === Direction.FORWARDS) {
injector.messages.showStatusBarMessage(editor, injector.messages.message("E385", pattern))
} else {
injector.messages.showStatusBarMessage(editor, injector.messages.message("E384", pattern))
}
return null
}
// When trying to find the end position for a match, we're allowed to match the current position. But if we do that
// on subsequent matches when we have a count, then we'll get stuck at the current location. Remove the flag.
options.remove(VimRegexOptions.CAN_MATCH_START_LOCATION)
for (i in 1 until count) {
val nextOffset = (result as VimMatchResult.Success).range.startOffset
result =
if (dir === Direction.FORWARDS) {
findNextWithWrapscan(editor, regex, nextOffset, options, wrap, showMessages)
} else {
findPreviousWithWrapscan(editor, regex, nextOffset, options, wrap, showMessages)
}
if (result is VimMatchResult.Failure) {
// We know this isn't pattern not found...
if (searchOptions.contains(SearchOptions.SHOW_MESSAGES)) {
if (dir === Direction.FORWARDS) {
injector.messages.showStatusBarMessage(editor, injector.messages.message("E385", pattern))
} else {
injector.messages.showStatusBarMessage(editor, injector.messages.message("E384", pattern))
}
}
return null
}
}
return (result as VimMatchResult.Success).range
}