akvelon / flutter-code-editor

Flutter Code Editor is a multi-platform code editor supporting syntax highlighting, code blocks folding, autocompletion, read-only code blocks, hiding specific code blocks, themes, and more.
https://akvelon.com
Apache License 2.0
213 stars 54 forks source link

Automatically insert pair character for brackets, square braces, angle brackets, parentheses, quotes #192

Open alexeyinkin opened 1 year ago

ivanmem commented 5 months ago

Pull request 231 works great! But they lack automatic removal of these same pairs of characters. @Malarg Any ideas on how to implement this?

ivanmem commented 5 months ago

I wrote an example of how it would also erase characters, but CodeModifier.updateString will need to be modified (added String newText)

  @override
  TextEditingValue? updateString(
    String text,
    String newText,
    TextSelection sel,
    EditorParams params,
  ) {
    if (newText.length > text.length) {
      final replaced =
          replace(text, sel.start, sel.end, '$openChar$closeString');
      return replaced.copyWith(
        selection: TextSelection(
          baseOffset: replaced.selection.baseOffset - closeString.length,
          extentOffset: replaced.selection.extentOffset - closeString.length,
        ),
      );
    }
    if (text.length - 1 == newText.length && text.length > sel.start) {
      final char = text[sel.start - 1];
      final nextChar = text[sel.start];
      if (char == openChar && nextChar == closeString) {
        final replaced = replace(text, sel.start - 1, sel.start + 1, '');
        return replaced;
      }
    }
    return null;
  }
abstract class CodeModifier {
  final String char;
  final bool insert;
  final bool remove;

  const CodeModifier(
    this.char, {
    this.insert = true,
    this.remove = false,
  });

  // Helper to insert [str] in [text] between [start] and [end]
  TextEditingValue replace(String text, int start, int end, String str) {
    final len = str.length;
    return TextEditingValue(
      text: text.replaceRange(start, end, str),
      selection: TextSelection(
        baseOffset: start + len,
        extentOffset: start + len,
      ),
    );
  }

  TextEditingValue? updateString(
    String text,
    String newText,
    TextSelection sel,
    EditorParams params,
  );
}

And change the code a little in code_controller.dart:

  int? _removedLoc(String a, String b) {
    final sel = selection;

    if (a.length - 1 != b.length || sel.start != sel.end || sel.start == -1) {
      return null;
    }

    return sel.start - 1;
  }

  void updateLoc(CodeModifier modifier) {
    final val = modifier.updateString(
      text,
      newValue.text,
      selection,
      params,
    );
    if (val != null) {
      // Update newValue
      newValue = newValue.copyWith(
        text: val.text,
        selection: val.selection,
      );
    }
  }

  final loc = _insertedLoc(text, newValue.text);
  if (loc != null) {
    final char = newValue.text[loc];
    final modifier = _modifierMap[char];
    if (modifier != null && modifier.insert) {
      updateLoc(modifier);
    }
  } else {
    final removedLoc = _removedLoc(text, newValue.text);
    if (removedLoc != null) {
      final char = text[removedLoc];
      final modifier = _modifierMap[char];
      if (modifier != null && modifier.remove) {
        updateLoc(modifier);
      }
    }
  }