list button implementation
This commit is contained in:
parent
8c0c478847
commit
3c274adee7
|
@ -1,16 +1,25 @@
|
|||
import 'package:flutter/services.dart';
|
||||
|
||||
extension on String {
|
||||
int getBeginningOfPreviousLine(int startingIndex) {
|
||||
extension Utilities on String {
|
||||
int getBeginningOfTheLine(int startingIndex) {
|
||||
if (startingIndex <= 0) return 0;
|
||||
for (var i = startingIndex; i >= 0; i--) {
|
||||
if (this[i] == '\n') return i + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getEndOfTheLine(int from) {
|
||||
for (var i = from; i < length; i++) {
|
||||
if (this[i] == '\n') return i;
|
||||
}
|
||||
|
||||
return length - 1;
|
||||
}
|
||||
|
||||
// returns the line that ends at endingIndex
|
||||
String lineBefore(int endingIndex) {
|
||||
return substring(getBeginningOfPreviousLine(endingIndex), endingIndex + 1);
|
||||
return substring(getBeginningOfTheLine(endingIndex), endingIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
|
||||
/// utililty class for traversing through multiline text
|
||||
class TextLinesIterator extends Iterator {
|
||||
String text;
|
||||
int beg;
|
||||
int end;
|
||||
TextSelection? selection;
|
||||
|
||||
TextLinesIterator(this.text, {this.selection})
|
||||
: end = -1,
|
||||
beg = -1;
|
||||
|
||||
factory TextLinesIterator.fromController(TextEditingController controller) =>
|
||||
TextLinesIterator(controller.text, selection: controller.selection);
|
||||
|
||||
bool get isWithinSelection {
|
||||
final selection = this.selection;
|
||||
if (selection == null || beg == -1) {
|
||||
return false;
|
||||
} else {
|
||||
return (selection.end >= beg && beg >= selection.start) ||
|
||||
(selection.end >= end && end >= selection.start) ||
|
||||
(end >= selection.start && selection.start >= beg) ||
|
||||
(end >= selection.end && selection.end >= beg) ||
|
||||
(beg <= selection.start &&
|
||||
selection.start <= end &&
|
||||
beg <= selection.end &&
|
||||
selection.end <= end);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
String get current {
|
||||
return text.substring(beg, end);
|
||||
}
|
||||
|
||||
set current(String newVal) {
|
||||
final selected = isWithinSelection;
|
||||
text = text.replaceRange(beg, end, newVal);
|
||||
final wordLen = end - beg;
|
||||
final dif = newVal.length - wordLen;
|
||||
end += dif;
|
||||
|
||||
final selection = this.selection;
|
||||
if (selection == null) return;
|
||||
|
||||
if (selected || selection.baseOffset > end) {
|
||||
this.selection =
|
||||
selection.copyWith(extentOffset: selection.extentOffset + dif);
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
end = -1;
|
||||
beg = -1;
|
||||
}
|
||||
|
||||
@override
|
||||
bool moveNext() {
|
||||
if (end == text.length) {
|
||||
return false;
|
||||
}
|
||||
if (beg == -1) {
|
||||
end = 0;
|
||||
beg = 0;
|
||||
} else {
|
||||
end += 1;
|
||||
beg = end;
|
||||
}
|
||||
for (; end < text.length; end++) {
|
||||
if (text[end] == '\n') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
end = text.length;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// returns the lines as a list but also moves the pointer to the back
|
||||
List<String> get asList {
|
||||
reset();
|
||||
final list = <String>[];
|
||||
while (moveNext()) {
|
||||
list.add(current);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
|
||||
import '../../formatter.dart';
|
||||
import '../../util/extensions/spaced.dart';
|
||||
import '../../util/text_lines_iterator.dart';
|
||||
|
||||
class Reformat {
|
||||
final String text;
|
||||
|
@ -43,6 +45,54 @@ extension on TextEditingController {
|
|||
));
|
||||
}
|
||||
|
||||
String get firstSelectedLine {
|
||||
if (text.isEmpty) return '';
|
||||
return text.substring(text.getBeginningOfTheLine(selection.start - 1),
|
||||
text.getEndOfTheLine(selection.end));
|
||||
}
|
||||
|
||||
void removeAtBeginningOfEverySelectedLine(String s) {
|
||||
final lines = TextLinesIterator.fromController(this);
|
||||
var linesCount = 0;
|
||||
while (lines.moveNext()) {
|
||||
if (lines.isWithinSelection) {
|
||||
if (lines.current.startsWith(RegExp.escape(s))) {
|
||||
lines.current = lines.current.substring(s.length);
|
||||
linesCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value = value.copyWith(
|
||||
text: lines.text,
|
||||
selection: selection.copyWith(
|
||||
baseOffset: selection.baseOffset - s.length,
|
||||
extentOffset: selection.extentOffset - s.length * linesCount,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void insertAtBeginningOfEverySelectedLine(String s) {
|
||||
final lines = TextLinesIterator.fromController(this);
|
||||
var linesCount = 0;
|
||||
while (lines.moveNext()) {
|
||||
if (lines.isWithinSelection) {
|
||||
if (!lines.current.startsWith(RegExp.escape(s))) {
|
||||
lines.current = '$s${lines.current}';
|
||||
linesCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value = value.copyWith(
|
||||
text: lines.text,
|
||||
selection: selection.copyWith(
|
||||
baseOffset: selection.baseOffset + s.length,
|
||||
extentOffset: selection.extentOffset + s.length * linesCount,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void reformat(Reformat Function(String selection) reformatter) {
|
||||
final beg = beforeSelectionText;
|
||||
final mid = selectionText;
|
||||
|
@ -101,9 +151,7 @@ class Toolbar extends HookWidget {
|
|||
icon: const Icon(Icons.person),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
//
|
||||
},
|
||||
onPressed: () {},
|
||||
icon: const Icon(Icons.home),
|
||||
),
|
||||
IconButton(
|
||||
|
@ -119,7 +167,17 @@ class Toolbar extends HookWidget {
|
|||
icon: const Icon(Icons.format_quote),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
final line = controller.firstSelectedLine;
|
||||
|
||||
if (line.startsWith(RegExp.escape('* '))) {
|
||||
controller.removeAtBeginningOfEverySelectedLine('* ');
|
||||
} else if (line.startsWith('- ')) {
|
||||
controller.removeAtBeginningOfEverySelectedLine('- ');
|
||||
} else {
|
||||
controller.insertAtBeginningOfEverySelectedLine('- ');
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.format_list_bulleted)),
|
||||
IconButton(
|
||||
onPressed: () => controller.surround('`'),
|
||||
|
|
Loading…
Reference in New Issue