override fun getMotionRange()

in vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimMotionGroupBase.kt [335:421]


  override fun getMotionRange(
    editor: VimEditor,
    caret: ImmutableVimCaret,
    context: ExecutionContext,
    argument: Argument,
    operatorArguments: OperatorArguments,
  ): TextRange? {
    if (argument !is Argument.Motion) {
      throw RuntimeException("Unexpected argument passed to getMotionRange2: $argument")
    }

    var start: Int
    var end: Int

    val action = argument.motion
    when (action) {
      is MotionActionHandler -> {
        // This is where we are now
        start = caret.offset

        // Execute the motion (without moving the cursor) and get where we end
        val motion = action.getHandlerOffset(editor, caret, context, argument.argument, operatorArguments)
        if (Motion.Error == motion || Motion.NoMotion == motion) return null

        end = (motion as AbsoluteOffset).offset

        // If inclusive, add the last character to the range
        if (action.motionType === MotionType.INCLUSIVE) {
          if (start > end) {
            if (start < editor.fileSize()) start++
          } else {
            if (end < editor.fileSize()) end++
          }
        }
      }

      is TextObjectActionHandler -> {
        val range: TextRange =
          action.getRange(editor, caret, context, operatorArguments.count1, operatorArguments.count0)
            ?: return null
        start = range.startOffset
        end = range.endOffset
        if (argument.isLinewiseMotion()) end--
      }

      is ExternalActionHandler -> {
        val range: TextRange = action.getRange(caret) ?: return null
        start = range.startOffset
        end = range.endOffset
        if (argument.isLinewiseMotion()) end--
      }

      else -> throw RuntimeException("Commands doesn't take " + action.javaClass.simpleName + " as an operator")
    }

    // Normalize the range
    if (start > end) {
      val t = start
      start = end
      end = t
    }

    // If we are a linewise motion we need to normalize the start and stop then move the start to the beginning
    // of the line and move the end to the end of the line.
    if (argument.isLinewiseMotion()) {
      start = editor.getLineStartForOffset(start)
      end = if (caret.getBufferPosition().line != editor.lineCount() - 1) {
        min((editor.getLineEndForOffset(end) + 1).toLong(), editor.fileSize()).toInt()
      } else {
        editor.getLineEndForOffset(end)
      }
    }

    // This is a kludge for dw, dW, and d[w. Without this kludge, an extra newline is operated when it shouldn't be.
    val text = editor.text().subSequence(start, end).toString()
    val lastNewLine = text.lastIndexOf('\n')
    if (lastNewLine > 0) {
      val id = action.id
      if (id == "VimMotionWordRightAction" || id == "VimMotionBigWordRightAction" || id == "VimMotionCamelRightAction") {
        if (!editor.anyNonWhitespace(end, -1)) {
          end = start + lastNewLine
        }
      }
    }

    return TextRange(start, end)
  }