override fun findPattern()

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
  }