syncImeBufferToFragment method

void syncImeBufferToFragment()

Implementation

void syncImeBufferToFragment() {
  if (connectionManager.connection == null ||
      !connectionManager.connection!.attached) {
    return;
  }
  if (state.isComposing) return;
  final doc = _document;
  if (doc == null) return;
  final currentFragId = doc.cursor.focusId.isNotEmpty
      ? doc.cursor.focusId
      : doc.cursor.anchorId;

  if (currentFragId != state.lastSyncedFragmentId) {
    _resetPlatformBuffer();
  }
  state.lastSyncedFragmentId = currentFragId;

  if (!_shouldSyncBuffer) {
    return;
  }

  final text = _getCurrentFragmentText();
  if (text == null) {
    _resetPlatformBuffer();
    return;
  }
  final cursor = doc.cursor;
  final isSingleFragSelection =
      !cursor.isCollapsed && cursor.anchorId == cursor.focusId;
  final isMultiFragSelection =
      !cursor.isCollapsed && cursor.anchorId != cursor.focusId;
  final offset = _getCursorOffsetInFragment();
  final bool usePlaceholder =
      defaultTargetPlatform == TargetPlatform.iOS &&
      cursor.isCollapsed &&
      offset == 0 &&
      !text.startsWith(_emptyFragmentPlaceholder);
  final syncedText = usePlaceholder
      ? '$_emptyFragmentPlaceholder$text'
      : text;
  final syncedOffset = usePlaceholder
      ? 1
      : offset.clamp(0, syncedText.length);
  final TextSelection syncedSelection;
  if (isSingleFragSelection && !usePlaceholder) {
    syncedSelection = TextSelection(
      baseOffset: cursor.anchorOffset.clamp(0, syncedText.length),
      extentOffset: cursor.focusOffset.clamp(0, syncedText.length),
    );
  } else if (isMultiFragSelection && !usePlaceholder) {
    syncedSelection = TextSelection(
      baseOffset: 0,
      extentOffset: syncedText.length,
    );
  } else {
    syncedSelection = TextSelection.collapsed(offset: syncedOffset);
  }

  final selectionChanged =
      state.prevSelectionKey !=
      '${syncedSelection.baseOffset}:${syncedSelection.extentOffset}';
  state.prevSelectionKey =
      '${syncedSelection.baseOffset}:${syncedSelection.extentOffset}';

  final wasUpdatingSelf = state.updatingSelf;
  state.updatingSelf = true;
  try {
    if (kIsWeb && syncedText.length < state.lastSyncedText.length) {
      connectionManager.connection!.setEditingState(const TextEditingValue());
    }
    if (defaultTargetPlatform == TargetPlatform.iOS && selectionChanged) {
      connectionManager.connection!.setEditingState(const TextEditingValue());
    }
    if (!kIsWeb && defaultTargetPlatform == TargetPlatform.macOS) {
      // On macOS, we need to set the editing state to an empty value to clear the composition
      final newValue = TextEditingValue(
        text: syncedText,
        selection: syncedSelection,
        composing: state.isComposing && state.composingRange.isValid
            ? state.composingRange
            : TextRange.empty,
      );
      final isDifferent =
          _currentPlatformValue.text != newValue.text ||
          _currentPlatformValue.composing != newValue.composing;

      if (isDifferent) {
        _currentPlatformValue = newValue; // Update cache!
        connectionManager.connection!.setEditingState(newValue);
      }
    } else {
      connectionManager.connection!.setEditingState(
        TextEditingValue(
          text: syncedText,
          selection: syncedSelection,
          composing: TextRange.empty,
        ),
      );
      state.lastSyncedText = syncedText;
    }
  } finally {
    state.updatingSelf = wasUpdatingSelf;
  }
}