update method

  1. @override
(ViewportModel, Cmd?) update(
  1. Msg msg
)
override

Updates the component state in response to a message.

Returns the updated component (often this) and an optional command.

Implementation

@override
(ViewportModel, Cmd?) update(Msg msg) {
  switch (msg) {
    case KeyMsg(:final key):
      if (key.matchesSingle(keyMap.pageDown)) {
        return (pageDown(), null);
      }
      if (key.matchesSingle(keyMap.pageUp)) {
        return (pageUp(), null);
      }
      if (key.matchesSingle(keyMap.halfPageDown)) {
        return (halfPageDown(), null);
      }
      if (key.matchesSingle(keyMap.halfPageUp)) {
        return (halfPageUp(), null);
      }
      if (key.matchesSingle(keyMap.down)) {
        return (scrollDown(1), null);
      }
      if (key.matchesSingle(keyMap.up)) {
        return (scrollUp(1), null);
      }
      if (horizontalStep > 0) {
        if (!softWrap && key.matchesSingle(keyMap.left)) {
          return (scrollLeft(horizontalStep), null);
        }
        if (!softWrap && key.matchesSingle(keyMap.right)) {
          return (scrollRight(horizontalStep), null);
        }
      }
      if (key.matchesSingle(keyMap.copy)) {
        final text = getSelectedText();
        if (text.isNotEmpty) {
          return (this, Cmd.setClipboard(text));
        }
      }
      return (this, null);

    case MouseMsg(
      :final button,
      :final action,
      :final x,
      :final y,
      :final shift,
    ):
      if (button == MouseButton.left) {
        final isOutside =
            y < 0 || (height != null ? y >= height! : y >= lines.length);
        if (isOutside) {
          if (action == MouseAction.press) {
            return (clearSelection(), null);
          }
          return (this, null);
        }

        if (action == MouseAction.press) {
          final contentX = x - gutter + xOffset;
          final contentY = y + yOffset;
          final now = DateTime.now();

          // Check for double click
          if (lastClickTime != null &&
              now.difference(lastClickTime!) <
                  const Duration(milliseconds: 500) &&
              lastClickPos == (contentX, contentY)) {
            final (start, end) = _findWordAt(contentX, contentY);
            return (
              copyWith(
                selectionStart: (start, contentY),
                selectionEnd: (end, contentY),
                lastClickTime: now,
                lastClickPos: (contentX, contentY),
              ),
              null,
            );
          }

          // Start selection
          return (
            copyWith(
              selectionStart: (contentX, contentY),
              selectionEnd: (contentX, contentY),
              lastClickTime: now,
              lastClickPos: (contentX, contentY),
            ),
            null,
          );
        }

        if (action == MouseAction.motion && selectionStart != null) {
          // Update selection
          final contentX = x - gutter + xOffset;
          final contentY = y + yOffset;
          return (copyWith(selectionEnd: (contentX, contentY)), null);
        }

        if (action == MouseAction.release && button == MouseButton.left) {
          // Finalize selection (keep it for copying)
          return (this, null);
        }
      }

      if (!mouseWheelEnabled ||
          (action != MouseAction.press && action != MouseAction.wheel)) {
        return (this, null);
      }

      switch (button) {
        case MouseButton.wheelUp:
          if (!softWrap && shift && horizontalStep > 0) {
            return (scrollLeft(horizontalStep), null);
          }
          return (scrollUp(mouseWheelDelta), null);

        case MouseButton.wheelDown:
          if (!softWrap && shift && horizontalStep > 0) {
            return (scrollRight(horizontalStep), null);
          }
          return (scrollDown(mouseWheelDelta), null);

        case MouseButton.wheelLeft:
          if (!softWrap && horizontalStep > 0) {
            return (scrollLeft(horizontalStep), null);
          }
          return (this, null);

        case MouseButton.wheelRight:
          if (!softWrap && horizontalStep > 0) {
            return (scrollRight(horizontalStep), null);
          }
          return (this, null);

        default:
          return (this, null);
      }

    default:
      return (this, null);
  }
}