insertNewlineAndIndent function

bool insertNewlineAndIndent(
  1. StateCommandTarget target
)

Replace the selection with a newline and compute smart indentation.

If the current line consists only of whitespace, this will also delete that whitespace. When the cursor is between matching brackets, an additional newline will be inserted after the cursor.

Implementation

bool insertNewlineAndIndent(StateCommandTarget target) {
  print('insertNewlineAndIndent called! pos=${target.state.selection.main.head}');
  if (target.state.isReadOnly) return false;

  final state = target.state;

  final result = state.changeByRange((range) {
    var from = range.from;
    var to = range.to;
    final line = state.doc.lineAt(from);

    // Check if cursor is between brackets like { | } or ( | )
    final explode = from == to ? _isBetweenBrackets(state, from) : null;

    // Create indent context with simulated break
    final cx = IndentContext(
      state,
      options: IndentContextOptions(
        simulateBreak: from,
        simulateDoubleBreak: explode != null,
      ),
    );

    // Get smart indentation
    var indent = getIndentation(cx, from);
    if (indent == null) {
      // Fall back to current line's indentation
      final lineIndentMatch = RegExp(r'^\s*').firstMatch(line.text);
      indent = countColumn(lineIndentMatch?.group(0) ?? '', state.tabSize);
    }

    // Delete trailing whitespace on current line (with bounds check)
    while (to < line.to && (to - line.from) < line.text.length) {
      final char = line.text[to - line.from];
      if (char != ' ' && char != '\t') break;
      to++;
    }

    // If cursor is in explosion zone, use that range
    if (explode != null) {
      from = explode.from;
      to = explode.to;
    } else if (from > line.from && from < line.from + 100 && (from - line.from) <= line.text.length) {
      // Delete leading whitespace on whitespace-only lines
      final beforeCursor = line.text.substring(0, from - line.from);
      if (!RegExp(r'\S').hasMatch(beforeCursor)) {
        from = line.from;
      }
    }

    // Build the insert text
    final indentStr = indentString(state, indent);
    String insertText;
    int cursorPos;

    if (explode != null) {
      // Between brackets: add two newlines with proper indentation
      int outerIndentCol;
      try {
        final cx = IndentContext(state);
        outerIndentCol = cx.lineIndent(line.from, -1);
      } catch (_) {
        outerIndentCol = 0;
      }
      final outerIndent = indentString(state, outerIndentCol);
      insertText = '${state.lineBreak}$indentStr${state.lineBreak}$outerIndent';
      cursorPos = from + 1 + indentStr.length;
    } else {
      insertText = '${state.lineBreak}$indentStr';
      cursorPos = from + 1 + indentStr.length;
    }

    return ChangeByRangeResult(
      changes: [ChangeSpec(from: from, to: to, insert: insertText)],
      range: EditorSelection.cursor(cursorPos),
    );
  });

  target.dispatch(state.update([
    TransactionSpec(
      changes: result.changes,
      selection: result.selection,
      scrollIntoView: true,
      userEvent: 'input',
    ),
  ]));
  return true;
}