Skip to content

Commit

Permalink
code refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
ilya-kozyrev committed Apr 14, 2022
1 parent 7cee1ce commit a2b3915
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 7 deletions.
41 changes: 35 additions & 6 deletions lib/src/code_controller.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:math';

import 'package:code_text_field/src/autocomplete/popup_controller.dart';
import 'package:code_text_field/src/multiline_controller.dart';
import 'package:code_text_field/src/autocomplete/suggestion.dart';
import 'package:code_text_field/src/autocomplete/suggestion_generator.dart';
import 'package:code_text_field/src/code_modifier.dart';
Expand Down Expand Up @@ -54,6 +55,7 @@ class CodeController extends TextEditingController {
bool isPopupShown = false;
RegExp? styleRegExp;
late PopupController popupController;
late MultilineController? multilineController;
SuggestionGenerator? suggestionGenerator;

CodeController({
Expand Down Expand Up @@ -82,6 +84,7 @@ class CodeController extends TextEditingController {
modifiers.forEach((el) {
modifierMap[el.char] = el;
});
this.multilineController = MultilineController();
suggestionGenerator = SuggestionGenerator(
'language_id'); // TODO: replace string with some generated value for current language id
this.popupController = PopupController(onCompletionSelected: this.insertSelectedWord);
Expand Down Expand Up @@ -127,7 +130,26 @@ class CodeController extends TextEditingController {
removeChar();
}

void handleTap(bool isMulti) {
if (isMulti) {
this.multilineController!.isMutli = true;
this.multilineController!.isCaret = true;
value = this.multilineController!.insertCaret(value);
} else {
multilineController!.updateCurrentSelection(
multilineController!.currentSelection, value.selection.start);
value = multilineController!.clearCarets(value);
}
}

KeyEventResult onKey(RawKeyEvent event) {
if (event.isKeyPressed(LogicalKeyboardKey.arrowDown) ||
event.isKeyPressed(LogicalKeyboardKey.arrowUp) ||
event.isKeyPressed(LogicalKeyboardKey.arrowRight) ||
event.isKeyPressed(LogicalKeyboardKey.arrowLeft)) {
value = this.multilineController!.clearCarets(value);
}

if (event.isKeyPressed(LogicalKeyboardKey.tab)) {
text = text.replaceRange(selection.start, selection.end, "\t");
return KeyEventResult.handled;
Expand Down Expand Up @@ -155,11 +177,13 @@ class CodeController extends TextEditingController {
String selectedWord = popupController.getSelectedWord();
int startPosition = selection.baseOffset -
suggestionGenerator!.getCurrentWordPrefix().length;
text = text.replaceRange(startPosition, selection.baseOffset, selectedWord);
selection = previousSelection.copyWith(
baseOffset: startPosition + selectedWord.length,
extentOffset: startPosition + selectedWord.length,
);
value = value.copyWith(
text: text.replaceRange(
startPosition, selection.baseOffset, selectedWord),
selection: previousSelection.copyWith(
baseOffset: startPosition + selectedWord.length,
extentOffset: startPosition + selectedWord.length,
));
popupController.hide();
}

Expand Down Expand Up @@ -201,7 +225,7 @@ class CodeController extends TextEditingController {
@override
set value(TextEditingValue newValue) {
final loc = _insertedLoc(text, newValue.text);
if (loc != null) {
if (loc != null && !multilineController!.isMutli) {
final char = newValue.text[loc];
final modifier = modifierMap[char];
final val = modifier?.updateString(rawText, selection, params);
Expand All @@ -215,9 +239,14 @@ class CodeController extends TextEditingController {
}
}

multilineController!.updateCurrentSelection(
newValue.selection.start, value.selection.start);

bool hasTextChanged = newValue.text != super.value.text;
bool hasSelectionChanged = (newValue.selection != super.value.selection);

newValue = multilineController!.updateMultiline(value, newValue);

//Because of this part of code ctrl + z dont't work. But maybe it's important, so please don't delete.
// Now fix the textfield for web
// if (_webSpaceFix)
Expand Down
7 changes: 6 additions & 1 deletion lib/src/code_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ class CodeFieldState extends State<CodeField> {
//
StreamSubscription<bool>? _keyboardVisibilitySubscription;
FocusNode? _focusNode;
bool isMultiline = false;
String? lines;
String longestLine = "";
late Size windowSize;
Expand Down Expand Up @@ -235,6 +236,8 @@ class CodeFieldState extends State<CodeField> {
}

KeyEventResult _onKey(FocusNode node, RawKeyEvent event) {
this.isMultiline =
event.isAltPressed && event.isControlPressed ? true : false;
return widget.controller.onKey(event);
}

Expand Down Expand Up @@ -396,7 +399,9 @@ class CodeFieldState extends State<CodeField> {
enabled: widget.enabled,
onChanged: widget.onChanged,
readOnly: widget.readOnly,
);
onTap: () {
widget.controller.handleTap(isMultiline);
});

final editingField = Theme(
data: Theme.of(context).copyWith(
Expand Down
135 changes: 135 additions & 0 deletions lib/src/multiline_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import 'package:flutter/material.dart';

class MultilineController {
List<int> carets = [];
late int currentSelection = 0;
bool isCaret = false;
bool isMutli = false;

MultilineController() : super();

TextEditingValue updateMultiline(
TextEditingValue value, TextEditingValue newValue) {
bool isDeleting = newValue.text.length < value.text.length;
bool isInserting = newValue.text.length > value.text.length;
if (this.isMutli) {
if (isDeleting || (isInserting && !isCaret)) {
int diff = newValue.text.length - value.text.length;
String newText = newValue.text;
int start = newValue.selection.start - diff;

String insertedValue =
diff > 0 ? newText.substring(start, start + diff) : "";

for (int i = 0; i < carets.length; i++) {
if (carets[i] >= currentSelection) {
carets[i] += diff;
}
}

carets.sort();

for (int i = 0; i < carets.length; i++) {
newText = newText.replaceRange(
carets[i] - (diff > 0 ? 0 : 1), carets[i], insertedValue);

carets[i] += diff;

if (isDeleting) {
bool isThisCaretCollide = carets.any((caret) =>
(carets[i] == caret && i != carets.indexOf(caret))) ||
carets[i] == newValue.selection.start ||
carets[i] == newValue.selection.start - 1;

if (isThisCaretCollide) {
newText = newText.replaceRange(carets[i] - 2, carets[i] - 1, "");
carets[i] = -1;
}
}

if (i + 1 != carets.length) {
carets[i + 1] += diff * (i + 1);
}
}

carets = carets.where((i) => i != -1).toList();

int newOffSet =
carets.where((pos) => pos <= currentSelection).length * diff;

newValue = newValue.copyWith(
selection: newValue.selection.copyWith(
baseOffset: newValue.selection.start + newOffSet,
extentOffset: newValue.selection.start + newOffSet),
text: newText.toString());
}
this.isCaret = false;
}
return newValue;
}

TextEditingValue clearCarets(TextEditingValue value) {
if (carets.isEmpty) {
return value;
}

this.isMutli = false;
String clearedText = value.text;
carets.sort();

for (int i = 0; i < carets.length; i++) {
clearedText = clearedText.replaceRange(carets[i], carets[i] + 1, "");
if (i + 1 != carets.length) {
carets[i + 1] -= i + 1;
}
}

value = value.copyWith(
text: clearedText,
selection: value.selection.copyWith(
baseOffset: value.selection.start - carets.length,
extentOffset: value.selection.start - carets.length));
carets.clear();

return value;
}

TextEditingValue insertCaret(TextEditingValue value) {
final sel = value.selection;
if (this.carets.contains(sel.start) ||
this.carets.contains(sel.start - 1) ||
value.selection.start == currentSelection) {
return value;
}

if (value.text.length == 0) {
currentSelection = 0;
}

int isAbove = currentSelection < value.selection.start ? 1 : 0;

for (int i = 0; i < carets.length; i++) {
if (carets[i] >= currentSelection) {
carets[i] += 1;
}
}

carets.add(currentSelection);

value = value.copyWith(
text: value.text.replaceRange(currentSelection, currentSelection, "|"),
selection: sel.copyWith(
baseOffset: sel.start + isAbove,
extentOffset: sel.start + isAbove,
));
currentSelection = value.selection.start;

return value;
}

void updateCurrentSelection(int newSelection, int selection) {
if (newSelection != selection || currentSelection == -1) {
currentSelection = selection;
}
}
}

0 comments on commit a2b3915

Please sign in to comment.