override fun processSubstituteCommand()

in vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimSearchGroupBase.kt [576:667]


  override fun processSubstituteCommand(
    editor: VimEditor,
    caret: VimCaret,
    context: ExecutionContext,
    range: LineRange,
    excmd: String,
    exarg: String,
    parent: VimLContext,
  ): Boolean {
    // Explicitly exit visual mode here, so that visual mode marks don't change when we move the cursor to a match.
    val exceptions: MutableList<ExException> = ArrayList()
    if (editor.inVisualMode) editor.exitVisualMode()

    // Parse Ex command and arguments to extract the pattern, substitute string, and line range
    val substituteCommandParse = parseSubstituteCommand(editor, range, excmd, exarg) ?: return false
    val pattern = substituteCommandParse.pattern
    val substituteString = substituteCommandParse.substituteString
    val line1 = substituteCommandParse.range.startLine
    val line2 = substituteCommandParse.range.endLine

    val options = enumSetOf<VimRegexOptions>()
    if (injector.globalOptions().smartcase) options.add(VimRegexOptions.SMART_CASE)
    if (injector.globalOptions().ignorecase) options.add(VimRegexOptions.IGNORE_CASE)

    val regex: VimRegex = try {
      VimRegex(pattern)
    } catch (e: VimRegexException) {
      injector.messages.showStatusBarMessage(editor, e.message)
      return false
    }

    val hasExpression = substituteString.length >= 2 && substituteString[0] == '\\' && substituteString[1] == '='

    val oldLastSubstituteString: String = lastSubstituteString ?: ""
    if (substituteString != "~") {
      lastSubstituteString = substituteString
    }

    setShouldShowSearchHighlights()
    updateSearchHighlights(true)

    if (!doAsk) {
      performSubstituteInLines(
        editor,
        caret,
        context,
        parent,
        regex,
        pattern,
        oldLastSubstituteString,
        line1,
        line2,
        0,
        hasExpression,
        substituteString,
        exceptions,
        options
      )
    } else {
      val lineToNextSubstitute = getNextSubstitute(
        editor,
        regex,
        oldLastSubstituteString,
        line1,
        line2,
        0,
        hasExpression,
        substituteString,
        options
      )
      if (lineToNextSubstitute == null) {
        injector.messages.indicateError()
        injector.messages.showStatusBarMessage(null, "E486: Pattern not found: $pattern")
        return true
      }
      val (line, nextSubstitute) = lineToNextSubstitute
      val matchRange = nextSubstitute.first.range
      caret.moveToOffset(matchRange.startOffset)
      val highlight = addSubstitutionConfirmationHighlight(editor, matchRange.startOffset, matchRange.endOffset)
      injector.modalInput.create(
        editor, context, injector.messages.message("command.substitute.replace.with.prompt", lineToNextSubstitute.second.second),
        SubstituteWithAskInputInterceptor(
          editor, caret, nextSubstitute, highlight, line, 0, parent, pattern, regex,
          oldLastSubstituteString, line2, hasExpression, substituteString, options,
          -1, mutableListOf(),
        )
      )
    }

    // TODO: Support reporting number of changes (:help 'report')
    return true
  }