diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6b6bcc8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,53 @@ +{ + "workbench.editor.scrollToSwitchTabs": true, + "workbench.editor.limit.enabled": true, + "dart.closingLabels": false, + // copied from: https://dartcode.org/docs/recommended-settings/ + // Causes the debug view to automatically appear when a breakpoint is hit. This + // setting is global and not configurable per-language. + "debug.openDebug": "openOnDebugBreak", + "[yaml]": { + "editor.formatOnSave": true + }, + "[dart]": { + // "editor.formatOnType": true, + // Disables built-in highlighting of words that match your selection. Without + // this, all instances of the selected text will be highlighted, interfering + // with Dart's ability to highlight only exact references to the selected variable. + "editor.selectionHighlight": false, + // By default, VS Code prevents code completion from popping open when in + // "snippet mode" (editing placeholders in inserted code). Setting this option + // to `false` stops that and allows completion to open as normal, as if you + // weren't in a snippet placeholder. + "editor.suggest.snippetsPreventQuickSuggestions": false, + // By default, VS Code will pre-select the most recently used item from code + // completion. This is usually not the most relevant item. + // + // "first" will always select top item + // "recentlyUsedByPrefix" will filter the recently used items based on the + // text immediately preceeding where completion was invoked. + "editor.suggestSelection": "first", + // Allows pressing to complete snippets such as `for` even when the + // completion list is not visible. + "editor.tabCompletion": "onlySnippets", + // By default, VS Code will populate code completion with words found in the + // current file when a language service does not provide its own completions. + // This results in code completion suggesting words when editing comments and + // strings. This setting will prevent that. + "editor.wordBasedSuggestions": "off" + }, + "editor.bracketPairColorization.enabled": true, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit", + "source.organizeImports": "explicit", + "quickfix.insertSemicolon": "explicit", + "source.fixAll.eslint": "explicit" + }, + "editor.formatOnSave": true, + "prettier.singleQuote": true, + "prettier.trailingComma": "all", + "dart.runPubGetOnPubspecChanges": "never", + "xmlTools.splitXmlnsOnFormat": false, + "xmlTools.splitAttributesOnFormat": true, + "arb-editor.suppressedWarnings": "all" +} diff --git a/analysis_options.yaml b/analysis_options.yaml index a5744c1..01cd42c 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,4 +1,3 @@ -include: package:flutter_lints/flutter.yaml - +include: package:dfc_lints/rules.yaml # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options diff --git a/example/assets/code.dart b/example/assets/code.dart index 0828525..85ae7da 100644 --- a/example/assets/code.dart +++ b/example/assets/code.dart @@ -1,16 +1,14 @@ import 'package:flutter/foundation.dart'; class ReEditor { + ReEditor(this.foo, this.bar); final String foo; final String bar; - ReEditor(this.foo, this.bar); - void hello(String name) { if (kDebugMode) { print('hello $name'); } } - -} \ No newline at end of file +} diff --git a/example/lib/editor_autocomplete.dart b/example/lib/editor_autocomplete.dart index 7d514d8..c7fe66f 100644 --- a/example/lib/editor_autocomplete.dart +++ b/example/lib/editor_autocomplete.dart @@ -9,90 +9,41 @@ import 'package:re_highlight/languages/dart.dart'; import 'package:re_highlight/styles/atom-one-light.dart'; const List _kStringPrompts = [ - CodeFieldPrompt( - word: 'length', - type: 'int' - ), - CodeFieldPrompt( - word: 'isEmpty', - type: 'bool' - ), - CodeFieldPrompt( - word: 'isNotEmpty', - type: 'bool' - ), - CodeFieldPrompt( - word: 'characters', - type: 'Characters' - ), - CodeFieldPrompt( - word: 'hashCode', - type: 'int' - ), - CodeFieldPrompt( - word: 'codeUnits', - type: 'List' - ), - CodeFieldPrompt( - word: 'runes', - type: 'Runes' - ), + CodeFieldPrompt(word: 'length', type: 'int'), + CodeFieldPrompt(word: 'isEmpty', type: 'bool'), + CodeFieldPrompt(word: 'isNotEmpty', type: 'bool'), + CodeFieldPrompt(word: 'characters', type: 'Characters'), + CodeFieldPrompt(word: 'hashCode', type: 'int'), + CodeFieldPrompt(word: 'codeUnits', type: 'List'), + CodeFieldPrompt(word: 'runes', type: 'Runes'), CodeFunctionPrompt( - word: 'codeUnitAt', - type: 'int', - parameters: { - 'index': 'int' - } - ), - CodeFunctionPrompt( - word: 'replaceAll', - type: 'String', - parameters: { - 'from': 'Pattern', - 'replace': 'String', - } - ), - CodeFunctionPrompt( - word: 'contains', - type: 'bool', - parameters: { - 'other': 'String', - } - ), - CodeFunctionPrompt( - word: 'split', - type: 'List', - parameters: { - 'pattern': 'Pattern', - } - ), - CodeFunctionPrompt( - word: 'endsWith', - type: 'bool', - parameters: { - 'other': 'String', - } - ), - CodeFunctionPrompt( - word: 'startsWith', - type: 'bool', - parameters: { - 'other': 'String', - } - ) + word: 'codeUnitAt', type: 'int', parameters: {'index': 'int'}), + CodeFunctionPrompt(word: 'replaceAll', type: 'String', parameters: { + 'from': 'Pattern', + 'replace': 'String', + }), + CodeFunctionPrompt(word: 'contains', type: 'bool', parameters: { + 'other': 'String', + }), + CodeFunctionPrompt(word: 'split', type: 'List', parameters: { + 'pattern': 'Pattern', + }), + CodeFunctionPrompt(word: 'endsWith', type: 'bool', parameters: { + 'other': 'String', + }), + CodeFunctionPrompt(word: 'startsWith', type: 'bool', parameters: { + 'other': 'String', + }) ]; class AutoCompleteEditor extends StatefulWidget { - const AutoCompleteEditor({super.key}); @override State createState() => _AutoCompleteEditorState(); - } class _AutoCompleteEditorState extends State { - final CodeLineEditingController _controller = CodeLineEditingController(); @override @@ -106,103 +57,81 @@ class _AutoCompleteEditorState extends State { @override Widget build(BuildContext context) { return CodeAutocomplete( - viewBuilder: (context, notifier, onSelected) { - return _DefaultCodeAutocompleteListView( - notifier: notifier, - onSelected: onSelected, - ); - }, - promptsBuilder: DefaultCodeAutocompletePromptsBuilder( - language: langDart, - directPrompts: const [ - CodeFieldPrompt( - word: 'foo', - type: 'String' - ), - CodeFieldPrompt( - word: 'bar', - type: 'String' - ), - CodeFunctionPrompt( - word: 'hello', - type: 'void', - parameters: { - 'value': 'String', - } - ) - ], - relatedPrompts: { - 'foo': _kStringPrompts, - 'bar': _kStringPrompts, - }, - ), - child: CodeEditor( - style: CodeEditorStyle( - fontSize: 18, - codeTheme: CodeHighlightTheme( - languages: { - 'dart': CodeHighlightThemeMode( - mode: langDart - ) - }, - theme: atomOneLightTheme - ), - ), - controller: _controller, - wordWrap: false, - indicatorBuilder: (context, editingController, chunkController, notifier) { - return Row( - children: [ - DefaultCodeLineNumber( - controller: editingController, - notifier: notifier, - ), - DefaultCodeChunkIndicator( - width: 20, - controller: chunkController, - notifier: notifier - ) - ], + viewBuilder: (context, notifier, onSelected) { + return _DefaultCodeAutocompleteListView( + notifier: notifier, + onSelected: onSelected, ); }, - findBuilder: (context, controller, readOnly) => CodeFindPanelView(controller: controller, readOnly: readOnly), - toolbarController: const ContextMenuControllerImpl(), - sperator: Container( - width: 1, - color: Colors.blue + promptsBuilder: DefaultCodeAutocompletePromptsBuilder( + language: langDart, + directPrompts: const [ + CodeFieldPrompt(word: 'foo', type: 'String'), + CodeFieldPrompt(word: 'bar', type: 'String'), + CodeFunctionPrompt(word: 'hello', type: 'void', parameters: { + 'value': 'String', + }) + ], + relatedPrompts: { + 'foo': _kStringPrompts, + 'bar': _kStringPrompts, + }, ), - ) - ); + child: CodeEditor( + style: CodeEditorStyle( + fontSize: 18, + codeTheme: CodeHighlightTheme( + languages: {'dart': CodeHighlightThemeMode(mode: langDart)}, + theme: atomOneLightTheme), + ), + controller: _controller, + wordWrap: false, + indicatorBuilder: + (context, editingController, chunkController, notifier) { + return Row( + children: [ + DefaultCodeLineNumber( + controller: editingController, + notifier: notifier, + ), + DefaultCodeChunkIndicator( + width: 20, controller: chunkController, notifier: notifier) + ], + ); + }, + findBuilder: (context, controller, readOnly) => + CodeFindPanelView(controller: controller, readOnly: readOnly), + toolbarController: const ContextMenuControllerImpl(), + sperator: Container(width: 1, color: Colors.blue), + )); } - } -class _DefaultCodeAutocompleteListView extends StatefulWidget implements PreferredSizeWidget { +class _DefaultCodeAutocompleteListView extends StatefulWidget + implements PreferredSizeWidget { + const _DefaultCodeAutocompleteListView({ + required this.notifier, + required this.onSelected, + }); static const double kItemHeight = 26; final ValueNotifier notifier; final ValueChanged onSelected; - const _DefaultCodeAutocompleteListView({ - required this.notifier, - required this.onSelected, - }); - @override Size get preferredSize => Size( - 250, - // 2 is border size - min(kItemHeight * notifier.value.prompts.length, 150) + 2 - ); + 250, + // 2 is border size + min(kItemHeight * notifier.value.prompts.length, 150) + 2); @override - State createState() => _DefaultCodeAutocompleteListViewState(); - + State createState() => + _DefaultCodeAutocompleteListViewState(); } -class _DefaultCodeAutocompleteListViewState extends State<_DefaultCodeAutocompleteListView> { - +class _DefaultCodeAutocompleteListViewState + extends State<_DefaultCodeAutocompleteListView> { @override void initState() { widget.notifier.addListener(_onValueChanged); @@ -218,64 +147,59 @@ class _DefaultCodeAutocompleteListViewState extends State<_DefaultCodeAutocomple @override Widget build(BuildContext context) { return Container( - constraints: BoxConstraints.loose(widget.preferredSize), - decoration: BoxDecoration( - color: Colors.grey, - borderRadius: BorderRadius.circular(6) - ), - child: AutoScrollListView( - controller: ScrollController(), - initialIndex: widget.notifier.value.index, - scrollDirection: Axis.vertical, - itemCount: widget.notifier.value.prompts.length, - itemBuilder:(context, index) { - final CodePrompt prompt = widget.notifier.value.prompts[index]; - final BorderRadius radius = BorderRadius.only( - topLeft: index == 0 ? const Radius.circular(5) : Radius.zero, - topRight: index == 0 ? const Radius.circular(5) : Radius.zero, - bottomLeft: index == widget.notifier.value.prompts.length - 1 ? const Radius.circular(5) : Radius.zero, - bottomRight: index == widget.notifier.value.prompts.length - 1 ? const Radius.circular(5) : Radius.zero, - ); - return InkWell( - borderRadius: radius, - onTap: () { - widget.onSelected(widget.notifier.value.copyWith( - index: index - ).autocomplete); - }, - child: Container( - width: double.infinity, - height: _DefaultCodeAutocompleteListView.kItemHeight, - padding: const EdgeInsets.only( - left: 5, - right: 5 - ), - alignment: Alignment.centerLeft, - decoration: BoxDecoration( - color: index == widget.notifier.value.index ? const Color.fromARGB(255, 255, 140, 0) : null, - borderRadius: radius - ), - child: RichText( - text: prompt.createSpan(context, widget.notifier.value.input), - overflow: TextOverflow.ellipsis, - maxLines: 1, - ), - ) - ); - }, - ) - ); + constraints: BoxConstraints.loose(widget.preferredSize), + decoration: BoxDecoration( + color: Colors.grey, borderRadius: BorderRadius.circular(6)), + child: AutoScrollListView( + controller: ScrollController(), + initialIndex: widget.notifier.value.index, + itemCount: widget.notifier.value.prompts.length, + itemBuilder: (context, index) { + final CodePrompt prompt = widget.notifier.value.prompts[index]; + final BorderRadius radius = BorderRadius.only( + topLeft: index == 0 ? const Radius.circular(5) : Radius.zero, + topRight: index == 0 ? const Radius.circular(5) : Radius.zero, + bottomLeft: index == widget.notifier.value.prompts.length - 1 + ? const Radius.circular(5) + : Radius.zero, + bottomRight: index == widget.notifier.value.prompts.length - 1 + ? const Radius.circular(5) + : Radius.zero, + ); + return InkWell( + borderRadius: radius, + onTap: () { + widget.onSelected(widget.notifier.value + .copyWith(index: index) + .autocomplete); + }, + child: Container( + width: double.infinity, + height: _DefaultCodeAutocompleteListView.kItemHeight, + padding: const EdgeInsets.only(left: 5, right: 5), + alignment: Alignment.centerLeft, + decoration: BoxDecoration( + color: index == widget.notifier.value.index + ? const Color.fromARGB(255, 255, 140, 0) + : null, + borderRadius: radius), + child: RichText( + text: + prompt.createSpan(context, widget.notifier.value.input), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + )); + }, + )); } void _onValueChanged() { - setState(() { - }); + setState(() {}); } - } extension _CodePromptExtension on CodePrompt { - InlineSpan createSpan(BuildContext context, String input) { const TextStyle style = TextStyle(); final InlineSpan span = style.createSpan( @@ -286,38 +210,25 @@ extension _CodePromptExtension on CodePrompt { ); final CodePrompt prompt = this; if (prompt is CodeFieldPrompt) { - return TextSpan( - children: [ - span, - TextSpan( - text: ' ${prompt.type}', - style: style.copyWith( - color: Colors.cyan - ) - ) - ] - ); + return TextSpan(children: [ + span, + TextSpan( + text: ' ${prompt.type}', style: style.copyWith(color: Colors.cyan)) + ]); } if (prompt is CodeFunctionPrompt) { - return TextSpan( - children: [ - span, - TextSpan( + return TextSpan(children: [ + span, + TextSpan( text: '(...) -> ${prompt.type}', - style: style.copyWith( - color: Colors.cyan - ) - ) - ] - ); + style: style.copyWith(color: Colors.cyan)) + ]); } return span; } - } extension _TextStyleExtension on TextStyle { - InlineSpan createSpan({ required String value, required String anchor, @@ -343,53 +254,40 @@ extension _TextStyleExtension on TextStyle { style: this, ); } - return TextSpan( - children: [ - TextSpan( - text: value.substring(0, index), - style: this - ), - TextSpan( + return TextSpan(children: [ + TextSpan(text: value.substring(0, index), style: this), + TextSpan( text: value.substring(index, index + anchor.length), style: copyWith( color: color, fontWeight: fontWeight, - ) - ), - TextSpan( - text: value.substring(index + anchor.length), - style: this - ) - ] - ); + )), + TextSpan(text: value.substring(index + anchor.length), style: this) + ]); } - } class AutoScrollListView extends StatefulWidget { - - final ScrollController controller; - final IndexedWidgetBuilder itemBuilder; - final int itemCount; - final int initialIndex; - final Axis scrollDirection; - const AutoScrollListView({ - super.key, required this.controller, required this.itemBuilder, required this.itemCount, + super.key, this.initialIndex = 0, this.scrollDirection = Axis.vertical, }); + final ScrollController controller; + final IndexedWidgetBuilder itemBuilder; + final int itemCount; + final int initialIndex; + final Axis scrollDirection; + @override State createState() => _AutoScrollListViewState(); - } class _AutoScrollListViewState extends State { - late final List _keys; @override @@ -404,7 +302,8 @@ class _AutoScrollListViewState extends State { @override void didUpdateWidget(covariant AutoScrollListView oldWidget) { if (widget.itemCount > oldWidget.itemCount) { - _keys.addAll(List.generate(widget.itemCount - oldWidget.itemCount, (index) => GlobalKey())); + _keys.addAll(List.generate( + widget.itemCount - oldWidget.itemCount, (index) => GlobalKey())); } else if (widget.itemCount < oldWidget.itemCount) { _keys.sublist(oldWidget.itemCount - widget.itemCount); } @@ -426,12 +325,14 @@ class _AutoScrollListViewState extends State { return SingleChildScrollView( controller: widget.controller, scrollDirection: widget.scrollDirection, - child: isHorizontal ? Row( - children: widgets, - ) : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: widgets, - ), + child: isHorizontal + ? Row( + children: widgets, + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: widgets, + ), ); } @@ -451,14 +352,14 @@ class _AutoScrollListViewState extends State { continue; } if (isHorizontal) { - double width = obj.size.width; + final double width = obj.size.width; if (i == widget.initialIndex) { cur = pre + width; break; } pre += width; } else { - double height = obj.size.height; + final double height = obj.size.height; if (i == widget.initialIndex) { cur = pre + height; break; @@ -471,11 +372,11 @@ class _AutoScrollListViewState extends State { } if (pre < widget.controller.offset) { controller.jumpTo(pre - 1); - } else if (cur > controller.offset + controller.position.viewportDimension) { + } else if (cur > + controller.offset + controller.position.viewportDimension) { controller.jumpTo(cur - controller.position.viewportDimension); } } bool get isHorizontal => widget.scrollDirection == Axis.horizontal; - -} \ No newline at end of file +} diff --git a/example/lib/editor_basic_field.dart b/example/lib/editor_basic_field.dart index 07a722f..153ee56 100644 --- a/example/lib/editor_basic_field.dart +++ b/example/lib/editor_basic_field.dart @@ -2,15 +2,14 @@ import 'package:flutter/material.dart'; import 'package:re_editor/re_editor.dart'; class BasicField extends StatelessWidget { - const BasicField({super.key}); @override Widget build(BuildContext context) { return CodeEditor( wordWrap: false, - controller: CodeLineEditingController.fromText(('${'Hello Reqable💐👏 ' * 10}\n') * 100), + controller: CodeLineEditingController.fromText( + '${'Hello Reqable💐👏 ' * 10}\n' * 100), ); } - -} \ No newline at end of file +} diff --git a/example/lib/editor_json.dart b/example/lib/editor_json.dart index 95d6064..b53f9a3 100644 --- a/example/lib/editor_json.dart +++ b/example/lib/editor_json.dart @@ -7,16 +7,13 @@ import 'package:re_highlight/languages/json.dart'; import 'package:re_highlight/styles/atom-one-light.dart'; class JsonEditor extends StatefulWidget { - const JsonEditor({super.key}); @override State createState() => _JsonEditorState(); - } class _JsonEditorState extends State { - final CodeLineEditingController _controller = CodeLineEditingController(); @override @@ -32,17 +29,13 @@ class _JsonEditorState extends State { return CodeEditor( style: CodeEditorStyle( codeTheme: CodeHighlightTheme( - languages: { - 'json': CodeHighlightThemeMode( - mode: langJson - ) - }, - theme: atomOneLightTheme - ), + languages: {'json': CodeHighlightThemeMode(mode: langJson)}, + theme: atomOneLightTheme), ), controller: _controller, wordWrap: false, - indicatorBuilder: (context, editingController, chunkController, notifier) { + indicatorBuilder: + (context, editingController, chunkController, notifier) { return Row( children: [ DefaultCodeLineNumber( @@ -50,20 +43,14 @@ class _JsonEditorState extends State { notifier: notifier, ), DefaultCodeChunkIndicator( - width: 20, - controller: chunkController, - notifier: notifier - ) + width: 20, controller: chunkController, notifier: notifier) ], ); }, - findBuilder: (context, controller, readOnly) => CodeFindPanelView(controller: controller, readOnly: readOnly), + findBuilder: (context, controller, readOnly) => + CodeFindPanelView(controller: controller, readOnly: readOnly), toolbarController: const ContextMenuControllerImpl(), - sperator: Container( - width: 1, - color: Colors.blue - ), + sperator: Container(width: 1, color: Colors.blue), ); } - -} \ No newline at end of file +} diff --git a/example/lib/editor_large_text.dart b/example/lib/editor_large_text.dart index 1019bb8..629caf8 100644 --- a/example/lib/editor_large_text.dart +++ b/example/lib/editor_large_text.dart @@ -5,16 +5,13 @@ import 'package:re_editor_exmaple/find.dart'; import 'package:re_editor_exmaple/menu.dart'; class LargeTextEditor extends StatefulWidget { - const LargeTextEditor({super.key}); @override State createState() => _LargeTextEditorState(); - } class _LargeTextEditorState extends State { - final CodeLineEditingController _controller = CodeLineEditingController(); @override @@ -30,7 +27,8 @@ class _LargeTextEditorState extends State { return CodeEditor( controller: _controller, wordWrap: false, - indicatorBuilder: (context, editingController, chunkController, notifier) { + indicatorBuilder: + (context, editingController, chunkController, notifier) { return Row( children: [ DefaultCodeLineNumber( @@ -38,20 +36,14 @@ class _LargeTextEditorState extends State { notifier: notifier, ), DefaultCodeChunkIndicator( - width: 20, - controller: chunkController, - notifier: notifier - ) + width: 20, controller: chunkController, notifier: notifier) ], ); }, - findBuilder: (context, controller, readOnly) => CodeFindPanelView(controller: controller, readOnly: readOnly), + findBuilder: (context, controller, readOnly) => + CodeFindPanelView(controller: controller, readOnly: readOnly), toolbarController: const ContextMenuControllerImpl(), - sperator: Container( - width: 1, - color: Colors.blue - ), + sperator: Container(width: 1, color: Colors.blue), ); } - -} \ No newline at end of file +} diff --git a/example/lib/find.dart b/example/lib/find.dart index fb6f290..3427f65 100644 --- a/example/lib/find.dart +++ b/example/lib/find.dart @@ -3,9 +3,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:re_editor/re_editor.dart'; -const EdgeInsetsGeometry _kDefaultFindMargin = EdgeInsets.only( - right: 10 -); +const EdgeInsetsGeometry _kDefaultFindMargin = EdgeInsets.only(right: 10); const double _kDefaultFindPanelWidth = 360; const double _kDefaultFindPanelHeight = 36; const double _kDefaultReplacePanelHeight = _kDefaultFindPanelHeight * 2; @@ -14,18 +12,33 @@ const double _kDefaultFindIconWidth = 30; const double _kDefaultFindIconHeight = 30; const double _kDefaultFindInputFontSize = 13; const double _kDefaultFindResultFontSize = 12; -const EdgeInsetsGeometry _kDefaultFindPadding = EdgeInsets.only( - left: 5, - right: 5, - top: 2.5, - bottom: 2.5 -); +const EdgeInsetsGeometry _kDefaultFindPadding = + EdgeInsets.only(left: 5, right: 5, top: 2.5, bottom: 2.5); const EdgeInsetsGeometry _kDefaultFindInputContentPadding = EdgeInsets.only( left: 5, right: 5, ); class CodeFindPanelView extends StatelessWidget implements PreferredSizeWidget { + const CodeFindPanelView( + {required this.controller, + required this.readOnly, + super.key, + this.margin = _kDefaultFindMargin, + this.iconSelectedColor, + this.iconColor, + this.iconSize = _kDefaultFindIconSize, + this.inputFontSize = _kDefaultFindInputFontSize, + this.resultFontSize = _kDefaultFindResultFontSize, + this.inputTextColor, + this.resultFontColor, + this.padding = _kDefaultFindPadding, + this.decoration = const InputDecoration( + filled: true, + contentPadding: _kDefaultFindInputContentPadding, + border: + OutlineInputBorder(borderRadius: BorderRadius.zero, gapPadding: 0), + )}); final CodeFindController controller; final EdgeInsetsGeometry margin; @@ -40,59 +53,38 @@ class CodeFindPanelView extends StatelessWidget implements PreferredSizeWidget { final EdgeInsetsGeometry padding; final InputDecoration decoration; - const CodeFindPanelView({ - super.key, - required this.controller, - this.margin = _kDefaultFindMargin, - required this.readOnly, - this.iconSelectedColor, - this.iconColor, - this.iconSize = _kDefaultFindIconSize, - this.inputFontSize = _kDefaultFindInputFontSize, - this.resultFontSize = _kDefaultFindResultFontSize, - this.inputTextColor, - this.resultFontColor, - this.padding = _kDefaultFindPadding, - this.decoration = const InputDecoration( - filled: true, - contentPadding: _kDefaultFindInputContentPadding, - border: OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(0)), - gapPadding: 0 - ), - ) - }); - @override Size get preferredSize => Size( - double.infinity, - controller.value == null ? 0 : - ((controller.value!.replaceMode ? _kDefaultReplacePanelHeight : _kDefaultFindPanelHeight) + margin.vertical) - ); + double.infinity, + controller.value == null + ? 0 + : ((controller.value!.replaceMode + ? _kDefaultReplacePanelHeight + : _kDefaultFindPanelHeight) + + margin.vertical)); @override Widget build(BuildContext context) { if (controller.value == null) { - return const SizedBox(width: 0, height: 0); + return const SizedBox.shrink(); } return Container( - margin: margin, - alignment: Alignment.topRight, - height: preferredSize.height, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SizedBox( - width: _kDefaultFindPanelWidth, - child: Column( - children: [ - _buildFindInputView(context), - if (controller.value!.replaceMode) - _buildReplaceInputView(context), - ], + margin: margin, + alignment: Alignment.topRight, + height: preferredSize.height, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: SizedBox( + width: _kDefaultFindPanelWidth, + child: Column( + children: [ + _buildFindInputView(context), + if (controller.value!.replaceMode) + _buildReplaceInputView(context), + ], + ), ), - ), - ) - ); + )); } Widget _buildFindInputView(BuildContext context) { @@ -106,72 +98,65 @@ class CodeFindPanelView extends StatelessWidget implements PreferredSizeWidget { return Row( children: [ SizedBox( - width: _kDefaultFindPanelWidth / 1.75, - height: _kDefaultFindPanelHeight, - child: Stack( - alignment: Alignment.center, - children: [ - _buildTextField( - context: context, - controller: controller.findInputController, - focusNode: controller.findInputFocusNode, - iconsWidth: _kDefaultFindIconWidth * 1.5 - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - _buildCheckText( + width: _kDefaultFindPanelWidth / 1.75, + height: _kDefaultFindPanelHeight, + child: Stack( + alignment: Alignment.center, + children: [ + _buildTextField( context: context, - text: 'Aa', - checked: value.option.caseSensitive, - onPressed: () { - controller.toggleCaseSensitive(); - } - ), - _buildCheckText( - context: context, - text: '.*', - checked: value.option.regex, - onPressed: () { - controller.toggleRegex(); - } - ) - ], - ) - ], - ) - ), + controller: controller.findInputController, + focusNode: controller.findInputFocusNode, + iconsWidth: _kDefaultFindIconWidth * 1.5), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + _buildCheckText( + context: context, + text: 'Aa', + checked: value.option.caseSensitive, + onPressed: () { + controller.toggleCaseSensitive(); + }), + _buildCheckText( + context: context, + text: '.*', + checked: value.option.regex, + onPressed: () { + controller.toggleRegex(); + }) + ], + ) + ], + )), Text(result, - style: TextStyle( - color: resultFontColor, - fontSize: resultFontSize - ) - ), + style: TextStyle(color: resultFontColor, fontSize: resultFontSize)), Expanded( child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ _buildIconButton( - onPressed: value.result == null ? null : () { - controller.previousMatch(); - }, - icon: Icons.arrow_upward, - tooltip: 'Previous' - ), + onPressed: value.result == null + ? null + : () { + controller.previousMatch(); + }, + icon: Icons.arrow_upward, + tooltip: 'Previous'), _buildIconButton( - onPressed: value.result == null ? null : () { - controller.nextMatch(); - }, - icon: Icons.arrow_downward, - tooltip: 'Next' - ), + onPressed: value.result == null + ? null + : () { + controller.nextMatch(); + }, + icon: Icons.arrow_downward, + tooltip: 'Next'), _buildIconButton( - onPressed: () { - controller.close(); - }, - icon: Icons.close, - tooltip: 'Close' - ) + onPressed: () { + controller.close(); + }, + icon: Icons.close, + tooltip: 'Close') ], ), ) @@ -193,19 +178,21 @@ class CodeFindPanelView extends StatelessWidget implements PreferredSizeWidget { ), ), _buildIconButton( - onPressed: value.result == null ? null : () { - controller.replaceMatch(); - }, - icon: Icons.done, - tooltip: 'Replace' - ), + onPressed: value.result == null + ? null + : () { + controller.replaceMatch(); + }, + icon: Icons.done, + tooltip: 'Replace'), _buildIconButton( - onPressed: value.result == null ? null : () { - controller.replaceAllMatches(); - }, - icon: Icons.done_all, - tooltip: 'Replace All' - ) + onPressed: value.result == null + ? null + : () { + controller.replaceAllMatches(); + }, + icon: Icons.done_all, + tooltip: 'Replace All') ], ); } @@ -219,17 +206,11 @@ class CodeFindPanelView extends StatelessWidget implements PreferredSizeWidget { return Padding( padding: padding, child: TextField( - maxLines: 1, focusNode: focusNode, - style: TextStyle( - color: inputTextColor, - fontSize: inputFontSize - ), + style: TextStyle(color: inputTextColor, fontSize: inputFontSize), decoration: decoration.copyWith( - contentPadding: (decoration.contentPadding ?? EdgeInsets.zero).add(EdgeInsets.only( - right: iconsWidth - ) - )), + contentPadding: (decoration.contentPadding ?? EdgeInsets.zero) + .add(EdgeInsets.only(right: iconsWidth))), controller: controller, ), ); @@ -241,30 +222,25 @@ class CodeFindPanelView extends StatelessWidget implements PreferredSizeWidget { required bool checked, required VoidCallback onPressed, }) { - final Color selectedColor = iconSelectedColor ?? Theme.of(context).primaryColor; + final Color selectedColor = + iconSelectedColor ?? Theme.of(context).primaryColor; return GestureDetector( - onTap: onPressed, - child: MouseRegion( - cursor: SystemMouseCursors.click, - child: SizedBox( - width: _kDefaultFindIconWidth * 0.75, - child: Text( - text, - style: TextStyle( - color: checked ? selectedColor : iconColor, - fontSize: inputFontSize, - ) + onTap: onPressed, + child: MouseRegion( + cursor: SystemMouseCursors.click, + child: SizedBox( + width: _kDefaultFindIconWidth * 0.75, + child: Text(text, + style: TextStyle( + color: checked ? selectedColor : iconColor, + fontSize: inputFontSize, + )), ), - ), - ) - ); + )); } - Widget _buildIconButton({ - required IconData icon, - VoidCallback? onPressed, - String? tooltip - }) { + Widget _buildIconButton( + {required IconData icon, VoidCallback? onPressed, String? tooltip}) { return IconButton( onPressed: onPressed, icon: Icon( @@ -272,12 +248,9 @@ class CodeFindPanelView extends StatelessWidget implements PreferredSizeWidget { size: iconSize, ), constraints: const BoxConstraints( - maxWidth: _kDefaultFindIconWidth, - maxHeight: _kDefaultFindIconHeight - ), + maxWidth: _kDefaultFindIconWidth, maxHeight: _kDefaultFindIconHeight), tooltip: tooltip, splashRadius: max(_kDefaultFindIconWidth, _kDefaultFindIconHeight) / 2, ); } - -} \ No newline at end of file +} diff --git a/example/lib/main.dart b/example/lib/main.dart index a245c5f..bfa8dd0 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -10,7 +10,7 @@ void main() { } class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); + const MyApp({super.key}); // This widget is the root of your application. @override @@ -18,17 +18,16 @@ class MyApp extends StatelessWidget { return MaterialApp( title: 'Re-Editor', theme: ThemeData( - colorScheme: const ColorScheme.light( - primary: Color.fromARGB(255, 255, 140, 0), - ) - ), + colorScheme: const ColorScheme.light( + primary: Color.fromARGB(255, 255, 140, 0), + )), home: const MyHomePage(title: 'Re-Editor Demo Page'), ); } } class MyHomePage extends StatefulWidget { - const MyHomePage({Key? key, required this.title}) : super(key: key); + const MyHomePage({required this.title, super.key}); // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect @@ -46,7 +45,6 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - static const Map _editors = { 'Basic Field': BasicField(), 'Json Editor': JsonEditor(), @@ -64,42 +62,36 @@ class _MyHomePageState extends State { title: Text(widget.title), ), body: Container( - margin: const EdgeInsets.all(20), - child: Column( - children: [ - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: _editors.entries.mapIndexed((index, entry) { - return TextButton( - onPressed: () { - setState(() { - _index = index; - }); - }, - child: Text( - entry.key, - style: TextStyle( - color: _index == index ? null : Colors.black + margin: const EdgeInsets.all(20), + child: Column( + children: [ + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: _editors.entries.mapIndexed((index, entry) { + return TextButton( + onPressed: () { + setState(() { + _index = index; + }); + }, + child: Text( + entry.key, + style: TextStyle( + color: _index == index ? null : Colors.black), ), - ), - ); - }).toList(), - ), - ), - Expanded( - child: Container( - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey - ) + ); + }).toList(), ), + ), + Expanded( + child: DecoratedBox( + decoration: + BoxDecoration(border: Border.all(color: Colors.grey)), child: child, - ) - ) - ], - ) - ), + )) + ], + )), ); } -} \ No newline at end of file +} diff --git a/example/lib/menu.dart b/example/lib/menu.dart index 8778eb1..5071651 100644 --- a/example/lib/menu.dart +++ b/example/lib/menu.dart @@ -1,65 +1,57 @@ import 'package:flutter/material.dart'; import 'package:re_editor/re_editor.dart'; -class ContextMenuItemWidget extends PopupMenuItem implements PreferredSizeWidget { - +class ContextMenuItemWidget extends PopupMenuItem + implements PreferredSizeWidget { ContextMenuItemWidget({ - Key? key, required String text, - required VoidCallback onTap, - }) : super( - key: key, - onTap: onTap, - child: Text(text) - ); + required VoidCallback super.onTap, + super.key, + }) : super(child: Text(text)); @override Size get preferredSize => const Size(150, 25); - } class ContextMenuControllerImpl implements SelectionToolbarController { - const ContextMenuControllerImpl(); @override - void hide(BuildContext context) { - } + void hide(BuildContext context) {} @override void show({ required BuildContext context, required CodeLineEditingController controller, required TextSelectionToolbarAnchors anchors, - Rect? renderRect, required LayerLink layerLink, required ValueNotifier visibility, + Rect? renderRect, }) { showMenu( - context: context, - position: RelativeRect.fromSize(anchors.primaryAnchor & const Size(150, double.infinity), - MediaQuery.of(context).size), - items: [ - ContextMenuItemWidget( - text: 'Cut', - onTap: () { - controller.cut(); - }, - ), - ContextMenuItemWidget( - text: 'Copy', - onTap: () { - controller.copy(); - }, - ), - ContextMenuItemWidget( - text: 'Paste', - onTap: () { - controller.paste(); - }, - ), - ] - ); + context: context, + position: RelativeRect.fromSize( + anchors.primaryAnchor & const Size(150, double.infinity), + MediaQuery.of(context).size), + items: [ + ContextMenuItemWidget( + text: 'Cut', + onTap: () { + controller.cut(); + }, + ), + ContextMenuItemWidget( + text: 'Copy', + onTap: () { + controller.copy(); + }, + ), + ContextMenuItemWidget( + text: 'Paste', + onTap: () { + controller.paste(); + }, + ), + ]); } - -} \ No newline at end of file +} diff --git a/example/pubspec.lock b/example/pubspec.lock index e943eb8..4c11e97 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,26 +5,26 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.13.0" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" collection: dependency: "direct main" description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" flutter: dependency: "direct main" description: flutter @@ -38,22 +38,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" - isolate_contactor: - dependency: transitive - description: - name: isolate_contactor - sha256: "6ba8434ceb58238a1389d6365111a3efe7baa1c68a66f4db6d63d351cf6c3a0f" - url: "https://pub.dev" - source: hosted - version: "4.1.0" isolate_manager: dependency: transitive description: name: isolate_manager - sha256: "22ed0c25f80ec3b5f21e3a55d060f4650afff33f27c2dff34c0f9409d5759ae5" + sha256: "470582fcde05989877f3d7a2dd5ff798249fdf709f14c06bb6c876ae9f51a27d" url: "https://pub.dev" source: hosted - version: "4.1.5+1" + version: "6.0.0+2" lints: dependency: transitive description: @@ -66,54 +58,55 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.16.0" path: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" re_editor: dependency: "direct main" description: path: ".." relative: true source: path - version: "0.4.0" + version: "0.7.0" re_highlight: dependency: "direct main" description: - name: re_highlight - sha256: "6c4ac3f76f939fb7ca9df013df98526634e17d8f7460e028bd23a035870024f2" - url: "https://pub.dev" - source: hosted + path: "." + ref: HEAD + resolved-ref: "49ca075fdb0b8114bc153357275314700e1307ed" + url: "https://github.com/sgehrman/re-highlight" + source: git version: "0.0.3" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" vector_math: dependency: transitive description: @@ -126,10 +119,10 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "1.1.1" sdks: - dart: ">=3.2.0-194.0.dev <4.0.0" + dart: ">=3.7.2 <4.0.0" flutter: ">=1.17.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c022198..e6e10c4 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -9,19 +9,19 @@ environment: flutter: ">=1.17.0" dependencies: + collection: ^1.17.1 flutter: sdk: flutter - collection: ^1.17.1 - re_highlight: ^0.0.2 re_editor: path: ../ + re_highlight: + git: https://github.com/sgehrman/re-highlight dev_dependencies: flutter_lints: ^2.0.3 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec - # The following section is specific to Flutter packages. flutter: @@ -34,13 +34,10 @@ flutter: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg - # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware - # For details regarding adding assets from package dependencies, see # https://flutter.dev/assets-and-images/#from-packages - # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a diff --git a/lib/re_editor.dart b/lib/re_editor.dart index 51e9788..46702b3 100644 --- a/lib/re_editor.dart +++ b/lib/re_editor.dart @@ -1 +1 @@ -export 'src/re_editor.dart'; \ No newline at end of file +export 'src/re_editor.dart'; diff --git a/lib/src/_code_autocomplete.dart b/lib/src/_code_autocomplete.dart index fae1006..9c859b2 100644 --- a/lib/src/_code_autocomplete.dart +++ b/lib/src/_code_autocomplete.dart @@ -1,64 +1,70 @@ -part of re_editor; - -class _DefaultCodeAutocompletePromptsBuilder implements DefaultCodeAutocompletePromptsBuilder { - - final Mode? language; - final List keywordPrompts; - final List directPrompts; - final Map> relatedPrompts; - - final Set _allKeywordPrompts = {}; +part of 're_editor.dart'; +class _DefaultCodeAutocompletePromptsBuilder + implements DefaultCodeAutocompletePromptsBuilder { _DefaultCodeAutocompletePromptsBuilder({ - this.language, required this.keywordPrompts, required this.directPrompts, - required this.relatedPrompts + required this.relatedPrompts, + this.language, }) { _allKeywordPrompts.addAll(keywordPrompts); _allKeywordPrompts.addAll(directPrompts); final dynamic keywords = language?.keywords; if (keywords is Map) { final dynamic keywordList = keywords['keyword']; - if (keywordList is List) { - _allKeywordPrompts.addAll(keywordList.map( - (keyword) => CodeKeywordPrompt(word: keyword)) + if (keywordList is List) { + _allKeywordPrompts.addAll( + keywordList.map((keyword) => CodeKeywordPrompt(word: keyword)), ); } final dynamic builtInList = keywords['built_in']; - if (builtInList is List) { - _allKeywordPrompts.addAll(builtInList.map( - (keyword) => CodeKeywordPrompt(word: keyword)) + if (builtInList is List) { + _allKeywordPrompts.addAll( + builtInList.map((keyword) => CodeKeywordPrompt(word: keyword)), ); } final dynamic literalList = keywords['literal']; - if (literalList is List) { - _allKeywordPrompts.addAll(literalList.map( - (keyword) => CodeKeywordPrompt(word: keyword)) + if (literalList is List) { + _allKeywordPrompts.addAll( + literalList.map((keyword) => CodeKeywordPrompt(word: keyword)), ); } final dynamic typeList = keywords['type']; - if (typeList is List) { - _allKeywordPrompts.addAll(typeList.map( - (keyword) => CodeKeywordPrompt(word: keyword)) + if (typeList is List) { + _allKeywordPrompts.addAll( + typeList.map((keyword) => CodeKeywordPrompt(word: keyword)), ); } } } + final Mode? language; + final List keywordPrompts; + final List directPrompts; + final Map> relatedPrompts; + + final Set _allKeywordPrompts = {}; @override - CodeAutocompleteEditingValue? build(BuildContext context, CodeLine codeLine, CodeLineSelection selection) { + CodeAutocompleteEditingValue? build( + BuildContext context, + CodeLine codeLine, + CodeLineSelection selection, + ) { final String text = codeLine.text; - final Characters charactersBefore = text.substring(0, selection.extentOffset).characters; + final Characters charactersBefore = + text.substring(0, selection.extentOffset).characters; if (charactersBefore.isEmpty) { return null; } - final Characters charactersAfter = text.substring(selection.extentOffset).characters; + final Characters charactersAfter = + text.substring(selection.extentOffset).characters; // FIXME:Check whether the position is inside a string - if (charactersBefore.containsSymbols(const ['\'', '"']) && charactersAfter.containsSymbols(const ['\'', '"'])) { + if (charactersBefore.containsSymbols(const ['\'', '"']) && + charactersAfter.containsSymbols(const ['\'', '"'])) { return null; } - // TODO Should check operator `->` for some languages like c/c++ + // TODOShould check operator `->` for some languages like c/c++ final Iterable prompts; final String input; if (charactersBefore.takeLast(1).string == '.') { @@ -69,7 +75,10 @@ class _DefaultCodeAutocompletePromptsBuilder implements DefaultCodeAutocompleteP break; } } - final String target = charactersBefore.getRange(start + 1, charactersBefore.length - 1).string; + final String target = + charactersBefore + .getRange(start + 1, charactersBefore.length - 1) + .string; prompts = relatedPrompts[target] ?? const []; } else { int start = charactersBefore.length - 1; @@ -78,7 +87,8 @@ class _DefaultCodeAutocompletePromptsBuilder implements DefaultCodeAutocompleteP break; } } - input = charactersBefore.getRange(start + 1, charactersBefore.length).string; + input = + charactersBefore.getRange(start + 1, charactersBefore.length).string; if (input.isEmpty) { return null; } @@ -90,29 +100,26 @@ class _DefaultCodeAutocompletePromptsBuilder implements DefaultCodeAutocompleteP } } final String target = charactersBefore.getRange(start + 1, mark).string; - prompts = relatedPrompts[target]?.where( - (prompt) => prompt.match(input) - ) ?? const []; + prompts = + relatedPrompts[target]?.where((prompt) => prompt.match(input)) ?? + const []; } else { - prompts = _allKeywordPrompts.where( - (prompt) => prompt.match(input) - ); + prompts = _allKeywordPrompts.where((prompt) => prompt.match(input)); } } if (prompts.isEmpty) { return null; } + return CodeAutocompleteEditingValue( input: input, prompts: prompts.toList(), - index: 0 + index: 0, ); } - } class _CodeAutocomplete extends StatefulWidget { - const _CodeAutocomplete({ required this.viewBuilder, required this.promptsBuilder, @@ -125,11 +132,9 @@ class _CodeAutocomplete extends StatefulWidget { @override State createState() => _CodeAutocompleteState(); - } class _CodeAutocompleteState extends State<_CodeAutocomplete> { - late final _CodeAutocompleteNavigateAction _navigateAction; late final _CodeAutocompleteAction _selectAction; @@ -157,9 +162,8 @@ class _CodeAutocompleteState extends State<_CodeAutocomplete> { } else if (newIndex >= value.prompts.length) { newIndex = 0; } - _notifier?.value = value.copyWith( - index: newIndex, - ); + _notifier?.value = value.copyWith(index: newIndex); + return intent; }, ); @@ -170,6 +174,7 @@ class _CodeAutocompleteState extends State<_CodeAutocomplete> { return null; } _onAutocomplete?.call(value.autocomplete); + return intent; }, ); @@ -187,7 +192,7 @@ class _CodeAutocompleteState extends State<_CodeAutocomplete> { CodeShortcutCursorMoveIntent: _navigateAction, CodeShortcutNewLineIntent: _selectAction, }, - child: widget.child + child: widget.child, ); } @@ -199,24 +204,26 @@ class _CodeAutocompleteState extends State<_CodeAutocomplete> { required ValueChanged onAutocomplete, }) { dismiss(); - final CodeAutocompleteEditingValue? autocompleteEditingValue = widget.promptsBuilder.build( - context, - value.codeLines[value.selection.extentIndex], - value.selection, - ); + final CodeAutocompleteEditingValue? autocompleteEditingValue = widget + .promptsBuilder + .build( + context, + value.codeLines[value.selection.extentIndex], + value.selection, + ); if (autocompleteEditingValue == null) { return; } _notifier = ValueNotifier(autocompleteEditingValue); _onAutocomplete = onAutocomplete; _overlayEntry = OverlayEntry( - builder:(context) { + builder: (context) { return _buildWidget(context, layerLink, position, lineHeight); }, ); Overlay.of(context, rootOverlay: true).insert(_overlayEntry!); - _navigateAction.setEnabled(true); - _selectAction.setEnabled(true); + _navigateAction.setEnabled = true; + _selectAction.setEnabled = true; } void dismiss() { @@ -224,15 +231,22 @@ class _CodeAutocompleteState extends State<_CodeAutocomplete> { _onAutocomplete = null; _overlayEntry?.remove(); _overlayEntry = null; - _navigateAction.setEnabled(false); - _selectAction.setEnabled(false); + _navigateAction.setEnabled = false; + _selectAction.setEnabled = false; } - Widget _buildWidget(BuildContext context, LayerLink layerLink, Offset position, double lineHeight) { - final PreferredSizeWidget child = widget.viewBuilder(context, _notifier!, (result) { + Widget _buildWidget( + BuildContext context, + LayerLink layerLink, + Offset position, + double lineHeight, + ) { + final PreferredSizeWidget child = widget.viewBuilder(context, _notifier!, ( + result, + ) { _onAutocomplete?.call(result); }); - final Size screenSize = MediaQuery.of(context).size; + final Size screenSize = MediaQuery.of(context).size; final double offsetX; if (position.dx + child.preferredSize.width > screenSize.width) { offsetX = screenSize.width - (position.dx + child.preferredSize.width); @@ -245,6 +259,7 @@ class _CodeAutocompleteState extends State<_CodeAutocomplete> { } else { offsetY = 0; } + return CompositedTransformFollower( link: layerLink, showWhenUnlinked: false, @@ -257,67 +272,55 @@ class _CodeAutocompleteState extends State<_CodeAutocomplete> { onTapOutside: (event) { dismiss(); }, - child: CodeEditorTapRegion( - child: ExcludeSemantics( - child: child, - ) - ) + child: CodeEditorTapRegion(child: ExcludeSemantics(child: child)), ), - ) + ), ), ); } - } class _CodeAutocompleteAction extends CallbackAction { - + _CodeAutocompleteAction({required super.onInvoke}); bool _isEnabled = false; - _CodeAutocompleteAction({ - required super.onInvoke - }); - - void setEnabled(bool enabled) { + set setEnabled(bool enabled) { _isEnabled = enabled; } @override bool get isActionEnabled => _isEnabled; - } -class _CodeAutocompleteNavigateAction extends _CodeAutocompleteAction { - - _CodeAutocompleteNavigateAction({ - required super.onInvoke - }); +class _CodeAutocompleteNavigateAction + extends _CodeAutocompleteAction { + _CodeAutocompleteNavigateAction({required super.onInvoke}); @override bool consumesKey(CodeShortcutCursorMoveIntent intent) { - return intent.direction == AxisDirection.up || intent.direction == AxisDirection.down; + return intent.direction == AxisDirection.up || + intent.direction == AxisDirection.down; } - } extension _CodeAutocompleteStringExtension on String { - bool get isValidVariablePart { final int char = codeUnits.first; - return (char >= 65 && char <= 90) || (char >= 97 && char <= 122) || char == 95; - } + return (char >= 65 && char <= 90) || + (char >= 97 && char <= 122) || + char == 95; + } } extension _CodeAutocompleteCharactersExtension on Characters { - bool containsSymbols(List symbols) { for (int i = length - 1; i >= 0; i--) { if (symbols.contains(elementAt(i))) { return true; } } + return false; } - -} \ No newline at end of file +} diff --git a/lib/src/_code_editable.dart b/lib/src/_code_editable.dart index fd7c821..9ceaf48 100644 --- a/lib/src/_code_editable.dart +++ b/lib/src/_code_editable.dart @@ -1,13 +1,53 @@ -part of re_editor; +part of 're_editor.dart'; -const double _kDefaultTextSize = 13.0; +const double _kDefaultTextSize = 13; const double _kDefaultFontHeight = 1.4; const double _kDefaultCaretWidth = 2; const EdgeInsetsGeometry _kDefaultPadding = EdgeInsets.all(5); const Duration _kCursorBlinkHalfPeriod = Duration(milliseconds: 500); class _CodeEditable extends StatefulWidget { - + const _CodeEditable({ + required this.editorKey, + required this.textStyle, + required this.selectionColor, + required this.highlightColor, + required this.cursorColor, + required this.cursorWidth, + required this.showCursorWhenReadOnly, + required this.padding, + required this.margin, + required this.sperator, + required this.focusNode, + required this.controller, + required this.inputController, + required this.floatingCursorController, + required this.codeTheme, + required this.readOnly, + required this.autofocus, + required this.wordWrap, + required this.findController, + required this.scrollController, + required this.chunkController, + required this.startHandleLayerLink, + required this.endHandleLayerLink, + required this.toolbarLayerLink, + required this.selectionOverlayController, + this.hint, + this.indicatorBuilder, + this.scrollbarBuilder, + this.verticalScrollbarWidth, + this.horizontalScrollbarHeight, + this.hintTextColor, + this.backgroundColor, + this.cursorLineColor, + this.chunkIndicatorColor, + this.border, + this.borderRadius, + this.clipBehavior = Clip.none, + this.onChanged, + this.maxLengthSingleLineRendering, + }); final GlobalKey editorKey; final String? hint; final CodeIndicatorBuilder? indicatorBuilder; @@ -48,55 +88,14 @@ class _CodeEditable extends StatefulWidget { final LayerLink toolbarLayerLink; final _SelectionOverlayController selectionOverlayController; - const _CodeEditable({ - required this.editorKey, - this.hint, - this.indicatorBuilder, - this.scrollbarBuilder, - this.verticalScrollbarWidth, - this.horizontalScrollbarHeight, - required this.textStyle, - this.hintTextColor, - this.backgroundColor, - required this.selectionColor, - required this.highlightColor, - required this.cursorColor, - this.cursorLineColor, - this.chunkIndicatorColor, - required this.cursorWidth, - required this.showCursorWhenReadOnly, - required this.padding, - required this.margin, - required this.sperator, - this.border, - this.borderRadius, - this.clipBehavior = Clip.none, - this.onChanged, - required this.focusNode, - required this.controller, - required this.inputController, - required this.floatingCursorController, - required this.codeTheme, - required this.readOnly, - required this.autofocus, - required this.wordWrap, - this.maxLengthSingleLineRendering, - required this.findController, - required this.scrollController, - required this.chunkController, - required this.startHandleLayerLink, - required this.endHandleLayerLink, - required this.toolbarLayerLink, - required this.selectionOverlayController, - }); - @override State createState() => _CodeEditableState(); - } -class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveClientMixin<_CodeEditable>, SingleTickerProviderStateMixin { - +class _CodeEditableState extends State<_CodeEditable> + with + AutomaticKeepAliveClientMixin<_CodeEditable>, + SingleTickerProviderStateMixin { late bool _didAutoFocus; late final _CodeCursorBlinkController _cursorController; @@ -203,7 +202,7 @@ class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveCli viewportBuilder: (context, ViewportOffset horizontal) { return _buildCodeField(vertical, horizontal); }, - scrollbarBuilder: widget.scrollbarBuilder + scrollbarBuilder: widget.scrollbarBuilder, ); } if (widget.controller.value.isInitial) { @@ -213,17 +212,16 @@ class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveCli children: [ codeField, IgnorePointer( - ignoring: true, child: Padding( padding: widget.padding, child: Text( hint, style: widget.textStyle.copyWith( - color: widget.hintTextColor + color: widget.hintTextColor, ), ), - ) - ) + ), + ), ], ); } @@ -232,8 +230,9 @@ class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveCli context, widget.controller, widget.chunkController, - _codeIndicatorValueNotifier + _codeIndicatorValueNotifier, ); + return Container( decoration: BoxDecoration( border: widget.border, @@ -245,24 +244,23 @@ class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveCli child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (indicator != null) - indicator, - if (widget.sperator != null) - widget.sperator!, + if (indicator != null) indicator, + if (widget.sperator != null) widget.sperator!, Expanded( child: RepaintBoundary( child: CompositedTransformTarget( link: widget.toolbarLayerLink, - child: codeField + child: codeField, ), ), - ) + ), ], ), ); }, - scrollbarBuilder: widget.scrollbarBuilder + scrollbarBuilder: widget.scrollbarBuilder, ); + return CodeEditorTapRegion( onTapOutside: (_) { widget.focusNode.unfocus(); @@ -272,10 +270,11 @@ class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveCli if (notification is ScrollStartNotification) { widget.selectionOverlayController.hideToolbar(); } + return false; }, - child: child - ) + child: child, + ), ); } @@ -284,8 +283,10 @@ class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveCli key: widget.editorKey, verticalViewport: vertical, horizontalViewport: horizontal, - verticalScrollbarWidth: widget.verticalScrollbarWidth ?? _kScrollbarThickness, - horizontalScrollbarHeight: widget.horizontalScrollbarHeight ?? _kScrollbarThickness, + verticalScrollbarWidth: + widget.verticalScrollbarWidth ?? _kScrollbarThickness, + horizontalScrollbarHeight: + widget.horizontalScrollbarHeight ?? _kScrollbarThickness, selection: widget.controller.selection, highlightSelections: widget.findController.allMatchSelections, codes: widget.controller.codeLines, @@ -297,7 +298,7 @@ class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveCli onRenderParagraphsChanged: (paragraphs) { _codeIndicatorValueNotifier.value = CodeIndicatorValue( paragraphs: paragraphs, - focusedIndex: widget.controller.selection.extentIndex + focusedIndex: widget.controller.selection.extentIndex, ); }, selectionColor: widget.selectionColor, @@ -309,7 +310,10 @@ class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveCli padding: widget.padding, readOnly: widget.readOnly, // Enable long text rendering when the find is on. - maxLengthSingleLineRendering: widget.findController.value != null ? null : widget.maxLengthSingleLineRendering, + maxLengthSingleLineRendering: + widget.findController.value != null + ? null + : widget.maxLengthSingleLineRendering, startHandleLayerLink: widget.startHandleLayerLink, endHandleLayerLink: widget.endHandleLayerLink, ); @@ -337,15 +341,14 @@ class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveCli } widget.onChanged?.call(widget.controller.value); if (widget.controller.codeLines != widget.controller.preValue?.codeLines && - widget.controller.preValue != null) { + widget.controller.preValue != null) { widget.selectionOverlayController.hideHandle(); widget.selectionOverlayController.hideToolbar(); } else { _updateAutoCompleteState(false); } _updateCursorState(); - setState(() { - }); + setState(() {}); } void _onCodeUserInputChanged() { @@ -365,29 +368,35 @@ class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveCli final CodeFindValue? value = widget.findController.value; if (value == null) { widget.focusNode.requestFocus(); + return; } if (widget.focusNode.hasFocus) { return; } - final CodeLineSelection? currentMatch = widget.findController.currentMatchSelection; + final CodeLineSelection? currentMatch = + widget.findController.currentMatchSelection; if (currentMatch == null) { widget.controller.selection = const CodeLineSelection.zero(); + return; } widget.controller.selection = currentMatch; if (currentMatch.isSameLine) { - widget.controller.makePositionCenterIfInvisible(CodeLinePosition( - index: currentMatch.start.index, - offset: (currentMatch.startOffset + currentMatch.endOffset) >> 1 - )); + widget.controller.makePositionCenterIfInvisible( + CodeLinePosition( + index: currentMatch.start.index, + offset: (currentMatch.startOffset + currentMatch.endOffset) >> 1, + ), + ); } else { widget.controller.makePositionCenterIfInvisible(currentMatch.start); } } void _updateCursorState() { - if (widget.focusNode.hasFocus && (!widget.readOnly || widget.showCursorWhenReadOnly)) { + if (widget.focusNode.hasFocus && + (!widget.readOnly || widget.showCursorWhenReadOnly)) { _cursorController.startBlink(); } else { _cursorController.stopBlink(); @@ -398,26 +407,37 @@ class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveCli if (!mounted) { return; } - final _CodeAutocompleteState? autocompleteState = context.findAncestorStateOfType<_CodeAutocompleteState>(); + final _CodeAutocompleteState? autocompleteState = + context.findAncestorStateOfType<_CodeAutocompleteState>(); if (autocompleteState == null) { return; } if (!isCodeLineChanged) { autocompleteState.dismiss(); + return; } - if (widget.controller.isComposing || !widget.controller.selection.isCollapsed) { + if (widget.controller.isComposing || + !widget.controller.selection.isCollapsed) { autocompleteState.dismiss(); + return; } - final _CodeFieldRender? render = widget.editorKey.currentContext?.findRenderObject() as _CodeFieldRender?; + final _CodeFieldRender? render = + widget.editorKey.currentContext?.findRenderObject() + as _CodeFieldRender?; if (render == null) { autocompleteState.dismiss(); + return; } - final Offset? position = render.calculateTextPositionScreenOffset(widget.controller.selection.extent, true); + final Offset? position = render.calculateTextPositionScreenOffset( + widget.controller.selection.extent, + true, + ); if (position == null) { autocompleteState.dismiss(); + return; } autocompleteState.show( @@ -428,24 +448,24 @@ class _CodeEditableState extends State<_CodeEditable> with AutomaticKeepAliveCli onAutocomplete: (value) { autocompleteState.dismiss(); final CodeLineSelection selection = widget.controller.selection; - widget.controller.replaceSelection(value.word, selection.copyWith( - baseOffset: selection.baseOffset - value.input.length, - )); + widget.controller.replaceSelection( + value.word, + selection.copyWith( + baseOffset: selection.baseOffset - value.input.length, + ), + ); widget.controller.selection = selection.copyWith( baseOffset: selection.baseOffset + value.selection.baseOffset, extentOffset: selection.extentOffset + value.selection.extentOffset, ); - } + }, ); } - } class _CodeCursorBlinkController extends ValueNotifier { - - Timer? _timer; - _CodeCursorBlinkController() : super(false); + Timer? _timer; void startBlink() { if (_timer != null) { @@ -480,5 +500,4 @@ class _CodeCursorBlinkController extends ValueNotifier { stopBlink(); super.dispose(); } - -} \ No newline at end of file +} diff --git a/lib/src/_code_extensions.dart b/lib/src/_code_extensions.dart index ef8a7ec..bbe6c7b 100644 --- a/lib/src/_code_extensions.dart +++ b/lib/src/_code_extensions.dart @@ -1,7 +1,6 @@ -part of re_editor; +part of 're_editor.dart'; extension _InlineSpanExtension on InlineSpan { - int get length => _computeLength(); int _computeLength() { @@ -11,13 +10,12 @@ extension _InlineSpanExtension on InlineSpan { } else { len += toPlainText(includePlaceholders: false).length; } + return len; } - } extension _TextSpanExtension on TextSpan { - int get length => _computeLength(); int _computeLength() { @@ -30,15 +28,13 @@ extension _TextSpanExtension on TextSpan { len += span.length; } } + return len; } - } extension _OffsetExtension on Offset { - bool isSamePosition(Offset offset) { return (this - offset).distance < 10; } - -} \ No newline at end of file +} diff --git a/lib/src/_code_field.dart b/lib/src/_code_field.dart index cb1610e..4278508 100644 --- a/lib/src/_code_field.dart +++ b/lib/src/_code_field.dart @@ -1,7 +1,37 @@ -part of re_editor; +part of 're_editor.dart'; class _CodeField extends SingleChildRenderObjectWidget { - + _CodeField({ + required this.verticalViewport, + required this.horizontalViewport, + required this.verticalScrollbarWidth, + required this.horizontalScrollbarHeight, + required this.codes, + required this.selection, + required this.highlightSelections, + required this.textStyle, + required this.hasFocus, + required this.highlighter, + required this.showCursorNotifier, + required this.floatingCursorNotifier, + required this.onRenderParagraphsChanged, + required this.selectionColor, + required this.highlightColor, + required this.cursorColor, + required this.cursorWidth, + required this.padding, + required this.readOnly, + required this.startHandleLayerLink, + required this.endHandleLayerLink, + super.key, + Color? floatingCursorColor, + this.cursorLineColor, + this.chunkIndicatorColor, + double? floatingCursorWidth, + this.maxLengthSingleLineRendering, + }) : assert(codes.isNotEmpty, 'Codes cannot be empty'), + floatingCursorColor = floatingCursorColor ?? cursorColor, + floatingCursorWidth = floatingCursorWidth ?? cursorWidth; final ViewportOffset verticalViewport; final ViewportOffset? horizontalViewport; final double verticalScrollbarWidth; @@ -29,39 +59,6 @@ class _CodeField extends SingleChildRenderObjectWidget { final LayerLink startHandleLayerLink; final LayerLink endHandleLayerLink; - _CodeField({ - super.key, - required this.verticalViewport, - required this.horizontalViewport, - required this.verticalScrollbarWidth, - required this.horizontalScrollbarHeight, - required this.codes, - required this.selection, - required this.highlightSelections, - required this.textStyle, - required this.hasFocus, - required this.highlighter, - required this.showCursorNotifier, - required this.floatingCursorNotifier, - required this.onRenderParagraphsChanged, - required this.selectionColor, - required this.highlightColor, - required this.cursorColor, - floatingCursorColor, - this.cursorLineColor, - this.chunkIndicatorColor, - required this.cursorWidth, - floatingCursorWidth, - required this.padding, - required this.readOnly, - this.maxLengthSingleLineRendering, - required this.startHandleLayerLink, - required this.endHandleLayerLink, - }): assert(codes.isNotEmpty), - floatingCursorColor = floatingCursorColor ?? cursorColor, - floatingCursorWidth = floatingCursorWidth ?? cursorWidth; - - @override RenderObject createRenderObject(BuildContext context) => _CodeFieldRender( verticalViewport: verticalViewport, @@ -93,7 +90,10 @@ class _CodeField extends SingleChildRenderObjectWidget { ); @override - void updateRenderObject(BuildContext context, covariant _CodeFieldRender renderObject) { + void updateRenderObject( + BuildContext context, + covariant _CodeFieldRender renderObject, + ) { renderObject ..verticalViewport = verticalViewport ..horizontalViewport = horizontalViewport @@ -122,41 +122,11 @@ class _CodeField extends SingleChildRenderObjectWidget { ..startHandleLayerLink = startHandleLayerLink ..endHandleLayerLink = endHandleLayerLink; } - } const Duration positionCenteringDuration = Duration(milliseconds: 300); class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { - - ViewportOffset _verticalViewport; - ViewportOffset? _horizontalViewport; - double _verticalScrollbarWidth; - double _horizontalScrollbarHeight; - CodeLines _codes; - CodeLineSelection _selection; - TextStyle _textStyle; - bool _hasFocus; - _CodeHighlighter _highlighter; - ValueNotifier _showCursorNotifier; - ValueNotifier<_FloatingCursorState> _floatingCursorNotifier; - ValueChanged> _onRenderParagraphsChanged; - EdgeInsetsGeometry _padding; - bool _readOnly; - int? _maxLengthSingleLineRendering; - Color? _chunkIndicatorColor; - - double? _horizontalViewportSize; - double? _verticalViewportSize; - MouseCursor _cursor; - - final Paint _paint; - final List _displayParagraphs; - final List<_CodeChunkIndicator> _chunkIndicators; - late final _CodeFieldExtraRender _foregroundRender; - late final _CodeFieldExtraRender _backgroundRender; - late double _preferredLineHeight; - _CodeFieldRender({ required ViewportOffset verticalViewport, required ViewportOffset? horizontalViewport, @@ -170,48 +140,52 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { required _CodeHighlighter highlighter, required ValueNotifier showCursorNotifier, required ValueNotifier<_FloatingCursorState> floatingCursorNotifier, - required ValueChanged> onRenderParagraphsChanged, + required ValueChanged> + onRenderParagraphsChanged, required Color selectionColor, required Color highlightColor, required Color cursorColor, required Color floatingCursorColor, - Color? cursorLineColor, - Color? chunkIndicatorColor, required double cursorWidth, required double floatingCursorWidth, required EdgeInsetsGeometry padding, required bool readOnly, - int? maxLengthSingleLineRendering, required LayerLink startHandleLayerLink, required LayerLink endHandleLayerLink, + Color? cursorLineColor, + Color? chunkIndicatorColor, + int? maxLengthSingleLineRendering, }) : _verticalViewport = verticalViewport, - _horizontalViewport = horizontalViewport, - _verticalScrollbarWidth = verticalScrollbarWidth, - _horizontalScrollbarHeight = horizontalScrollbarHeight, - _codes = codes, - _selection = selection, - _textStyle = textStyle, - _hasFocus = hasFocus, - _highlighter = highlighter, - _showCursorNotifier = showCursorNotifier, - _floatingCursorNotifier = floatingCursorNotifier, - _onRenderParagraphsChanged = onRenderParagraphsChanged, - _padding = padding, - _readOnly = readOnly, - _maxLengthSingleLineRendering = maxLengthSingleLineRendering, - _chunkIndicatorColor = chunkIndicatorColor, - _paint = Paint(), - _displayParagraphs = [], - _chunkIndicators = [], - _cursor = SystemMouseCursors.text, - _startHandleLayerLink = startHandleLayerLink, - _endHandleLayerLink = endHandleLayerLink { + _horizontalViewport = horizontalViewport, + _verticalScrollbarWidth = verticalScrollbarWidth, + _horizontalScrollbarHeight = horizontalScrollbarHeight, + _codes = codes, + _selection = selection, + _textStyle = textStyle, + _hasFocus = hasFocus, + _highlighter = highlighter, + _showCursorNotifier = showCursorNotifier, + _floatingCursorNotifier = floatingCursorNotifier, + _onRenderParagraphsChanged = onRenderParagraphsChanged, + _padding = padding, + _readOnly = readOnly, + _maxLengthSingleLineRendering = maxLengthSingleLineRendering, + _chunkIndicatorColor = chunkIndicatorColor, + _paint = Paint(), + _displayParagraphs = [], + _chunkIndicators = [], + _cursor = SystemMouseCursors.text, + _startHandleLayerLink = startHandleLayerLink, + _endHandleLayerLink = endHandleLayerLink { _backgroundRender = _CodeFieldExtraRender( painters: [ _CodeCursorLinePainter(cursorLineColor, _selection), _CodeFieldSelectionPainter(selectionColor, _selection), - _CodeFieldHighlightPainter(highlightColor, highlightSelections ?? const []) - ] + _CodeFieldHighlightPainter( + highlightColor, + highlightSelections ?? const [], + ), + ], ); adoptChild(_backgroundRender); _foregroundRender = _CodeFieldExtraRender( @@ -220,20 +194,47 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { position: _selection.extent, color: cursorColor, width: cursorWidth, - height: 0.0, - visible: _showCursorNotifier.value + height: 0, + visible: _showCursorNotifier.value, ), _CodeFieldFloatingCursorPainter( position: _floatingCursorNotifier.value, color: floatingCursorColor, width: floatingCursorWidth, - height: 0.0, - ) - ] + height: 0, + ), + ], ); adoptChild(_foregroundRender); _calculatePreferredLineHeight(); } + ViewportOffset _verticalViewport; + ViewportOffset? _horizontalViewport; + double _verticalScrollbarWidth; + double _horizontalScrollbarHeight; + CodeLines _codes; + CodeLineSelection _selection; + TextStyle _textStyle; + bool _hasFocus; + _CodeHighlighter _highlighter; + ValueNotifier _showCursorNotifier; + ValueNotifier<_FloatingCursorState> _floatingCursorNotifier; + ValueChanged> _onRenderParagraphsChanged; + EdgeInsetsGeometry _padding; + bool _readOnly; + int? _maxLengthSingleLineRendering; + Color? _chunkIndicatorColor; + + double? _horizontalViewportSize; + double? _verticalViewportSize; + MouseCursor _cursor; + + final Paint _paint; + final List _displayParagraphs; + final List<_CodeChunkIndicator> _chunkIndicators; + late final _CodeFieldExtraRender _foregroundRender; + late final _CodeFieldExtraRender _backgroundRender; + late double _preferredLineHeight; set verticalViewport(ViewportOffset value) { if (_verticalViewport == value) { @@ -296,13 +297,15 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { _backgroundRender.find<_CodeFieldSelectionPainter>().selection = value; _foregroundRender.find<_CodeFieldCursorPainter>().position = value.extent; if (kIsAndroid || kIsIOS) { - _foregroundRender.find<_CodeFieldCursorPainter>().willDraw = _selection.isCollapsed; + _foregroundRender.find<_CodeFieldCursorPainter>().willDraw = + _selection.isCollapsed; } markNeedsLayout(); } set highlightSelections(List? value) { - _backgroundRender.find<_CodeFieldHighlightPainter>().selections = value ?? const []; + _backgroundRender.find<_CodeFieldHighlightPainter>().selections = + value ?? const []; } set textStyle(TextStyle value) { @@ -373,7 +376,9 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { } } - set onRenderParagraphsChanged(ValueChanged> value) { + set onRenderParagraphsChanged( + ValueChanged> value, + ) { if (_onRenderParagraphsChanged == value) { return; } @@ -468,8 +473,11 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { /// This bool indicates whether the text is scrolled so that the handle is /// inside the text field viewport, as opposed to whether it is actually /// visible on the screen. - ValueListenable get selectionStartInViewport => _selectionStartInViewport; - final ValueNotifier _selectionStartInViewport = ValueNotifier(true); + ValueListenable get selectionStartInViewport => + _selectionStartInViewport; + final ValueNotifier _selectionStartInViewport = ValueNotifier( + true, + ); /// Track whether position of the end of the selected text is within the viewport. /// @@ -500,7 +508,9 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { if (_padding == value) { return; } - double offset = value.resolve(TextDirection.ltr).top - _padding.resolve(TextDirection.ltr).top; + final double offset = + value.resolve(TextDirection.ltr).top - + _padding.resolve(TextDirection.ltr).top; if (_verticalViewport.pixels > 0) { if (_verticalViewport.pixels + offset < 0) { _verticalViewport.correctBy(0); @@ -530,7 +540,8 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { List get displayParagraphs => _displayParagraphs; - Offset get paintOffset => Offset(_horizontalViewport?.pixels ?? 0, _verticalViewport.pixels); + Offset get paintOffset => + Offset(_horizontalViewport?.pixels ?? 0, _verticalViewport.pixels); CodeLineRenderParagraph? findDisplayParagraphByLineIndex(int index) { for (final CodeLineRenderParagraph paragraph in _displayParagraphs) { @@ -538,12 +549,11 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { return paragraph; } } + return null; } - CodeLineSelection? setPositionAt({ - required Offset position, - }) { + CodeLineSelection? setPositionAt({required Offset position}) { final Offset localPosition = globalToLocal(position); if (!isValidPointer(localPosition)) { return null; @@ -552,9 +562,8 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { if (result == null) { return null; } - return CodeLineSelection.fromPosition( - position: result, - ); + + return CodeLineSelection.fromPosition(position: result); } CodeLineSelection? extendPositionTo({ @@ -570,47 +579,47 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { final CodeLinePosition? result = calculateTextPosition( Offset( min(size.width, max(0, localPosition.dx)), - min(size.height - _preferredLineHeight / 2, max(_preferredLineHeight / 2, localPosition.dy)) - ) + min( + size.height - _preferredLineHeight / 2, + max(_preferredLineHeight / 2, localPosition.dy), + ), + ), ); if (result == null) { return null; } if (anchor != null) { if (result.isBefore(anchor.start)) { - return CodeLineSelection.fromPosition( - position: result - ).copyWith( + return CodeLineSelection.fromPosition(position: result).copyWith( baseIndex: anchor.end.index, baseOffset: anchor.end.offset, baseAffinity: anchor.end.affinity, ); } if (result.isAfter(anchor.end)) { - return CodeLineSelection.fromPosition( - position: result - ).copyWith( + return CodeLineSelection.fromPosition(position: result).copyWith( baseIndex: anchor.start.index, baseOffset: anchor.start.offset, baseAffinity: anchor.start.affinity, ); } + return anchor; } + return oldSelection.copyWith( extentIndex: result.index, extentOffset: result.offset, - extentAffinity: result.affinity + extentAffinity: result.affinity, ); } - CodeLineRange? selectWord({ - required Offset position, - }) { + CodeLineRange? selectWord({required Offset position}) { final Offset localPosition = globalToLocal(position); if (!isValidPointer(localPosition)) { return null; } + return _selectWord(localPosition); } @@ -620,11 +629,20 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { if (_displayParagraphs.isNotEmpty) { final CodeLineRenderParagraph first = _displayParagraphs.first; if (position.index < first.index) { - _verticalViewport.jumpTo(first.top + _preferredLineHeight * (position.index - first.index)); + _verticalViewport.jumpTo( + first.top + _preferredLineHeight * (position.index - first.index), + ); } final CodeLineRenderParagraph last = _displayParagraphs.last; if (position.index > last.index) { - _verticalViewport.jumpTo(max(0, last.bottom - size.height + _preferredLineHeight * (position.index - first.index))); + _verticalViewport.jumpTo( + max( + 0, + last.bottom - + size.height + + _preferredLineHeight * (position.index - first.index), + ), + ); } } if (tryCount < 10) { @@ -632,26 +650,43 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { makePositionVisible(position, tryCount + 1); }); } + return; } if (offset.dy < 0) { _verticalViewport.jumpTo(_verticalViewport.pixels + offset.dy); } else if (offset.dy > size.height - _preferredLineHeight) { - _verticalViewport.jumpTo(_verticalViewport.pixels + offset.dy - (size.height - _preferredLineHeight)); + _verticalViewport.jumpTo( + _verticalViewport.pixels + + offset.dy - + (size.height - _preferredLineHeight), + ); } if (_horizontalViewport != null) { if (offset.dx < 0) { _horizontalViewport!.jumpTo(_horizontalViewport!.pixels + offset.dx); } else if (offset.dx > size.width - _preferredLineHeight) { - _horizontalViewport!.jumpTo(_horizontalViewport!.pixels + offset.dx - (size.width - _preferredLineHeight)); + _horizontalViewport!.jumpTo( + _horizontalViewport!.pixels + + offset.dx - + (size.width - _preferredLineHeight), + ); } } } - void makePositionCenterIfInvisible(CodeLinePosition position, {int tryCount = 0, bool animated = false}) { + void makePositionCenterIfInvisible( + CodeLinePosition position, { + int tryCount = 0, + bool animated = false, + }) { void scrollViewport(ViewportOffset viewport, num target) { if (animated) { - viewport.animateTo(target.toDouble(), duration: positionCenteringDuration, curve: Curves.decelerate); + viewport.animateTo( + target.toDouble(), + duration: positionCenteringDuration, + curve: Curves.decelerate, + ); } else { viewport.jumpTo(target.toDouble()); } @@ -662,14 +697,21 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { if (_displayParagraphs.isNotEmpty) { final CodeLineRenderParagraph first = _displayParagraphs.first; if (position.index < first.index) { - final target = max(0, first.top - _preferredLineHeight * (first.index - position.index) - size.height / 2); + final target = max( + 0, + first.top - + _preferredLineHeight * (first.index - position.index) - + size.height / 2, + ); scrollViewport(_verticalViewport, target); } final CodeLineRenderParagraph last = _displayParagraphs.last; if (position.index > last.index) { final target = min( _verticalViewportSize!, - last.bottom + size.height / 2 + _preferredLineHeight * (position.index - first.index), + last.bottom + + size.height / 2 + + _preferredLineHeight * (position.index - first.index), ); scrollViewport(_verticalViewport, target); } @@ -679,28 +721,41 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { makePositionCenterIfInvisible(position, tryCount: tryCount + 1); }); } + return; } if (offset.dy < 0) { - final target = max(0, _verticalViewport.pixels + offset.dy - size.height / 2); + final target = max( + 0, + _verticalViewport.pixels + offset.dy - size.height / 2, + ); scrollViewport(_verticalViewport, target); } else if (offset.dy > size.height - _preferredLineHeight) { final target = min( _verticalViewportSize!, - _verticalViewport.pixels + offset.dy + _preferredLineHeight - size.height / 2, + _verticalViewport.pixels + + offset.dy + + _preferredLineHeight - + size.height / 2, ); scrollViewport(_verticalViewport, target); } if (_horizontalViewport != null) { if (offset.dx < 0) { - final target = max(0, _horizontalViewport!.pixels + offset.dx - size.width / 2); + final target = max( + 0, + _horizontalViewport!.pixels + offset.dx - size.width / 2, + ); scrollViewport(_horizontalViewport!, target); } else if (offset.dx > size.width - _preferredLineHeight) { final target = min( _horizontalViewportSize!, - _horizontalViewport!.pixels + offset.dx + _preferredLineHeight - size.width / 2, + _horizontalViewport!.pixels + + offset.dx + + _preferredLineHeight - + size.width / 2, ); scrollViewport(_horizontalViewport!, target); } @@ -718,20 +773,18 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { final double unit = _preferredLineHeight; if (_verticalViewportSize != null) { if (offset.dy < unit) { - _alignTopEdge( - offset: _verticalViewport.pixels - unit - ); + _alignTopEdge(offset: _verticalViewport.pixels - unit); } else if (offset.dy > size.height - unit) { - _alignBottomEdge( - offset: _verticalViewport.pixels + unit - ); + _alignBottomEdge(offset: _verticalViewport.pixels + unit); } } if (_horizontalViewport != null && _horizontalViewportSize != null) { if (offset.dx < unit) { _horizontalViewport!.jumpTo(max(0, _horizontalViewport!.pixels - unit)); } else if (offset.dx > size.width - unit) { - _horizontalViewport!.jumpTo(min(_horizontalViewport!.pixels + unit, _horizontalViewportSize!)); + _horizontalViewport!.jumpTo( + min(_horizontalViewport!.pixels + unit, _horizontalViewportSize!), + ); } } } @@ -740,20 +793,19 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { final double unit = _preferredLineHeight; if (_verticalViewportSize != null) { if (offset.dy == paintBounds.top + paddingTop) { - _alignTopEdge( - offset: _verticalViewport.pixels - unit - ); - } else if (offset.dy == paintBounds.bottom - paddingBottom - floatingCursorHeight) { - _alignBottomEdge( - offset: _verticalViewport.pixels + unit - ); + _alignTopEdge(offset: _verticalViewport.pixels - unit); + } else if (offset.dy == + paintBounds.bottom - paddingBottom - floatingCursorHeight) { + _alignBottomEdge(offset: _verticalViewport.pixels + unit); } } if (_horizontalViewport != null && _horizontalViewportSize != null) { if (offset.dx < unit) { _horizontalViewport!.jumpTo(max(0, _horizontalViewport!.pixels - unit)); } else if (offset.dx > size.width - unit) { - _horizontalViewport!.jumpTo(min(_horizontalViewport!.pixels + unit, _horizontalViewportSize!)); + _horizontalViewport!.jumpTo( + min(_horizontalViewport!.pixels + unit, _horizontalViewportSize!), + ); } } } @@ -763,15 +815,20 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { if (!isValidPointer(localPosition)) { return -1; } - final int index = _chunkIndicators.indexWhere((chunk) => chunk.canExpand && chunk.region.contains(localPosition)); + final int index = _chunkIndicators.indexWhere( + (chunk) => chunk.canExpand && chunk.region.contains(localPosition), + ); if (index < 0) { return -1; } + return _chunkIndicators[index].index; } CodeLinePosition? getUpPosition(CodeLinePosition position) { - final CodeLineRenderParagraph? paragraph = findDisplayParagraphByLineIndex(position.index); + final CodeLineRenderParagraph? paragraph = findDisplayParagraphByLineIndex( + position.index, + ); if (paragraph == null) { return null; } @@ -780,10 +837,13 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { return null; } if (offset.dy > 0) { - return paragraph.getPosition(offset - Offset(0, paragraph.preferredLineHeight)); + return paragraph.getPosition( + offset - Offset(0, paragraph.preferredLineHeight), + ); } // The up position is not in this code line - IParagraph? upParagraph = findDisplayParagraphByLineIndex(position.index - 1)?.paragraph; + IParagraph? upParagraph = + findDisplayParagraphByLineIndex(position.index - 1)?.paragraph; if (upParagraph == null) { if (position.index > 0) { upParagraph = _buildParagraph(position.index - 1); @@ -791,14 +851,19 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { return null; } } + return CodeLinePosition.from( index: position.index - 1, - position: upParagraph.getPosition(Offset(offset.dx, upParagraph.height - upParagraph.preferredLineHeight)) + position: upParagraph.getPosition( + Offset(offset.dx, upParagraph.height - upParagraph.preferredLineHeight), + ), ); } CodeLinePosition? getDownPosition(CodeLinePosition position) { - final CodeLineRenderParagraph? paragraph = findDisplayParagraphByLineIndex(position.index); + final CodeLineRenderParagraph? paragraph = findDisplayParagraphByLineIndex( + position.index, + ); if (paragraph == null) { return null; } @@ -807,10 +872,13 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { return null; } if (offset.dy < paragraph.height - paragraph.preferredLineHeight) { - return paragraph.getPosition(offset + Offset(0, paragraph.preferredLineHeight)); + return paragraph.getPosition( + offset + Offset(0, paragraph.preferredLineHeight), + ); } // The up position is not in this code line - IParagraph? downParagraph = findDisplayParagraphByLineIndex(position.index + 1)?.paragraph; + IParagraph? downParagraph = + findDisplayParagraphByLineIndex(position.index + 1)?.paragraph; if (downParagraph == null) { if (position.index < _codes.length - 1) { downParagraph = _buildParagraph(position.index + 1); @@ -818,9 +886,10 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { return null; } } + return CodeLinePosition.from( index: position.index + 1, - position: downParagraph.getPosition(Offset(offset.dx, 0)) + position: downParagraph.getPosition(Offset(offset.dx, 0)), ); } @@ -837,24 +906,44 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { bool get validForMouseTracker => true; @override - bool hitTest(BoxHitTestResult result, { required Offset position }) { + bool hitTest(BoxHitTestResult result, {required Offset position}) { bool hitTarget = false; if (size.contains(position)) { result.add(BoxHitTestEntry(this, position)); - final CodeLineRenderParagraph? paragraph = _findDisplayRenderParagraph(position + paintOffset); - final InlineSpan? span = paragraph?.getSpanForPosition(position - paragraph.offset + paintOffset); + final CodeLineRenderParagraph? paragraph = _findDisplayRenderParagraph( + position + paintOffset, + ); + final InlineSpan? span = paragraph?.getSpanForPosition( + position - paragraph.offset + paintOffset, + ); if (span is MouseTrackerAnnotationTextSpan) { - result.add(HitTestEntry(_MouseTrackerAnnotationTextSpan( - id: paragraph!.index, - rects: paragraph.getRangeRects(paragraph.getRangeForSpan(span)).map((rect) { - return Rect.fromPoints(localToGlobal(rect.topLeft + paragraph.offset - paintOffset), localToGlobal(rect.bottomRight + paragraph.offset - paintOffset)); - }).toList(), - span: span, - ))); + result.add( + HitTestEntry( + _MouseTrackerAnnotationTextSpan( + id: paragraph!.index, + rects: + paragraph.getRangeRects(paragraph.getRangeForSpan(span)).map(( + rect, + ) { + return Rect.fromPoints( + localToGlobal( + rect.topLeft + paragraph.offset - paintOffset, + ), + localToGlobal( + rect.bottomRight + paragraph.offset - paintOffset, + ), + ); + }).toList(), + span: span, + ), + ), + ); } else if (span is HitTestTarget) { - result.add(HitTestEntry(span as HitTestTarget)); + result.add(HitTestEntry(span! as HitTestTarget)); } - if (_chunkIndicators.where((chunk) => chunk.canExpand && chunk.region.contains(position)).isNotEmpty) { + if (_chunkIndicators + .where((chunk) => chunk.canExpand && chunk.region.contains(position)) + .isNotEmpty) { _cursor = SystemMouseCursors.click; } else if (span is TextSpan && span.mouseCursor != MouseCursor.defer) { _cursor = span.mouseCursor; @@ -863,6 +952,7 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { } hitTarget = true; } + return hitTarget; } @@ -918,10 +1008,14 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { @override void performLayout() { // _Trace.begin('CodeField performLayout'); - assert(constraints.maxWidth > 0 && constraints.maxWidth != double.infinity, - '_CodeField should have an explicit width.'); - assert(constraints.maxHeight > 0 && constraints.maxHeight != double.infinity, - '_CodeField should have an explicit height.'); + assert( + constraints.maxWidth > 0 && constraints.maxWidth != double.infinity, + '_CodeField should have an explicit width.', + ); + assert( + constraints.maxHeight > 0 && constraints.maxHeight != double.infinity, + '_CodeField should have an explicit height.', + ); size = Size(constraints.maxWidth, constraints.maxHeight); _foregroundRender.layout(constraints); _backgroundRender.layout(constraints); @@ -940,7 +1034,9 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { final Canvas canvas = context.canvas; canvas.save(); - canvas.clipRect(Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height)); + canvas.clipRect( + Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height), + ); _drawText(canvas, offset); canvas.restore(); @@ -948,13 +1044,27 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { context.paintChild(_foregroundRender, offset); - final Offset? startHandlePosition = calculateTextPositionViewportOffset(_selection.start); + final Offset? startHandlePosition = calculateTextPositionViewportOffset( + _selection.start, + ); if (startHandlePosition != null) { - _drawHandleLayer(context, _startHandleLayerLink, startHandlePosition, offset + Offset(0, _preferredLineHeight)); + _drawHandleLayer( + context, + _startHandleLayerLink, + startHandlePosition, + offset + Offset(0, _preferredLineHeight), + ); } - final Offset? endHandlePosition = calculateTextPositionViewportOffset(_selection.end); + final Offset? endHandlePosition = calculateTextPositionViewportOffset( + _selection.end, + ); if (endHandlePosition != null) { - _drawHandleLayer(context, _endHandleLayerLink, endHandlePosition, offset + Offset(0, _preferredLineHeight)); + _drawHandleLayer( + context, + _endHandleLayerLink, + endHandlePosition, + offset + Offset(0, _preferredLineHeight), + ); } // _Trace.end('CodeField paint'); } @@ -968,15 +1078,21 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { CodeLinePosition? calculateTextPosition(Offset localPosition) { final Offset offset = localPosition + paintOffset; - final CodeLineRenderParagraph? target = _findDisplayRenderParagraph(offset, true); + final CodeLineRenderParagraph? target = _findDisplayRenderParagraph( + offset, + true, + ); if (target == null) { return null; } + return target.getPosition(offset - target.offset); } Offset? calculateTextPositionViewportOffset(CodeLinePosition position) { - final CodeLineRenderParagraph? paragraph = findDisplayParagraphByLineIndex(position.index); + final CodeLineRenderParagraph? paragraph = findDisplayParagraphByLineIndex( + position.index, + ); if (paragraph == null) { return null; } @@ -984,14 +1100,21 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { if (offset == null) { return null; } + return offset + paragraph.offset - paintOffset; } - Offset? calculateTextPositionScreenOffset(CodeLinePosition position, bool rightBottom) { + Offset? calculateTextPositionScreenOffset( + CodeLinePosition position, + bool rightBottom, + ) { final Offset? offset = calculateTextPositionViewportOffset(position); if (offset != null) { - return localToGlobal(rightBottom ? offset + Offset(0, _preferredLineHeight) : offset); + return localToGlobal( + rightBottom ? offset + Offset(0, _preferredLineHeight) : offset, + ); } + return null; } @@ -1009,13 +1132,19 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { if (target <= paddingTop) { startIndex = 0; } else { - startIndex = min(((target - paddingTop) / _preferredLineHeight).ceil(), _codes.length - 1); + startIndex = min( + ((target - paddingTop) / _preferredLineHeight).ceil(), + _codes.length - 1, + ); } - _displayParagraphs.addAll(_buildDisplayRenderParagraphs(startIndex, effectiveWidth)); + _displayParagraphs.addAll( + _buildDisplayRenderParagraphs(startIndex, effectiveWidth), + ); } else { if (_codes.length <= _displayParagraphs.first.index) { _displayParagraphs.clear(); _updateDisplayRenderParagraphs(); + return; } if (target < _displayParagraphs.first.top) { @@ -1033,7 +1162,9 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { } _verticalViewport.correctBy(delta); _displayParagraphs.clear(); - _displayParagraphs.addAll(_buildDisplayRenderParagraphs(startIndex, effectiveWidth)); + _displayParagraphs.addAll( + _buildDisplayRenderParagraphs(startIndex, effectiveWidth), + ); } else if (target > _displayParagraphs.last.bottom) { final int startIndex; if (target <= paddingTop) { @@ -1042,7 +1173,9 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { startIndex = (target / _preferredLineHeight).floor(); } _displayParagraphs.clear(); - _displayParagraphs.addAll(_buildDisplayRenderParagraphs(startIndex, effectiveWidth)); + _displayParagraphs.addAll( + _buildDisplayRenderParagraphs(startIndex, effectiveWidth), + ); } else { int startIndex = -1; double delta = 0; @@ -1053,37 +1186,62 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { } delta += paragraph.paragraph.height - _preferredLineHeight; } - assert(startIndex >= 0); + assert(startIndex >= 0, 'startIndex should be >= 0'); _verticalViewport.correctBy(-delta); _displayParagraphs.clear(); - _displayParagraphs.addAll(_buildDisplayRenderParagraphs(startIndex, effectiveWidth)); + _displayParagraphs.addAll( + _buildDisplayRenderParagraphs(startIndex, effectiveWidth), + ); } } // The codes length maybe changed, this will make the displayParagraphs empty. if (_displayParagraphs.isEmpty) { _updateDisplayRenderParagraphs(); + return; } - final double totalHeight = _displayParagraphs.last.bottom + (_codes.length - (_displayParagraphs.last.index + 1)) * _preferredLineHeight + paddingBottom; + final double totalHeight = + _displayParagraphs.last.bottom + + (_codes.length - (_displayParagraphs.last.index + 1)) * + _preferredLineHeight + + paddingBottom; _verticalViewportSize = max(0, totalHeight - size.height); if (_verticalViewport.pixels > _verticalViewportSize!) { - _verticalViewport.correctBy(_verticalViewportSize! - _verticalViewport.pixels); + _verticalViewport.correctBy( + _verticalViewportSize! - _verticalViewport.pixels, + ); } _verticalViewport.applyContentDimensions(0, _verticalViewportSize!); if (_horizontalViewport != null) { - final double maxWidth = _displayParagraphs.map((e) => e.width).reduce(max); - _horizontalViewportSize = max(0, maxWidth + _padding.horizontal - size.width); + final double maxWidth = _displayParagraphs + .map((e) => e.width) + .reduce(max); + _horizontalViewportSize = max( + 0, + maxWidth + _padding.horizontal - size.width, + ); _horizontalViewport!.applyContentDimensions(0, _horizontalViewportSize!); } // applyContentDimensions will change the _verticalViewport.pixels, we should rebuild. - if (_displayParagraphs.first.offset.dy > _verticalViewport.pixels + paddingTop) { + if (_displayParagraphs.first.offset.dy > + _verticalViewport.pixels + paddingTop) { _updateDisplayRenderParagraphs(); + return; } - _onRenderParagraphsChanged(_displayParagraphs.map((e) => e.copyWith( - offset: Offset(e.offset.dx - (_horizontalViewport?.pixels ?? 0) , e.offset.dy - _verticalViewport.pixels) - )).toList()); + _onRenderParagraphsChanged( + _displayParagraphs + .map( + (e) => e.copyWith( + offset: Offset( + e.offset.dx - (_horizontalViewport?.pixels ?? 0), + e.offset.dy - _verticalViewport.pixels, + ), + ), + ) + .toList(), + ); } void _drawText(Canvas canvas, Offset offset) { @@ -1100,20 +1258,34 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { canvas.restore(); } - void _drawChunkIndicatorIfNeeded(Canvas canvas, CodeLineRenderParagraph paragraph, Offset offset) { + void _drawChunkIndicatorIfNeeded( + Canvas canvas, + CodeLineRenderParagraph paragraph, + Offset offset, + ) { if (!paragraph.chunkParent && !paragraph.chunkLongText) { return; } - final Color? chunkIndicatorColor = _chunkIndicatorColor ?? _textStyle.color?.withAlpha(128); - if (chunkIndicatorColor == null || chunkIndicatorColor == Colors.transparent) { + final Color? chunkIndicatorColor = + _chunkIndicatorColor ?? _textStyle.color?.withAlpha(128); + if (chunkIndicatorColor == null || + chunkIndicatorColor == Colors.transparent) { return; } - final Offset? end = paragraph.getOffset(TextPosition(offset: paragraph.length)); + final Offset? end = paragraph.getOffset( + TextPosition(offset: paragraph.length), + ); if (end == null) { return; } - final Rect region = _drawChunkIndicator(canvas, chunkIndicatorColor, offset + end); - _chunkIndicators.add(_CodeChunkIndicator(region, paragraph.index, paragraph.chunkParent)); + final Rect region = _drawChunkIndicator( + canvas, + chunkIndicatorColor, + offset + end, + ); + _chunkIndicators.add( + _CodeChunkIndicator(region, paragraph.index, paragraph.chunkParent), + ); } Rect _drawChunkIndicator(Canvas canvas, Color color, Offset offset) { @@ -1124,14 +1296,29 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { const double interval = 3; canvas.drawCircle(offset + Offset(start, dy), radius, _paint); canvas.drawCircle(offset + Offset(start + interval, dy), radius, _paint); - canvas.drawCircle(offset + Offset(start + interval * 2, dy), radius, _paint); - return Rect.fromLTWH(offset.dx + start - radius, offset.dy, start + interval * 2 + radius, _preferredLineHeight); + canvas.drawCircle( + offset + Offset(start + interval * 2, dy), + radius, + _paint, + ); + + return Rect.fromLTWH( + offset.dx + start - radius, + offset.dy, + start + interval * 2 + radius, + _preferredLineHeight, + ); } - void _drawHandleLayer(PaintingContext context, LayerLink layer, Offset position, Offset offset) { + void _drawHandleLayer( + PaintingContext context, + LayerLink layer, + Offset position, + Offset offset, + ) { final Offset point = Offset( - clampDouble(position.dx, 0.0, size.width), - clampDouble(position.dy, 0.0, size.height), + clampDouble(position.dx, 0, size.width), + clampDouble(position.dy, 0, size.height), ); context.pushLayer( LeaderLayer(link: layer, offset: point + offset), @@ -1152,60 +1339,74 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { // _applyFloatingPointHack. Ideally, the rounding mismatch will be fixed and // this can be changed to be a strict check instead of an approximation. const double visibleRegionSlop = 0.5; - final Offset? startOffset = calculateTextPositionViewportOffset(_selection.start); + final Offset? startOffset = calculateTextPositionViewportOffset( + _selection.start, + ); if (startOffset == null) { _selectionStartInViewport.value = false; } else { _selectionStartInViewport.value = visibleRegion - .inflate(visibleRegionSlop) - .contains(startOffset); + .inflate(visibleRegionSlop) + .contains(startOffset); } - final Offset? endOffset = calculateTextPositionViewportOffset(_selection.end); + final Offset? endOffset = calculateTextPositionViewportOffset( + _selection.end, + ); if (endOffset == null) { _selectionEndInViewport.value = false; } else { _selectionEndInViewport.value = visibleRegion - .inflate(visibleRegionSlop) - .contains(endOffset.dy < 0 ? endOffset : endOffset + Offset(0, _preferredLineHeight)); + .inflate(visibleRegionSlop) + .contains( + endOffset.dy < 0 + ? endOffset + : endOffset + Offset(0, _preferredLineHeight), + ); } } void _calculatePreferredLineHeight() { - final TextPainter painter = TextPainter( - textDirection: TextDirection.ltr, - ); - painter.text = TextSpan( - text: '0', - style: _textStyle, - ); + final TextPainter painter = TextPainter(textDirection: TextDirection.ltr); + painter.text = TextSpan(text: '0', style: _textStyle); _preferredLineHeight = painter.preferredLineHeight; - _foregroundRender.find<_CodeFieldCursorPainter>().height = painter.preferredLineHeight; - _foregroundRender.find<_CodeFieldFloatingCursorPainter>().height = painter.preferredLineHeight; + _foregroundRender.find<_CodeFieldCursorPainter>().height = + painter.preferredLineHeight; + _foregroundRender.find<_CodeFieldFloatingCursorPainter>().height = + painter.preferredLineHeight; } void _onCursorVisibleChanged() { - _foregroundRender.find<_CodeFieldCursorPainter>().visible = _showCursorNotifier.value; + _foregroundRender.find<_CodeFieldCursorPainter>().visible = + _showCursorNotifier.value; } void _onFloatingCursorChanged() { - _foregroundRender.find<_CodeFieldFloatingCursorPainter>().position = _floatingCursorNotifier.value; + _foregroundRender.find<_CodeFieldFloatingCursorPainter>().position = + _floatingCursorNotifier.value; } bool isValidPointer(Offset localPosition) { - if (localPosition.dx <= 0 || localPosition.dx >= size.width - _verticalScrollbarWidth) { + if (localPosition.dx <= 0 || + localPosition.dx >= size.width - _verticalScrollbarWidth) { return false; } if (localPosition.dy <= 0) { return false; } - if (localPosition.dy >= size.height - ((_horizontalViewportSize ?? -1) <= 0 ? 0 : _horizontalScrollbarHeight)) { + if (localPosition.dy >= + size.height - + ((_horizontalViewportSize ?? -1) <= 0 + ? 0 + : _horizontalScrollbarHeight)) { return false; } + return true; } bool isValidPointer2(Offset globalPosition) { final Offset localPosition = globalToLocal(globalPosition); + return isValidPointer(localPosition); } @@ -1219,10 +1420,14 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { if (range.isCollapsed) { return null; } + return range; } - CodeLineRenderParagraph? _findDisplayRenderParagraph(Offset offset, [bool canOverflow = false]) { + CodeLineRenderParagraph? _findDisplayRenderParagraph( + Offset offset, [ + bool canOverflow = false, + ]) { for (final CodeLineRenderParagraph paragraph in _displayParagraphs) { if (paragraph.inVerticalRange(offset)) { return paragraph; @@ -1238,26 +1443,24 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { return bottom; } } + return null; } - void _alignTopEdge({ - double? offset - }) { + void _alignTopEdge({double? offset}) { final double position = offset ?? _verticalViewport.pixels; if (position < paddingTop) { _verticalViewport.jumpTo(max(position, 0)); } else { - final double scroll = position ~/ _preferredLineHeight * _preferredLineHeight + paddingTop; + final double scroll = + position ~/ _preferredLineHeight * _preferredLineHeight + paddingTop; if (scroll < _verticalViewport.pixels) { _verticalViewport.jumpTo(scroll); } } } - void _alignBottomEdge({ - double? offset - }) { + void _alignBottomEdge({double? offset}) { final double? viewportMax = _verticalViewportSize; if (viewportMax == null) { return; @@ -1266,31 +1469,42 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { if (position > viewportMax - paddingBottom) { _verticalViewport.jumpTo(min(position, viewportMax)); } else { - final double delta = (size.height / _preferredLineHeight).ceil() * _preferredLineHeight - size.height; - final double scroll = position ~/ _preferredLineHeight * _preferredLineHeight + delta + paddingTop; + final double delta = + (size.height / _preferredLineHeight).ceil() * _preferredLineHeight - + size.height; + final double scroll = + position ~/ _preferredLineHeight * _preferredLineHeight + + delta + + paddingTop; if (scroll > _verticalViewport.pixels) { _verticalViewport.jumpTo(min(scroll, viewportMax)); } } } - List _buildDisplayRenderParagraphs(int startIndex, double maxWidth) { + List _buildDisplayRenderParagraphs( + int startIndex, + double maxWidth, + ) { double offset = startIndex * _preferredLineHeight; final List paragraphs = []; for (int i = startIndex; i < _codes.length; i++) { final IParagraph paragraph = _buildParagraph(i, maxWidth); - _displayParagraphs.add(CodeLineRenderParagraph( - index: i, - paragraph: paragraph, - offset: Offset(paddingLeft, offset + paddingTop), - chunkParent: _codes[i].chunkParent, - chunkLongText: paragraph.trucated, - )); + _displayParagraphs.add( + CodeLineRenderParagraph( + index: i, + paragraph: paragraph, + offset: Offset(paddingLeft, offset + paddingTop), + chunkParent: _codes[i].chunkParent, + chunkLongText: paragraph.trucated, + ), + ); offset += paragraph.height; if (offset + paddingTop >= _verticalViewport.pixels + size.height) { break; } } + return paragraphs; } @@ -1298,36 +1512,31 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { return _highlighter.build( index: index, style: _textStyle, - maxWidth: maxWidth ?? (_horizontalViewport == null ? size.width - padding.horizontal : double.infinity), + maxWidth: + maxWidth ?? + (_horizontalViewport == null + ? size.width - padding.horizontal + : double.infinity), maxLengthSingleLineRendering: _maxLengthSingleLineRendering, ); } - } class _CodeChunkIndicator { - + const _CodeChunkIndicator(this.region, this.index, this.canExpand); final Rect region; final int index; final bool canExpand; - - const _CodeChunkIndicator(this.region, this.index, this.canExpand); } abstract class _CodeFieldExtraPainter extends ChangeNotifier { - void paint(Canvas canvas, Size size, _CodeFieldRender render); - } class _CodeFieldExtraRender extends RenderBox { - + _CodeFieldExtraRender({required this.painters}); final List<_CodeFieldExtraPainter> painters; - _CodeFieldExtraRender({ - required this.painters - }); - @override _CodeFieldRender? get parent => super.parent as _CodeFieldRender?; @@ -1340,11 +1549,13 @@ class _CodeFieldExtraRender extends RenderBox { @override void paint(PaintingContext context, Offset offset) { final _CodeFieldRender? parent = this.parent; - assert(parent != null); + assert(parent != null, 'parent should not be null'); // _Trace.begin('CodeField ExtraRender'); final Canvas canvas = context.canvas; canvas.save(); - canvas.clipRect(Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height)); + canvas.clipRect( + Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height), + ); for (final _CodeFieldExtraPainter painter in painters) { painter.paint(context.canvas, size, parent!); } @@ -1380,21 +1591,20 @@ class _CodeFieldExtraRender extends RenderBox { } } assert(result != null, 'Failed to find $T'); + return result!; } } class _CodeCursorLinePainter extends _CodeFieldExtraPainter { - - final Paint _paint; - Color? _color; - CodeLineSelection _selection; - _CodeCursorLinePainter(this._color, this._selection) : _paint = Paint() { _paint - ..style = PaintingStyle.stroke - ..strokeWidth = 1; + ..style = PaintingStyle.stroke + ..strokeWidth = 1; } + final Paint _paint; + Color? _color; + CodeLineSelection _selection; set color(Color? value) { if (_color == value) { @@ -1414,13 +1624,14 @@ class _CodeCursorLinePainter extends _CodeFieldExtraPainter { @override void paint(Canvas canvas, Size size, _CodeFieldRender render) { - if (_color == null || _color == Colors.transparent || _color!.alpha == 0) { + if (_color == null || _color == Colors.transparent || _color!.a == 0) { return; } if (!_selection.isCollapsed) { return; } - final CodeLineRenderParagraph? paragraph = render.findDisplayParagraphByLineIndex(_selection.extentIndex); + final CodeLineRenderParagraph? paragraph = render + .findDisplayParagraphByLineIndex(_selection.extentIndex); if (paragraph == null) { return; } @@ -1429,27 +1640,32 @@ class _CodeCursorLinePainter extends _CodeFieldExtraPainter { return; } offset += paragraph.offset - render.paintOffset; - if (offset.dy + paragraph.preferredLineHeight < 0 || offset.dy >= size.height) { + if (offset.dy + paragraph.preferredLineHeight < 0 || + offset.dy >= size.height) { return; } _paint.color = _color!; - canvas.drawLine(Offset(0, offset.dy), Offset(size.width, offset.dy), _paint); - canvas.drawLine(Offset(0, offset.dy + paragraph.preferredLineHeight), - Offset(size.width, offset.dy + paragraph.preferredLineHeight), _paint); + canvas.drawLine( + Offset(0, offset.dy), + Offset(size.width, offset.dy), + _paint, + ); + canvas.drawLine( + Offset(0, offset.dy + paragraph.preferredLineHeight), + Offset(size.width, offset.dy + paragraph.preferredLineHeight), + _paint, + ); } - } abstract class _CodeFieldSelectionsPainter extends _CodeFieldExtraPainter { - - static const Offset _newLinePadding = Offset(5.0, 0.0); + _CodeFieldSelectionsPainter(this._color, this._selections) : _paint = Paint(); + static const Offset _newLinePadding = Offset(5, 0); final Paint _paint; Color _color; List _selections; - _CodeFieldSelectionsPainter(this._color, this._selections) : _paint = Paint(); - set color(Color value) { if (_color == value) { return; @@ -1468,7 +1684,7 @@ abstract class _CodeFieldSelectionsPainter extends _CodeFieldExtraPainter { @override void paint(Canvas canvas, Size size, _CodeFieldRender render) { - if (_color == Colors.transparent || _color.alpha == 0) { + if (_color == Colors.transparent || _color.a == 0) { return; } final List paragraphs = render.displayParagraphs; @@ -1499,27 +1715,36 @@ abstract class _CodeFieldSelectionsPainter extends _CodeFieldExtraPainter { } final List rects; if (startIndex == endIndex) { - final Offset? offset = paragraph.getOffset(TextPosition(offset: startIndex)); + final Offset? offset = paragraph.getOffset( + TextPosition(offset: startIndex), + ); if (offset == null) { rects = const []; } else { rects = [ - Rect.fromLTWH(offset.dx, offset.dy, 0, paragraph.preferredLineHeight) + Rect.fromLTWH( + offset.dx, + offset.dy, + 0, + paragraph.preferredLineHeight, + ), ]; } } else { - rects = paragraph.getRangeRects(TextRange( - start: startIndex, - end: endIndex - )); + rects = paragraph.getRangeRects( + TextRange(start: startIndex, end: endIndex), + ); } if (rects.isEmpty) { continue; } for (final Rect rect in rects) { if (rect == rects.last && paragraph.index < end.index) { - _drawRect(canvas, Rect.fromPoints(rect.topLeft, rect.bottomRight + _newLinePadding), - paragraph.offset - render.paintOffset); + _drawRect( + canvas, + Rect.fromPoints(rect.topLeft, rect.bottomRight + _newLinePadding), + paragraph.offset - render.paintOffset, + ); } else if (!rect.isEmpty) { _drawRect(canvas, rect, paragraph.offset - render.paintOffset); } @@ -1530,38 +1755,27 @@ abstract class _CodeFieldSelectionsPainter extends _CodeFieldExtraPainter { void _drawRect(Canvas canvas, Rect rect, Offset offset) { _paint.color = _color; - canvas.drawRect(Rect.fromPoints(rect.topLeft + offset, rect.bottomRight + offset), _paint); + canvas.drawRect( + Rect.fromPoints(rect.topLeft + offset, rect.bottomRight + offset), + _paint, + ); } - } class _CodeFieldSelectionPainter extends _CodeFieldSelectionsPainter { - - _CodeFieldSelectionPainter(Color color, CodeLineSelection selection) : - super(color, [selection]); + _CodeFieldSelectionPainter(Color color, CodeLineSelection selection) + : super(color, [selection]); set selection(CodeLineSelection value) { selections = [value]; } - } class _CodeFieldHighlightPainter extends _CodeFieldSelectionsPainter { - _CodeFieldHighlightPainter(super.color, super.selections); - } class _CodeFieldCursorPainter extends _CodeFieldExtraPainter { - - final Paint _paint; - CodeLinePosition _position; - Color _color; - double _width; - double _height; - bool _visible; - bool _willDraw; - _CodeFieldCursorPainter({ required CodeLinePosition position, required Color color, @@ -1569,12 +1783,19 @@ class _CodeFieldCursorPainter extends _CodeFieldExtraPainter { required double height, required bool visible, }) : _position = position, - _color = color, - _width = width, - _height = height, - _visible = visible, - _willDraw = true, - _paint = Paint(); + _color = color, + _width = width, + _height = height, + _visible = visible, + _willDraw = true, + _paint = Paint(); + final Paint _paint; + CodeLinePosition _position; + Color _color; + double _width; + double _height; + bool _visible; + bool _willDraw; set position(CodeLinePosition value) { if (_position == value) { @@ -1628,10 +1849,14 @@ class _CodeFieldCursorPainter extends _CodeFieldExtraPainter { @override void paint(Canvas canvas, Size size, _CodeFieldRender render) { - if (!_visible || !_willDraw || _color == Colors.transparent || _color.alpha == 0) { + if (!_visible || + !_willDraw || + _color == Colors.transparent || + _color.a == 0) { return; } - final CodeLineRenderParagraph? paragraph = render.findDisplayParagraphByLineIndex(_position.index); + final CodeLineRenderParagraph? paragraph = render + .findDisplayParagraphByLineIndex(_position.index); if (paragraph == null) { return; } @@ -1640,7 +1865,10 @@ class _CodeFieldCursorPainter extends _CodeFieldExtraPainter { return; } offset += paragraph.offset - render.paintOffset; - if (offset.dx + _width < 0 || offset.dx >= size.width || offset.dy + _height < 0 || offset.dy >= size.height) { + if (offset.dx + _width < 0 || + offset.dx >= size.width || + offset.dy + _height < 0 || + offset.dy >= size.height) { return; } _drawCaret(canvas, offset, size); @@ -1648,29 +1876,33 @@ class _CodeFieldCursorPainter extends _CodeFieldExtraPainter { void _drawCaret(Canvas canvas, Offset offset, Size size) { _paint.color = _color; - canvas.drawRRect(RRect.fromRectXY(Rect.fromLTWH(offset.dx - _width / 2, offset.dy, _width, _height), _width / 2, _width / 2), _paint); + canvas.drawRRect( + RRect.fromRectXY( + Rect.fromLTWH(offset.dx - _width / 2, offset.dy, _width, _height), + _width / 2, + _width / 2, + ), + _paint, + ); } - } class _CodeFieldFloatingCursorPainter extends _CodeFieldExtraPainter { - - final Paint _paint; - _FloatingCursorState _position; - Color _color; - double _width; - double _height; - _CodeFieldFloatingCursorPainter({ required _FloatingCursorState position, required Color color, required double width, required double height, }) : _position = position, - _color = color, - _width = width, - _height = height, - _paint = Paint(); + _color = color, + _width = width, + _height = height, + _paint = Paint(); + final Paint _paint; + _FloatingCursorState _position; + Color _color; + double _width; + double _height; set position(_FloatingCursorState value) { if (_position == value) { @@ -1710,7 +1942,9 @@ class _CodeFieldFloatingCursorPainter extends _CodeFieldExtraPainter { @override void paint(Canvas canvas, Size size, _CodeFieldRender render) { - if (!_position.isActive() || _color == Colors.transparent || _color.alpha == 0) { + if (!_position.isActive() || + _color == Colors.transparent || + _color.a == 0) { return; } _drawFloatingCaret(canvas, _position.floatingCursorOffset!, size); @@ -1727,20 +1961,28 @@ class _CodeFieldFloatingCursorPainter extends _CodeFieldExtraPainter { ); final path = Path()..addRRect(caretRect); - canvas.drawShadow( - path, - Colors.black, - 4.0, - true, - ); + canvas.drawShadow(path, Colors.black, 4, true); _paint.color = _color; - canvas.drawRRect(RRect.fromRectXY(Rect.fromLTWH(offset.dx - _width / 2, offset.dy, _width, _height), _width / 2, _width / 2), _paint); + canvas.drawRRect( + RRect.fromRectXY( + Rect.fromLTWH(offset.dx - _width / 2, offset.dy, _width, _height), + _width / 2, + _width / 2, + ), + _paint, + ); } void _drawPreviewCursor(Canvas canvas, Offset offset, Size size) { _paint.color = _color.withAlpha(150); - canvas.drawRRect(RRect.fromRectXY(Rect.fromLTWH(offset.dx - _width / 2, offset.dy, _width, _height), _width / 2, _width / 2), _paint); + canvas.drawRRect( + RRect.fromRectXY( + Rect.fromLTWH(offset.dx - _width / 2, offset.dy, _width, _height), + _width / 2, + _width / 2, + ), + _paint, + ); } - } diff --git a/lib/src/_code_find.dart b/lib/src/_code_find.dart index 132ddbf..4ddef5d 100644 --- a/lib/src/_code_find.dart +++ b/lib/src/_code_find.dart @@ -1,19 +1,20 @@ -part of re_editor; - -class _CodeFindControllerImpl extends ValueNotifier implements CodeFindController { - - late final CodeLineEditingController _controller; - late final _IsolateTasker<_CodeFindPayload, CodeFindResult?> _tasker; - late final TextEditingController _findInputController; - late final FocusNode _findInputFocusNode; - late final TextEditingController _replaceInputController; - late final FocusNode _replaceInputFocusNode; - late bool _shouldNotUpdateResults; - - _CodeFindControllerImpl(CodeLineEditingController controller, [CodeFindValue? value]) : super(value) { - _controller = controller is _CodeLineEditingControllerDelegate ? controller.delegate : controller; +part of 're_editor.dart'; + +class _CodeFindControllerImpl extends ValueNotifier + implements CodeFindController { + _CodeFindControllerImpl( + CodeLineEditingController controller, [ + CodeFindValue? value, + ]) : super(value) { + _controller = + controller is _CodeLineEditingControllerDelegate + ? controller.delegate + : controller; _controller.addListener(_updateResult); - _tasker = _IsolateTasker<_CodeFindPayload, CodeFindResult?>('CodeFind', _run); + _tasker = _IsolateTasker<_CodeFindPayload, CodeFindResult?>( + 'CodeFind', + _run, + ); _findInputController = TextEditingController(); _findInputController.addListener(_onFindPatternChanged); _findInputFocusNode = FocusNode(); @@ -22,6 +23,13 @@ class _CodeFindControllerImpl extends ValueNotifier implements C _shouldNotUpdateResults = false; _updateResult(); } + late final CodeLineEditingController _controller; + late final _IsolateTasker<_CodeFindPayload, CodeFindResult?> _tasker; + late final TextEditingController _findInputController; + late final FocusNode _findInputFocusNode; + late final TextEditingController _replaceInputController; + late final FocusNode _replaceInputFocusNode; + late bool _shouldNotUpdateResults; @override void dispose() { @@ -64,6 +72,7 @@ class _CodeFindControllerImpl extends ValueNotifier implements C } selections.add(selection); } + return selections; } @@ -76,6 +85,7 @@ class _CodeFindControllerImpl extends ValueNotifier implements C if (value!.result!.dirty) { return null; } + return convertMatchToSelection(currentMatch); } @@ -89,23 +99,21 @@ class _CodeFindControllerImpl extends ValueNotifier implements C text: autoFilled, selection: TextSelection( baseOffset: 0, - extentOffset: autoFilled.length - ) + extentOffset: autoFilled.length, + ), ); } else { _findInputController.selection = TextSelection( baseOffset: 0, - extentOffset: _findInputController.text.length + extentOffset: _findInputController.text.length, ); } _findInputController.addListener(_onFindPatternChanged); final CodeFindValue preValue = value ?? const CodeFindValue.empty(); value = preValue.copyWith( - option: preValue.option.copyWith( - pattern: _findInputController.text - ), + option: preValue.option.copyWith(pattern: _findInputController.text), result: null, - searching: true + searching: true, ); _updateResult(); } @@ -120,24 +128,22 @@ class _CodeFindControllerImpl extends ValueNotifier implements C text: autoFilled, selection: TextSelection( baseOffset: 0, - extentOffset: autoFilled.length - ) + extentOffset: autoFilled.length, + ), ); } else { _findInputController.selection = TextSelection( baseOffset: 0, - extentOffset: _findInputController.text.length + extentOffset: _findInputController.text.length, ); } _findInputController.addListener(_onFindPatternChanged); final CodeFindValue preValue = value ?? const CodeFindValue.empty(); value = preValue.copyWith( - option: preValue.option.copyWith( - pattern: _findInputController.text, - ), + option: preValue.option.copyWith(pattern: _findInputController.text), replaceMode: true, result: null, - searching: true + searching: true, ); _updateResult(); } @@ -147,7 +153,7 @@ class _CodeFindControllerImpl extends ValueNotifier implements C _findInputFocusNode.requestFocus(); _findInputController.selection = TextSelection( baseOffset: 0, - extentOffset: _findInputController.text.length + extentOffset: _findInputController.text.length, ); } @@ -156,7 +162,7 @@ class _CodeFindControllerImpl extends ValueNotifier implements C _replaceInputFocusNode.requestFocus(); _replaceInputController.selection = TextSelection( baseOffset: 0, - extentOffset: _replaceInputController.text.length + extentOffset: _replaceInputController.text.length, ); } @@ -168,7 +174,7 @@ class _CodeFindControllerImpl extends ValueNotifier implements C } value = preValue.copyWith( replaceMode: !preValue.replaceMode, - result: preValue.result + result: preValue.result, ); } @@ -184,11 +190,9 @@ class _CodeFindControllerImpl extends ValueNotifier implements C return; } value = value?.copyWith( - option: option.copyWith( - regex: !option.regex, - ), + option: option.copyWith(regex: !option.regex), result: null, - searching: true + searching: true, ); _updateResult(); } @@ -200,11 +204,9 @@ class _CodeFindControllerImpl extends ValueNotifier implements C return; } value = value?.copyWith( - option: option.copyWith( - caseSensitive: !option.caseSensitive, - ), + option: option.copyWith(caseSensitive: !option.caseSensitive), result: null, - searching: true + searching: true, ); _updateResult(); } @@ -215,9 +217,7 @@ class _CodeFindControllerImpl extends ValueNotifier implements C if (result == null || result.dirty) { return; } - final CodeFindValue newValue = value!.copyWith( - result: result.previous - ); + final CodeFindValue newValue = value!.copyWith(result: result.previous); _expandChunkIfNeeded(newValue); value = newValue; if (result.matches.length == 1) { @@ -234,9 +234,7 @@ class _CodeFindControllerImpl extends ValueNotifier implements C if (result == null || result.dirty) { return; } - final CodeFindValue newValue = value!.copyWith( - result: result.next - ); + final CodeFindValue newValue = value!.copyWith(result: result.next); _expandChunkIfNeeded(newValue); value = newValue; if (result.matches.length == 1) { @@ -264,8 +262,8 @@ class _CodeFindControllerImpl extends ValueNotifier implements C _controller.replaceSelection(_replaceInputController.text, selection); final CodeFindValue newValue = value!.copyWith( result: result.next.copyWith( - dirty: !preCodeLine.equals(_controller.codeLines) - ) + dirty: !preCodeLine.equals(_controller.codeLines), + ), ); _expandChunkIfNeeded(newValue); value = newValue; @@ -289,14 +287,16 @@ class _CodeFindControllerImpl extends ValueNotifier implements C _controller.replaceAll(regExp, _replaceInputController.text); value = value?.copyWith( result: result.copyWith( - dirty: !preCodeLine.equals(_controller.codeLines) - ) + dirty: !preCodeLine.equals(_controller.codeLines), + ), ); } @override CodeLineSelection? convertMatchToSelection(CodeLineSelection match) { - final CodeLineIndex baseIndex = _controller.lineIndex2Index(match.baseIndex); + final CodeLineIndex baseIndex = _controller.lineIndex2Index( + match.baseIndex, + ); if (baseIndex.chunkIndex >= 0) { // This match is in a collapsed chunk, invisble return null; @@ -311,9 +311,10 @@ class _CodeFindControllerImpl extends ValueNotifier implements C // This match is in a collapsed chunk, invisble return null; } + return match.copyWith( baseIndex: baseIndex.index, - extentIndex: extentIndex.index + extentIndex: extentIndex.index, ); } @@ -326,11 +327,9 @@ class _CodeFindControllerImpl extends ValueNotifier implements C return; } value = value?.copyWith( - option: option.copyWith( - pattern: _findInputController.text, - ), + option: option.copyWith(pattern: _findInputController.text), result: null, - searching: true + searching: true, ); _updateResult(); } @@ -340,6 +339,7 @@ class _CodeFindControllerImpl extends ValueNotifier implements C if (selection.isCollapsed || !selection.isSameLine) { return null; } + return _controller.selectedText; } @@ -349,37 +349,38 @@ class _CodeFindControllerImpl extends ValueNotifier implements C } final CodeFindOption? option = value?.option; if (option == null || option.pattern.isEmpty) { - value = value?.copyWith( - result: null, - searching: false - ); + value = value?.copyWith(result: null, searching: false); + return; } final bool optionChanged = value?.result?.option != option; - if (!optionChanged && _controller.codeLines.equals(value?.result?.codeLines)) { - value = value?.copyWith( - result: value?.result, - searching: false - ); + if (!optionChanged && + _controller.codeLines.equals(value?.result?.codeLines)) { + value = value?.copyWith(result: value?.result, searching: false); + return; } - _tasker.run(_CodeFindPayload(_controller.codeLines, _controller.unforldLineSelection, option), (result) { - if (option == value?.option) { - final CodeFindValue newValue = value!.copyWith( - result: result, - searching: false - ); - if (optionChanged) { - _expandChunkIfNeeded(newValue); + _tasker.run( + _CodeFindPayload( + _controller.codeLines, + _controller.unforldLineSelection, + option, + ), + (result) { + if (option == value?.option) { + final CodeFindValue newValue = value!.copyWith( + result: result, + searching: false, + ); + if (optionChanged) { + _expandChunkIfNeeded(newValue); + } + value = newValue; + } else { + value = value?.copyWith(result: null, searching: false); } - value = newValue; - } else { - value = value?.copyWith( - result: null, - searching: false - ); - } - }); + }, + ); } void _expandChunkIfNeeded(CodeFindValue value) { @@ -419,11 +420,17 @@ class _CodeFindControllerImpl extends ValueNotifier implements C if (regExp == null) { return null; } - final List rawCodeLines = payload.codeLines.toList().fold([], (previousValue, element) { + final List rawCodeLines = payload.codeLines.toList().fold([], ( + previousValue, + element, + ) { previousValue.addAll(element.flat()); + return previousValue; }); - final Iterable matches = regExp.allMatches(rawCodeLines.join(TextLineBreak.lf.value)); + final Iterable matches = regExp.allMatches( + rawCodeLines.join(TextLineBreak.lf.value), + ); if (matches.isEmpty) { return null; } @@ -431,32 +438,38 @@ class _CodeFindControllerImpl extends ValueNotifier implements C for (final Match match in matches) { final CodeLinePosition start = _findPosition(rawCodeLines, match.start); final CodeLinePosition end = _findPosition(rawCodeLines, match.end); - selections.add(CodeLineSelection( - baseIndex: start.index, - baseOffset: start.offset, - extentIndex: end.index, - extentOffset: end.offset - )); + selections.add( + CodeLineSelection( + baseIndex: start.index, + baseOffset: start.offset, + extentIndex: end.index, + extentOffset: end.offset, + ), + ); } int index = selections.length - 1; for (; index > 0; index--) { if (selections[index].contains(payload.unforldLineSelection)) { break; } - if (selections[index].endIndex < payload.unforldLineSelection.startIndex) { + if (selections[index].endIndex < + payload.unforldLineSelection.startIndex) { break; } - if (selections[index].endIndex == payload.unforldLineSelection.startIndex && - selections[index].endOffset <= payload.unforldLineSelection.startOffset) { + if (selections[index].endIndex == + payload.unforldLineSelection.startIndex && + selections[index].endOffset <= + payload.unforldLineSelection.startOffset) { break; } } + return CodeFindResult( index: index, matches: selections, option: payload.option, codeLines: payload.codeLines, - dirty: false + dirty: false, ); } @@ -471,20 +484,18 @@ class _CodeFindControllerImpl extends ValueNotifier implements C } start += codeLines[line].length + 1; } - return CodeLinePosition( - index: line, - offset: offset - ); - } + return CodeLinePosition(index: line, offset: offset); + } } class _CodeFindPayload { - + const _CodeFindPayload( + this.codeLines, + this.unforldLineSelection, + this.option, + ); final CodeLines codeLines; final CodeLineSelection unforldLineSelection; final CodeFindOption option; - - const _CodeFindPayload(this.codeLines, this.unforldLineSelection, this.option); - -} \ No newline at end of file +} diff --git a/lib/src/_code_floating_cursor.dart b/lib/src/_code_floating_cursor.dart index caa31b7..ec88a91 100644 --- a/lib/src/_code_floating_cursor.dart +++ b/lib/src/_code_floating_cursor.dart @@ -1,4 +1,4 @@ -part of re_editor; +part of 're_editor.dart'; // The time the animation of the floating cursor snapping to the final cursor position will take. const Duration floatingCursorSnapDuration = Duration(milliseconds: 300); @@ -6,18 +6,18 @@ const Duration floatingCursorSnapDuration = Duration(milliseconds: 300); // Class containing the floating cursor control logic. class _CodeFloatingCursorController extends ValueNotifier<_FloatingCursorState> { + _CodeFloatingCursorController() : super(const _FloatingCursorState()); late final _CodeCursorBlinkController _blinkController; late final AnimationController _animationController; - _CodeFloatingCursorController() : super(const _FloatingCursorState()); - /// Sets the [Offset] and [CodeLineSelection] of the cursors. Setting either one of these offsets /// to null is equivalent to turning off the corresponding cursor. - void setFloatingCursorPositions( - {Offset? floatingCursorOffset, - Offset? previewCursorOffset, - Offset? finalCursorOffset, - CodeLineSelection? finalCursorSelection}) { + void setFloatingCursorPositions({ + Offset? floatingCursorOffset, + Offset? previewCursorOffset, + Offset? finalCursorOffset, + CodeLineSelection? finalCursorSelection, + }) { if (value.floatingCursorOffset != null && floatingCursorOffset == null) { // Starting the floating cursor, stop blinking of the normal cursor _blinkController.startBlink(); @@ -51,24 +51,36 @@ class _CodeFloatingCursorController disableFloatingCursor(); } else { final double lerpValue = _animationController.value; - final double lerpX = ui.lerpDouble(value.floatingCursorOffset!.dx, - value.finalCursorOffset!.dx, lerpValue)!; - final double lerpY = ui.lerpDouble(value.floatingCursorOffset!.dy, - value.finalCursorOffset!.dy, lerpValue)!; + final double lerpX = + ui.lerpDouble( + value.floatingCursorOffset!.dx, + value.finalCursorOffset!.dx, + lerpValue, + )!; + final double lerpY = + ui.lerpDouble( + value.floatingCursorOffset!.dy, + value.finalCursorOffset!.dy, + lerpValue, + )!; setFloatingCursorPositions( - floatingCursorOffset: Offset(lerpX, lerpY), - previewCursorOffset: value.previewCursorOffset, - finalCursorOffset: value.finalCursorOffset, - finalCursorSelection: value.finalCursorSelection); + floatingCursorOffset: Offset(lerpX, lerpY), + previewCursorOffset: value.previewCursorOffset, + finalCursorOffset: value.finalCursorOffset, + finalCursorSelection: value.finalCursorSelection, + ); } } /// Performs the "snapping" animation and turns of the floating cursor. void animateDisableFloatingCursor() { _animationController.value = 0.0; - _animationController.animateTo(1, - duration: floatingCursorSnapDuration, curve: Curves.decelerate); + _animationController.animateTo( + 1, + duration: floatingCursorSnapDuration, + curve: Curves.decelerate, + ); } @override @@ -95,6 +107,13 @@ class _CodeFloatingCursorController } class _FloatingCursorState { + const _FloatingCursorState({ + this.floatingCursorOffset, + this.previewCursorOffset, + this.finalCursorOffset, + this.finalCursorSelection, + }); + /// The offset of the floating cursor. final Offset? floatingCursorOffset; @@ -108,12 +127,6 @@ class _FloatingCursorState { final CodeLineSelection? finalCursorSelection; - const _FloatingCursorState( - {this.floatingCursorOffset, - this.previewCursorOffset, - this.finalCursorOffset, - this.finalCursorSelection}); - /// Creates a copy of this instance with the specified values overridden. _FloatingCursorState copyWith({ Offset? floatingCursorOffset, @@ -144,6 +157,10 @@ class _FloatingCursorState { finalCursorSelection == other.finalCursorSelection); @override - int get hashCode => Object.hash(floatingCursorOffset, previewCursorOffset, - finalCursorOffset, finalCursorSelection); + int get hashCode => Object.hash( + floatingCursorOffset, + previewCursorOffset, + finalCursorOffset, + finalCursorSelection, + ); } diff --git a/lib/src/_code_formatter.dart b/lib/src/_code_formatter.dart index 9c19820..7f6cecb 100644 --- a/lib/src/_code_formatter.dart +++ b/lib/src/_code_formatter.dart @@ -1,44 +1,48 @@ -part of re_editor; +part of 're_editor.dart'; class _DefaultCodeCommentFormatter implements DefaultCodeCommentFormatter { - - final String? singleLinePrefix; - final String? multiLinePrefix; - final String? multiLineSuffix; - const _DefaultCodeCommentFormatter({ this.singleLinePrefix, this.multiLinePrefix, - this.multiLineSuffix + this.multiLineSuffix, }); + final String? singleLinePrefix; + final String? multiLinePrefix; + final String? multiLineSuffix; @override - CodeLineEditingValue format(CodeLineEditingValue value, String indent, bool single) { + CodeLineEditingValue format( + CodeLineEditingValue value, + String indent, + bool single, + ) { if (single && (singleLinePrefix == null || singleLinePrefix!.isEmpty)) { return value; } - if (!single && (multiLinePrefix == null || multiLinePrefix!.isEmpty) && (multiLineSuffix == null || multiLineSuffix!.isEmpty)) { + if (!single && + (multiLinePrefix == null || multiLinePrefix!.isEmpty) && + (multiLineSuffix == null || multiLineSuffix!.isEmpty)) { return value; } final _DefaultCommentFormatter formatter; if (single) { formatter = _DefaultSingleLineCommentFormatter(singleLinePrefix!); } else { - formatter = _DefaultMultiLineCommentFormatter(multiLinePrefix!, multiLineSuffix!); + formatter = _DefaultMultiLineCommentFormatter( + multiLinePrefix!, + multiLineSuffix!, + ); } + return formatter.format(value, indent); } - } abstract class _DefaultCommentFormatter { - - final String symbol; - const _DefaultCommentFormatter(this.symbol); + final String symbol; CodeLineEditingValue format(CodeLineEditingValue value, String indent); - } class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { @@ -54,8 +58,12 @@ class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { } } - CodeLineEditingValue _formatSelectedCodeLine(CodeLineEditingValue value, String indent) { - final String trimCode = value.codeLines[value.selection.baseIndex].text.trimLeft(); + CodeLineEditingValue _formatSelectedCodeLine( + CodeLineEditingValue value, + String indent, + ) { + final String trimCode = + value.codeLines[value.selection.baseIndex].text.trimLeft(); if (trimCode.startsWith('$symbol ')) { return _uncommentSelectedCodeLine(value, '$symbol '); } else if (trimCode.startsWith(symbol)) { @@ -65,7 +73,10 @@ class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { } } - CodeLineEditingValue _uncommentSelectedCodeLine(CodeLineEditingValue value, String prefix) { + CodeLineEditingValue _uncommentSelectedCodeLine( + CodeLineEditingValue value, + String prefix, + ) { final CodeLineSelection selection = value.selection; final CodeLines codeLines = value.codeLines; final int lineIndex = selection.baseIndex; @@ -73,7 +84,9 @@ class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { final int index = codeLine.text.indexOf(prefix); final CodeLines newCodeLines = CodeLines.from(codeLines); newCodeLines[lineIndex] = codeLine.copyWith( - text: codeLine.text.substring(0, index) + codeLine.text.substring(index + prefix.length) + text: + codeLine.text.substring(0, index) + + codeLine.text.substring(index + prefix.length), ); int relocation(int offset) { if (offset <= index) { @@ -82,16 +95,21 @@ class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { return max(index, offset - prefix.length); } } + return value.copyWith( codeLines: newCodeLines, selection: selection.copyWith( baseOffset: relocation(selection.baseOffset), extentOffset: relocation(selection.extentOffset), - ) + ), ); } - CodeLineEditingValue _commentSelectedCodeLine(CodeLineEditingValue value, String indent, String prefix) { + CodeLineEditingValue _commentSelectedCodeLine( + CodeLineEditingValue value, + String indent, + String prefix, + ) { final CodeLineSelection selection = value.selection; final CodeLines codeLines = value.codeLines; final int lineIndex = selection.baseIndex; @@ -99,7 +117,7 @@ class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { final int index = codeLine.text.getOffsetWithoutIndent(indent); final CodeLines newCodeLines = CodeLines.from(codeLines); newCodeLines[lineIndex] = codeLine.copyWith( - text: codeLine.text.insert(prefix, index) + text: codeLine.text.insert(prefix, index), ); final int baseOffset; final int extentOffset; @@ -126,16 +144,20 @@ class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { extentOffset = selection.extentOffset; } } + return value.copyWith( codeLines: newCodeLines, selection: selection.copyWith( baseOffset: baseOffset, extentOffset: extentOffset, - ) + ), ); } - CodeLineEditingValue _formatSelectedCodeLines(CodeLineEditingValue value, String indent) { + CodeLineEditingValue _formatSelectedCodeLines( + CodeLineEditingValue value, + String indent, + ) { final CodeLineSelection selection = value.selection; final CodeLines codeLines = value.codeLines; final List texts = []; @@ -156,7 +178,11 @@ class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { } } - CodeLineEditingValue _commentSelectedCodeLines(CodeLineEditingValue value, String indent, String prefix) { + CodeLineEditingValue _commentSelectedCodeLines( + CodeLineEditingValue value, + String indent, + String prefix, + ) { final CodeLineSelection selection = value.selection; final CodeLines codeLines = value.codeLines; int? index; @@ -183,14 +209,15 @@ class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { } final newChunks = _commentChunks(codeLine, prefix, index); newCodeLines[i] = codeLine.copyWith( - text: codeLine.text.insert(prefix, index), - chunks: newChunks + text: codeLine.text.insert(prefix, index), + chunks: newChunks, ); } final int baseOffset; final int extentOffset; if (selection.baseIndex < selection.extentIndex) { - if (selection.baseOffset < index || newCodeLines[selection.baseIndex].text.isEmpty) { + if (selection.baseOffset < index || + newCodeLines[selection.baseIndex].text.isEmpty) { baseOffset = selection.baseOffset; } else { baseOffset = selection.baseOffset + prefix.length; @@ -206,23 +233,25 @@ class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { } else { baseOffset = selection.baseOffset + prefix.length; } - if (selection.extentOffset < index || newCodeLines[selection.extentIndex].text.isEmpty) { + if (selection.extentOffset < index || + newCodeLines[selection.extentIndex].text.isEmpty) { extentOffset = selection.extentOffset; } else { extentOffset = selection.extentOffset + prefix.length; } } + return value.copyWith( codeLines: newCodeLines, selection: selection.copyWith( baseOffset: baseOffset, extentOffset: extentOffset, - ) + ), ); } List _commentChunks(CodeLine codeLine, String prefix, int index) { - final List newCodeChunks = List.from(codeLine.chunks); + final List newCodeChunks = List.of(codeLine.chunks); for (int j = 0; j < newCodeChunks.length; j++) { final CodeLine codeLineChunk = newCodeChunks[j]; if (codeLineChunk.text.isEmpty) { @@ -230,13 +259,19 @@ class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { } final newCodeLineChunks = _commentChunks(codeLineChunk, prefix, index); newCodeChunks[j] = codeLineChunk.copyWith( - text: codeLineChunk.text.insert(prefix, index), - chunks: newCodeLineChunks); + text: codeLineChunk.text.insert(prefix, index), + chunks: newCodeLineChunks, + ); } + return newCodeChunks; } - CodeLineEditingValue _uncommentSelectedCodeLines(CodeLineEditingValue value, String indent, String prefix) { + CodeLineEditingValue _uncommentSelectedCodeLines( + CodeLineEditingValue value, + String indent, + String prefix, + ) { final CodeLineSelection selection = value.selection; final CodeLines newCodeLines = CodeLines.from(value.codeLines); int? baseOffset; @@ -256,8 +291,10 @@ class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { final int index = codeLine.text.indexOf(deletion); final codeChunks = _uncommentChunks(codeLine, deletion, index); newCodeLines[i] = codeLine.copyWith( - text: codeLine.text.substring(0, index) + codeLine.text.substring(index + deletion.length), - chunks: codeChunks + text: + codeLine.text.substring(0, index) + + codeLine.text.substring(index + deletion.length), + chunks: codeChunks, ); if (i == selection.baseIndex) { if (selection.baseOffset > index) { @@ -270,41 +307,50 @@ class _DefaultSingleLineCommentFormatter extends _DefaultCommentFormatter { } } } + return value.copyWith( codeLines: newCodeLines, selection: selection.copyWith( baseOffset: baseOffset, extentOffset: extentOffset, - ) + ), ); } List _uncommentChunks( - CodeLine codeLine, String deletion, int index) { - final List newCodeChunks = List.from(codeLine.chunks); + CodeLine codeLine, + String deletion, + int index, + ) { + final List newCodeChunks = List.of(codeLine.chunks); for (int j = 0; j < newCodeChunks.length; j++) { final CodeLine codeLineChunk = newCodeChunks[j]; if (codeLineChunk.text.isEmpty) { continue; } - final newCodeLineChunks = - _uncommentChunks(codeLineChunk, deletion, index); + final newCodeLineChunks = _uncommentChunks( + codeLineChunk, + deletion, + index, + ); newCodeChunks[j] = codeLineChunk.copyWith( - text: codeLineChunk.text.substring(0, index) + - codeLineChunk.text.substring(index + deletion.length), - chunks: newCodeLineChunks); + text: + codeLineChunk.text.substring(0, index) + + codeLineChunk.text.substring(index + deletion.length), + chunks: newCodeLineChunks, + ); } + return newCodeChunks; } } class _DefaultMultiLineCommentFormatter extends _DefaultCommentFormatter { - + _DefaultMultiLineCommentFormatter(this.prefix, this.suffix) + : super(prefix + suffix); final String prefix; final String suffix; - _DefaultMultiLineCommentFormatter(this.prefix, this.suffix) : super(prefix + suffix); - @override CodeLineEditingValue format(CodeLineEditingValue value, String indent) { final CodeLineSelection selection = value.selection; @@ -339,18 +385,10 @@ class _DefaultMultiLineCommentFormatter extends _DefaultCommentFormatter { final int prefixIndex; final int suffixIndex = codeLine.indexOf(suffix, extent); - prefixIndex = _getIndexOfPrefix( - codeLine, - base, - ); + prefixIndex = _getIndexOfPrefix(codeLine, base); if (prefixIndex == -1 || suffixIndex == -1 || base < prefixIndex) { - return _commentSelectedCodeLine( - value, - indent, - '$prefix ', - ' $suffix', - ); + return _commentSelectedCodeLine(value, indent, '$prefix ', ' $suffix'); } if (codeLine.startsWith('$prefix ', prefixIndex) && @@ -392,12 +430,7 @@ class _DefaultMultiLineCommentFormatter extends _DefaultCommentFormatter { suffixIndex, ); } else { - return _commentSelectedCodeLine( - value, - indent, - '$prefix ', - ' $suffix', - ); + return _commentSelectedCodeLine(value, indent, '$prefix ', ' $suffix'); } } @@ -416,7 +449,8 @@ class _DefaultMultiLineCommentFormatter extends _DefaultCommentFormatter { final CodeLines newCodeLines = CodeLines.from(codeLines); newCodeLines[lineIndex] = codeLine.copyWith( - text: codeLine.text.substring(0, prefixIndex) + + text: + codeLine.text.substring(0, prefixIndex) + codeLine.text.substring(prefixIndex + prefix.length, suffixIndex) + codeLine.text.substring(suffixIndex + suffix.length), ); @@ -555,18 +589,10 @@ class _DefaultMultiLineCommentFormatter extends _DefaultCommentFormatter { final int prefixIndex; final int suffixIndex = codeLastLine.indexOf(suffix, extent); - prefixIndex = _getIndexOfPrefix( - codeFirstLine, - base, - ); + prefixIndex = _getIndexOfPrefix(codeFirstLine, base); if (prefixIndex == -1 || suffixIndex == -1 || base < prefixIndex) { - return _commentSelectedCodeLines( - value, - indent, - '$prefix ', - ' $suffix', - ); + return _commentSelectedCodeLines(value, indent, '$prefix ', ' $suffix'); } if (codeFirstLine.startsWith('$prefix ', prefixIndex) && @@ -608,12 +634,7 @@ class _DefaultMultiLineCommentFormatter extends _DefaultCommentFormatter { suffixIndex, ); } else { - return _commentSelectedCodeLines( - value, - indent, - '$prefix ', - ' $suffix', - ); + return _commentSelectedCodeLines(value, indent, '$prefix ', ' $suffix'); } } @@ -642,12 +663,14 @@ class _DefaultMultiLineCommentFormatter extends _DefaultCommentFormatter { codeLastLine = codeLines[extentIndex]; newCodeLines[baseIndex] = codeFirstLine.copyWith( - text: codeFirstLine.text.substring(0, prefixIndex) + + text: + codeFirstLine.text.substring(0, prefixIndex) + codeFirstLine.text.substring(prefixIndex + prefix.length), ); newCodeLines[extentIndex] = codeLastLine.copyWith( - text: codeLastLine.text.substring(0, suffixIndex) + + text: + codeLastLine.text.substring(0, suffixIndex) + codeLastLine.text.substring(suffixIndex + suffix.length), ); @@ -669,12 +692,14 @@ class _DefaultMultiLineCommentFormatter extends _DefaultCommentFormatter { codeLastLine = codeLines[baseIndex]; newCodeLines[extentIndex] = codeFirstLine.copyWith( - text: codeFirstLine.text.substring(0, prefixIndex) + + text: + codeFirstLine.text.substring(0, prefixIndex) + codeFirstLine.text.substring(prefixIndex + prefix.length), ); newCodeLines[baseIndex] = codeLastLine.copyWith( - text: codeLastLine.text.substring(0, suffixIndex) + + text: + codeLastLine.text.substring(0, suffixIndex) + codeLastLine.text.substring(suffixIndex + suffix.length), ); @@ -762,13 +787,10 @@ class _DefaultMultiLineCommentFormatter extends _DefaultCommentFormatter { ); } - int _getIndexOfPrefix( - String text, - int baseIndex, - ) { + int _getIndexOfPrefix(String text, int baseIndex) { int index = -1; - int prefixLength = prefix.length - 1; - int suffixLength = suffix.length - 1; + final int prefixLength = prefix.length - 1; + final int suffixLength = suffix.length - 1; if (baseIndex >= text.length - 1) { return index; @@ -791,5 +813,4 @@ class _DefaultMultiLineCommentFormatter extends _DefaultCommentFormatter { return index; } - -} \ No newline at end of file +} diff --git a/lib/src/_code_highlight.dart b/lib/src/_code_highlight.dart index 963bae7..67eb672 100644 --- a/lib/src/_code_highlight.dart +++ b/lib/src/_code_highlight.dart @@ -1,27 +1,25 @@ -part of re_editor; +part of 're_editor.dart'; class _CodeHighlighter extends ValueNotifier> { - - final BuildContext _context; - final _CodeParagraphProvider _provider; - final _CodeHighlightEngine _engine; - - CodeLineEditingController _controller; - CodeHighlightTheme? _theme; - _CodeHighlighter({ required BuildContext context, required CodeLineEditingController controller, CodeHighlightTheme? theme, }) : _context = context, - _provider = _CodeParagraphProvider(), - _controller = controller, - _theme = theme, - _engine = _CodeHighlightEngine(theme), - super(const []) { + _provider = _CodeParagraphProvider(), + _controller = controller, + _theme = theme, + _engine = _CodeHighlightEngine(theme), + super(const []) { _controller.addListener(_onCodesChanged); _processHighlight(); } + final BuildContext _context; + final _CodeParagraphProvider _provider; + final _CodeHighlightEngine _engine; + + CodeLineEditingController _controller; + CodeHighlightTheme? _theme; set controller(CodeLineEditingController value) { if (_controller == value) { @@ -50,12 +48,16 @@ class _CodeHighlighter extends ValueNotifier> { }) { _provider.updateBaseStyle(style); _provider.updateMaxLengthSingleLineRendering(maxLengthSingleLineRendering); - return _provider.build(_controller.buildTextSpan( - context: _context, - index: index, - textSpan: _buildSpan(index, style), - style: style - ), maxWidth); + + return _provider.build( + _controller.buildTextSpan( + context: _context, + index: index, + textSpan: _buildSpan(index, style), + style: style, + ), + maxWidth, + ); } @override @@ -68,17 +70,11 @@ class _CodeHighlighter extends ValueNotifier> { TextSpan _buildSpan(int index, TextStyle style) { final String text = _controller.codeLines[index].text; if (index >= value.length) { - return TextSpan( - text: text, - style: style - ); + return TextSpan(text: text, style: style); } final _HighlightResult result = value[index]; if (result.nodes.isEmpty) { - return TextSpan( - text: text, - style: style - ); + return TextSpan(text: text, style: style); } if (result.source == text) { return _buildSpanFromNodes(result.nodes, style); @@ -108,29 +104,44 @@ class _CodeHighlighter extends ValueNotifier> { } final _HighlightNode? midNode; if (startNodes.isEmpty) { - midNode = _HighlightNode(text.substring(start, end), result.nodes[0].className); + midNode = _HighlightNode( + text.substring(start, end), + + result.nodes.first.className, + ); } else if (startNodes.length < result.nodes.length) { - midNode = _HighlightNode(text.substring(start, end), result.nodes[startNodes.length].className); - } else if (end > start){ - midNode = _HighlightNode(text.substring(start, end), result.nodes.last.className); + midNode = _HighlightNode( + text.substring(start, end), + result.nodes[startNodes.length].className, + ); + } else if (end > start) { + midNode = _HighlightNode( + text.substring(start, end), + result.nodes.last.className, + ); } else { midNode = null; } + return _buildSpanFromNodes([ ...startNodes, - if (midNode != null) - midNode, - ...endNodes + if (midNode != null) midNode, + ...endNodes, ], style); } - TextSpan _buildSpanFromNodes(List<_HighlightNode> nodes, TextStyle baseStyle) { + TextSpan _buildSpanFromNodes( + List<_HighlightNode> nodes, + TextStyle baseStyle, + ) { return TextSpan( - children: nodes.map((e) => TextSpan( - text: e.value, - style: _findStyle(e.className) - )).toList(), - style: baseStyle + children: + nodes + .map( + (e) => TextSpan(text: e.value, style: _findStyle(e.className)), + ) + .toList(), + style: baseStyle, ); } @@ -138,20 +149,24 @@ class _CodeHighlighter extends ValueNotifier> { if (className == null) { return null; } - while(true) { - final TextStyle? style = _theme?.theme[className]; + + var name = className; + + while (true) { + final TextStyle? style = _theme?.theme[name]; if (style != null) { return style; } - final int pieceIndex = className!.indexOf('-'); + final int pieceIndex = name.indexOf('-'); if (pieceIndex < 0) { break; } - className = className.substring(pieceIndex + 1); - if (className.isEmpty) { + name = name.substring(pieceIndex + 1); + if (name.isEmpty) { break; } } + return null; } @@ -165,21 +180,21 @@ class _CodeHighlighter extends ValueNotifier> { void _processHighlight() { _engine.run(_controller.codeLines, (result) => value = result); } - } class _CodeHighlightEngine { - + _CodeHighlightEngine(final CodeHighlightTheme? theme) { + this.theme = theme; + _tasker = _IsolateTasker<_HighlightPayload, List<_HighlightResult>>( + 'CodeHighlightEngine', + _run, + ); + } late final _IsolateTasker<_HighlightPayload, List<_HighlightResult>> _tasker; Highlight? _highlight; CodeHighlightTheme? _theme; - _CodeHighlightEngine(final CodeHighlightTheme? theme) { - this.theme = theme; - _tasker = _IsolateTasker<_HighlightPayload, List<_HighlightResult>>('CodeHighlightEngine', _run); - } - set theme(CodeHighlightTheme? value) { if (_theme == value) { return; @@ -190,10 +205,11 @@ class _CodeHighlightEngine { _highlight = null; } else { final Highlight highlight = Highlight(); - highlight.registerLanguages(modes.map((key, value) => MapEntry(key, value.mode))); - for (final HLPlugin plugin in _theme!.plugins) { - highlight.addPlugin(plugin); - } + highlight.registerLanguages( + modes.map((key, value) => MapEntry(key, value.mode)), + ); + _theme!.plugins.forEach(highlight.addPlugin); + _highlight = highlight; } } @@ -206,20 +222,25 @@ class _CodeHighlightEngine { final Highlight? highlight = _highlight; if (highlight == null) { callback(const []); + return; } final Map? modes = _theme?.languages; if (modes == null) { callback(const []); + return; } - _tasker.run(_HighlightPayload( - highlight: highlight, - codes: codes, - languages: modes.keys.toList(), - maxSizes: modes.values.map((e) => e.maxSize).toList(), - maxLineLengths: modes.values.map((e) => e.maxLineLength).toList(), - ), callback); + _tasker.run( + _HighlightPayload( + highlight: highlight, + codes: codes, + languages: modes.keys.toList(), + maxSizes: modes.values.map((e) => e.maxSize).toList(), + maxLineLengths: modes.values.map((e) => e.maxLineLength).toList(), + ), + callback, + ); } @pragma('vm:entry-point') @@ -243,25 +264,21 @@ class _CodeHighlightEngine { if (!canHighlight) { result = payload.highlight.justTextHighlightResult(code); } else if (payload.languages.length == 1) { - result = payload.highlight.highlight(code: code, language: payload.languages.first); + result = payload.highlight.highlight( + code: code, + language: payload.languages.first, + ); } else { result = payload.highlight.highlightAuto(code, payload.languages); } final _HighlightLineRenderer renderer = _HighlightLineRenderer(); result.render(renderer); + return renderer.lineResults; } - } class _HighlightPayload { - - final Highlight highlight; - final CodeLines codes; - final List languages; - final List maxSizes; - final List maxLineLengths; - const _HighlightPayload({ required this.highlight, required this.codes, @@ -269,32 +286,32 @@ class _HighlightPayload { required this.maxSizes, required this.maxLineLengths, }); - + final Highlight highlight; + final CodeLines codes; + final List languages; + final List maxSizes; + final List maxLineLengths; } class _HighlightResult { - final List<_HighlightNode> nodes; - _HighlightResult(this.nodes); + final List<_HighlightNode> nodes; String get source => nodes.map((e) => e.value).join(); } class _HighlightNode { - + const _HighlightNode(this.value, [this.className]); final String? className; final String value; - - const _HighlightNode(this.value, [this.className]); } class _HighlightLineRenderer implements HighlightRenderer { - + _HighlightLineRenderer() + : lineResults = [_HighlightResult([])], + classNames = []; final List<_HighlightResult> lineResults; final List classNames; - _HighlightLineRenderer(): lineResults = [ - _HighlightResult([]) - ], classNames = []; @override void addText(String text) { @@ -303,7 +320,9 @@ class _HighlightLineRenderer implements HighlightRenderer { lineResults.last.nodes.add(_HighlightNode(lines.first, className)); if (lines.length > 1) { for (int i = 1; i < lines.length; i++) { - lineResults.add(_HighlightResult([_HighlightNode(lines[i], className)])); + lineResults.add( + _HighlightResult([_HighlightNode(lines[i], className)]), + ); } } } @@ -317,17 +336,14 @@ class _HighlightLineRenderer implements HighlightRenderer { } else { newClassName = '$className-${node.scope!}'; } - newClassName = newClassName?.split('.')[0]; + newClassName = newClassName?.split('.').first; classNames.add(newClassName); } - @override void closeNode(DataNode node) { if (classNames.isNotEmpty) { classNames.removeLast(); } } - } - diff --git a/lib/src/_code_indicator.dart b/lib/src/_code_indicator.dart index 4393f41..dc9cf62 100644 --- a/lib/src/_code_indicator.dart +++ b/lib/src/_code_indicator.dart @@ -1,7 +1,21 @@ -part of re_editor; +part of 're_editor.dart'; class CodeLineNumberRenderObject extends RenderBox { - + CodeLineNumberRenderObject({ + required CodeLineEditingController controller, + required CodeIndicatorValueNotifier notifier, + required TextStyle textStyle, + required TextStyle focusedTextStyle, + required int minNumberCount, + String Function(int lineIndex)? custonLineIndex2Text, + }) : _controller = controller, + _notifier = notifier, + _textStyle = textStyle, + _focusedTextStyle = focusedTextStyle, + _minNumberCount = minNumberCount, + _allLineCount = controller.lineCount, + _customLineIndex2Text = custonLineIndex2Text, + _textPainter = TextPainter(textDirection: TextDirection.ltr); CodeLineEditingController _controller; CodeIndicatorValueNotifier _notifier; TextStyle _textStyle; @@ -12,24 +26,6 @@ class CodeLineNumberRenderObject extends RenderBox { final String Function(int lineIndex)? _customLineIndex2Text; final TextPainter _textPainter; - CodeLineNumberRenderObject({ - required CodeLineEditingController controller, - required CodeIndicatorValueNotifier notifier, - required TextStyle textStyle, - required TextStyle focusedTextStyle, - required int minNumberCount, - String Function(int lineIndex)? custonLineIndex2Text, - }) : _controller = controller, - _notifier = notifier, - _textStyle = textStyle, - _focusedTextStyle = focusedTextStyle, - _minNumberCount = minNumberCount, - _allLineCount = controller.lineCount, - _customLineIndex2Text = custonLineIndex2Text, - _textPainter = TextPainter( - textDirection: TextDirection.ltr, - ); - set controller(CodeLineEditingController value) { if (_controller == value) { return; @@ -89,7 +85,9 @@ class CodeLineNumberRenderObject extends RenderBox { void handleEvent(PointerEvent event, BoxHitTestEntry entry) { if (event is PointerDownEvent) { final Offset position = globalToLocal(event.position); - final CodeLineRenderParagraph? paragraph = _findParagraphByPosition(position); + final CodeLineRenderParagraph? paragraph = _findParagraphByPosition( + position, + ); if (paragraph != null) { _controller.selectLine(paragraph.index); } @@ -113,8 +111,10 @@ class CodeLineNumberRenderObject extends RenderBox { @override void performLayout() { - assert(constraints.maxHeight > 0 && constraints.maxHeight != double.infinity, - 'CodeLineNumber should have an explicit height.'); + assert( + constraints.maxHeight > 0 && constraints.maxHeight != double.infinity, + 'CodeLineNumber should have an explicit height.', + ); _textPainter.text = TextSpan( text: '0' * max(_minNumberCount, _allLineCount.toString().length), style: _textStyle, @@ -132,16 +132,31 @@ class CodeLineNumberRenderObject extends RenderBox { return; } canvas.save(); - canvas.clipRect(Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height)); - int firstLineIndex = _controller.index2lineIndex(value.paragraphs.first.index); + canvas.clipRect( + Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height), + ); + int firstLineIndex = _controller.index2lineIndex( + value.paragraphs.first.index, + ); for (final CodeLineRenderParagraph paragraph in value.paragraphs) { - final lineIndexText = _customLineIndex2Text?.call(firstLineIndex) ?? (firstLineIndex + 1).toString(); + final lineIndexText = + _customLineIndex2Text?.call(firstLineIndex) ?? + (firstLineIndex + 1).toString(); _textPainter.text = TextSpan( text: lineIndexText, - style: paragraph.index == value.focusedIndex ? _focusedTextStyle : _textStyle + style: + paragraph.index == value.focusedIndex + ? _focusedTextStyle + : _textStyle, ); _textPainter.layout(); - _textPainter.paint(canvas, Offset(offset.dx + size.width - _textPainter.width, offset.dy + paragraph.offset.dy)); + _textPainter.paint( + canvas, + Offset( + offset.dx + size.width - _textPainter.width, + offset.dy + paragraph.offset.dy, + ), + ); firstLineIndex += _controller.codeLines[paragraph.index].lineCount; } canvas.restore(); @@ -153,7 +168,7 @@ class CodeLineNumberRenderObject extends RenderBox { } final int newAllLineCount = _controller.lineCount; if (max(_minNumberCount, newAllLineCount.toString().length) != - max(_minNumberCount, _allLineCount.toString().length)) { + max(_minNumberCount, _allLineCount.toString().length)) { _allLineCount = newAllLineCount; markNeedsLayout(); } else { @@ -163,26 +178,19 @@ class CodeLineNumberRenderObject extends RenderBox { } CodeLineRenderParagraph? _findParagraphByPosition(Offset position) { - final int? index = _notifier.value?.paragraphs.indexWhere((e) => position.dy > e.top - && position.dy < e.bottom); + final int? index = _notifier.value?.paragraphs.indexWhere( + (e) => position.dy > e.top && position.dy < e.bottom, + ); if (index == null || index < 0) { return null; } + return _notifier.value?.paragraphs[index]; } - } -class CodeChunkIndicatorRenderObject extends RenderBox implements MouseTrackerAnnotation { - - double _width; - CodeChunkController _controller; - CodeIndicatorValueNotifier _notifier; - CodeChunkIndicatorPainter _painter; - bool _collapseIndicatorVisible; - bool _expandIndicatorVisible; - MouseCursor _cursor; - +class CodeChunkIndicatorRenderObject extends RenderBox + implements MouseTrackerAnnotation { CodeChunkIndicatorRenderObject({ required double width, required CodeChunkController controller, @@ -191,12 +199,19 @@ class CodeChunkIndicatorRenderObject extends RenderBox implements MouseTrackerAn required bool collapseIndicatorVisible, required bool expandIndicatorVisible, }) : _width = width, - _controller = controller, - _notifier = notifier, - _painter = painter, - _collapseIndicatorVisible = collapseIndicatorVisible, - _expandIndicatorVisible = expandIndicatorVisible, - _cursor = MouseCursor.defer; + _controller = controller, + _notifier = notifier, + _painter = painter, + _collapseIndicatorVisible = collapseIndicatorVisible, + _expandIndicatorVisible = expandIndicatorVisible, + _cursor = MouseCursor.defer; + double _width; + CodeChunkController _controller; + CodeIndicatorValueNotifier _notifier; + CodeChunkIndicatorPainter _painter; + bool _collapseIndicatorVisible; + bool _expandIndicatorVisible; + MouseCursor _cursor; set width(double value) { if (_width == value) { @@ -282,6 +297,7 @@ class CodeChunkIndicatorRenderObject extends RenderBox implements MouseTrackerAn } hitTarget = true; } + return hitTarget; } @@ -289,7 +305,9 @@ class CodeChunkIndicatorRenderObject extends RenderBox implements MouseTrackerAn void handleEvent(PointerEvent event, BoxHitTestEntry entry) { if (event is PointerDownEvent) { final Offset position = globalToLocal(event.position); - final CodeLineRenderParagraph? paragraph = _findParagraphByPosition(position); + final CodeLineRenderParagraph? paragraph = _findParagraphByPosition( + position, + ); if (paragraph != null) { _controller.toggle(paragraph.index); } @@ -313,9 +331,13 @@ class CodeChunkIndicatorRenderObject extends RenderBox implements MouseTrackerAn @override void performLayout() { - assert(_width > 0 && _width != double.infinity && - constraints.maxHeight > 0 && constraints.maxHeight != double.infinity, - 'CodeChunkIndicator should have an explicit width and height.'); + assert( + _width > 0 && + _width != double.infinity && + constraints.maxHeight > 0 && + constraints.maxHeight != double.infinity, + 'CodeChunkIndicator should have an explicit width and height.', + ); size = Size(_width, constraints.maxHeight); } @@ -331,7 +353,9 @@ class CodeChunkIndicatorRenderObject extends RenderBox implements MouseTrackerAn return; } canvas.save(); - canvas.clipRect(Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height)); + canvas.clipRect( + Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height), + ); for (final CodeLineRenderParagraph paragraph in value.paragraphs) { final Offset newOffset = offset + Offset(0, paragraph.offset.dy); final Size container = Size(_width, paragraph.preferredLineHeight); @@ -355,19 +379,22 @@ class CodeChunkIndicatorRenderObject extends RenderBox implements MouseTrackerAn } CodeLineRenderParagraph? _findParagraphByPosition(Offset position) { - final int? index = _notifier.value?.paragraphs.indexWhere((e) => position.dy > e.top - && position.dy < e.top + e.preferredLineHeight); + final int? index = _notifier.value?.paragraphs.indexWhere( + (e) => position.dy > e.top && position.dy < e.top + e.preferredLineHeight, + ); if (index == null || index < 0) { return null; } - final CodeLineRenderParagraph? paragraph = _notifier.value?.paragraphs[index]; + final CodeLineRenderParagraph? paragraph = + _notifier.value?.paragraphs[index]; if (paragraph == null) { return null; } - if (paragraph.chunkParent || _controller.findByIndex(paragraph.index) != null) { + if (paragraph.chunkParent || + _controller.findByIndex(paragraph.index) != null) { return paragraph; } + return null; } - } diff --git a/lib/src/_code_input.dart b/lib/src/_code_input.dart index d0ebfb3..5dd66e7 100644 --- a/lib/src/_code_input.dart +++ b/lib/src/_code_input.dart @@ -1,7 +1,22 @@ -part of re_editor; - -class _CodeInputController extends ChangeNotifier implements DeltaTextInputClient { +part of 're_editor.dart'; +class _CodeInputController extends ChangeNotifier + implements DeltaTextInputClient { + _CodeInputController({ + required CodeLineEditingController controller, + required _CodeFloatingCursorController floatingCursorController, + required FocusNode focusNode, + required bool readOnly, + required bool autocompleteSymbols, + }) : _controller = controller, + _floatingCursorController = floatingCursorController, + _focusNode = focusNode, + _readOnly = readOnly, + _updateCausedByFloatingCursor = false, + _autocompleteSymbols = autocompleteSymbols { + _controller.addListener(_onCodeEditingChanged); + _focusNode.addListener(_onFocusChanged); + } CodeLineEditingController _controller; FocusNode _focusNode; bool _readOnly; @@ -17,23 +32,7 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien GlobalKey? _editorKey; - _CodeInputController({ - required CodeLineEditingController controller, - required _CodeFloatingCursorController floatingCursorController, - required FocusNode focusNode, - required bool readOnly, - required bool autocompleteSymbols, - }) : _controller = controller, - _floatingCursorController = floatingCursorController, - _focusNode = focusNode, - _readOnly = readOnly, - _updateCausedByFloatingCursor = false, - _autocompleteSymbols = autocompleteSymbols { - _controller.addListener(_onCodeEditingChanged); - _focusNode.addListener(_onFocusChanged); - } - - void bindEditor(GlobalKey key) { + set bindEditor(GlobalKey key) { _editorKey = key; } @@ -91,8 +90,7 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien TextRange get composing => _controller.composing; @override - void connectionClosed() { - } + void connectionClosed() {} @override AutofillScope? get currentAutofillScope => null; @@ -112,24 +110,19 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien } @override - void performPrivateCommand(String action, Map data) { - } + void performPrivateCommand(String action, Map data) {} @override - void showAutocorrectionPromptRect(int start, int end) { - } + void showAutocorrectionPromptRect(int start, int end) {} @override - void showToolbar() { - } + void showToolbar() {} @override - void insertTextPlaceholder(Size size) { - } + void insertTextPlaceholder(Size size) {} @override - void removeTextPlaceholder() { - } + void removeTextPlaceholder() {} @override void updateEditingValueWithDeltas(List textEditingDeltas) { @@ -137,16 +130,21 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien // This is necessary because otherwise the content of the line where the floating cursor was started // will be pasted over to the line where the floating cursor was stopped. _updateCausedByFloatingCursor = false; + return; } - - if (textEditingDeltas.any((delta) => delta is TextEditingDeltaInsertion && delta.textInserted == '\n')) { + + if (textEditingDeltas.any( + (delta) => + delta is TextEditingDeltaInsertion && delta.textInserted == '\n', + )) { TextEditingValue newValue = _remoteEditingValue!; for (final TextEditingDelta delta in textEditingDeltas) { newValue = delta.apply(newValue); } _remoteEditingValue = newValue; _controller.applyNewLine(); + return; } @@ -155,7 +153,9 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien bool smartChange = false; for (final TextEditingDelta delta in textEditingDeltas) { if (_autocompleteSymbols) { - TextEditingDelta newDelta = _SmartTextEditingDelta(delta).apply(selection); + final TextEditingDelta newDelta = _SmartTextEditingDelta( + delta, + ).apply(selection); if (newDelta != delta) { smartChange = true; } @@ -187,48 +187,58 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien } @override - void updateEditingValue(TextEditingValue textEditingValue) { - } + void updateEditingValue(TextEditingValue textEditingValue) {} @override void updateFloatingCursor(RawFloatingCursorPoint point) { _updateCausedByFloatingCursor = true; - final _CodeFieldRender? render = _editorKey?.currentContext?.findRenderObject() as _CodeFieldRender?; + final _CodeFieldRender? render = + _editorKey?.currentContext?.findRenderObject() as _CodeFieldRender?; if (render == null) { return; } - switch(point.state) { + switch (point.state) { case FloatingCursorDragState.Start: - _floatingCursorStartingOffset = render.calculateTextPositionViewportOffset(selection.base)!; + _floatingCursorStartingOffset = + render.calculateTextPositionViewportOffset(selection.base)!; _floatingCursorController.setFloatingCursorPositions( floatingCursorOffset: _floatingCursorStartingOffset, finalCursorSelection: selection, ); break; case FloatingCursorDragState.Update: - final Offset updatedOffset = _floatingCursorStartingOffset + point.offset!; + final Offset updatedOffset = + _floatingCursorStartingOffset + point.offset!; final double topBound = render.paintBounds.top + render.paddingTop; final double leftBound = render.paintBounds.left + render.paddingLeft; - final double bottomBound = render.paintBounds.bottom - render.paddingBottom - render.floatingCursorHeight; - final double rightBound = render.paintBounds.right - render.paddingRight; + final double bottomBound = + render.paintBounds.bottom - + render.paddingBottom - + render.floatingCursorHeight; + final double rightBound = + render.paintBounds.right - render.paddingRight; // Clamp the offset coordinates to the paint bounds - Offset clampedUpdatedOffset = Offset( + final Offset clampedUpdatedOffset = Offset( updatedOffset.dx.clamp(leftBound, rightBound), updatedOffset.dy.clamp(topBound, bottomBound), ); - // An adjustment is made on the y-axis so that whenever it is in between lines, the line where the center + // An adjustment is made on the y-axis so that whenever it is in between lines, the line where the center // of the floating cursor is will be selected. - Offset adjustedClampedUpdatedOffset = clampedUpdatedOffset + Offset(0, render.floatingCursorHeight / 2); - final CodeLinePosition newPosition = render.calculateTextPosition(adjustedClampedUpdatedOffset)!; + final Offset adjustedClampedUpdatedOffset = + clampedUpdatedOffset + Offset(0, render.floatingCursorHeight / 2); + final CodeLinePosition newPosition = + render.calculateTextPosition(adjustedClampedUpdatedOffset)!; // The offset at which the actual cursor would end up if floating cursor was terminated now. - final Offset? snappedNewOffset = render.calculateTextPositionViewportOffset(newPosition); - - CodeLineSelection newSelection = CodeLineSelection.fromPosition(position: newPosition); + final Offset? snappedNewOffset = render + .calculateTextPositionViewportOffset(newPosition); + final CodeLineSelection newSelection = CodeLineSelection.fromPosition( + position: newPosition, + ); if (clampedUpdatedOffset != updatedOffset) { // When the cursor is at one of the edges, adjust the starting offset so that the floating cursor @@ -236,45 +246,54 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien _floatingCursorStartingOffset += clampedUpdatedOffset - updatedOffset; } - if (clampedUpdatedOffset.dy == topBound || clampedUpdatedOffset.dy == bottomBound || clampedUpdatedOffset.dx == rightBound || clampedUpdatedOffset.dx == leftBound) { - _floatingCursorScrollTimer ??= Timer.periodic(const Duration(milliseconds: 50), (timer) { - render.autoScrollWhenDraggingFloatingCursor(clampedUpdatedOffset); - final CodeLinePosition newPos = render.calculateTextPosition(adjustedClampedUpdatedOffset)!; - final Offset? snappedNewOffset = render.calculateTextPositionViewportOffset(newPos); - - // This step ensures that the preview cursor will keep updating when scrolling - if (adjustedClampedUpdatedOffset.dx > snappedNewOffset!.dx + render.textStyle.fontSize!) { - _floatingCursorController.updatePreviewCursorOffset(snappedNewOffset); - } - else { - _floatingCursorController.updatePreviewCursorOffset(null); - } - }); - } - else { + if (clampedUpdatedOffset.dy == topBound || + clampedUpdatedOffset.dy == bottomBound || + clampedUpdatedOffset.dx == rightBound || + clampedUpdatedOffset.dx == leftBound) { + _floatingCursorScrollTimer ??= Timer.periodic( + const Duration(milliseconds: 50), + (timer) { + render.autoScrollWhenDraggingFloatingCursor(clampedUpdatedOffset); + final CodeLinePosition newPos = + render.calculateTextPosition(adjustedClampedUpdatedOffset)!; + final Offset? snappedNewOffset = render + .calculateTextPositionViewportOffset(newPos); + + // This step ensures that the preview cursor will keep updating when scrolling + if (adjustedClampedUpdatedOffset.dx > + snappedNewOffset!.dx + render.textStyle.fontSize!) { + _floatingCursorController.updatePreviewCursorOffset( + snappedNewOffset, + ); + } else { + _floatingCursorController.updatePreviewCursorOffset(null); + } + }, + ); + } else { if (_floatingCursorScrollTimer != null) { _floatingCursorScrollTimer!.cancel(); _floatingCursorScrollTimer = null; } } - + // Only turn on the preview cursor if we are away from the end of the line (relatively to the font size) - if (adjustedClampedUpdatedOffset.dx > snappedNewOffset!.dx + render.textStyle.fontSize!) { + if (adjustedClampedUpdatedOffset.dx > + snappedNewOffset!.dx + render.textStyle.fontSize!) { _floatingCursorController.setFloatingCursorPositions( - floatingCursorOffset: clampedUpdatedOffset, - previewCursorOffset: snappedNewOffset, - finalCursorOffset: snappedNewOffset, - finalCursorSelection:newSelection + floatingCursorOffset: clampedUpdatedOffset, + previewCursorOffset: snappedNewOffset, + finalCursorOffset: snappedNewOffset, + finalCursorSelection: newSelection, ); - } - else { + } else { _floatingCursorController.setFloatingCursorPositions( - floatingCursorOffset: clampedUpdatedOffset, - finalCursorOffset: snappedNewOffset, - finalCursorSelection: newSelection + floatingCursorOffset: clampedUpdatedOffset, + finalCursorOffset: snappedNewOffset, + finalCursorSelection: newSelection, ); } - + break; case FloatingCursorDragState.End: if (_floatingCursorScrollTimer != null) { @@ -283,42 +302,44 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien } selection = _floatingCursorController.value.finalCursorSelection!; final CodeLinePosition finalPosition = CodeLinePosition( - index: selection.baseIndex, - offset: selection.baseOffset, - affinity: selection.baseAffinity); - - final Offset? finalOffset = render.calculateTextPositionViewportOffset(finalPosition); - + index: selection.baseIndex, + offset: selection.baseOffset, + affinity: selection.baseAffinity, + ); + + final Offset? finalOffset = render.calculateTextPositionViewportOffset( + finalPosition, + ); + // If the final selection is in not the viewport, make it visible without animating the floating cursor. // Otherwise, play the floating cursor reset animation. if (finalOffset != null && (finalOffset.dx < 0 || finalOffset.dy < 0)) { render.makePositionCenterIfInvisible( CodeLinePosition( - index: selection.baseIndex, - offset: selection.baseOffset, - affinity: selection.baseAffinity), - animated: true); - _floatingCursorController.disableFloatingCursor(); - } - else { + index: selection.baseIndex, + offset: selection.baseOffset, + affinity: selection.baseAffinity, + ), + animated: true, + ); + _floatingCursorController.disableFloatingCursor(); + } else { _floatingCursorController.animateDisableFloatingCursor(); } - - } } @override - void didChangeInputControl(TextInputControl? oldControl, TextInputControl? newControl) { - } + void didChangeInputControl( + TextInputControl? oldControl, + TextInputControl? newControl, + ) {} @override - void performSelector(String selectorName) { - } + void performSelector(String selectorName) {} @override - void insertContent(KeyboardInsertedContent content) { - } + void insertContent(KeyboardInsertedContent content) {} void ensureInput() { if (_focusNode.hasFocus) { @@ -359,10 +380,10 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien if (localValue == _remoteEditingValue) { return; } - if (localValue.composing.isValid && max(localValue.composing.start, localValue.composing.end) > localValue.text.length) { - localValue = localValue.copyWith( - composing: TextRange.empty - ); + if (localValue.composing.isValid && + max(localValue.composing.start, localValue.composing.end) > + localValue.text.length) { + localValue = localValue.copyWith(composing: TextRange.empty); } // print('post text ${localValue.text}'); // print('post selection ${localValue.selection}'); @@ -372,33 +393,44 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien _textInputConnection!.setEditingState(localValue); } - void _updateRemoteComposingIfNeeded({ - bool retry = false - }) { + void _updateRemoteComposingIfNeeded({bool retry = false}) { if (!_hasInputConnection) { return; } - final _CodeFieldRender? render = _editorKey?.currentContext?.findRenderObject() as _CodeFieldRender?; + final _CodeFieldRender? render = + _editorKey?.currentContext?.findRenderObject() as _CodeFieldRender?; if (render == null) { return; } - final Offset? composingStart = render.calculateTextPositionViewportOffset(selection.base.copyWith( - offset: _remoteEditingValue?.composing.start - )); - final Offset? composingEnd = render.calculateTextPositionViewportOffset(selection.extent.copyWith( - offset: _remoteEditingValue?.composing.end - )); + final Offset? composingStart = render.calculateTextPositionViewportOffset( + selection.base.copyWith(offset: _remoteEditingValue?.composing.start), + ); + final Offset? composingEnd = render.calculateTextPositionViewportOffset( + selection.extent.copyWith(offset: _remoteEditingValue?.composing.end), + ); if (composingStart != null && composingEnd != null) { - _textInputConnection!.setComposingRect(Rect.fromPoints(composingStart, composingEnd + Offset(0, render.lineHeight))); + _textInputConnection!.setComposingRect( + Rect.fromPoints( + composingStart, + composingEnd + Offset(0, render.lineHeight), + ), + ); } - final Offset? caret = render.calculateTextPositionViewportOffset(selection.base) ?? composingStart; + final Offset? caret = + render.calculateTextPositionViewportOffset(selection.base) ?? + composingStart; if (caret != null) { - _textInputConnection!.setCaretRect(Rect.fromLTWH(caret.dx, caret.dy, render.cursorWidth, render.lineHeight)); + _textInputConnection!.setCaretRect( + Rect.fromLTWH( + caret.dx, + caret.dy, + render.cursorWidth, + render.lineHeight, + ), + ); } else if (!retry) { Future.delayed(const Duration(milliseconds: 10), () { - _updateRemoteComposingIfNeeded( - retry: true - ); + _updateRemoteComposingIfNeeded(retry: true); }); } } @@ -407,11 +439,15 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien if (!_hasInputConnection) { return; } - final _CodeFieldRender? render = _editorKey?.currentContext?.findRenderObject() as _CodeFieldRender?; + final _CodeFieldRender? render = + _editorKey?.currentContext?.findRenderObject() as _CodeFieldRender?; if (render == null || !render.hasSize) { return; } - _textInputConnection!.setEditableSizeAndTransform(render.size, render.getTransformTo(null)); + _textInputConnection!.setEditableSizeAndTransform( + render.size, + render.getTransformTo(null), + ); } void _onFocusChanged() { @@ -431,10 +467,11 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien void _openInputConnection() { if (!_hasInputConnection) { - final TextInputConnection connection = TextInput.attach(this, + final TextInputConnection connection = TextInput.attach( + this, const TextInputConfiguration( enableDeltaModel: true, - inputAction: TextInputAction.newline + inputAction: TextInputAction.newline, ), ); _remoteEditingValue = _buildTextEditingValue(); @@ -460,41 +497,39 @@ class _CodeInputController extends ChangeNotifier implements DeltaTextInputClien if (selection.isSameLine) { textSelection = TextSelection( baseOffset: selection.baseOffset, - extentOffset: selection.extentOffset + extentOffset: selection.extentOffset, ); } else { if (selection.baseIndex < selection.extentIndex) { textSelection = TextSelection( baseOffset: selection.baseOffset, - extentOffset: codeLines[selection.baseIndex].length + extentOffset: codeLines[selection.baseIndex].length, ); } else { textSelection = TextSelection( baseOffset: 0, - extentOffset: selection.baseOffset + extentOffset: selection.baseOffset, ); } } + return TextEditingValue( text: codeLines[selection.baseIndex].text, selection: textSelection, - composing: composing + composing: composing, ).appendPrefixIfNecessary(); } - } class _SmartTextEditingDelta { - + _SmartTextEditingDelta(this._delta); static const List<_ClosureSymbol> _closureSymbols = [ _ClosureSymbol('{', '}'), _ClosureSymbol('[', ']'), _ClosureSymbol('(', ')'), ]; - static const List _quoteSymbols = [ - '\'', '"', '`' - ]; + static const List _quoteSymbols = ['\'', '"', '`']; static const List<_ClosureSymbol> _wrapSymbols = [ _ClosureSymbol('{', '}'), @@ -507,8 +542,6 @@ class _SmartTextEditingDelta { final TextEditingDelta _delta; - _SmartTextEditingDelta(this._delta); - TextEditingDelta apply(CodeLineSelection selection) { TextEditingDelta delta = _delta; if (delta is TextEditingDeltaInsertion) { @@ -516,6 +549,7 @@ class _SmartTextEditingDelta { } else if (delta is TextEditingDeltaReplacement) { delta = _smartReplacement(delta, selection); } + return delta; } @@ -525,6 +559,7 @@ class _SmartTextEditingDelta { if (!_shouldAutoClosed(delta.oldText, delta.insertionOffset, symbol)) { break; } + return TextEditingDeltaInsertion( oldText: delta.oldText, textInserted: symbol.toString(), @@ -536,12 +571,11 @@ class _SmartTextEditingDelta { if (!_shouldSkipClosed(delta.oldText, delta.insertionOffset, symbol)) { break; } + return TextEditingDeltaNonTextUpdate( oldText: delta.oldText, - selection: TextSelection.collapsed( - offset: delta.insertionOffset + 1 - ), - composing: delta.composing + selection: TextSelection.collapsed(offset: delta.insertionOffset + 1), + composing: delta.composing, ); } } @@ -552,6 +586,7 @@ class _SmartTextEditingDelta { if (!_shouldAutoQuoted(delta.oldText, symbol, delta.insertionOffset)) { break; } + return TextEditingDeltaInsertion( oldText: delta.oldText, textInserted: symbol * 2, @@ -560,30 +595,37 @@ class _SmartTextEditingDelta { composing: delta.composing, ); } + return delta; } - TextEditingDelta _smartReplacement(TextEditingDeltaReplacement delta, CodeLineSelection selection) { + TextEditingDelta _smartReplacement( + TextEditingDeltaReplacement delta, + CodeLineSelection selection, + ) { if (!selection.isSameLine) { return delta; } if (delta.replacementText.length > 1) { return delta; } - final int index = _wrapSymbols.indexWhere((element) => element.left == delta.replacementText); + final int index = _wrapSymbols.indexWhere( + (element) => element.left == delta.replacementText, + ); if (index < 0) { return delta; } final _ClosureSymbol symbol = _wrapSymbols[index]; + return TextEditingDeltaReplacement( oldText: delta.oldText, replacementText: symbol.left + delta.textReplaced + symbol.right, replacedRange: delta.replacedRange, selection: TextSelection( baseOffset: selection.startOffset + 1, - extentOffset: selection.endOffset + 1 + extentOffset: selection.endOffset + 1, ), - composing: delta.composing + composing: delta.composing, ); } @@ -610,6 +652,7 @@ class _SmartTextEditingDelta { } } } + return max(0, leftSymbolCount) >= rightSymbolCount; } @@ -620,6 +663,7 @@ class _SmartTextEditingDelta { if (offset == text.length) { return false; } + return text.substring(offset, offset + 1) == symbol.right; } @@ -646,33 +690,30 @@ class _SmartTextEditingDelta { return true; } if (rightSymbolCount == 0) { - return leftSymbolCount % 2 == 0; + return leftSymbolCount.isEven; } if (leftSymbolCount == 0) { - return rightSymbolCount % 2 == 0; + return rightSymbolCount.isEven; } + return leftSymbolCount % 2 == rightSymbolCount % 2; } - } class _ClosureSymbol { + const _ClosureSymbol(this.left, this.right); final String left; final String right; - const _ClosureSymbol(this.left, this.right); - @override String toString() { return left + right; } - } const String _kPrefix = '\u200b'; extension _TextEditingValueExtension on TextEditingValue { - bool get startWithPrefix => text.startsWith(_kPrefix); bool get usePrefix => kIsIOS || kIsAndroid; @@ -681,16 +722,17 @@ extension _TextEditingValueExtension on TextEditingValue { if (!usePrefix) { return this; } + return copyWith( text: '$_kPrefix$text', selection: selection.copyWith( baseOffset: selection.baseOffset + 1, extentOffset: selection.extentOffset + 1, ), - composing: composing.isValid ? TextRange( - start: composing.start + 1, - end: composing.end + 1 - ) : composing + composing: + composing.isValid + ? TextRange(start: composing.start + 1, end: composing.end + 1) + : composing, ); } @@ -701,17 +743,20 @@ extension _TextEditingValueExtension on TextEditingValue { if (!startWithPrefix) { return this; } + return copyWith( text: text.substring(1), selection: selection.copyWith( baseOffset: max(0, selection.baseOffset - 1), extentOffset: max(0, selection.extentOffset - 1), ), - composing: composing.isValid ? TextRange( - start: max(0, composing.start - 1), - end: max(0, composing.end - 1) - ) : null + composing: + composing.isValid + ? TextRange( + start: max(0, composing.start - 1), + end: max(0, composing.end - 1), + ) + : null, ); } - -} \ No newline at end of file +} diff --git a/lib/src/_code_line.dart b/lib/src/_code_line.dart index d3d8b8c..dcc5268 100644 --- a/lib/src/_code_line.dart +++ b/lib/src/_code_line.dart @@ -1,25 +1,15 @@ -part of re_editor; +part of 're_editor.dart'; const CodeLines _kInitialCodeLines = CodeLines([ - CodeLineSegment(codeLines: [ - CodeLine.empty - ]) + CodeLineSegment(codeLines: [CodeLine.empty]), ]); const int _kUnitCodeWhitespace = 0x20; const List _kClosures = ['{}', '[]', '()']; const List _kClosureAndQuates = ['{}', '[]', '()', '\'\'', '""', '``']; -class _CodeLineEditingControllerImpl extends ValueNotifier implements CodeLineEditingController { - - @override - final CodeLineOptions options; - final CodeLineSpanBuilder? spanBuilder; - late final _CodeLineEditingCache _cache; - late int _preEditLineIndex; - CodeLineEditingValue? _preValue; - GlobalKey? _editorKey; - +class _CodeLineEditingControllerImpl extends ValueNotifier + implements CodeLineEditingController { _CodeLineEditingControllerImpl({ required CodeLines codeLines, required this.options, @@ -29,25 +19,38 @@ class _CodeLineEditingControllerImpl extends ValueNotifier _preEditLineIndex = -1; } - factory _CodeLineEditingControllerImpl.fromText(String? text, [ - CodeLineOptions options = const CodeLineOptions() + factory _CodeLineEditingControllerImpl.fromText( + String? text, [ + CodeLineOptions options = const CodeLineOptions(), ]) { return _CodeLineEditingControllerImpl( codeLines: CodeLineUtils.toCodeLines(text ?? ''), - options: options + options: options, ); } - factory _CodeLineEditingControllerImpl.fromTextAsync(String? text, [ - CodeLineOptions options = const CodeLineOptions() + factory _CodeLineEditingControllerImpl.fromTextAsync( + String? text, [ + CodeLineOptions options = const CodeLineOptions(), ]) { - final _CodeLineEditingControllerImpl controller = _CodeLineEditingControllerImpl( - codeLines: _kInitialCodeLines, - options: options - ); - CodeLineUtils.toCodeLinesAsync(text ?? '').then((value) => controller.codeLines = value); + final _CodeLineEditingControllerImpl controller = + _CodeLineEditingControllerImpl( + codeLines: _kInitialCodeLines, + options: options, + ); + CodeLineUtils.toCodeLinesAsync( + text ?? '', + ).then((value) => controller.codeLines = value); + return controller; } + @override + final CodeLineOptions options; + final CodeLineSpanBuilder? spanBuilder; + late final _CodeLineEditingCache _cache; + late int _preEditLineIndex; + CodeLineEditingValue? _preValue; + GlobalKey? _editorKey; @override set value(CodeLineEditingValue value) { @@ -58,22 +61,18 @@ class _CodeLineEditingControllerImpl extends ValueNotifier @override set codeLines(CodeLines newCodeLines) { value = value.copyWith( - codeLines: newCodeLines.isEmpty ? _kInitialCodeLines : newCodeLines + codeLines: newCodeLines.isEmpty ? _kInitialCodeLines : newCodeLines, ); } @override set selection(CodeLineSelection newSelection) { - value = value.copyWith( - selection: newSelection - ); + value = value.copyWith(selection: newSelection); } @override set composing(TextRange newComposing) { - value = value.copyWith( - composing: newComposing - ); + value = value.copyWith(composing: newComposing); } TextLineBreak get lineBreak => options.lineBreak; @@ -134,6 +133,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } } } + return sb.toString(); } @@ -150,9 +150,10 @@ class _CodeLineEditingControllerImpl extends ValueNotifier baseRawIndex = index2lineIndex(selection.baseIndex); extentRawIndex = index2lineIndex(selection.extentIndex); } + return selection.copyWith( baseIndex: baseRawIndex, - extentIndex: extentRawIndex + extentIndex: extentRawIndex, ); } @@ -160,8 +161,11 @@ class _CodeLineEditingControllerImpl extends ValueNotifier bool get isEmpty => codeLines == _kInitialCodeLines; @override - bool get isAllSelected => selection.start.index == 0 && selection.start.offset == 0 && - selection.end.index == codeLines.length - 1 && selection.end.offset == codeLines.last.length; + bool get isAllSelected => + selection.start.index == 0 && + selection.start.offset == 0 && + selection.end.index == codeLines.length - 1 && + selection.end.offset == codeLines.last.length; @override bool get canUndo => _cache.canUndo; @@ -173,22 +177,22 @@ class _CodeLineEditingControllerImpl extends ValueNotifier set text(String value) { runRevocableOp(() { this.value = CodeLineEditingValue( - codeLines: CodeLineUtils.toCodeLines(value) + codeLines: CodeLineUtils.toCodeLines(value), ); }); } @override set textAsync(String value) { - CodeLineUtils.toCodeLinesAsync(value).then((value) { - runRevocableOp(() { - this.value = CodeLineEditingValue( - codeLines: value - ); - }); - }).onError((error, stackTrace) { - // Should not happen - }); + CodeLineUtils.toCodeLinesAsync(value) + .then((value) { + runRevocableOp(() { + this.value = CodeLineEditingValue(codeLines: value); + }); + }) + .onError((error, stackTrace) { + // Should not happen + }); } @override @@ -208,16 +212,18 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } else { newCodeLines = CodeLines.from(codeLines); newCodeLines[selection.startIndex] = startLine.copyWith( - text: newValue.text + text: newValue.text, ); } newSelection = newValue.selection; newComposing = newValue.composing; } else if (selection.baseIndex < selection.extentIndex) { newCodeLines = codeLines.sublines(0, selection.startIndex); - newCodeLines.add(endLine.copyWith( - text: newValue.text + endLine.substring(selection.endOffset) - )); + newCodeLines.add( + endLine.copyWith( + text: newValue.text + endLine.substring(selection.endOffset), + ), + ); if (selection.endIndex + 1 < codeLines.length) { newCodeLines.addFrom(codeLines, selection.endIndex + 1); } @@ -225,14 +231,16 @@ class _CodeLineEditingControllerImpl extends ValueNotifier newComposing = newValue.composing; } else { newCodeLines = codeLines.sublines(0, selection.startIndex); - newCodeLines.add(endLine.copyWith( - text: startLine.substring(0, selection.startOffset) + newValue.text - )); + newCodeLines.add( + endLine.copyWith( + text: startLine.substring(0, selection.startOffset) + newValue.text, + ), + ); if (selection.endIndex + 1 < codeLines.length) { newCodeLines.addFrom(codeLines, selection.endIndex + 1); } newSelection = TextSelection.collapsed( - offset: selection.startOffset + newValue.selection.baseOffset + offset: selection.startOffset + newValue.selection.baseOffset, ); if (newValue.composing.isValid) { newComposing = TextRange( @@ -245,7 +253,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } if (_preEditLineIndex != selection.extentIndex) { _preEditLineIndex = selection.extentIndex; - _cache.markNewRecord(true); + _cache.markNewRecord = true; } value = value.copyWith( codeLines: newCodeLines, @@ -253,9 +261,9 @@ class _CodeLineEditingControllerImpl extends ValueNotifier index: selection.startIndex, selection: newSelection, ), - composing: newComposing + composing: newComposing, ); - _cache.markNewRecord(false); + _cache.markNewRecord = false; makeCursorCenterIfInvisible(); } @@ -286,16 +294,14 @@ class _CodeLineEditingControllerImpl extends ValueNotifier baseIndex: 0, baseOffset: 0, extentIndex: codeLines.length - 1, - extentOffset: codeLines.last.length + extentOffset: codeLines.last.length, ); } @override void cancelSelection() { if (!selection.isCollapsed) { - selection = CodeLineSelection.fromPosition( - position: selection.extent - ); + selection = CodeLineSelection.fromPosition(position: selection.extent); makeCursorCenterIfInvisible(); } } @@ -315,14 +321,12 @@ class _CodeLineEditingControllerImpl extends ValueNotifier switch (direction) { case AxisDirection.left: if (!selection.isCollapsed) { - selection = CodeLineSelection.fromPosition( - position: selection.start - ); + selection = CodeLineSelection.fromPosition(position: selection.start); } else if (selection.extentIndex != 0 || selection.extentOffset != 0) { if (selection.baseAffinity != selection.extentAffinity) { selection = selection.copyWith( baseAffinity: TextAffinity.upstream, - extentAffinity: TextAffinity.upstream + extentAffinity: TextAffinity.upstream, ); } else { final int index; @@ -333,37 +337,47 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } else { index = selection.extentIndex; // Skip 1 character to left - offset = codeLines[index].substring(0, selection.extentOffset).characters.skipLast(1).string.length; + offset = + codeLines[index] + .substring(0, selection.extentOffset) + .characters + .skipLast(1) + .string + .length; } selection = CodeLineSelection.collapsed( index: index, offset: offset, - affinity: TextAffinity.downstream, ); } } break; case AxisDirection.right: if (!selection.isCollapsed) { - selection = CodeLineSelection.fromPosition( - position: selection.end - ); - } else if (selection.extentIndex != codeLines.length - 1 || selection.extentOffset != codeLines.last.length) { + selection = CodeLineSelection.fromPosition(position: selection.end); + } else if (selection.extentIndex != codeLines.length - 1 || + selection.extentOffset != codeLines.last.length) { if (selection.baseAffinity != selection.extentAffinity) { selection = selection.copyWith( baseAffinity: TextAffinity.downstream, - extentAffinity: TextAffinity.downstream + extentAffinity: TextAffinity.downstream, ); } else { final int index; final int offset; - if (selection.extentOffset == extentLine.length){ + if (selection.extentOffset == extentLine.length) { index = selection.extentIndex + 1; offset = 0; } else { index = selection.extentIndex; // Skip 1 character to right - offset = selection.extentOffset + codeLines[index].substring(selection.extentOffset).characters.first.length; + offset = + selection.extentOffset + + codeLines[index] + .substring(selection.extentOffset) + .characters + .first + .length; } selection = CodeLineSelection.collapsed( index: index, @@ -374,43 +388,40 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } break; case AxisDirection.up: - final CodeLinePosition? position = _render?.getUpPosition(selection.start); + final CodeLinePosition? position = _render?.getUpPosition( + selection.start, + ); if (position != null) { - selection = CodeLineSelection.fromPosition( - position: position - ); + selection = CodeLineSelection.fromPosition(position: position); } else { final CodeLinePosition current = selection.start; if (current.index == 0) { - selection = const CodeLineSelection.collapsed( - index: 0, - offset: 0 - ); + selection = const CodeLineSelection.collapsed(index: 0, offset: 0); } else { selection = CodeLineSelection.collapsed( index: current.index - 1, - offset: min(codeLines[current.index - 1].length, current.offset) + offset: min(codeLines[current.index - 1].length, current.offset), ); } } break; case AxisDirection.down: - final CodeLinePosition? position = _render?.getDownPosition(selection.start); + final CodeLinePosition? position = _render?.getDownPosition( + selection.start, + ); if (position != null) { - selection = CodeLineSelection.fromPosition( - position: position - ); + selection = CodeLineSelection.fromPosition(position: position); } else { final CodeLinePosition current = selection.end; if (current.index == codeLines.length - 1) { selection = CodeLineSelection.collapsed( index: codeLines.length - 1, - offset: codeLines.last.length + offset: codeLines.last.length, ); } else { selection = CodeLineSelection.collapsed( index: current.index + 1, - offset: min(codeLines[current.index + 1].length, current.offset) + offset: min(codeLines[current.index + 1].length, current.offset), ); } } @@ -435,7 +446,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } selection = CodeLineSelection.collapsed( index: selection.extentIndex, - offset: offset + offset: offset, ); makeCursorVisible(); } @@ -444,17 +455,14 @@ class _CodeLineEditingControllerImpl extends ValueNotifier void moveCursorToLineEnd() { selection = CodeLineSelection.collapsed( index: selection.extentIndex, - offset: extentLine.length + offset: extentLine.length, ); makeCursorVisible(); } @override void moveCursorToPageStart() { - selection = const CodeLineSelection.collapsed( - index: 0, - offset: 0 - ); + selection = const CodeLineSelection.collapsed(index: 0, offset: 0); makeCursorVisible(); } @@ -462,19 +470,19 @@ class _CodeLineEditingControllerImpl extends ValueNotifier void moveCursorToPageEnd() { selection = CodeLineSelection.collapsed( index: codeLines.length - 1, - offset: codeLines.last.length + offset: codeLines.last.length, ); makeCursorVisible(); } @override void moveCursorToPageUp() { - // TODO + // TODO(XXX): Implement this } @override void moveCursorToPageDown() { - // TODO + // TODO(XXX): Implement this } @override @@ -514,7 +522,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier int i = offset - 1; while (i > 0) { - bool isCurrentAlphanumeric = _isAlphanumeric(current.codeUnitAt(i)); + final bool isCurrentAlphanumeric = _isAlphanumeric(current.codeUnitAt(i)); if (isBeforeAlphanumeric != isCurrentAlphanumeric) { break; @@ -546,10 +554,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier return; } - selection = CodeLineSelection.collapsed( - index: newIndex, - offset: 0, - ); + selection = CodeLineSelection.collapsed(index: newIndex, offset: 0); makeCursorVisible(); } @@ -574,7 +579,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier int i = offset + 1; while (i < current.length) { - bool isCurrentAlphanumeric = _isAlphanumeric(current.codeUnitAt(i)); + final bool isCurrentAlphanumeric = _isAlphanumeric(current.codeUnitAt(i)); if (isBeforeAlphanumeric != isCurrentAlphanumeric) { break; @@ -603,77 +608,88 @@ class _CodeLineEditingControllerImpl extends ValueNotifier offset = codeLines[index].length; } else { index = selection.extentIndex; - final Characters characters = extentLine.substring(0, selection.extentOffset).characters; - offset = selection.extentOffset - characters.takeLast(1).first.length; + final Characters characters = + extentLine.substring(0, selection.extentOffset).characters; + offset = + selection.extentOffset - characters.takeLast(1).first.length; } selection = selection.copyWith( extentIndex: index, extentOffset: offset, - extentAffinity: TextAffinity.downstream + extentAffinity: TextAffinity.downstream, ); } break; case AxisDirection.right: - if (selection.extentIndex != codeLines.length - 1 || selection.extentOffset != codeLines.last.length) { + if (selection.extentIndex != codeLines.length - 1 || + selection.extentOffset != codeLines.last.length) { final int index; final int offset; - if (selection.extentOffset == extentLine.length){ + if (selection.extentOffset == extentLine.length) { index = selection.extentIndex + 1; offset = 0; } else { - final Characters characters = extentLine.substring(selection.extentOffset).characters; + final Characters characters = + extentLine.substring(selection.extentOffset).characters; index = selection.extentIndex; - offset = selection.extentOffset + characters.elementAt(0).length; + offset = selection.extentOffset + characters.first.length; } selection = selection.copyWith( extentIndex: index, extentOffset: offset, - extentAffinity: TextAffinity.upstream + extentAffinity: TextAffinity.upstream, ); } break; case AxisDirection.up: - final CodeLinePosition? position = _render?.getUpPosition(selection.extent); + final CodeLinePosition? position = _render?.getUpPosition( + selection.extent, + ); if (position != null) { selection = selection.copyWith( extentIndex: position.index, extentOffset: position.offset, - extentAffinity: position.affinity + extentAffinity: position.affinity, ); } else { final CodeLinePosition current = selection.extent; if (current.index == 0) { - selection = selection.copyWith( - extentIndex: 0, - extentOffset: 0 - ); + selection = selection.copyWith(extentIndex: 0, extentOffset: 0); } else { selection = selection.copyWith( extentIndex: current.index - 1, - extentOffset: min(codeLines[current.index - 1].length, current.offset) + extentOffset: min( + codeLines[current.index - 1].length, + current.offset, + ), ); } } break; case AxisDirection.down: - final CodeLinePosition? position = _render?.getDownPosition(selection.extent); + final CodeLinePosition? position = _render?.getDownPosition( + selection.extent, + ); if (position != null) { selection = selection.copyWith( extentIndex: position.index, extentOffset: position.offset, - extentAffinity: position.affinity + extentAffinity: position.affinity, ); } else { final CodeLinePosition current = selection.extent; if (current.index == codeLines.length - 1) { selection = selection.copyWith( extentIndex: codeLines.length - 1, - extentOffset: codeLines.last.length + extentOffset: codeLines.last.length, ); } else { selection = selection.copyWith( extentIndex: current.index + 1, - extentOffset: min(codeLines[current.index + 1].length, current.offset) + extentOffset: min( + codeLines[current.index + 1].length, + current.offset, + ), ); } } @@ -684,9 +700,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier @override void extendSelectionToLineStart() { - selection = selection.copyWith( - extentOffset: 0 - ); + selection = selection.copyWith(extentOffset: 0); makeCursorVisible(); } @@ -694,17 +708,14 @@ class _CodeLineEditingControllerImpl extends ValueNotifier void extendSelectionToLineEnd() { selection = selection.copyWith( extentIndex: selection.extentIndex, - extentOffset: extentLine.length + extentOffset: extentLine.length, ); makeCursorVisible(); } @override void extendSelectionToPageStart() { - selection = selection.copyWith( - extentIndex: 0, - extentOffset: 0 - ); + selection = selection.copyWith(extentIndex: 0, extentOffset: 0); makeCursorVisible(); } @@ -712,7 +723,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier void extendSelectionToPageEnd() { selection = selection.copyWith( extentIndex: codeLines.length - 1, - extentOffset: codeLines.last.length + extentOffset: codeLines.last.length, ); makeCursorVisible(); } @@ -754,7 +765,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier int i = offset - 1; while (i > 0) { - bool isCurrentAlphanumeric = _isAlphanumeric(current.codeUnitAt(i)); + final bool isCurrentAlphanumeric = _isAlphanumeric(current.codeUnitAt(i)); if (isBeforeAlphanumeric != isCurrentAlphanumeric) { break; @@ -786,10 +797,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier return; } - selection = selection.copyWith( - extentIndex: newIndex, - extentOffset: 0, - ); + selection = selection.copyWith(extentIndex: newIndex, extentOffset: 0); makeCursorVisible(); } @@ -814,7 +822,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier int i = offset + 1; while (i < current.length) { - bool isCurrentAlphanumeric = _isAlphanumeric(current.codeUnitAt(i)); + final bool isCurrentAlphanumeric = _isAlphanumeric(current.codeUnitAt(i)); if (isBeforeAlphanumeric != isCurrentAlphanumeric) { break; @@ -916,7 +924,9 @@ class _CodeLineEditingControllerImpl extends ValueNotifier @override Future copy() { if (selection.isCollapsed) { - return Clipboard.setData(ClipboardData(text: extentLine.text + lineBreak.value)); + return Clipboard.setData( + ClipboardData(text: extentLine.text + lineBreak.value), + ); } else { return Clipboard.setData(ClipboardData(text: selectedText)); } @@ -926,35 +936,41 @@ class _CodeLineEditingControllerImpl extends ValueNotifier void cut() { copy(); if (selection.isCollapsed) { - deleteSelectionLines(true); + deleteSelectionLines(); } else { deleteSelection(); } } @override - void paste() { - Clipboard.getData(Clipboard.kTextPlain).then((data) { - final String? text = data?.text; - if (text == null || text.isEmpty) { - return; - } - replaceSelection(text); - }); + Future paste() async { + final data = await Clipboard.getData(Clipboard.kTextPlain); + + final String? text = data?.text; + if (text == null || text.isEmpty) { + return; + } + + replaceSelection(text); } @override void collapseChunk(int start, int end) { - if (start < 0 || start >= codeLines.length || end <= start + 1 || end > codeLines.length) { + if (start < 0 || + start >= codeLines.length || + end <= start + 1 || + end > codeLines.length) { return; } if (codeLines[start].chunkParent) { return; } final CodeLines newCodeLines = codeLines.sublines(0, start); - newCodeLines.add(codeLines[start].copyWith( - chunks: codeLines.sublines(start + 1, end).toList() - )); + newCodeLines.add( + codeLines[start].copyWith( + chunks: codeLines.sublines(start + 1, end).toList(), + ), + ); if (end < codeLines.length) { newCodeLines.addFrom(codeLines, end); } @@ -988,14 +1004,14 @@ class _CodeLineEditingControllerImpl extends ValueNotifier baseIndex: newStartIndex, baseOffset: newStartOffset, extentIndex: newEndIndex, - extentOffset: newEndOffset + extentOffset: newEndOffset, ); } else { newSelection = selection.copyWith( baseIndex: newEndIndex, baseOffset: newEndOffset, extentIndex: newStartIndex, - extentOffset: newStartOffset + extentOffset: newStartOffset, ); } final TextRange newComposing; @@ -1007,7 +1023,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier value = value.copyWith( codeLines: newCodeLines, selection: newSelection, - composing: newComposing + composing: newComposing, ); } @@ -1017,9 +1033,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier return; } final CodeLines newCodeLines = codeLines.sublines(0, index); - newCodeLines.add(codeLines[index].copyWith( - chunks: const [] - )); + newCodeLines.add(codeLines[index].copyWith(chunks: const [])); final List collapsedChunks = codeLines[index].chunks; newCodeLines.addAll(collapsedChunks); if (index + 1 < codeLines.length) { @@ -1031,30 +1045,25 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } else if (selection.startIndex <= index) { if (selection.baseIndex < selection.extentIndex) { newSelection = selection.copyWith( - extentIndex: selection.extentIndex + collapsedChunks.length + extentIndex: selection.extentIndex + collapsedChunks.length, ); } else { newSelection = selection.copyWith( - baseIndex: selection.baseIndex + collapsedChunks.length + baseIndex: selection.baseIndex + collapsedChunks.length, ); } } else { newSelection = selection.copyWith( baseIndex: selection.baseIndex + collapsedChunks.length, - extentIndex: selection.extentIndex + collapsedChunks.length + extentIndex: selection.extentIndex + collapsedChunks.length, ); } - value = value.copyWith( - codeLines: newCodeLines, - selection: newSelection, - ); + value = value.copyWith(codeLines: newCodeLines, selection: newSelection); } @override void clearComposing() { - value = value.copyWith( - composing: TextRange.empty - ); + value = value.copyWith(composing: TextRange.empty); } @override @@ -1066,7 +1075,8 @@ class _CodeLineEditingControllerImpl extends ValueNotifier int index2lineIndex(int index) => codeLines.index2lineIndex(index); @override - CodeLineIndex lineIndex2Index(int lineIndex) => codeLines.lineIndex2Index(lineIndex); + CodeLineIndex lineIndex2Index(int lineIndex) => + codeLines.lineIndex2Index(lineIndex); @override void makeCursorCenterIfInvisible() { @@ -1095,9 +1105,9 @@ class _CodeLineEditingControllerImpl extends ValueNotifier @override void runRevocableOp(VoidCallback op) { - _cache.markNewRecord(true); + _cache.markNewRecord = true; op(); - _cache.markNewRecord(false); + _cache.markNewRecord = false; } @override @@ -1107,7 +1117,8 @@ class _CodeLineEditingControllerImpl extends ValueNotifier super.dispose(); } - _CodeFieldRender? get _render => _editorKey?.currentContext?.findRenderObject() as _CodeFieldRender?; + _CodeFieldRender? get _render => + _editorKey?.currentContext?.findRenderObject() as _CodeFieldRender?; bool _isAlphanumeric(int codeUnit) { return (codeUnit <= 57 && codeUnit >= 48) || @@ -1130,7 +1141,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier selection: selection.copyWith( baseIndex: selection.baseIndex - 1, extentIndex: selection.extentIndex - 1, - ) + ), ); makeCursorCenterIfInvisible(); } @@ -1150,7 +1161,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier selection: selection.copyWith( baseIndex: selection.baseIndex + 1, extentIndex: selection.extentIndex + 1, - ) + ), ); makeCursorCenterIfInvisible(); } @@ -1158,34 +1169,36 @@ class _CodeLineEditingControllerImpl extends ValueNotifier void _deleteLineForward() { if (!selection.isCollapsed) { _deleteForward(); + return; } if (selection.extentOffset >= extentLine.length) { _deleteForward(); + return; } final CodeLines newCodeLines = CodeLines.from(codeLines); newCodeLines[selection.extentIndex] = extentLine.copyWith( - text: _codeTextBefore(selection.extent) - ); - value = value.copyWith( - codeLines: newCodeLines, + text: _codeTextBefore(selection.extent), ); + value = value.copyWith(codeLines: newCodeLines); makeCursorVisible(); } void _deleteLineBackward() { if (!selection.isCollapsed) { _deleteBackward(); + return; } if (selection.extentOffset == 0) { _deleteBackward(); + return; } final CodeLines newCodeLines = CodeLines.from(codeLines); newCodeLines[selection.extentIndex] = extentLine.copyWith( - text: _codeTextAfter(selection.extent) + text: _codeTextAfter(selection.extent), ); value = value.copyWith( codeLines: newCodeLines, @@ -1211,16 +1224,13 @@ class _CodeLineEditingControllerImpl extends ValueNotifier final int index = min(selection.startIndex, newCodeLines.length - 1); final int offset; if (keepExtentOffset) { - offset = min(newCodeLines[index].length, selection.extentOffset); + offset = min(newCodeLines[index].length, selection.extentOffset); } else { offset = 0; } value = value.copyWith( codeLines: newCodeLines, - selection: CodeLineSelection.collapsed( - index: index, - offset: offset - ), + selection: CodeLineSelection.collapsed(index: index, offset: offset), ); makeCursorCenterIfInvisible(); } @@ -1231,9 +1241,9 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } final CodeLines newCodeLines = codeLines.sublines(0, selection.startIndex); final CodeLine after = _codeLineAfter(selection.end); - newCodeLines.add(after.copyWith( - text: _codeTextBefore(selection.start) + after.text, - )); + newCodeLines.add( + after.copyWith(text: _codeTextBefore(selection.start) + after.text), + ); if (selection.endIndex + 1 < codeLines.length) { newCodeLines.addFrom(codeLines, selection.endIndex + 1); } @@ -1242,8 +1252,8 @@ class _CodeLineEditingControllerImpl extends ValueNotifier selection: CodeLineSelection.collapsed( index: selection.startIndex, offset: selection.startOffset, - affinity: selection.start.affinity - ) + affinity: selection.start.affinity, + ), ); makeCursorCenterIfInvisible(); } @@ -1256,15 +1266,20 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } if (selection.baseOffset == 0) { // Delete this line and merge into the previous line - final CodeLines newCodeLines = codeLines.sublines(0, selection.baseIndex - 1); + final CodeLines newCodeLines = codeLines.sublines( + 0, + selection.baseIndex - 1, + ); final CodeLine preLine = codeLines[selection.baseIndex - 1]; if (preLine.chunkParent) { // Should expand this chunk newCodeLines.add(CodeLine(preLine.text)); - newCodeLines.addAll(preLine.chunks.sublist(0, preLine.chunks.length - 1)); - newCodeLines.add(baseLine.copyWith( - text: preLine.chunks.last.text + baseLine.text - )); + newCodeLines.addAll( + preLine.chunks.sublist(0, preLine.chunks.length - 1), + ); + newCodeLines.add( + baseLine.copyWith(text: preLine.chunks.last.text + baseLine.text), + ); if (selection.baseIndex + 1 < codeLines.length) { newCodeLines.addFrom(codeLines, selection.baseIndex + 1); } @@ -1273,12 +1288,12 @@ class _CodeLineEditingControllerImpl extends ValueNotifier selection: CodeLineSelection.collapsed( index: selection.baseIndex + preLine.chunks.length - 1, offset: preLine.chunks.last.length, - ) + ), ); } else { - newCodeLines.add(baseLine.copyWith( - text: preLine.text + baseLine.text - )); + newCodeLines.add( + baseLine.copyWith(text: preLine.text + baseLine.text), + ); if (selection.baseIndex + 1 < codeLines.length) { newCodeLines.addFrom(codeLines, selection.baseIndex + 1); } @@ -1287,7 +1302,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier selection: CodeLineSelection.collapsed( index: selection.baseIndex - 1, offset: preLine.length, - ) + ), ); } } else { @@ -1296,14 +1311,16 @@ class _CodeLineEditingControllerImpl extends ValueNotifier // Delete left and right closure symbols at same time, like this: // abc{|}123 -> abc123 newCodeLines[selection.baseIndex] = baseLine.copyWith( - text: baseLine.substring(0, selection.baseOffset - 1) + baseLine.substring(selection.baseOffset + 1) + text: + baseLine.substring(0, selection.baseOffset - 1) + + baseLine.substring(selection.baseOffset + 1), ); value = value.copyWith( codeLines: newCodeLines, selection: CodeLineSelection.collapsed( index: selection.baseIndex, - offset: selection.baseOffset - 1 - ) + offset: selection.baseOffset - 1, + ), ); } else { String backward = _codeTextBefore(selection.base); @@ -1316,14 +1333,14 @@ class _CodeLineEditingControllerImpl extends ValueNotifier backward = characters.skipLast(1).string; } newCodeLines[selection.baseIndex] = baseLine.copyWith( - text: backward + baseLine.substring(selection.baseOffset) + text: backward + baseLine.substring(selection.baseOffset), ); value = value.copyWith( codeLines: newCodeLines, selection: CodeLineSelection.collapsed( index: selection.baseIndex, - offset: backward.length - ) + offset: backward.length, + ), ); } } @@ -1335,27 +1352,33 @@ class _CodeLineEditingControllerImpl extends ValueNotifier void _deleteForward() { if (selection.isCollapsed) { - if (selection.extentIndex == codeLines.length - 1 && selection.extentOffset == codeLines.last.length) { + if (selection.extentIndex == codeLines.length - 1 && + selection.extentOffset == codeLines.last.length) { // At the end position of page, nothing to delete return; } if (selection.extentOffset == extentLine.length) { // Delete next line and merge into the current line - final CodeLines newCodeLines = codeLines.sublines(0, selection.extentIndex); + final CodeLines newCodeLines = codeLines.sublines( + 0, + selection.extentIndex, + ); if (extentLine.chunkParent) { final CodeLine nextLine = extentLine.chunks.first; // Should expand this chunk - newCodeLines.add(nextLine.copyWith( - text: extentLine.text + nextLine.text - )); + newCodeLines.add( + nextLine.copyWith(text: extentLine.text + nextLine.text), + ); newCodeLines.addAll(extentLine.chunks.sublist(1)); if (selection.extentIndex + 1 < codeLines.length) { newCodeLines.addFrom(codeLines, selection.extentIndex + 1); } } else { - newCodeLines.add(codeLines[selection.extentIndex + 1].copyWith( - text: extentLine.text + codeLines[selection.extentIndex + 1].text - )); + newCodeLines.add( + codeLines[selection.extentIndex + 1].copyWith( + text: extentLine.text + codeLines[selection.extentIndex + 1].text, + ), + ); if (selection.extentIndex + 2 < codeLines.length) { newCodeLines.addFrom(codeLines, selection.extentIndex + 2); } @@ -1365,7 +1388,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier selection: CodeLineSelection.collapsed( index: selection.extentIndex, offset: extentLine.length, - ) + ), ); } else { final CodeLines newCodeLines = CodeLines.from(codeLines); @@ -1373,19 +1396,22 @@ class _CodeLineEditingControllerImpl extends ValueNotifier // Delete left and right closure symbols at same time, like this: // abc{|}123 -> abc123 newCodeLines[selection.extentIndex] = extentLine.copyWith( - text: extentLine.substring(0, selection.extentOffset - 1) + extentLine.substring(selection.extentOffset + 1) + text: + extentLine.substring(0, selection.extentOffset - 1) + + extentLine.substring(selection.extentOffset + 1), ); value = value.copyWith( codeLines: newCodeLines, selection: CodeLineSelection.collapsed( index: selection.extentIndex, - offset: selection.extentOffset - 1 - ) + offset: selection.extentOffset - 1, + ), ); } else { String forward = _codeTextAfter(selection.extent); final int indentSizeInForward = _prefixWhitespaceCount(forward); - if (indentSizeInForward > 0 && indentSizeInForward % indent.length == 0) { + if (indentSizeInForward > 0 && + indentSizeInForward % indent.length == 0) { forward = forward.substring(indent.length); } else { // Delete the next character normally @@ -1393,14 +1419,14 @@ class _CodeLineEditingControllerImpl extends ValueNotifier forward = characters.skip(1).string; } newCodeLines[selection.extentIndex] = extentLine.copyWith( - text: _codeTextBefore(selection.extent) + forward + text: _codeTextBefore(selection.extent) + forward, ); value = value.copyWith( codeLines: newCodeLines, selection: CodeLineSelection.collapsed( index: selection.extentIndex, - offset: selection.extentOffset - ) + offset: selection.extentOffset, + ), ); } } @@ -1413,10 +1439,12 @@ class _CodeLineEditingControllerImpl extends ValueNotifier void _deleteWordBackward() { if (!selection.isCollapsed) { _deleteBackward(); + return; } if (selection.extentOffset == 0) { _deleteBackward(); + return; } final String current = extentLine.text; @@ -1432,7 +1460,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier bool isBeforeAlphanumeric = _isAlphanumeric(codeUnit); int i = offset - 1; while (i > 0) { - bool isCurrentAlphanumeric = _isAlphanumeric(current.codeUnitAt(i)); + final bool isCurrentAlphanumeric = _isAlphanumeric(current.codeUnitAt(i)); if (isBeforeAlphanumeric != isCurrentAlphanumeric) { break; } @@ -1446,9 +1474,9 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } final CodeLines newCodeLines = CodeLines.from(codeLines); newCodeLines[selection.extentIndex] = extentLine.copyWith( - text: _codeTextBefore(selection.extent.copyWith( - offset: i - )) + _codeTextAfter(selection.extent) + text: + _codeTextBefore(selection.extent.copyWith(offset: i)) + + _codeTextAfter(selection.extent), ); value = value.copyWith( codeLines: newCodeLines, @@ -1463,10 +1491,12 @@ class _CodeLineEditingControllerImpl extends ValueNotifier void _deleteWordForward() { if (!selection.isCollapsed) { _deleteForward(); + return; } if (selection.extentOffset >= extentLine.length) { _deleteForward(); + return; } final String current = extentLine.text; @@ -1485,7 +1515,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier bool isBeforeAlphanumeric = _isAlphanumeric(codeUnit); int i = offset + 1; while (i < current.length) { - bool isCurrentAlphanumeric = _isAlphanumeric(current.codeUnitAt(i)); + final bool isCurrentAlphanumeric = _isAlphanumeric(current.codeUnitAt(i)); if (isBeforeAlphanumeric != isCurrentAlphanumeric) { break; } @@ -1494,13 +1524,11 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } final CodeLines newCodeLines = CodeLines.from(codeLines); newCodeLines[selection.extentIndex] = extentLine.copyWith( - text: _codeTextBefore(selection.extent) + _codeTextAfter(selection.extent.copyWith( - offset: i - )) - ); - value = value.copyWith( - codeLines: newCodeLines, + text: + _codeTextBefore(selection.extent) + + _codeTextAfter(selection.extent.copyWith(offset: i)), ); + value = value.copyWith(codeLines: newCodeLines); makeCursorVisible(); } @@ -1524,9 +1552,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier offset = alignIndent.length; } // Align the next line's intent with pre code line - newCodeLines.add(after.copyWith( - text: alignIndent + after.text - )); + newCodeLines.add(after.copyWith(text: alignIndent + after.text)); if (selection.endIndex + 1 < codeLines.length) { newCodeLines.addFrom(codeLines, selection.endIndex + 1); } @@ -1534,7 +1560,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier codeLines: newCodeLines, selection: CodeLineSelection.collapsed( index: selection.startIndex + 1, - offset: offset + offset: offset, ), ); makeCursorCenterIfInvisible(); @@ -1543,30 +1569,39 @@ class _CodeLineEditingControllerImpl extends ValueNotifier void _applyIndent() { final CodeLines newCodeLines = CodeLines.from(codeLines); if (selection.isSameLine) { - if (selection.isCollapsed || selection.startOffset != 0 || selection.endOffset != endLine.length) { + if (selection.isCollapsed || + selection.startOffset != 0 || + selection.endOffset != endLine.length) { final String textBefore = _codeTextBefore(selection.start); - final int indentLength = indent.length - textBefore.length % indent.length; + final int indentLength = + indent.length - textBefore.length % indent.length; newCodeLines[selection.extentIndex] = extentLine.copyWith( - text: textBefore + ' ' * indentLength + _codeTextAfter(selection.end) + text: textBefore + ' ' * indentLength + _codeTextAfter(selection.end), ); value = value.copyWith( codeLines: newCodeLines, selection: CodeLineSelection.collapsed( index: selection.startIndex, - offset: selection.startOffset + indentLength - ) + offset: selection.startOffset + indentLength, + ), ); } else { // This whole line is selected, just add the indent newCodeLines[selection.extentIndex] = extentLine.copyWith( - text: _applyTextIndent(extentLine.text) + text: _applyTextIndent(extentLine.text), ); value = value.copyWith( codeLines: newCodeLines, selection: selection.copyWith( - baseOffset: selection.baseOffset == 0 ? 0 : newCodeLines[selection.baseIndex].length, - extentOffset: selection.extentOffset == 0 ? 0 : newCodeLines[selection.extentIndex].length - ) + baseOffset: + selection.baseOffset == 0 + ? 0 + : newCodeLines[selection.baseIndex].length, + extentOffset: + selection.extentOffset == 0 + ? 0 + : newCodeLines[selection.extentIndex].length, + ), ); } } else { @@ -1582,17 +1617,27 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } newCodeLines[i] = codeLines[i].copyWith( text: _applyTextIndent(codeLines[i].text), - chunks: chunks + chunks: chunks, ); } value = value.copyWith( codeLines: newCodeLines, selection: selection.copyWith( - baseOffset: _whitespaceCountBefore(baseLine.text, selection.baseOffset) == selection.baseOffset ? - selection.baseOffset : selection.baseOffset + (newCodeLines[selection.baseIndex].length - baseLine.text.length), - extentOffset: _whitespaceCountBefore(extentLine.text, selection.extentOffset) == selection.extentOffset ? - selection.extentOffset : selection.extentOffset + (newCodeLines[selection.extentIndex].length - extentLine.text.length), - ) + baseOffset: + _whitespaceCountBefore(baseLine.text, selection.baseOffset) == + selection.baseOffset + ? selection.baseOffset + : selection.baseOffset + + (newCodeLines[selection.baseIndex].length - + baseLine.text.length), + extentOffset: + _whitespaceCountBefore(extentLine.text, selection.extentOffset) == + selection.extentOffset + ? selection.extentOffset + : selection.extentOffset + + (newCodeLines[selection.extentIndex].length - + extentLine.text.length), + ), ); } makeCursorCenterIfInvisible(); @@ -1602,7 +1647,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier final CodeLines newCodeLines; if (selection.isSameLine) { final CodeLine outdentCodeLine = extentLine.copyWith( - text: _applyTextOutdent(extentLine.text) + text: _applyTextOutdent(extentLine.text), ); if (outdentCodeLine == extentLine) { // Nothing changed @@ -1624,12 +1669,19 @@ class _CodeLineEditingControllerImpl extends ValueNotifier // Apply indent to collapsed chunks chunks = _applyOutdents(chunks); } - outdentCodeLines.add(codeLines[i].copyWith( - text: _applyTextOutdent(codeLines[i].text), - chunks: chunks - )); + outdentCodeLines.add( + codeLines[i].copyWith( + text: _applyTextOutdent(codeLines[i].text), + chunks: chunks, + ), + ); } - if (outdentCodeLines.equals(codeLines.sublines(selection.startIndex, lastSkipped ? selection.endIndex : selection.endIndex + 1))) { + if (outdentCodeLines.equals( + codeLines.sublines( + selection.startIndex, + lastSkipped ? selection.endIndex : selection.endIndex + 1, + ), + )) { // Nothing changed return; } @@ -1639,16 +1691,40 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } } // If there are enough whitespace after the selection, we should keep the selection offset. - final int whitespaceCountAfterBaseLine = max(0, _prefixWhitespaceCount(baseLine.text) - selection.baseOffset); - final int baseOffset = max(0, selection.baseOffset - max(0, baseLine.length - newCodeLines[selection.baseIndex].length - whitespaceCountAfterBaseLine)); - final int whitespaceCountAfterExtentLine = max(0, _prefixWhitespaceCount(extentLine.text) - selection.extentOffset); - final int extentOffset = max(0, selection.extentOffset - max(0, extentLine.length - newCodeLines[selection.extentIndex].length - whitespaceCountAfterExtentLine)); + final int whitespaceCountAfterBaseLine = max( + 0, + _prefixWhitespaceCount(baseLine.text) - selection.baseOffset, + ); + final int baseOffset = max( + 0, + selection.baseOffset - + max( + 0, + baseLine.length - + newCodeLines[selection.baseIndex].length - + whitespaceCountAfterBaseLine, + ), + ); + final int whitespaceCountAfterExtentLine = max( + 0, + _prefixWhitespaceCount(extentLine.text) - selection.extentOffset, + ); + final int extentOffset = max( + 0, + selection.extentOffset - + max( + 0, + extentLine.length - + newCodeLines[selection.extentIndex].length - + whitespaceCountAfterExtentLine, + ), + ); value = value.copyWith( codeLines: newCodeLines, selection: selection.copyWith( baseOffset: baseOffset, extentOffset: extentOffset, - ) + ), ); makeCursorCenterIfInvisible(); } @@ -1671,19 +1747,17 @@ class _CodeLineEditingControllerImpl extends ValueNotifier newCodeLines = CodeLines.from(codeLines); final String take = preLine.takeLastCharacter(1); newCodeLines[selection.baseIndex - 1] = preLine.copyWith( - text: preLine.skipLastCharacter(1) - ); - newCodeLines[selection.baseIndex] = baseLine.copyWith( - text: take + text: preLine.skipLastCharacter(1), ); + newCodeLines[selection.baseIndex] = baseLine.copyWith(text: take); newOffset = take.length; } else { newCodeLines = CodeLines.from(codeLines); newCodeLines[selection.baseIndex - 1] = preLine.copyWith( - text: preLine.text + baseLine.takeCharacter(1) + text: preLine.text + baseLine.takeCharacter(1), ); newCodeLines[selection.baseIndex] = baseLine.copyWith( - text: baseLine.skipCharacter(1) + text: baseLine.skipCharacter(1), ); newOffset = 0; } @@ -1692,54 +1766,51 @@ class _CodeLineEditingControllerImpl extends ValueNotifier selection: selection.copyWith( baseOffset: newOffset, extentOffset: newOffset, - ) + ), ); - } else if (selection.baseOffset == baseLine.length && baseLine.characterLength == 1) { + } else if (selection.baseOffset == baseLine.length && + baseLine.characterLength == 1) { if (selection.baseIndex == 0) { return; } final CodeLine preLine = codeLines[selection.baseIndex - 1]; final CodeLines newCodeLines = CodeLines.from(codeLines); newCodeLines[selection.baseIndex - 1] = preLine.copyWith( - text: preLine.text + baseLine.text - ); - newCodeLines[selection.baseIndex] = baseLine.copyWith( - text: '' + text: preLine.text + baseLine.text, ); + newCodeLines[selection.baseIndex] = baseLine.copyWith(text: ''); value = value.copyWith( codeLines: newCodeLines, - selection: selection.copyWith( - baseOffset: 0, - extentOffset: 0, - ) + selection: selection.copyWith(baseOffset: 0, extentOffset: 0), ); } else if (selection.baseOffset == baseLine.length) { final CodeLines newCodeLines = CodeLines.from(codeLines); newCodeLines[selection.baseIndex] = baseLine.copyWith( - text: baseLine.skipLastCharacter(2) + - baseLine.takeCharacterAtLastIndex(0) + - baseLine.takeCharacterAtLastIndex(1) - ); - value = value.copyWith( - codeLines: newCodeLines, + text: + baseLine.skipLastCharacter(2) + + baseLine.takeCharacterAtLastIndex(0) + + baseLine.takeCharacterAtLastIndex(1), ); + value = value.copyWith(codeLines: newCodeLines); } else { final CodeLines newCodeLines = CodeLines.from(codeLines); final Characters characters = baseLine.text.characters; - final int index = baseLine.text.substring(0, selection.baseOffset).characters.length; + final int index = + baseLine.text.substring(0, selection.baseOffset).characters.length; final String start = characters.take(index - 1).string; final String right = characters.elementAt(index); final String left = characters.elementAt(index - 1); - final String end = characters.takeLast(characters.length - index - 1).string; + final String end = + characters.takeLast(characters.length - index - 1).string; newCodeLines[selection.baseIndex] = baseLine.copyWith( - text: start + right + left + end + text: start + right + left + end, ); value = value.copyWith( codeLines: newCodeLines, selection: selection.copyWith( baseOffset: selection.baseOffset + right.length, extentOffset: selection.extentOffset + right.length, - ) + ), ); } } @@ -1749,25 +1820,36 @@ class _CodeLineEditingControllerImpl extends ValueNotifier if (replacement.isEmpty && range.isCollapsed) { return; } - final List replaceCodeLines = CodeLineUtils.toTextLines(replacement); + final List replaceCodeLines = CodeLineUtils.toTextLines( + replacement, + ); final CodeLines newCodeLines = codeLines.sublines(0, range.startIndex); int index = 0; int offset = 0; if (replaceCodeLines.length == 1) { - newCodeLines.add(codeLines[range.endIndex].copyWith( - text: _codeTextBefore(range.start) + replaceCodeLines.first + _codeTextAfter(range.end) - )); + newCodeLines.add( + codeLines[range.endIndex].copyWith( + text: + _codeTextBefore(range.start) + + replaceCodeLines.first + + _codeTextAfter(range.end), + ), + ); index = range.startIndex; offset = range.startOffset + replaceCodeLines.first.length; } else { for (int i = 0; i < replaceCodeLines.length; i++) { final String replaceCodeLine = replaceCodeLines[i]; if (i == 0) { - newCodeLines.add(CodeLine(_codeTextBefore(range.start) + replaceCodeLine)); + newCodeLines.add( + CodeLine(_codeTextBefore(range.start) + replaceCodeLine), + ); } else if (i == replaceCodeLines.length - 1) { - newCodeLines.add(codeLines[range.endIndex].copyWith( - text: replaceCodeLine + _codeTextAfter(range.end) - )); + newCodeLines.add( + codeLines[range.endIndex].copyWith( + text: replaceCodeLine + _codeTextAfter(range.end), + ), + ); index = newCodeLines.length - 1; offset = replaceCodeLine.length; } else { @@ -1783,8 +1865,8 @@ class _CodeLineEditingControllerImpl extends ValueNotifier selection: CodeLineSelection.collapsed( index: index, offset: offset, - affinity: range.extentAffinity - ) + affinity: range.extentAffinity, + ), ); makeCursorCenterIfInvisible(); } @@ -1803,6 +1885,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier if (match.end <= extentOffset) { delta += replacement.length - (match.end - match.start); } + return replacement; }); if (preText == newText) { @@ -1815,7 +1898,8 @@ class _CodeLineEditingControllerImpl extends ValueNotifier extentOffset += delta; final int length = newCodeLines.length; for (int i = 0; i < length; i++) { - final int end = start + newCodeLines[i].charCount + lineBreak.value.length; + final int end = + start + newCodeLines[i].charCount + lineBreak.value.length; if (extentOffset >= start && extentOffset < end) { newExtentIndex = i; newExtentOffset = extentOffset - start; @@ -1827,8 +1911,8 @@ class _CodeLineEditingControllerImpl extends ValueNotifier codeLines: newCodeLines, selection: CodeLineSelection.collapsed( index: newExtentIndex, - offset: newExtentOffset - ) + offset: newExtentOffset, + ), ); makeCursorCenterIfInvisible(); } @@ -1839,8 +1923,14 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } final List newChildren = []; for (final CodeLine codeLine in children) { - newChildren.add(CodeLine(_applyTextIndent(codeLine.text), _applyIndents(codeLine.chunks))); + newChildren.add( + CodeLine( + _applyTextIndent(codeLine.text), + _applyIndents(codeLine.chunks), + ), + ); } + return newChildren; } @@ -1850,14 +1940,21 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } final List newChildren = []; for (final CodeLine codeLine in children) { - newChildren.add(CodeLine(_applyTextOutdent(codeLine.text), _applyOutdents(codeLine.chunks))); + newChildren.add( + CodeLine( + _applyTextOutdent(codeLine.text), + _applyOutdents(codeLine.chunks), + ), + ); } + return newChildren; } String _applyTextIndent(String text) { // Indent the mod count of whitespace final int mod = _prefixWhitespaceCount(text) % indent.length; + return ' ' * (mod == 0 ? indent.length : mod) + text; } @@ -1868,6 +1965,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } // Outdent the mod count of whitespace final int mod = index % indent.length; + return text.substring(mod == 0 ? indent.length : mod); } @@ -1894,6 +1992,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier break; } } + return index; } @@ -1905,6 +2004,7 @@ class _CodeLineEditingControllerImpl extends ValueNotifier } count++; } + return count; } @@ -1915,11 +2015,14 @@ class _CodeLineEditingControllerImpl extends ValueNotifier if (offset == 0 || offset == text.length) { return false; } + return _kClosureAndQuates.contains(text.substring(offset - 1, offset + 1)); } - bool _isMultipleIndent(String text) => text.isNotEmpty && text.length % indent.length == 0 - && _prefixWhitespaceCount(text) == text.length; + bool _isMultipleIndent(String text) => + text.isNotEmpty && + text.length % indent.length == 0 && + _prefixWhitespaceCount(text) == text.length; bool get _selectionInClosure { int? forwardUnitCode; @@ -1946,7 +2049,10 @@ class _CodeLineEditingControllerImpl extends ValueNotifier if (backwardUnitCode == null) { return false; } - return _kClosures.contains(String.fromCharCodes([forwardUnitCode, backwardUnitCode])); + + return _kClosures.contains( + String.fromCharCodes([forwardUnitCode, backwardUnitCode]), + ); } @override @@ -1957,27 +2063,25 @@ class _CodeLineEditingControllerImpl extends ValueNotifier required TextStyle style, }) { return spanBuilder?.call( - context: context, - index: index, - codeLine: codeLines[index], - textSpan: textSpan, - style: style - ) ?? textSpan; + context: context, + index: index, + codeLine: codeLines[index], + textSpan: textSpan, + style: style, + ) ?? + textSpan; } - } class _CodeLineEditingCache { - - final CodeLineEditingController controller; - late _CodeLineEditingCacheNode _node; - late bool _markNewRecord; - _CodeLineEditingCache(this.controller) { controller.addListener(_onValueChanged); _node = _CodeLineEditingCacheNode(controller.value); _markNewRecord = false; } + final CodeLineEditingController controller; + late _CodeLineEditingCacheNode _node; + late bool _markNewRecord; bool get canUndo => _node.pre != null; @@ -2006,7 +2110,7 @@ class _CodeLineEditingCache { controller.removeListener(_onValueChanged); } - void markNewRecord(bool flag) { + set markNewRecord(bool flag) { _markNewRecord = flag; } @@ -2016,22 +2120,27 @@ class _CodeLineEditingCache { } if (_node.isInitial) { _appendNewNode(); + return; } if (!_node.isTail) { _appendNewNode(); + return; } if (_markNewRecord) { _markNewRecord = false; _appendNewNode(); + return; } _node.value = controller.value; } void _appendNewNode() { - final _CodeLineEditingCacheNode newNode = _CodeLineEditingCacheNode(controller.value); + final _CodeLineEditingCacheNode newNode = _CodeLineEditingCacheNode( + controller.value, + ); if (_node.next != null) { _node.next!.pre = null; } @@ -2039,27 +2148,22 @@ class _CodeLineEditingCache { newNode.pre = _node; _node = newNode; } - } class _CodeLineEditingCacheNode { - + _CodeLineEditingCacheNode(this.value); _CodeLineEditingCacheNode? pre; _CodeLineEditingCacheNode? next; CodeLineEditingValue value; - _CodeLineEditingCacheNode(this.value); - bool get isRoot => pre == null; bool get isInitial => pre == null && next == null; bool get isTail => next == null; - } extension _StringExtension on String { - int get indentLength { int index = 0; for (; index < length; index++) { @@ -2067,6 +2171,7 @@ extension _StringExtension on String { break; } } + return index; } @@ -2075,26 +2180,24 @@ extension _StringExtension on String { while (startsWith(indent, index)) { index += indent.length; } + return index; } String insert(String value, int index) { return substring(0, index) + value + substring(index); } - } class _CodeLineEditingControllerDelegate implements CodeLineEditingController { - late CodeLineEditingController _delegate; final List _listeners = []; CodeLineEditingController get delegate => _delegate; set delegate(CodeLineEditingController value) { - for (final listener in _listeners) { - value.addListener(listener); - } + _listeners.forEach(value.addListener); + _delegate = value; notifyListeners(); } @@ -2179,7 +2282,7 @@ class _CodeLineEditingControllerDelegate implements CodeLineEditingController { context: context, index: index, textSpan: textSpan, - style: style + style: style, ); } @@ -2499,5 +2602,4 @@ class _CodeLineEditingControllerDelegate implements CodeLineEditingController { void undo() { _delegate.undo(); } - -} \ No newline at end of file +} diff --git a/lib/src/_code_lines.dart b/lib/src/_code_lines.dart index 20f39a5..8c0ecdb 100644 --- a/lib/src/_code_lines.dart +++ b/lib/src/_code_lines.dart @@ -1,15 +1,13 @@ -part of re_editor; +part of 're_editor.dart'; class _CodeLineSegmentQuckLineCount extends CodeLineSegment { - - late int _lineCount; - _CodeLineSegmentQuckLineCount({ required super.codeLines, required super.dirty, }) { _lineCount = super.lineCount; } + late int _lineCount; @override int get lineCount => _lineCount; @@ -31,6 +29,4 @@ class _CodeLineSegmentQuckLineCount extends CodeLineSegment { super[index] = value; _lineCount = super.lineCount; } - } - diff --git a/lib/src/_code_paragraph.dart b/lib/src/_code_paragraph.dart index 2f5ac90..d4b15b2 100644 --- a/lib/src/_code_paragraph.dart +++ b/lib/src/_code_paragraph.dart @@ -1,7 +1,15 @@ -part of re_editor; +part of 're_editor.dart'; class _ParagraphImpl extends IParagraph { - + _ParagraphImpl({ + required this.text, + required this.span, + required this.paragraph, + required bool trucated, + required double preferredLineHeight, + }) : _trucated = trucated, + _preferredLineHeight = preferredLineHeight, + _lineCount = (paragraph.height / preferredLineHeight).ceil(); // Unicode value for a zero width joiner character. static const int _zwjUtf16 = 0x200d; @@ -15,22 +23,13 @@ class _ParagraphImpl extends IParagraph { // For performance, do not init here Map? _offsets; - _ParagraphImpl({ - required this.text, - required this.span, - required this.paragraph, - required bool trucated, - required double preferredLineHeight, - }) : _trucated = trucated, - _preferredLineHeight = preferredLineHeight, - _lineCount = (paragraph.height / preferredLineHeight).ceil(); - int get runeLength => text.runes.length; int? codeUnitAt(int index) { if (index < 0 || index >= length) { return null; } + return text.codeUnitAt(index); } @@ -59,8 +58,7 @@ class _ParagraphImpl extends IParagraph { @override TextPosition getPosition(Offset offset) { - final TextPosition position = paragraph.getPositionForOffset(offset); - return position; + return paragraph.getPositionForOffset(offset); } @override @@ -68,6 +66,7 @@ class _ParagraphImpl extends IParagraph { if (position.offset >= length - 1) { return null; } + return span.getSpanForPosition(position); } @@ -79,12 +78,11 @@ class _ParagraphImpl extends IParagraph { return false; } offset += child.length; + return true; }); - return TextRange( - start: offset, - end: offset + span.length - ); + + return TextRange(start: offset, end: offset + span.length); } @override @@ -110,25 +108,36 @@ class _ParagraphImpl extends IParagraph { return Offset.zero; } if (position.affinity == TextAffinity.downstream) { - offset = _getOffsetDownstream(position.offset) ?? _getOffsetUpstream(position.offset); + offset = + _getOffsetDownstream(position.offset) ?? + _getOffsetUpstream(position.offset); } else { - offset = _getOffsetUpstream(position.offset) ?? _getOffsetDownstream(position.offset); + offset = + _getOffsetUpstream(position.offset) ?? + _getOffsetDownstream(position.offset); } (_offsets ??= {})[position] = offset; + return offset; } @override List getRangeRects(TextRange range) { if (text.isEmpty) { - return [ - Rect.fromLTWH(0, 0, 0, _preferredLineHeight) - ]; + return [Rect.fromLTWH(0, 0, 0, _preferredLineHeight)]; } if (range.isCollapsed) { return const []; } - return paragraph.getBoxesForRange(range.start, range.end, boxHeightStyle: ui.BoxHeightStyle.max).map((e) => e.toRect()).toList(); + + return paragraph + .getBoxesForRange( + range.start, + range.end, + boxHeightStyle: ui.BoxHeightStyle.max, + ) + .map((e) => e.toRect()) + .toList(); } Offset? _getOffsetDownstream(int position) { @@ -137,13 +146,21 @@ class _ParagraphImpl extends IParagraph { return null; } // Check for multi-code-unit glyphs such as emojis or zero width joiner. - final int graphemeClusterLength = _isUtf16Surrogate(nextCodeUnit) || - _isUnicodeDirectionality(nextCodeUnit) || codeUnitAt(position) == _zwjUtf16 ? 2 : 1; - final List boxes = paragraph.getBoxesForRange(position, - position + graphemeClusterLength, boxHeightStyle: ui.BoxHeightStyle.strut); + final int graphemeClusterLength = + _isUtf16Surrogate(nextCodeUnit) || + _isUnicodeDirectionality(nextCodeUnit) || + codeUnitAt(position) == _zwjUtf16 + ? 2 + : 1; + final List boxes = paragraph.getBoxesForRange( + position, + position + graphemeClusterLength, + boxHeightStyle: ui.BoxHeightStyle.strut, + ); if (boxes.isEmpty) { return null; } + return Offset(boxes.first.left, boxes.first.top); } @@ -153,13 +170,21 @@ class _ParagraphImpl extends IParagraph { return null; } // Check for multi-code-unit glyphs such as emojis or zero width joiner. - final int graphemeClusterLength = _isUtf16Surrogate(prevCodeUnit) || - _isUnicodeDirectionality(prevCodeUnit) || codeUnitAt(position) == _zwjUtf16 ? 2 : 1; - final List boxes = paragraph.getBoxesForRange(position - graphemeClusterLength, - position, boxHeightStyle: ui.BoxHeightStyle.strut); + final int graphemeClusterLength = + _isUtf16Surrogate(prevCodeUnit) || + _isUnicodeDirectionality(prevCodeUnit) || + codeUnitAt(position) == _zwjUtf16 + ? 2 + : 1; + final List boxes = paragraph.getBoxesForRange( + position - graphemeClusterLength, + position, + boxHeightStyle: ui.BoxHeightStyle.strut, + ); if (boxes.isEmpty) { return null; } + return Offset(boxes.first.right, boxes.first.top); } @@ -190,11 +215,10 @@ class _ParagraphImpl extends IParagraph { double _applyFloatingPointHack(double layoutValue) { return layoutValue.ceilToDouble(); } - } class _CodeParagraphProvider { - + _CodeParagraphProvider() : _cachedParagraphs = {}; final Map _cachedParagraphs; ui.TextStyle? _style; @@ -203,8 +227,6 @@ class _CodeParagraphProvider { double? _preferredLineHeight; int? _maxLengthSingleLineRendering; - _CodeParagraphProvider() : _cachedParagraphs = {}; - void updateBaseStyle(TextStyle style) { final ui.TextStyle uiStyle = style.getTextStyle(); if (uiStyle == _style) { @@ -218,16 +240,11 @@ class _CodeParagraphProvider { fontFamily: style.fontFamily, height: style.height, forceStrutHeight: true, - ) + ), ); _style = uiStyle; - final TextPainter painter = TextPainter( - textDirection: TextDirection.ltr, - ); - painter.text = TextSpan( - text: '0', - style: style - ); + final TextPainter painter = TextPainter(textDirection: TextDirection.ltr); + painter.text = TextSpan(text: '0', style: style); _preferredLineHeight = painter.preferredLineHeight; _cachedParagraphs.clear(); } @@ -242,9 +259,7 @@ class _CodeParagraphProvider { IParagraph build(TextSpan span, double maxWidth) { if (maxWidth != _constraints?.width) { - _constraints = ui.ParagraphConstraints( - width: maxWidth - ); + _constraints = ui.ParagraphConstraints(width: maxWidth); _cachedParagraphs.clear(); } final _ParagraphImpl? cache = _cachedParagraphs[span]; @@ -256,11 +271,16 @@ class _CodeParagraphProvider { final String plainText = span.toPlainText(); final int? renderingLength = _maxLengthSingleLineRendering; if (renderingLength != null && plainText.length > renderingLength) { - impl = _build(trucate(span, renderingLength), plainText.substring(0, renderingLength), true); + impl = _build( + trucate(span, renderingLength), + plainText.substring(0, renderingLength), + true, + ); } else { impl = _build(span, plainText, false); } _cachedParagraphs[span] = impl; + return impl; } @@ -272,18 +292,16 @@ class _CodeParagraphProvider { } String? text = span.text; if (text != null) { - int remainingLength = maxLength - currentLength; + final int remainingLength = maxLength - currentLength; if (text.length > remainingLength) { text = text.substring(0, remainingLength); } currentLength += text.length; - return TextSpan( - text: text, - style: span.style - ); + + return TextSpan(text: text, style: span.style); } final List children = []; - for (InlineSpan child in span.children ?? const []) { + for (final InlineSpan child in span.children ?? const []) { if (currentLength >= maxLength) { break; } @@ -293,11 +311,10 @@ class _CodeParagraphProvider { children.add(child); } } - return TextSpan( - children: children, - style: span.style - ); + + return TextSpan(children: children, style: span.style); } + return truncateSpan(span); } @@ -310,6 +327,7 @@ class _CodeParagraphProvider { span.build(builder); final ui.Paragraph paragraph = builder.build(); paragraph.layout(_constraints!); + return _ParagraphImpl( text: plainText, span: span, @@ -318,5 +336,4 @@ class _CodeParagraphProvider { preferredLineHeight: _preferredLineHeight!, ); } - } diff --git a/lib/src/_code_scroll.dart b/lib/src/_code_scroll.dart index 9ee525c..f492d60 100644 --- a/lib/src/_code_scroll.dart +++ b/lib/src/_code_scroll.dart @@ -1,20 +1,18 @@ -part of re_editor; +part of 're_editor.dart'; -const double _kScrollbarThickness = 8.0; +const double _kScrollbarThickness = 8; class _CodeScrollable extends StatelessWidget { - - final AxisDirection axisDirection; - final ScrollController? controller; - final ViewportBuilder viewportBuilder; - final CodeScrollbarBuilder? scrollbarBuilder; - const _CodeScrollable({ required this.axisDirection, - this.controller, required this.viewportBuilder, - this.scrollbarBuilder + this.controller, + this.scrollbarBuilder, }); + final AxisDirection axisDirection; + final ScrollController? controller; + final ViewportBuilder viewportBuilder; + final CodeScrollbarBuilder? scrollbarBuilder; @override Widget build(BuildContext context) { @@ -27,18 +25,19 @@ class _CodeScrollable extends StatelessWidget { physics: const ClampingScrollPhysics(), ); } - } class _ScrollBehavior extends MaterialScrollBehavior { - + _ScrollBehavior(this.scrollbarBuilder) : physics = _ScrollPhysics(); final _ScrollPhysics physics; final CodeScrollbarBuilder? scrollbarBuilder; - _ScrollBehavior(this.scrollbarBuilder) : physics = _ScrollPhysics(); - @override - Widget buildScrollbar(BuildContext context, Widget child, ScrollableDetails details) { + Widget buildScrollbar( + BuildContext context, + Widget child, + ScrollableDetails details, + ) { final Widget? scrollbar = scrollbarBuilder?.call(context, child, details); if (scrollbar != null) { return scrollbar; @@ -59,6 +58,7 @@ class _ScrollBehavior extends MaterialScrollBehavior { child: child, ); } + return _RawScrollbar( physics: physics, controller: details.controller ?? ScrollController(), @@ -72,36 +72,27 @@ class _ScrollBehavior extends MaterialScrollBehavior { ScrollPhysics getScrollPhysics(BuildContext context) { return physics; } - } class _RawScrollbar extends RawScrollbar { - - final _ScrollPhysics physics; - const _RawScrollbar({ required this.physics, - required Widget child, - required ScrollController controller, - ScrollbarOrientation? scrollbarOrientation, - required bool thumbVisibility, + required super.child, + required ScrollController super.controller, + required bool super.thumbVisibility, + super.scrollbarOrientation, }) : super( - controller: controller, - scrollbarOrientation: scrollbarOrientation, - thumbVisibility: thumbVisibility, - thickness: _kScrollbarThickness, - radius: const Radius.circular(10), - crossAxisMargin: 2, - child: child, - ); + thickness: _kScrollbarThickness, + radius: const Radius.circular(10), + crossAxisMargin: 2, + ); + final _ScrollPhysics physics; @override RawScrollbarState<_RawScrollbar> createState() => _RawScrollbarState(); - } class _RawScrollbarState extends RawScrollbarState<_RawScrollbar> { - Offset? downPosition; double? downOffset; @@ -115,16 +106,19 @@ class _RawScrollbarState extends RawScrollbarState<_RawScrollbar> { @override void handleThumbPressUpdate(Offset localPosition) { if (getScrollbarDirection() == Axis.vertical) { - widget.physics.setScrollPosition(downOffset! + scrollbarPainter.getTrackToScroll(localPosition.dy - downPosition!.dy)); + widget.physics.setScrollPosition( + downOffset! + + scrollbarPainter.getTrackToScroll( + localPosition.dy - downPosition!.dy, + ), + ); } super.handleThumbPressUpdate(localPosition); } - } -// ignore: must_be_immutable +// ignore: must-be-immutable class _ScrollPhysics extends ScrollPhysics { - double? _position; void setScrollPosition(double position) { @@ -136,7 +130,7 @@ class _ScrollPhysics extends ScrollPhysics { if (_position == null) { return super.applyBoundaryConditions(position, value); } + return value - _position!; } - -} \ No newline at end of file +} diff --git a/lib/src/_code_selection.dart b/lib/src/_code_selection.dart index 6df7f6d..24e5ee7 100644 --- a/lib/src/_code_selection.dart +++ b/lib/src/_code_selection.dart @@ -1,31 +1,29 @@ -part of re_editor; +part of 're_editor.dart'; class _CodeSelectionGestureDetector extends StatefulWidget { - - final CodeLineEditingController controller; - final _CodeInputController inputController; - final CodeChunkController chunkController; - final HitTestBehavior? behavior; - final GlobalKey editorKey; - final _SelectionOverlayController selectionOverlayController; - final Widget child; - const _CodeSelectionGestureDetector({ required this.controller, required this.inputController, required this.chunkController, - this.behavior, required this.editorKey, required this.selectionOverlayController, required this.child, + this.behavior, }); + final CodeLineEditingController controller; + final _CodeInputController inputController; + final CodeChunkController chunkController; + final HitTestBehavior? behavior; + final GlobalKey editorKey; + final _SelectionOverlayController selectionOverlayController; + final Widget child; @override State createState() => _CodeSelectionGestureDetectorState(); - } -class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDetector> { +class _CodeSelectionGestureDetectorState + extends State<_CodeSelectionGestureDetector> { Offset? _dragPosition; bool _dragging = false; DateTime? _pointerTapTimestamp; @@ -34,7 +32,8 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete bool _longPressOnSelection = false; CodeLineSelection? _anchorSelection; - _CodeFieldRender get render => widget.editorKey.currentContext?.findRenderObject() as _CodeFieldRender; + _CodeFieldRender get render => + widget.editorKey.currentContext!.findRenderObject()! as _CodeFieldRender; bool _tapping = false; @@ -43,7 +42,7 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete if (_isMobile) { return GestureDetector( onLongPressMoveUpdate: (details) { - if (_longPressOnSelection == true) { + if (_longPressOnSelection) { return; } if (details.localOffsetFromOrigin.distance < 1) { @@ -55,18 +54,26 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete onLongPressStart: (details) { _dragPosition = details.globalPosition; widget.inputController.ensureInput(); - _longPressOnSelection = _isPositionOnSelection(details.globalPosition); - if (_longPressOnSelection != true) { + _longPressOnSelection = _isPositionOnSelection( + details.globalPosition, + ); + if (!_longPressOnSelection) { _onMobileLongPressedStart(details.globalPosition); _autoScrollWhenDragging(); } else { - widget.selectionOverlayController.showToolbar(context, details.globalPosition); + widget.selectionOverlayController.showToolbar( + context, + details.globalPosition, + ); } widget.selectionOverlayController.showHandle(context); }, onLongPressEnd: (details) { - if (_longPressOnSelection != true) { - widget.selectionOverlayController.showToolbar(context, details.globalPosition); + if (!_longPressOnSelection) { + widget.selectionOverlayController.showToolbar( + context, + details.globalPosition, + ); } _dragPosition = null; _longPressOnSelection = false; @@ -163,11 +170,15 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete bool get _isMobile => kIsAndroid || kIsIOS; - bool get _isShiftPressed => _isMobile ? false : HardwareKeyboard.instance.logicalKeysPressed - .any({ - LogicalKeyboardKey.shiftLeft, - LogicalKeyboardKey.shiftRight, - }.contains); + bool get _isShiftPressed => + _isMobile + ? false + : HardwareKeyboard.instance.logicalKeysPressed.any( + { + LogicalKeyboardKey.shiftLeft, + LogicalKeyboardKey.shiftRight, + }.contains, + ); void _onMobileTapDown(Offset position) { _selectPosition(position, _SelectionChangedCause.tapDown); @@ -177,8 +188,12 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete void _onMobileTapUp(Offset position) { final DateTime now = DateTime.now(); - if (_pointerTapTimestamp != null && (now.millisecondsSinceEpoch - _pointerTapTimestamp!.millisecondsSinceEpoch) < - kDoubleTapTimeout.inMilliseconds && _pointerTapPosition != null && _pointerTapPosition!.isSamePosition(position)) { + if (_pointerTapTimestamp != null && + (now.millisecondsSinceEpoch - + _pointerTapTimestamp!.millisecondsSinceEpoch) < + kDoubleTapTimeout.inMilliseconds && + _pointerTapPosition != null && + _pointerTapPosition!.isSamePosition(position)) { _onDoubleTap(position); widget.selectionOverlayController.showHandle(context); widget.selectionOverlayController.showToolbar(context, position); @@ -193,14 +208,12 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete } void _onMobileLongPressedStart(Offset position) { - final CodeLineRange? range = render.selectWord( - position: position, - ); + final CodeLineRange? range = render.selectWord(position: position); if (range == null) { return; } final CodeLineSelection selection = CodeLineSelection.fromRange( - range: range + range: range, ); widget.controller.selection = selection; widget.controller.makeCursorVisible(); @@ -214,13 +227,18 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete return; } final DateTime now = DateTime.now(); - if (_pointerTapTimestamp != null && (now.millisecondsSinceEpoch - _pointerTapTimestamp!.millisecondsSinceEpoch) < - kDoubleTapTimeout.inMilliseconds && _pointerTapPosition != null && _pointerTapPosition!.isSamePosition(position)) { + if (_pointerTapTimestamp != null && + (now.millisecondsSinceEpoch - + _pointerTapTimestamp!.millisecondsSinceEpoch) < + kDoubleTapTimeout.inMilliseconds && + _pointerTapPosition != null && + _pointerTapPosition!.isSamePosition(position)) { _onDoubleTap(position); } else { if (widget.controller.selection.baseOffset != -1) { if (_isShiftPressed) { _extendSelection(position, _SelectionChangedCause.tapDown); + return; } } @@ -243,27 +261,25 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete } void _onDoubleTap(Offset position) { - final CodeLineRange? range = render.selectWord( - position: position, - ); + final CodeLineRange? range = render.selectWord(position: position); if (range == null) { return; } final CodeLineSelection selection; - if (_isShiftPressed && widget.controller.selection.base.offset <= range.start) { + if (_isShiftPressed && + widget.controller.selection.base.offset <= range.start) { selection = widget.controller.selection.copyWith( extentIndex: range.index, - extentOffset: range.end + extentOffset: range.end, ); - } else if (_isShiftPressed && widget.controller.selection.base.offset >= range.end) { + } else if (_isShiftPressed && + widget.controller.selection.base.offset >= range.end) { selection = widget.controller.selection.copyWith( extentIndex: range.index, - extentOffset: range.start + extentOffset: range.start, ); } else { - selection = CodeLineSelection.fromRange( - range: range - ); + selection = CodeLineSelection.fromRange(range: range); } widget.controller.selection = selection; widget.controller.makeCursorVisible(); @@ -302,11 +318,15 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete return; } widget.controller.clearComposing(); - widget.selectionOverlayController.showToolbar(context, details.globalPosition); + widget.selectionOverlayController.showToolbar( + context, + details.globalPosition, + ); } void _extendSelection(Offset offset, _SelectionChangedCause cause) { - if (cause == _SelectionChangedCause.tapDown || cause == _SelectionChangedCause.tapUp) { + if (cause == _SelectionChangedCause.tapDown || + cause == _SelectionChangedCause.tapUp) { if (expandChunkIfNeeded(render.chunkIndicatorHitIndex(offset))) { return; } @@ -331,14 +351,13 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete } void _selectPosition(Offset offset, _SelectionChangedCause cause) { - if (cause == _SelectionChangedCause.tapDown || cause == _SelectionChangedCause.tapUp) { + if (cause == _SelectionChangedCause.tapDown || + cause == _SelectionChangedCause.tapUp) { if (expandChunkIfNeeded(render.chunkIndicatorHitIndex(offset))) { return; } } - final CodeLineSelection? selection = render.setPositionAt( - position: offset, - ); + final CodeLineSelection? selection = render.setPositionAt(position: offset); if (selection == null) { return; } @@ -347,8 +366,10 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete } if (cause == _SelectionChangedCause.tapDown) { - if (!widget.controller.selection.isCollapsed && widget.controller.selection.contains(selection)) { + if (!widget.controller.selection.isCollapsed && + widget.controller.selection.contains(selection)) { _handleByNextEvent = true; + return; } } @@ -369,12 +390,13 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete if (widget.controller.selection == selection) { return false; } + return widget.controller.selection.contains(selection); } void _autoScrollWhenDragging() { final Offset? position = _dragPosition; - Future.delayed(const Duration(milliseconds: 100), (() { + Future.delayed(const Duration(milliseconds: 100), () { if (_dragPosition == null || position == null) { return; } @@ -383,7 +405,7 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete _extendSelection(_dragPosition!, _SelectionChangedCause.drag); } _autoScrollWhenDragging(); - })); + }); } bool expandChunkIfNeeded(int index) { @@ -391,9 +413,9 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete return false; } widget.chunkController.expand(index); + return true; } - } enum _SelectionChangedCause { @@ -408,11 +430,9 @@ enum _SelectionChangedCause { /// The user used the mouse to change the selection by dragging over a piece /// of text. drag, - } abstract class _SelectionOverlayController { - void showHandle(BuildContext context); void hideHandle(); @@ -422,28 +442,29 @@ abstract class _SelectionOverlayController { void hideToolbar(); void dispose(); - } -typedef OnToolbarShow = void Function(BuildContext context, TextSelectionToolbarAnchors anchors, Rect? renderRect); - -class _DesktopSelectionOverlayController implements _SelectionOverlayController { - - final OnToolbarShow onShowToolbar; - final VoidCallback onHideToolbar; +typedef OnToolbarShow = + void Function( + BuildContext context, + TextSelectionToolbarAnchors anchors, + Rect? renderRect, + ); +class _DesktopSelectionOverlayController + implements _SelectionOverlayController { const _DesktopSelectionOverlayController({ required this.onShowToolbar, - required this.onHideToolbar + required this.onHideToolbar, }); + final OnToolbarShow onShowToolbar; + final VoidCallback onHideToolbar; @override - void hideHandle() { - } + void hideHandle() {} @override - void showHandle(BuildContext context) { - } + void showHandle(BuildContext context) {} @override void hideToolbar() { @@ -455,19 +476,32 @@ class _DesktopSelectionOverlayController implements _SelectionOverlayController if (position == null) { return; } - onShowToolbar(context, TextSelectionToolbarAnchors( - primaryAnchor: position - ), null); + onShowToolbar( + context, + TextSelectionToolbarAnchors(primaryAnchor: position), + null, + ); } @override - void dispose() { - } - + void dispose() {} } class _MobileSelectionOverlayController implements _SelectionOverlayController { - + _MobileSelectionOverlayController({ + required BuildContext context, + required this.controller, + required this.editorKey, + required this.startHandleLayerLink, + required this.endHandleLayerLink, + required this.toolbarVisibility, + required this.focusNode, + required this.onShowToolbar, + required this.onHideToolbar, + }) { + _context = context; + controller.addListener(_updateTextSelectionHandle); + } final CodeLineEditingController controller; final GlobalKey editorKey; final LayerLink startHandleLayerLink; @@ -480,8 +514,11 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { bool _inited = false; bool _handlesVisible = false; - final ValueNotifier _effectiveStartHandleVisibility = ValueNotifier(false); - final ValueNotifier _effectiveEndHandleVisibility = ValueNotifier(false); + final ValueNotifier _effectiveStartHandleVisibility = + ValueNotifier(false); + final ValueNotifier _effectiveEndHandleVisibility = ValueNotifier( + false, + ); late BuildContext _context; // The contact position of the gesture at the current start handle location. @@ -507,21 +544,6 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { List? _handles; bool? _handleCollapsed; - _MobileSelectionOverlayController({ - required BuildContext context, - required this.controller, - required this.editorKey, - required this.startHandleLayerLink, - required this.endHandleLayerLink, - required this.toolbarVisibility, - required this.focusNode, - required this.onShowToolbar, - required this.onHideToolbar, - }) { - _context = context; - controller.addListener(_updateTextSelectionHandle); - } - TextSelectionControls get selectionControls { if (kIsAndroid) { return materialTextSelectionControls; @@ -546,7 +568,7 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { _handlesVisible = false; _handleCollapsed = null; if (_handles != null) { - _handles![0].remove(); + _handles!.first.remove(); _handles![1].remove(); _handles = null; } @@ -559,7 +581,7 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { @override void showToolbar(BuildContext context, Offset globalPosition) { - globalPosition = _clampPosition(globalPosition); + final Offset gPosition = _clampPosition(globalPosition); final Rect editingRegion = Rect.fromPoints( ensureRender.localToGlobal(Offset.zero), ensureRender.localToGlobal(ensureRender.size.bottomRight(Offset.zero)), @@ -568,46 +590,60 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { final TextSelectionToolbarAnchors anchors; if (selection.isCollapsed) { anchors = TextSelectionToolbarAnchors( - primaryAnchor: ensureRender.calculateTextPositionScreenOffset(selection.start, false) ?? globalPosition, + primaryAnchor: + ensureRender.calculateTextPositionScreenOffset( + selection.start, + false, + ) ?? + gPosition, ); } else { - Offset startPosition = ensureRender.calculateTextPositionScreenOffset(selection.start, false) ?? editingRegion.topLeft; - Offset endPosition = ensureRender.calculateTextPositionScreenOffset(selection.end, true) ?? editingRegion.bottomRight; + Offset startPosition = + ensureRender.calculateTextPositionScreenOffset( + selection.start, + false, + ) ?? + editingRegion.topLeft; + Offset endPosition = + ensureRender.calculateTextPositionScreenOffset(selection.end, true) ?? + editingRegion.bottomRight; if (startPosition.dy < editingRegion.top) { startPosition = Offset(startPosition.dx, editingRegion.top); } if (endPosition.dy > editingRegion.bottom) { endPosition = Offset(endPosition.dx, editingRegion.bottom); } - if (startPosition.dy <= editingRegion.top + lineHeight && endPosition.dy >= editingRegion.bottom - lineHeight) { - anchors = TextSelectionToolbarAnchors( - primaryAnchor: globalPosition, - ); + if (startPosition.dy <= editingRegion.top + lineHeight && + endPosition.dy >= editingRegion.bottom - lineHeight) { + anchors = TextSelectionToolbarAnchors(primaryAnchor: gPosition); } else { - final double distanceToStart = (globalPosition - startPosition).distance; - final double distanceToEnd = (globalPosition - endPosition).distance; + final double distanceToStart = (gPosition - startPosition).distance; + final double distanceToEnd = (gPosition - endPosition).distance; if (distanceToStart < distanceToEnd) { anchors = TextSelectionToolbarAnchors( primaryAnchor: startPosition, - secondaryAnchor: endPosition + secondaryAnchor: endPosition, ); } else { anchors = TextSelectionToolbarAnchors( // This is trick, make secondary anchor takes effect primaryAnchor: const Offset(-10000, -10000), - secondaryAnchor: endPosition + secondaryAnchor: endPosition, ); } } - } onShowToolbar(context, anchors, editingRegion); } void init() { _inited = true; - ensureRender.selectionStartInViewport.addListener(_updateTextSelectionOverlayVisibilities); - ensureRender.selectionEndInViewport.addListener(_updateTextSelectionOverlayVisibilities); + ensureRender.selectionStartInViewport.addListener( + _updateTextSelectionOverlayVisibilities, + ); + ensureRender.selectionEndInViewport.addListener( + _updateTextSelectionOverlayVisibilities, + ); } @override @@ -618,28 +654,38 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { controller.removeListener(_updateTextSelectionHandle); _effectiveStartHandleVisibility.dispose(); _effectiveEndHandleVisibility.dispose(); - final _CodeFieldRender? render = editorKey.currentContext?.findRenderObject() as _CodeFieldRender?; + final _CodeFieldRender? render = + editorKey.currentContext?.findRenderObject() as _CodeFieldRender?; if (render == null) { return; } - render.selectionStartInViewport.removeListener(_updateTextSelectionOverlayVisibilities); - render.selectionEndInViewport.removeListener(_updateTextSelectionOverlayVisibilities); + render.selectionStartInViewport.removeListener( + _updateTextSelectionOverlayVisibilities, + ); + render.selectionEndInViewport.removeListener( + _updateTextSelectionOverlayVisibilities, + ); } double get lineHeight { - final _CodeFieldRender? render = editorKey.currentContext?.findRenderObject() as _CodeFieldRender?; + final _CodeFieldRender? render = + editorKey.currentContext?.findRenderObject() as _CodeFieldRender?; if (render == null) { return 0; } + return render.lineHeight; } bool get attached { - final _CodeFieldRender? render = editorKey.currentContext?.findRenderObject() as _CodeFieldRender?; + final _CodeFieldRender? render = + editorKey.currentContext?.findRenderObject() as _CodeFieldRender?; + return render != null && render.attached; } - _CodeFieldRender get ensureRender => editorKey.currentContext?.findRenderObject() as _CodeFieldRender; + _CodeFieldRender get ensureRender => + editorKey.currentContext!.findRenderObject()! as _CodeFieldRender; void _updateTextSelectionHandle() { if (!_handlesVisible) { @@ -652,12 +698,15 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { } void _updateTextSelectionOverlayVisibilities() { - final _CodeFieldRender? render = editorKey.currentContext?.findRenderObject() as _CodeFieldRender?; + final _CodeFieldRender? render = + editorKey.currentContext?.findRenderObject() as _CodeFieldRender?; if (render == null) { return; } - _effectiveStartHandleVisibility.value = _handlesVisible && render.selectionStartInViewport.value; - _effectiveEndHandleVisibility.value = _handlesVisible && render.selectionEndInViewport.value; + _effectiveStartHandleVisibility.value = + _handlesVisible && render.selectionStartInViewport.value; + _effectiveEndHandleVisibility.value = + _handlesVisible && render.selectionEndInViewport.value; } void _buildHandles(BuildContext context) { @@ -667,17 +716,31 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { } _handleCollapsed = isCollapsed; if (_handles != null) { - _handles![0].remove(); + _handles!.first.remove(); _handles![1].remove(); _handles = null; } _handles = [ - OverlayEntry(builder: (context) { - return _buildStartHandle(context, isCollapsed ? TextSelectionHandleType.collapsed : TextSelectionHandleType.left); - }), - OverlayEntry(builder: (context) { - return _buildEndHandle(context, isCollapsed ? TextSelectionHandleType.collapsed : TextSelectionHandleType.right); - }), + OverlayEntry( + builder: (context) { + return _buildStartHandle( + context, + isCollapsed + ? TextSelectionHandleType.collapsed + : TextSelectionHandleType.left, + ); + }, + ), + OverlayEntry( + builder: (context) { + return _buildEndHandle( + context, + isCollapsed + ? TextSelectionHandleType.collapsed + : TextSelectionHandleType.right, + ); + }, + ), ]; Overlay.of(context, rootOverlay: true).insertAll(_handles!); } @@ -686,13 +749,18 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { if (kIsIOS && type == TextSelectionHandleType.collapsed) { type = TextSelectionHandleType.right; } + return CodeEditorTapRegion( child: ExcludeSemantics( child: _SelectionHandleOverlay( type: type, handleLayerLink: startHandleLayerLink, onSelectionHandleTapped: () { - final Offset? position = ensureRender.calculateTextPositionScreenOffset(controller.selection.start, false); + final Offset? position = ensureRender + .calculateTextPositionScreenOffset( + controller.selection.start, + false, + ); if (position == null) { return; } @@ -709,7 +777,7 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { selectionControls: selectionControls, visibility: _effectiveStartHandleVisibility, preferredLineHeight: lineHeight, - ) + ), ), ); } @@ -724,7 +792,11 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { type: type, handleLayerLink: endHandleLayerLink, onSelectionHandleTapped: () { - final Offset? position = ensureRender.calculateTextPositionScreenOffset(controller.selection.end, false); + final Offset? position = ensureRender + .calculateTextPositionScreenOffset( + controller.selection.end, + false, + ); if (position == null) { return; } @@ -743,20 +815,22 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { preferredLineHeight: lineHeight, ); } - return CodeEditorTapRegion( - child: ExcludeSemantics( - child: handle, - ), - ); + + return CodeEditorTapRegion(child: ExcludeSemantics(child: handle)); } void _handleStartHandleDragStart(DragStartDetails details) { _startHandleDragging = true; _startHandleDragLastPosition = details.globalPosition; _startHandleDragPosition = details.globalPosition.dy; - final Offset startPoint = ensureRender.localToGlobal(ensureRender.calculateTextPositionViewportOffset(controller.selection.start)!); + final Offset startPoint = ensureRender.localToGlobal( + ensureRender.calculateTextPositionViewportOffset( + controller.selection.start, + )!, + ); final double centerOfLine = startPoint.dy + ensureRender.lineHeight / 2; - _startHandleDragPositionToCenterOfLine = centerOfLine - _startHandleDragPosition; + _startHandleDragPositionToCenterOfLine = + centerOfLine - _startHandleDragPosition; toolbarVisibility.value = false; _autoScrollWhenStartHandleDragging(); } @@ -765,25 +839,31 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { if (!attached) { return; } - _startHandleDragPosition = _getHandleDy(offset.dy, _startHandleDragPosition); + _startHandleDragPosition = _getHandleDy( + offset.dy, + _startHandleDragPosition, + ); _startHandleDragLastPosition = offset; - final Offset adjustedOffset = ensureRender.globalToLocal(Offset( - offset.dx, - _startHandleDragPosition + _startHandleDragPositionToCenterOfLine, - )); - final CodeLinePosition? position = ensureRender.calculateTextPosition(adjustedOffset); + final Offset adjustedOffset = ensureRender.globalToLocal( + Offset( + offset.dx, + _startHandleDragPosition + _startHandleDragPositionToCenterOfLine, + ), + ); + final CodeLinePosition? position = ensureRender.calculateTextPosition( + adjustedOffset, + ); if (position == null) { return; } final CodeLineSelection newSelection; if (controller.selection.isCollapsed) { - newSelection = CodeLineSelection.fromPosition( - position : position - ); + newSelection = CodeLineSelection.fromPosition(position: position); if (controller.selection != newSelection) { HapticFeedback.selectionClick(); } controller.selection = newSelection; + return; } if (kIsAndroid) { @@ -793,9 +873,10 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { baseAffinity: position.affinity, extentIndex: controller.selection.endIndex, extentOffset: controller.selection.endOffset, - extentAffinity: controller.selection.end.affinity + extentAffinity: controller.selection.end.affinity, ); - if (position.index >= controller.selection.endIndex && position.offset >= controller.selection.endOffset) { + if (position.index >= controller.selection.endIndex && + position.offset >= controller.selection.endOffset) { // Don't allow order swapping. return; } @@ -811,7 +892,8 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { extentOffset: position.offset, extentAffinity: position.affinity, ); - if (newSelection.extentIndex >= controller.selection.endIndex && newSelection.extentOffset >= controller.selection.endOffset) { + if (newSelection.extentIndex >= controller.selection.endIndex && + newSelection.extentOffset >= controller.selection.endOffset) { // Don't allow order swapping. return; } @@ -831,10 +913,14 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { _endHandleDragging = true; _endHandleDragPosition = details.globalPosition.dy; _endHandleDragLastPosition = details.globalPosition; - final Offset endPoint = - ensureRender.localToGlobal(ensureRender.calculateTextPositionViewportOffset(controller.selection.end)!); + final Offset endPoint = ensureRender.localToGlobal( + ensureRender.calculateTextPositionViewportOffset( + controller.selection.end, + )!, + ); final double centerOfLine = endPoint.dy + ensureRender.lineHeight / 2; - _endHandleDragPositionToCenterOfLine = centerOfLine - _endHandleDragPosition; + _endHandleDragPositionToCenterOfLine = + centerOfLine - _endHandleDragPosition; toolbarVisibility.value = false; _autoScrollWhenEndHandleDragging(); } @@ -845,23 +931,26 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { } _endHandleDragPosition = _getHandleDy(offset.dy, _endHandleDragPosition); _endHandleDragLastPosition = offset; - final Offset adjustedOffset = ensureRender.globalToLocal(Offset( - offset.dx, - _endHandleDragPosition + _endHandleDragPositionToCenterOfLine, - )); - final CodeLinePosition? position = ensureRender.calculateTextPosition(adjustedOffset); + final Offset adjustedOffset = ensureRender.globalToLocal( + Offset( + offset.dx, + _endHandleDragPosition + _endHandleDragPositionToCenterOfLine, + ), + ); + final CodeLinePosition? position = ensureRender.calculateTextPosition( + adjustedOffset, + ); if (position == null) { return; } final CodeLineSelection newSelection; if (controller.selection.isCollapsed) { - newSelection = CodeLineSelection.fromPosition( - position : position - ); + newSelection = CodeLineSelection.fromPosition(position: position); if (controller.selection != newSelection) { HapticFeedback.selectionClick(); } controller.selection = newSelection; + return; } @@ -874,7 +963,8 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { extentOffset: position.offset, extentAffinity: position.affinity, ); - if (newSelection.baseIndex >= newSelection.extentIndex && newSelection.baseOffset >= newSelection.extentOffset) { + if (newSelection.baseIndex >= newSelection.extentIndex && + newSelection.baseOffset >= newSelection.extentOffset) { // Don't allow order swapping. return; } @@ -890,7 +980,8 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { baseOffset: controller.selection.startOffset, baseAffinity: controller.selection.start.affinity, ); - if (position.index <= controller.selection.startIndex && position.offset <= controller.selection.startOffset) { + if (position.index <= controller.selection.startIndex && + position.offset <= controller.selection.startOffset) { // Don't allow order swapping. return; } @@ -905,25 +996,25 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { } void _autoScrollWhenStartHandleDragging() { - Future.delayed(const Duration(milliseconds: 100), (() { + Future.delayed(const Duration(milliseconds: 100), () { if (!_startHandleDragging) { return; } ensureRender.autoScrollWhenDragging(_startHandleDragLastPosition); _handleStartHandleDragUpdate(_startHandleDragLastPosition); _autoScrollWhenStartHandleDragging(); - })); + }); } void _autoScrollWhenEndHandleDragging() { - Future.delayed(const Duration(milliseconds: 100), (() { + Future.delayed(const Duration(milliseconds: 100), () { if (!_endHandleDragging) { return; } ensureRender.autoScrollWhenDragging(_endHandleDragLastPosition); _handleEndHandleDragUpdate(_endHandleDragLastPosition); _autoScrollWhenEndHandleDragging(); - })); + }); } /// Given a handle position and drag position, returns the position of handle @@ -937,16 +1028,23 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController { final double distanceDragged = dragDy - handleDy; final int dragDirection = distanceDragged < 0.0 ? -1 : 1; final int linesDragged = - dragDirection * (distanceDragged.abs() / ensureRender.lineHeight).floor(); + dragDirection * + (distanceDragged.abs() / ensureRender.lineHeight).floor(); + return handleDy + linesDragged * ensureRender.lineHeight; } Offset _clampPosition(Offset position) { - final RenderBox box = _context.findRenderObject() as RenderBox; + final RenderBox box = _context.findRenderObject()! as RenderBox; final Offset offset = box.globalToLocal(position); - return box.localToGlobal(Offset(min(max(0, offset.dx), box.size.width), min(max(0, offset.dy), box.size.height))); - } + return box.localToGlobal( + Offset( + min(max(0, offset.dx), box.size.width), + min(max(0, offset.dy), box.size.height), + ), + ); + } } class _SelectionHandleOverlay extends StatefulWidget { @@ -954,14 +1052,14 @@ class _SelectionHandleOverlay extends StatefulWidget { const _SelectionHandleOverlay({ required this.type, required this.handleLayerLink, + required this.selectionControls, + required this.preferredLineHeight, this.onSelectionHandleTapped, this.onSelectionHandleDragStart, this.onSelectionHandleDragUpdate, this.onSelectionHandleDragEnd, this.onSelectionHandleDragCancel, - required this.selectionControls, this.visibility, - required this.preferredLineHeight, }); final LayerLink handleLayerLink; @@ -976,18 +1074,22 @@ class _SelectionHandleOverlay extends StatefulWidget { final TextSelectionHandleType type; @override - State<_SelectionHandleOverlay> createState() => _SelectionHandleOverlayState(); + State<_SelectionHandleOverlay> createState() => + _SelectionHandleOverlayState(); } -class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> with SingleTickerProviderStateMixin { - +class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> + with SingleTickerProviderStateMixin { late AnimationController _controller; Animation get _opacity => _controller.view; @override void initState() { super.initState(); - _controller = AnimationController(duration: SelectionOverlay.fadeDuration, vsync: this); + _controller = AnimationController( + duration: SelectionOverlay.fadeDuration, + vsync: this, + ); _handleVisibilityChanged(); widget.visibility?.addListener(_handleVisibilityChanged); @@ -1035,7 +1137,10 @@ class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> with S // Make sure the GestureDetector is big enough to be easily interactive. final Rect interactiveRect = handleRect.expandToInclude( - Rect.fromCircle(center: handleRect.center, radius: kMinInteractiveDimension/ 2), + Rect.fromCircle( + center: handleRect.center, + radius: kMinInteractiveDimension / 2, + ), ); final RelativeRect padding = RelativeRect.fromLTRB( max((interactiveRect.width - handleRect.width) / 2, 0), @@ -1057,7 +1162,9 @@ class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> with S child: RawGestureDetector( behavior: HitTestBehavior.translucent, gestures: { - PanGestureRecognizer: GestureRecognizerFactoryWithHandlers( + PanGestureRecognizer: GestureRecognizerFactoryWithHandlers< + PanGestureRecognizer + >( () => PanGestureRecognizer( debugOwner: this, // Mouse events select the text and do not drag the cursor. @@ -1098,15 +1205,12 @@ class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> with S } } -class _MobileSelectionToolbarController implements MobileSelectionToolbarController { - +class _MobileSelectionToolbarController + implements MobileSelectionToolbarController { + _MobileSelectionToolbarController({required this.builder}); final ToolbarMenuBuilder builder; OverlayEntry? _entry; - _MobileSelectionToolbarController({ - required this.builder - }); - @override void hide(BuildContext context) { _entry?.remove(); @@ -1118,9 +1222,9 @@ class _MobileSelectionToolbarController implements MobileSelectionToolbarControl required BuildContext context, required CodeLineEditingController controller, required TextSelectionToolbarAnchors anchors, - Rect? renderRect, required LayerLink layerLink, required ValueNotifier visibility, + Rect? renderRect, }) { hide(context); final OverlayState? overlay = Overlay.maybeOf(context, rootOverlay: true); @@ -1128,34 +1232,34 @@ class _MobileSelectionToolbarController implements MobileSelectionToolbarControl return; } final OverlayEntry entry = OverlayEntry( - builder: (_) => _SelectionToolbarWrapper( - visibility: visibility, - layerLink: layerLink, - offset: -renderRect!.topLeft, - child: builder( - context: context, - anchors: anchors, - controller: controller, - onDismiss: () { - hide(context); - }, - onRefresh: () { - show( + builder: + (_) => _SelectionToolbarWrapper( + visibility: visibility, + layerLink: layerLink, + offset: -renderRect!.topLeft, + child: builder( context: context, - controller: controller, anchors: anchors, - renderRect: renderRect, - layerLink: layerLink, - visibility: visibility - ); - }, - ) - ) + controller: controller, + onDismiss: () { + hide(context); + }, + onRefresh: () { + show( + context: context, + controller: controller, + anchors: anchors, + renderRect: renderRect, + layerLink: layerLink, + visibility: visibility, + ); + }, + ), + ), ); overlay.insert(entry); _entry = entry; } - } // TODO(justinmc): Currently this fades in but not out on all platforms. It @@ -1166,10 +1270,10 @@ class _MobileSelectionToolbarController implements MobileSelectionToolbarControl // TextSelectionControls.buildToolbar. class _SelectionToolbarWrapper extends StatefulWidget { const _SelectionToolbarWrapper({ - this.visibility, required this.layerLink, required this.offset, required this.child, + this.visibility, }); final Widget child; @@ -1178,10 +1282,12 @@ class _SelectionToolbarWrapper extends StatefulWidget { final ValueListenable? visibility; @override - State<_SelectionToolbarWrapper> createState() => _SelectionToolbarWrapperState(); + State<_SelectionToolbarWrapper> createState() => + _SelectionToolbarWrapperState(); } -class _SelectionToolbarWrapperState extends State<_SelectionToolbarWrapper> with SingleTickerProviderStateMixin { +class _SelectionToolbarWrapperState extends State<_SelectionToolbarWrapper> + with SingleTickerProviderStateMixin { late AnimationController _controller; Animation get _opacity => _controller.view; @@ -1189,7 +1295,10 @@ class _SelectionToolbarWrapperState extends State<_SelectionToolbarWrapper> with void initState() { super.initState(); - _controller = AnimationController(duration: SelectionOverlay.fadeDuration, vsync: this); + _controller = AnimationController( + duration: SelectionOverlay.fadeDuration, + vsync: this, + ); _toolbarVisibilityChanged(); widget.visibility?.addListener(_toolbarVisibilityChanged); @@ -1238,4 +1347,4 @@ class _SelectionToolbarWrapperState extends State<_SelectionToolbarWrapper> with ), ); } -} \ No newline at end of file +} diff --git a/lib/src/_code_shortcuts.dart b/lib/src/_code_shortcuts.dart index 76b10be..1dba7a7 100644 --- a/lib/src/_code_shortcuts.dart +++ b/lib/src/_code_shortcuts.dart @@ -1,11 +1,10 @@ -part of re_editor; +part of 're_editor.dart'; class _CodeShortcuts extends StatefulWidget { + const _CodeShortcuts({required this.builder, required this.child}); final CodeShortcutsActivatorsBuilder builder; final Widget child; - const _CodeShortcuts({required this.builder, required this.child}); - @override State createState() => _CodeShortcutsState(); } @@ -58,23 +57,22 @@ class _CodeShortcutsState extends State<_CodeShortcuts> { } class _CodeShortcutActions extends StatelessWidget { - final CodeLineEditingController editingController; - final _CodeInputController inputController; - final CodeFindController? findController; - final CodeCommentFormatter? commentFormatter; - final Map>? overrideActions; - final bool readOnly; - final Widget child; - const _CodeShortcutActions({ required this.editingController, required this.inputController, - this.findController, - this.commentFormatter, required this.overrideActions, required this.readOnly, required this.child, + this.findController, + this.commentFormatter, }); + final CodeLineEditingController editingController; + final _CodeInputController inputController; + final CodeFindController? findController; + final CodeCommentFormatter? commentFormatter; + final Map>? overrideActions; + final bool readOnly; + final Widget child; @override Widget build(BuildContext context) { @@ -102,25 +100,34 @@ class _CodeShortcutActions extends StatelessWidget { }, ); } - return Actions(actions: { - ...actions, - ...{ - DoNothingAndStopPropagationTextIntent: - DoNothingAction(consumesKey: false), + + return Actions( + actions: { + ...actions, + ...{ + DoNothingAndStopPropagationTextIntent: DoNothingAction( + consumesKey: false, + ), + }, + if (overrideActions != null) ...overrideActions!, }, - if (overrideActions != null) ...overrideActions! - }, child: child); + child: child, + ); } - static final Map actions = { + static final Map< + Type, + void Function(Intent intent, _CodeShortcutActions actions) + > + actions = { CodeShortcutSelectAllIntent: (intent, actions) { actions.editingController.selectAll(); }, CodeShortcutLineSelectIntent: (intent, actions) { actions.editingController.selectLines( - actions.editingController.selection.baseIndex, - actions.editingController.selection.extentIndex); + actions.editingController.selection.baseIndex, + actions.editingController.selection.extentIndex, + ); }, CodeShortcutCutIntent: (intent, actions) { actions.editingController.cut(); @@ -138,7 +145,7 @@ class _CodeShortcutActions extends StatelessWidget { actions.editingController.redo(); }, ShortcutLineDeleteIntent: (intent, actions) { - actions.editingController.deleteSelectionLines(true); + actions.editingController.deleteSelectionLines(); }, ShortcutLineDeleteDirectionIntent: (intent, actions) { if ((intent as ShortcutLineDeleteDirectionIntent).forward) { @@ -163,9 +170,10 @@ class _CodeShortcutActions extends StatelessWidget { }, CodeShortcutCommentIntent: (intent, actions) { final CodeLineEditingValue? value = actions.commentFormatter?.format( - actions.editingController.value, - actions.editingController.options.indent, - (intent as CodeShortcutCommentIntent).single); + actions.editingController.value, + actions.editingController.options.indent, + (intent as CodeShortcutCommentIntent).single, + ); if (value != null) { actions.editingController.runRevocableOp(() { actions.editingController.value = value; @@ -173,8 +181,9 @@ class _CodeShortcutActions extends StatelessWidget { } }, CodeShortcutCursorMoveIntent: (intent, actions) { - actions.editingController - .moveCursor((intent as CodeShortcutCursorMoveIntent).direction); + actions.editingController.moveCursor( + (intent as CodeShortcutCursorMoveIntent).direction, + ); }, CodeShortcutCursorMoveLineEdgeIntent: (intent, actions) { if ((intent as CodeShortcutCursorMoveLineEdgeIntent).forward) { @@ -206,7 +215,8 @@ class _CodeShortcutActions extends StatelessWidget { }, CodeShortcutSelectionExtendIntent: (intent, actions) { actions.editingController.extendSelection( - (intent as CodeShortcutSelectionExtendIntent).direction); + (intent as CodeShortcutSelectionExtendIntent).direction, + ); }, CodeShortcutSelectionExtendLineEdgeIntent: (intent, actions) { if ((intent as CodeShortcutSelectionExtendLineEdgeIntent).forward) { @@ -268,10 +278,10 @@ class _CodeShortcutActions extends StatelessWidget { } else { actions.editingController.cancelSelection(); } - } + }, }; - Object? _onAction(BuildContext context, Intent intent) { + Intent? _onAction(BuildContext context, Intent intent) { final Action? action = Actions.maybeFind(context, intent: intent); if (action != null && action.isActionEnabled && @@ -279,6 +289,7 @@ class _CodeShortcutActions extends StatelessWidget { if (action is CallbackAction) { action.invoke(intent); } + return null; } if (intent is CodeShortcutEditableIntent && readOnly) { @@ -287,7 +298,7 @@ class _CodeShortcutActions extends StatelessWidget { if (editingController.isComposing) { return null; } - bool keepAutoCompleteState = intent is CodeShortcutDeleteIntent; + final bool keepAutoCompleteState = intent is CodeShortcutDeleteIntent; final handler = actions[intent.runtimeType]; if (handler != null) { handler(intent, this); @@ -297,18 +308,18 @@ class _CodeShortcutActions extends StatelessWidget { context.findAncestorStateOfType<_CodeAutocompleteState>(); autocompleteState?.dismiss(); } + return intent; } } class _CompoDoNothingCallbackAction extends CallbackAction { - final CodeLineEditingController controller; - _CompoDoNothingCallbackAction({ required this.controller, required super.onInvoke, }); + final CodeLineEditingController controller; @override bool consumesKey(T intent) { @@ -317,14 +328,13 @@ class _CompoDoNothingCallbackAction } class _EscCallbackAction extends CallbackAction { - final CodeLineEditingController controller; - final CodeFindController? findController; - _EscCallbackAction({ required this.controller, required this.findController, required super.onInvoke, }); + final CodeLineEditingController controller; + final CodeFindController? findController; @override bool isEnabled(T intent) { diff --git a/lib/src/_code_span.dart b/lib/src/_code_span.dart index 700facc..f79ecf0 100644 --- a/lib/src/_code_span.dart +++ b/lib/src/_code_span.dart @@ -1,17 +1,15 @@ -part of re_editor; +part of 're_editor.dart'; @immutable class _MouseTrackerAnnotationTextSpan extends TextSpan { - - final int id; - final MouseTrackerAnnotationTextSpan span; - final List rects; - const _MouseTrackerAnnotationTextSpan({ required this.id, required this.rects, required this.span, }); + final int id; + final MouseTrackerAnnotationTextSpan span; + final List rects; @override PointerEnterEventListener? get onEnter => (event) { @@ -31,8 +29,9 @@ class _MouseTrackerAnnotationTextSpan extends TextSpan { if (identical(this, other)) { return true; } - return other is _MouseTrackerAnnotationTextSpan && span == other.span && - id == other.id; - } -} \ No newline at end of file + return other is _MouseTrackerAnnotationTextSpan && + span == other.span && + id == other.id; + } +} diff --git a/lib/src/_consts.dart b/lib/src/_consts.dart index 3d978db..0b2cd6e 100644 --- a/lib/src/_consts.dart +++ b/lib/src/_consts.dart @@ -1,4 +1,4 @@ -part of re_editor; +part of 're_editor.dart'; final kIsMacOS = defaultTargetPlatform == TargetPlatform.macOS; final kIsAndroid = defaultTargetPlatform == TargetPlatform.android; diff --git a/lib/src/_isolate.dart b/lib/src/_isolate.dart index ffd4bae..1ebfd8a 100644 --- a/lib/src/_isolate.dart +++ b/lib/src/_isolate.dart @@ -1,33 +1,33 @@ -part of re_editor; +part of 're_editor.dart'; typedef IsolateRunnable = Res Function(Req req); typedef IsolateCallback = void Function(Res res); class _IsolateTasker { + _IsolateTasker(this.name, IsolateRunnable runnable) { + _closed = false; + _isolateManager = IsolateManager.create(runnable); + } final String name; late bool _closed; late IsolateManager? _isolateManager; - _IsolateTasker(this.name, IsolateRunnable runnable) { - _closed = false; - _isolateManager = IsolateManager.create( - runnable, - concurrent: 1, // one is enough - ); - } - - void run(Req req, IsolateCallback callback) async { + Future run(Req req, IsolateCallback callback) async { if (_closed) { return; } - _isolateManager?.compute(req, callback: (message) async { - if (_closed) { - return false; - } - callback(message); - return true; - }); + await _isolateManager?.compute( + req, + callback: (message) { + if (_closed) { + return false; + } + callback(message); + + return true; + }, + ); } void close() { diff --git a/lib/src/code_autocomplete.dart b/lib/src/code_autocomplete.dart index 4e924c6..d5c69b2 100644 --- a/lib/src/code_autocomplete.dart +++ b/lib/src/code_autocomplete.dart @@ -1,13 +1,10 @@ -part of re_editor; +part of 're_editor.dart'; /// Define code autocomplate prompt information. /// /// See also [CodeKeywordPrompt], [CodeFieldPrompt] and [CodeFunctionPrompt]. abstract class CodePrompt { - - const CodePrompt({ - required this.word - }); + const CodePrompt({required this.word}); /// Content associated with user input. /// @@ -22,18 +19,15 @@ abstract class CodePrompt { /// Check whether the input meets this prompt condition. bool match(String input); - } /// The keyword autocomplate prompt. such as 'return', 'class', 'new' and so on. class CodeKeywordPrompt extends CodePrompt { - - const CodeKeywordPrompt({ - required super.word - }); + const CodeKeywordPrompt({required super.word}); @override - CodeAutocompleteResult get autocomplete => CodeAutocompleteResult.fromWord(word); + CodeAutocompleteResult get autocomplete => + CodeAutocompleteResult.fromWord(word); @override bool match(String input) { @@ -45,12 +39,12 @@ class CodeKeywordPrompt extends CodePrompt { if (identical(this, other)) { return true; } + return other is CodeKeywordPrompt && other.word == word; } @override int get hashCode => word.hashCode; - } /// The field autocomplate prompt. Compared to [CodeKeywordPrompt], @@ -58,7 +52,6 @@ class CodeKeywordPrompt extends CodePrompt { /// /// If a line of code is 'String foo;', 'foo' is the word and 'String' is the type. class CodeFieldPrompt extends CodePrompt { - const CodeFieldPrompt({ required super.word, required this.type, @@ -72,7 +65,8 @@ class CodeFieldPrompt extends CodePrompt { final CodeAutocompleteResult? customAutocomplete; @override - CodeAutocompleteResult get autocomplete => customAutocomplete ?? CodeAutocompleteResult.fromWord(word); + CodeAutocompleteResult get autocomplete => + customAutocomplete ?? CodeAutocompleteResult.fromWord(word); @override bool match(String input) { @@ -84,18 +78,19 @@ class CodeFieldPrompt extends CodePrompt { if (identical(this, other)) { return true; } - return other is CodeFieldPrompt && other.word == word && other.type == type - && other.customAutocomplete == customAutocomplete; + + return other is CodeFieldPrompt && + other.word == word && + other.type == type && + other.customAutocomplete == customAutocomplete; } @override int get hashCode => Object.hash(word, type, customAutocomplete); - } /// The function autocomplate prompt. class CodeFunctionPrompt extends CodePrompt { - const CodeFunctionPrompt({ required super.word, required this.type, @@ -117,7 +112,9 @@ class CodeFunctionPrompt extends CodePrompt { final CodeAutocompleteResult? customAutocomplete; @override - CodeAutocompleteResult get autocomplete => customAutocomplete ?? CodeAutocompleteResult.fromWord('$word(${parameters.keys.join(', ')})'); + CodeAutocompleteResult get autocomplete => + customAutocomplete ?? + CodeAutocompleteResult.fromWord('$word(${parameters.keys.join(', ')})'); @override bool match(String input) { @@ -129,33 +126,39 @@ class CodeFunctionPrompt extends CodePrompt { if (identical(this, other)) { return true; } - return other is CodeFunctionPrompt && other.word == word && other.type == type && - mapEquals(other.parameters, parameters) && mapEquals(other.optionalParameters, optionalParameters) - && other.customAutocomplete == customAutocomplete; + + return other is CodeFunctionPrompt && + other.word == word && + other.type == type && + mapEquals(other.parameters, parameters) && + mapEquals(other.optionalParameters, optionalParameters) && + other.customAutocomplete == customAutocomplete; } @override - int get hashCode => Object.hash(word, type, parameters, optionalParameters, customAutocomplete); - + int get hashCode => Object.hash( + word, + type, + parameters, + optionalParameters, + customAutocomplete, + ); } /// The autocomplete result selected by user, the editor will apply this /// to code content. class CodeAutocompleteResult { - const CodeAutocompleteResult({ required this.input, required this.word, - required this.selection + required this.selection, }); factory CodeAutocompleteResult.fromWord(String word) { return CodeAutocompleteResult( input: '', word: word, - selection: TextSelection.collapsed( - offset: word.length - ) + selection: TextSelection.collapsed(offset: word.length), ); } @@ -167,12 +170,10 @@ class CodeAutocompleteResult { /// The new selection after the autocompletion. final TextSelection selection; - } /// The current user input and prompts for editing a run of text. class CodeAutocompleteEditingValue { - const CodeAutocompleteEditingValue({ required this.input, required this.prompts, @@ -209,37 +210,36 @@ class CodeAutocompleteEditingValue { baseOffset: result.selection.baseOffset - input.length, extentOffset: result.selection.extentOffset - input.length, ); + return CodeAutocompleteResult( input: input, word: result.word, selection: finalSelection, ); } - } /// Builds the overlay autocomplete prompts view. -typedef CodeAutocompleteWidgetBuilder = PreferredSizeWidget Function( - BuildContext context, - ValueNotifier notifier, - ValueChanged onSelected -); +typedef CodeAutocompleteWidgetBuilder = + PreferredSizeWidget Function( + BuildContext context, + ValueNotifier notifier, + ValueChanged onSelected, + ); /// The autocomplete prompts builder. abstract class CodeAutocompletePromptsBuilder { - /// Build the prompts with the current code. CodeAutocompleteEditingValue? build( BuildContext context, CodeLine codeLine, CodeLineSelection selection, ); - } /// The default autocomplete prompts builder. -abstract class DefaultCodeAutocompletePromptsBuilder implements CodeAutocompletePromptsBuilder { - +abstract class DefaultCodeAutocompletePromptsBuilder + implements CodeAutocompletePromptsBuilder { /// Constructs the builder with defined prompts. factory DefaultCodeAutocompletePromptsBuilder({ Mode? language, @@ -252,7 +252,6 @@ abstract class DefaultCodeAutocompletePromptsBuilder implements CodeAutocomplete directPrompts: directPrompts, relatedPrompts: relatedPrompts, ); - } /// A widget enables code autocomplete for [CodeEditor]. @@ -286,12 +285,11 @@ abstract class DefaultCodeAutocompletePromptsBuilder implements CodeAutocomplete /// ) /// ``` class CodeAutocomplete extends StatelessWidget { - const CodeAutocomplete({ - super.key, required this.viewBuilder, required this.promptsBuilder, required this.child, + super.key, }); final CodeAutocompleteWidgetBuilder viewBuilder; @@ -303,8 +301,7 @@ class CodeAutocomplete extends StatelessWidget { return _CodeAutocomplete( viewBuilder: viewBuilder, promptsBuilder: promptsBuilder, - child: child + child: child, ); } - -} \ No newline at end of file +} diff --git a/lib/src/code_chunk.dart b/lib/src/code_chunk.dart index f964f99..830819a 100644 --- a/lib/src/code_chunk.dart +++ b/lib/src/code_chunk.dart @@ -1,22 +1,28 @@ -part of re_editor; +part of 're_editor.dart'; class CodeChunkController extends ValueNotifier> { - + CodeChunkController(CodeLineEditingController controller, this._analyzer) + : super(const []) { + _controller = + controller is _CodeLineEditingControllerDelegate + ? controller.delegate + : controller; + _controller.addListener(_onCodeChanged); + _tasker = _IsolateTasker<_CodeChunkAnalyzePayload, _CodeChunkAnalyzeResult>( + 'CodeChunk', + _run, + ); + _shouldNotUpdateChunks = false; + _runChunkAnalyzeTask(); + } late final CodeLineEditingController _controller; final CodeChunkAnalyzer _analyzer; - late final _IsolateTasker<_CodeChunkAnalyzePayload, _CodeChunkAnalyzeResult> _tasker; + late final _IsolateTasker<_CodeChunkAnalyzePayload, _CodeChunkAnalyzeResult> + _tasker; late bool _shouldNotUpdateChunks; - CodeChunkController(CodeLineEditingController controller, this._analyzer) : super(const []) { - _controller = controller is _CodeLineEditingControllerDelegate ? controller.delegate : controller; - _controller.addListener(_onCodeChanged); - _tasker = _IsolateTasker<_CodeChunkAnalyzePayload, _CodeChunkAnalyzeResult>('CodeChunk', _run); - _shouldNotUpdateChunks = false; - _runChunkAnalyzeTask(); - } - void collapse(int index) { final CodeChunk? chunk = findByIndex(index); if (chunk == null) { @@ -34,8 +40,9 @@ class CodeChunkController extends ValueNotifier> { for (int i = 0; i < codeChunks.length; i++) { final CodeChunk e = codeChunks[i]; if (e.index >= index || e.end >= index) { - codeChunks[i] = CodeChunk(e.index > index ? e.index - chunk.collapseSize : e.index, - e.end > index ? e.end - chunk.collapseSize : e.end + codeChunks[i] = CodeChunk( + e.index > index ? e.index - chunk.collapseSize : e.index, + e.end > index ? e.end - chunk.collapseSize : e.end, ); } } @@ -56,8 +63,9 @@ class CodeChunkController extends ValueNotifier> { for (int i = 0; i < codeChunks.length; i++) { final CodeChunk e = codeChunks[i]; if (e.index >= index || e.end >= index) { - codeChunks[i] = CodeChunk(e.index > index ? e.index + codeLine.chunks.length : e.index, - e.end > index ? e.end + codeLine.chunks.length : e.end + codeChunks[i] = CodeChunk( + e.index > index ? e.index + codeLine.chunks.length : e.index, + e.end > index ? e.end + codeLine.chunks.length : e.end, ); } if (e.index == index) { @@ -90,6 +98,7 @@ class CodeChunkController extends ValueNotifier> { break; } } + return null; } @@ -110,6 +119,7 @@ class CodeChunkController extends ValueNotifier> { } if (_controller.codeLines.length < 3 && value.isEmpty) { value = []; + return; } if (_controller.codeLines.equals(_controller.preValue?.codeLines)) { @@ -130,7 +140,7 @@ class CodeChunkController extends ValueNotifier> { void _expandInvalidCollapsedChunks(List indexes) { // Expand invalid chunks from bottom to top - for (int i = indexes.length - 1; i >=0; i--) { + for (int i = indexes.length - 1; i >= 0; i--) { expand(indexes[i]); } } @@ -148,18 +158,16 @@ class CodeChunkController extends ValueNotifier> { invalidCollapsedChunkIndexes.add(i); } } + return _CodeChunkAnalyzeResult(chunks, invalidCollapsedChunkIndexes); } - } class CodeChunk { - + const CodeChunk(this.index, this.end); final int index; final int end; - const CodeChunk(this.index, this.end); - bool get canCollapse => collapseSize > 0; int get collapseSize => end - index - 1; @@ -169,9 +177,8 @@ class CodeChunk { if (identical(this, other)) { return true; } - return other is CodeChunk - && other.index == index - && other.end == end; + + return other is CodeChunk && other.index == index && other.end == end; } @override @@ -181,35 +188,28 @@ class CodeChunk { String toString() { return '[$index, $end]'; } - } abstract class CodeChunkAnalyzer { - List run(CodeLines codeLines); - } class NonCodeChunkAnalyzer implements CodeChunkAnalyzer { - const NonCodeChunkAnalyzer(); @override List run(CodeLines codeLines) => const []; - } class DefaultCodeChunkAnalyzer implements CodeChunkAnalyzer { - + const DefaultCodeChunkAnalyzer(); static const Map _chunkSymbols = { '(': ')', '[': ']', - '{': '}' + '{': '}', }; static final List _tokens = '"\'()[]{}'.codeUnits; - const DefaultCodeChunkAnalyzer(); - @override List run(CodeLines codeLines) { final List chunks = []; @@ -220,10 +220,11 @@ class DefaultCodeChunkAnalyzer implements CodeChunkAnalyzer { stack.add(symbol); continue; } - while(stack.isNotEmpty) { + while (stack.isNotEmpty) { final CodeChunkSymbol pop = stack.removeLast(); if (_chunkSymbols[pop.value] == symbol.value) { - if (symbol.index - pop.index >= 1 && chunks.where((e) => e.index == pop.index).isEmpty) { + if (symbol.index - pop.index >= 1 && + chunks.where((e) => e.index == pop.index).isEmpty) { chunks.add(CodeChunk(pop.index, symbol.index)); } break; @@ -232,6 +233,7 @@ class DefaultCodeChunkAnalyzer implements CodeChunkAnalyzer { } // sort by index chunks.sort((a, b) => a.index - b.index); + return chunks; } @@ -245,6 +247,7 @@ class DefaultCodeChunkAnalyzer implements CodeChunkAnalyzer { } symbols.addAll(_parseLine(text, i)); } + return symbols; } @@ -308,30 +311,29 @@ class DefaultCodeChunkAnalyzer implements CodeChunkAnalyzer { } } } + return symbols; } bool isPreEscapeChar(List codeUnits, int index) { - return index > 0 && codeUnits[index - 1] == '\\'.codeUnits.first; + return index > 0 && codeUnits[index - 1] == r'\'.codeUnits.first; } - } class CodeChunkSymbol { - + const CodeChunkSymbol(this.value, this.index); final String value; final int index; - const CodeChunkSymbol(this.value, this.index); - @override bool operator ==(Object other) { if (identical(this, other)) { return true; } - return other is CodeChunkSymbol - && other.value == value - && other.index == index; + + return other is CodeChunkSymbol && + other.value == value && + other.index == index; } @override @@ -341,23 +343,16 @@ class CodeChunkSymbol { String toString() { return '$value@$index'; } - } class _CodeChunkAnalyzePayload { - + const _CodeChunkAnalyzePayload(this.analyzer, this.codeLines); final CodeChunkAnalyzer analyzer; final CodeLines codeLines; - - const _CodeChunkAnalyzePayload(this.analyzer, this.codeLines); - } class _CodeChunkAnalyzeResult { - + const _CodeChunkAnalyzeResult(this.chunks, this.invalidCollapsedChunkIndexes); final List chunks; final List invalidCollapsedChunkIndexes; - - const _CodeChunkAnalyzeResult(this.chunks, this.invalidCollapsedChunkIndexes); - -} \ No newline at end of file +} diff --git a/lib/src/code_editor.dart b/lib/src/code_editor.dart index 6cc6dcf..f979801 100644 --- a/lib/src/code_editor.dart +++ b/lib/src/code_editor.dart @@ -1,8 +1,7 @@ -part of re_editor; +part of 're_editor.dart'; /// An immutable style describing how to format and paint editor content. class CodeEditorStyle { - /// Creates a code editor style. const CodeEditorStyle({ this.fontSize, @@ -18,9 +17,18 @@ class CodeEditorStyle { this.cursorLineColor, this.chunkIndicatorColor, this.codeTheme, - }) : assert(fontSize == null || fontSize > 0), - assert(fontHeight == null || fontHeight >= 1.0), - assert(cursorWidth == null || cursorWidth > 0); + }) : assert( + fontSize == null || fontSize > 0, + 'fontSize must be greater than 0', + ), + assert( + fontHeight == null || fontHeight >= 1.0, + 'fontHeight must be greater than or equal to 1.0', + ), + assert( + cursorWidth == null || cursorWidth > 0, + 'cursorWidth must be greater than 0', + ); /// The size of fonts (in logical pixels) to use when painting the text. /// @@ -123,7 +131,6 @@ class CodeEditorStyle { /// The code syntax highlighting rules and styles. final CodeHighlightTheme? codeTheme; - } /// Creates a code editor. @@ -155,7 +162,6 @@ class CodeEditorStyle { /// By default, the editor will use [DefaultCodeChunkAnalyzer]. This works for some commonly used languages, /// but may not work for some languages (such as python). class CodeEditor extends StatefulWidget { - const CodeEditor({ super.key, this.controller, @@ -187,7 +193,11 @@ class CodeEditor extends StatefulWidget { this.maxLengthSingleLineRendering, this.chunkAnalyzer, this.commentFormatter, - }) : assert(indicatorBuilder != null || (indicatorBuilder == null && sperator == null)); + }) : assert( + indicatorBuilder != null || + (indicatorBuilder == null && sperator == null), + 'indicatorBuilder and sperator cannot be both null', + ); /// Similar to [TextField], editor uses [CodeLineEditingController] as the content controller. final CodeLineEditingController? controller; @@ -255,7 +265,6 @@ class CodeEditor extends StatefulWidget { /// If null, the corners will not be rounded. final BorderRadius? borderRadius; - /// How the content should be clipped if it overflows the editor's bounds. final Clip clipBehavior; @@ -294,7 +303,7 @@ class CodeEditor extends StatefulWidget { /// The maximum number of characters per line to render. /// - /// Due to the performance limitations of the Skia text engine, + /// Due to the performance limitations of the Skia text engine, /// setting a reasonable length can improve the performance of the editor. /// /// If null, there is no limit. @@ -312,11 +321,9 @@ class CodeEditor extends StatefulWidget { @override State createState() => _CodeEditorState(); - } class _CodeEditorState extends State { - late final GlobalKey _editorKey; late FocusNode _focusNode; late _CodeLineEditingControllerDelegate _editingController; @@ -329,7 +336,9 @@ class _CodeEditorState extends State { final LayerLink _startHandleLayerLink = LayerLink(); final LayerLink _endHandleLayerLink = LayerLink(); final LayerLink _toolbarLayerLink = LayerLink(); - final ValueNotifier _effectiveToolbarVisibility = ValueNotifier(true); + final ValueNotifier _effectiveToolbarVisibility = ValueNotifier( + true, + ); late _SelectionOverlayController _selectionOverlayController; @@ -339,7 +348,8 @@ class _CodeEditorState extends State { _editorKey = GlobalKey(); _focusNode = widget.focusNode ?? FocusNode(); _editingController = _CodeLineEditingControllerDelegate(); - _editingController.delegate = widget.controller ?? CodeLineEditingController(); + _editingController.delegate = + widget.controller ?? CodeLineEditingController(); _editingController.bindEditor(_editorKey); _floatingCursorController = _CodeFloatingCursorController(); @@ -351,50 +361,57 @@ class _CodeEditorState extends State { readOnly: widget.readOnly ?? false, autocompleteSymbols: widget.autocompleteSymbols ?? true, ); - _inputController.bindEditor(_editorKey); + _inputController.bindEditor = _editorKey; - _findController = widget.findController ?? CodeFindController(_editingController); + _findController = + widget.findController ?? CodeFindController(_editingController); _findController.addListener(_updateWidget); _scrollController = widget.scrollController ?? CodeScrollController(); - _scrollController.bindEditor(_editorKey); - _chunkController = CodeChunkController(_editingController, widget.chunkAnalyzer ?? const DefaultCodeChunkAnalyzer()); - - _selectionOverlayController = kIsAndroid || kIsIOS ? _MobileSelectionOverlayController( - context: context, - controller: _editingController, - editorKey: _editorKey, - startHandleLayerLink: _startHandleLayerLink, - endHandleLayerLink: _endHandleLayerLink, - toolbarVisibility: _effectiveToolbarVisibility, - focusNode: _focusNode, - onShowToolbar: (context, anchors, renderRect) { - widget.toolbarController?.show( - context: _editorKey.currentContext ?? context, - controller: _editingController, - anchors: anchors, - renderRect: renderRect, - layerLink: _toolbarLayerLink, - visibility: _effectiveToolbarVisibility, - ); - }, - onHideToolbar: () { - widget.toolbarController?.hide(context); - }, - ) : _DesktopSelectionOverlayController( - onShowToolbar: (context, anchors, renderRect) { - widget.toolbarController?.show( - context: context, - controller: _editingController, - anchors: anchors, - renderRect: renderRect, - layerLink: _toolbarLayerLink, - visibility: _effectiveToolbarVisibility, - ); - }, - onHideToolbar: () { - widget.toolbarController?.hide(context); - }, + _scrollController.bindEditor = _editorKey; + _chunkController = CodeChunkController( + _editingController, + widget.chunkAnalyzer ?? const DefaultCodeChunkAnalyzer(), ); + + _selectionOverlayController = + kIsAndroid || kIsIOS + ? _MobileSelectionOverlayController( + context: context, + controller: _editingController, + editorKey: _editorKey, + startHandleLayerLink: _startHandleLayerLink, + endHandleLayerLink: _endHandleLayerLink, + toolbarVisibility: _effectiveToolbarVisibility, + focusNode: _focusNode, + onShowToolbar: (context, anchors, renderRect) { + widget.toolbarController?.show( + context: _editorKey.currentContext ?? context, + controller: _editingController, + anchors: anchors, + renderRect: renderRect, + layerLink: _toolbarLayerLink, + visibility: _effectiveToolbarVisibility, + ); + }, + onHideToolbar: () { + widget.toolbarController?.hide(context); + }, + ) + : _DesktopSelectionOverlayController( + onShowToolbar: (context, anchors, renderRect) { + widget.toolbarController?.show( + context: context, + controller: _editingController, + anchors: anchors, + renderRect: renderRect, + layerLink: _toolbarLayerLink, + visibility: _effectiveToolbarVisibility, + ); + }, + onHideToolbar: () { + widget.toolbarController?.hide(context); + }, + ); } @override @@ -410,7 +427,7 @@ class _CodeEditorState extends State { if (widget.findController == null) { _findController.dispose(); } - if (widget.scrollController== null) { + if (widget.scrollController == null) { _scrollController.dispose(); } _chunkController.dispose(); @@ -432,14 +449,17 @@ class _CodeEditorState extends State { if (oldWidget.controller == null) { _editingController.dispose(); } - _editingController.delegate = widget.controller ?? CodeLineEditingController(); + _editingController.delegate = + widget.controller ?? CodeLineEditingController(); _editingController.bindEditor(_editorKey); } - if (oldWidget.findController != widget.findController || oldWidget.controller != widget.controller) { + if (oldWidget.findController != widget.findController || + oldWidget.controller != widget.controller) { if (oldWidget.findController == null) { _findController.dispose(); } - _findController = widget.findController ?? CodeFindController(_editingController); + _findController = + widget.findController ?? CodeFindController(_editingController); _findController.removeListener(_updateWidget); _findController.addListener(_updateWidget); } @@ -448,11 +468,15 @@ class _CodeEditorState extends State { _scrollController.dispose(); } _scrollController = widget.scrollController ?? CodeScrollController(); - _scrollController.bindEditor(_editorKey); + _scrollController.bindEditor = _editorKey; } - if (oldWidget.chunkAnalyzer != widget.chunkAnalyzer || oldWidget.controller != widget.controller) { + if (oldWidget.chunkAnalyzer != widget.chunkAnalyzer || + oldWidget.controller != widget.controller) { _chunkController.dispose(); - _chunkController = CodeChunkController(_editingController, widget.chunkAnalyzer ?? const DefaultCodeChunkAnalyzer()); + _chunkController = CodeChunkController( + _editingController, + widget.chunkAnalyzer ?? const DefaultCodeChunkAnalyzer(), + ); } if (oldWidget.readOnly != widget.readOnly) { _inputController.readOnly = widget.readOnly ?? false; @@ -466,7 +490,9 @@ class _CodeEditorState extends State { @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); - final TextSelectionThemeData selectionTheme = TextSelectionTheme.of(context); + final TextSelectionThemeData selectionTheme = TextSelectionTheme.of( + context, + ); final TextStyle baseStyle = TextStyle( fontSize: widget.style?.fontSize ?? _kDefaultTextSize, fontFamily: widget.style?.fontFamily, @@ -475,7 +501,11 @@ class _CodeEditorState extends State { final bool readOnly = widget.readOnly ?? false; final bool autofocus = widget.autofocus ?? true; final bool wordWrap = widget.wordWrap ?? true; - final PreferredSizeWidget? find = widget.findBuilder?.call(context, _findController, readOnly); + final PreferredSizeWidget? find = widget.findBuilder?.call( + context, + _findController, + readOnly, + ); final Widget editable = _CodeEditable( editorKey: _editorKey, hint: widget.hint, @@ -488,9 +518,18 @@ class _CodeEditorState extends State { ), hintTextColor: widget.style?.hintTextColor, backgroundColor: widget.style?.backgroundColor, - selectionColor: widget.style?.selectionColor ?? selectionTheme.selectionColor ?? theme.colorScheme.primary.withOpacity(0.4), - highlightColor: widget.style?.highlightColor ?? selectionTheme.selectionColor ?? theme.colorScheme.primary.withOpacity(0.4), - cursorColor: widget.style?.cursorColor ?? selectionTheme.cursorColor ?? theme.colorScheme.primary, + selectionColor: + widget.style?.selectionColor ?? + selectionTheme.selectionColor ?? + theme.colorScheme.primary.withValues(alpha: 0.4), + highlightColor: + widget.style?.highlightColor ?? + selectionTheme.selectionColor ?? + theme.colorScheme.primary.withValues(alpha: 0.4), + cursorColor: + widget.style?.cursorColor ?? + selectionTheme.cursorColor ?? + theme.colorScheme.primary, cursorLineColor: widget.style?.cursorLineColor, chunkIndicatorColor: widget.style?.chunkIndicatorColor, cursorWidth: widget.style?.cursorWidth ?? _kDefaultCaretWidth, @@ -501,10 +540,10 @@ class _CodeEditorState extends State { clipBehavior: widget.clipBehavior, onChanged: widget.onChanged, focusNode: _focusNode, - padding: (widget.padding ?? _kDefaultPadding).add(EdgeInsets.only( - top: find == null ? 0 : find.preferredSize.height - )), - margin: widget.margin ?? EdgeInsets.zero, + padding: (widget.padding ?? _kDefaultPadding).add( + EdgeInsets.only(top: find == null ? 0 : find.preferredSize.height), + ), + margin: widget.margin ?? EdgeInsets.zero, controller: _editingController, inputController: _inputController, codeTheme: widget.style?.codeTheme, @@ -528,30 +567,35 @@ class _CodeEditorState extends State { selectionOverlayController: _selectionOverlayController, behavior: HitTestBehavior.translucent, editorKey: _editorKey, - child: editable + child: editable, ); final Widget child; if (kIsAndroid || kIsIOS) { child = Focus( autofocus: autofocus, focusNode: _focusNode, - onKey: (node, event) { - if (event.isKeyPressed(LogicalKeyboardKey.backspace)) { + onKeyEvent: (node, KeyEvent event) { + if (event.logicalKey == LogicalKeyboardKey.backspace) { _editingController.deleteBackward(); + return KeyEventResult.handled; - } else if (event.isKeyPressed(LogicalKeyboardKey.enter)) { + } else if (event.logicalKey == LogicalKeyboardKey.enter) { _editingController.applyNewLine(); + return KeyEventResult.handled; } + return KeyEventResult.ignored; }, includeSemantics: false, debugLabel: 'CodeEditor', - child: detector + child: detector, ); } else { child = _CodeShortcuts( - builder: widget.shortcutsActivatorsBuilder ?? const DefaultCodeShortcutsActivatorsBuilder(), + builder: + widget.shortcutsActivatorsBuilder ?? + const DefaultCodeShortcutsActivatorsBuilder(), child: _CodeShortcutActions( editingController: _editingController, inputController: _inputController, @@ -564,25 +608,18 @@ class _CodeEditorState extends State { focusNode: _focusNode, includeSemantics: false, debugLabel: 'CodeEditor', - child: detector - ) + child: detector, + ), ), ); } - return Stack( - children: [ - child, - if (find != null) - find, - ], - ); + + return Stack(children: [child, if (find != null) find]); } void _updateWidget() { - setState(() { - }); + setState(() {}); } - } /// A [TapRegion] that adds its children to the tap region group for widgets @@ -598,17 +635,15 @@ class _CodeEditorState extends State { /// * [TapRegion], the widget that this widget uses to add widgets to the group /// of text fields. class CodeEditorTapRegion extends TapRegion { - /// Creates a const [CodeEditorTapRegion]. /// /// The [child] field is required. const CodeEditorTapRegion({ - super.key, required super.child, + super.key, super.enabled = true, super.behavior = HitTestBehavior.deferToChild, super.onTapOutside, super.onTapInside, }) : super(groupId: CodeEditor); - -} \ No newline at end of file +} diff --git a/lib/src/code_find.dart b/lib/src/code_find.dart index 911aaa5..04e8cba 100644 --- a/lib/src/code_find.dart +++ b/lib/src/code_find.dart @@ -1,14 +1,13 @@ -part of re_editor; +part of 're_editor.dart'; -typedef CodeFindBuilder = PreferredSizeWidget Function(BuildContext context, CodeFindController controller, bool readonly); +typedef CodeFindBuilder = + PreferredSizeWidget Function( + BuildContext context, + CodeFindController controller, + bool readonly, + ); class CodeFindValue { - - final CodeFindOption option; - final bool replaceMode; - final CodeFindResult? result; - final bool searching; - const CodeFindValue({ required this.option, required this.replaceMode, @@ -16,19 +15,24 @@ class CodeFindValue { this.searching = false, }); - const CodeFindValue.empty() : this( - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - replaceMode: false, - ); + const CodeFindValue.empty() + : this( + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + replaceMode: false, + ); + final CodeFindOption option; + final bool replaceMode; + final CodeFindResult? result; + final bool searching; CodeFindValue copyWith({ + required CodeFindResult? result, CodeFindOption? option, bool? replaceMode, - required CodeFindResult? result, bool? searching, }) { return CodeFindValue( @@ -44,11 +48,12 @@ class CodeFindValue { if (identical(this, other)) { return true; } - return other is CodeFindValue - && other.option == option - && other.replaceMode == replaceMode - && other.result == result - && other.searching == searching; + + return other is CodeFindValue && + other.option == option && + other.replaceMode == replaceMode && + other.result == result && + other.searching == searching; } @override @@ -58,26 +63,19 @@ class CodeFindValue { String toString() { return '{option: $option replaceMode: $replaceMode result: $result searching:$searching}'; } - } class CodeFindOption { - - final String pattern; - final bool caseSensitive; - final bool regex; - const CodeFindOption({ required this.pattern, required this.caseSensitive, required this.regex, }); + final String pattern; + final bool caseSensitive; + final bool regex; - CodeFindOption copyWith({ - String? pattern, - bool? caseSensitive, - bool? regex, - }) { + CodeFindOption copyWith({String? pattern, bool? caseSensitive, bool? regex}) { return CodeFindOption( pattern: pattern ?? this.pattern, caseSensitive: caseSensitive ?? this.caseSensitive, @@ -102,10 +100,11 @@ class CodeFindOption { if (identical(this, other)) { return true; } - return other is CodeFindOption - && other.pattern == pattern - && other.caseSensitive == caseSensitive - && other.regex == regex; + + return other is CodeFindOption && + other.pattern == pattern && + other.caseSensitive == caseSensitive && + other.regex == regex; } @override @@ -115,17 +114,9 @@ class CodeFindOption { String toString() { return '{pattern: $pattern caseSensitive: $caseSensitive regex: $regex}'; } - } class CodeFindResult { - - final int index; - final List matches; - final CodeFindOption option; - final CodeLines codeLines; - final bool dirty; - const CodeFindResult({ required this.index, required this.matches, @@ -133,14 +124,17 @@ class CodeFindResult { required this.codeLines, required this.dirty, }); + final int index; + final List matches; + final CodeFindOption option; + final CodeLines codeLines; + final bool dirty; - CodeFindResult get previous => copyWith( - index: index == 0 ? matches.length - 1 : index - 1 - ); + CodeFindResult get previous => + copyWith(index: index == 0 ? matches.length - 1 : index - 1); - CodeFindResult get next => copyWith( - index: index == matches.length - 1 ? 0 : index + 1 - ); + CodeFindResult get next => + copyWith(index: index == matches.length - 1 ? 0 : index + 1); CodeLineSelection? get currentMatch => index == -1 ? null : matches[index]; @@ -165,23 +159,24 @@ class CodeFindResult { if (identical(this, other)) { return true; } - return other is CodeFindResult - && other.index == index - && listEquals(other.matches, matches) - && other.option == option - && other.codeLines.equals(codeLines) - && other.dirty == dirty; + + return other is CodeFindResult && + other.index == index && + listEquals(other.matches, matches) && + other.option == option && + other.codeLines.equals(codeLines) && + other.dirty == dirty; } @override int get hashCode => Object.hash(index, matches, option, codeLines, dirty); - } abstract class CodeFindController extends ValueNotifier { - - factory CodeFindController(CodeLineEditingController controller, [CodeFindValue? value]) - => _CodeFindControllerImpl(controller, value); + factory CodeFindController( + CodeLineEditingController controller, [ + CodeFindValue? value, + ]) => _CodeFindControllerImpl(controller, value); TextEditingController get findInputController; @@ -220,5 +215,4 @@ abstract class CodeFindController extends ValueNotifier { void replaceAllMatches(); CodeLineSelection? convertMatchToSelection(CodeLineSelection match); - -} \ No newline at end of file +} diff --git a/lib/src/code_formatter.dart b/lib/src/code_formatter.dart index 2df6422..6d46c2e 100644 --- a/lib/src/code_formatter.dart +++ b/lib/src/code_formatter.dart @@ -1,21 +1,21 @@ -part of re_editor; +part of 're_editor.dart'; abstract class CodeCommentFormatter { - - CodeLineEditingValue format(CodeLineEditingValue value, String indent, bool single); - + CodeLineEditingValue format( + CodeLineEditingValue value, + String indent, + bool single, + ); } abstract class DefaultCodeCommentFormatter implements CodeCommentFormatter { - factory DefaultCodeCommentFormatter({ - String? singleLinePrefix, + String? singleLinePrefix, String? multiLinePrefix, - String? multiLineSuffix + String? multiLineSuffix, }) => _DefaultCodeCommentFormatter( singleLinePrefix: singleLinePrefix, multiLinePrefix: multiLinePrefix, - multiLineSuffix: multiLineSuffix + multiLineSuffix: multiLineSuffix, ); - -} \ No newline at end of file +} diff --git a/lib/src/code_indicator.dart b/lib/src/code_indicator.dart index 63fc81a..e6a2106 100644 --- a/lib/src/code_indicator.dart +++ b/lib/src/code_indicator.dart @@ -1,26 +1,22 @@ -part of re_editor; +part of 're_editor.dart'; const int _kDefaultMinNumberCount = 3; const Size _kDefaultChunkIndicatorSize = Size(7, 7); typedef CodeIndicatorValueNotifier = ValueNotifier; -typedef CodeIndicatorBuilder = Widget Function( - BuildContext context, - CodeLineEditingController editingController, - CodeChunkController chunkController, - CodeIndicatorValueNotifier notifier, -); +typedef CodeIndicatorBuilder = + Widget Function( + BuildContext context, + CodeLineEditingController editingController, + CodeChunkController chunkController, + CodeIndicatorValueNotifier notifier, + ); class CodeIndicatorValue { - + CodeIndicatorValue({required this.paragraphs, this.focusedIndex = -1}); final List paragraphs; final int focusedIndex; - CodeIndicatorValue({ - required this.paragraphs, - this.focusedIndex = -1, - }); - @override int get hashCode => Object.hashAll([paragraphs, focusedIndex]); @@ -29,6 +25,7 @@ class CodeIndicatorValue { if (other is! CodeIndicatorValue) { return false; } + return listEquals(other.paragraphs, paragraphs) && other.focusedIndex == focusedIndex; } @@ -42,40 +39,41 @@ class CodeIndicatorValue { focusedIndex: focusedIndex ?? this.focusedIndex, ); } - } class DefaultCodeLineNumber extends LeafRenderObjectWidget { - - final CodeLineEditingController controller; - final CodeIndicatorValueNotifier notifier; - final TextStyle? textStyle; - final TextStyle? focusedTextStyle; - final int? minNumberCount; - final String Function(int lineIndex)? customLineIndex2Text; - const DefaultCodeLineNumber({ - super.key, required this.notifier, required this.controller, + super.key, this.textStyle, this.focusedTextStyle, this.minNumberCount, this.customLineIndex2Text, }); + final CodeLineEditingController controller; + final CodeIndicatorValueNotifier notifier; + final TextStyle? textStyle; + final TextStyle? focusedTextStyle; + final int? minNumberCount; + final String Function(int lineIndex)? customLineIndex2Text; @override - RenderObject createRenderObject(BuildContext context) => CodeLineNumberRenderObject( - controller: controller, - notifier: notifier, - textStyle: textStyle ?? _useCodeTextStyle(context, false), - focusedTextStyle: focusedTextStyle ?? _useCodeTextStyle(context, true), - minNumberCount: minNumberCount ?? _kDefaultMinNumberCount, - custonLineIndex2Text: customLineIndex2Text, - ); + RenderObject createRenderObject(BuildContext context) => + CodeLineNumberRenderObject( + controller: controller, + notifier: notifier, + textStyle: textStyle ?? _useCodeTextStyle(context, false), + focusedTextStyle: focusedTextStyle ?? _useCodeTextStyle(context, true), + minNumberCount: minNumberCount ?? _kDefaultMinNumberCount, + custonLineIndex2Text: customLineIndex2Text, + ); @override - void updateRenderObject(BuildContext context, covariant CodeLineNumberRenderObject renderObject) { + void updateRenderObject( + BuildContext context, + covariant CodeLineNumberRenderObject renderObject, + ) { renderObject ..controller = controller ..notifier = notifier @@ -86,92 +84,92 @@ class DefaultCodeLineNumber extends LeafRenderObjectWidget { } TextStyle _useCodeTextStyle(BuildContext context, bool focused) { - final _CodeEditable? editor = context.findAncestorWidgetOfExactType<_CodeEditable>(); - assert(editor != null); + final _CodeEditable? editor = + context.findAncestorWidgetOfExactType<_CodeEditable>(); + assert(editor != null, 'editor is null'); + return editor!.textStyle.copyWith( - color: focused ? null : editor.textStyle.color?.withAlpha(128) + color: focused ? null : editor.textStyle.color?.withAlpha(128), ); } - } class DefaultCodeChunkIndicator extends LeafRenderObjectWidget { - - final double width; - final CodeChunkController controller; - final CodeIndicatorValueNotifier notifier; - final CodeChunkIndicatorPainter? painter; - final bool collapseIndicatorVisible; - final bool expandIndicatorVisible; - const DefaultCodeChunkIndicator({ - super.key, required this.width, required this.controller, required this.notifier, + super.key, this.painter, this.collapseIndicatorVisible = true, this.expandIndicatorVisible = true, }); + final double width; + final CodeChunkController controller; + final CodeIndicatorValueNotifier notifier; + final CodeChunkIndicatorPainter? painter; + final bool collapseIndicatorVisible; + final bool expandIndicatorVisible; @override - RenderObject createRenderObject(BuildContext context) => CodeChunkIndicatorRenderObject( - width: width, - controller: controller, - notifier: notifier, - painter: painter ?? DefaultCodeChunkIndicatorPainter( - color: _useCodeTextColor(context), - ), - collapseIndicatorVisible: collapseIndicatorVisible, - expandIndicatorVisible: expandIndicatorVisible, - ); + RenderObject createRenderObject(BuildContext context) => + CodeChunkIndicatorRenderObject( + width: width, + controller: controller, + notifier: notifier, + painter: + painter ?? + DefaultCodeChunkIndicatorPainter(color: _useCodeTextColor(context)), + collapseIndicatorVisible: collapseIndicatorVisible, + expandIndicatorVisible: expandIndicatorVisible, + ); @override - void updateRenderObject(BuildContext context, covariant CodeChunkIndicatorRenderObject renderObject) { + void updateRenderObject( + BuildContext context, + covariant CodeChunkIndicatorRenderObject renderObject, + ) { renderObject ..width = width ..controller = controller ..notifier = notifier - ..painter = painter ?? DefaultCodeChunkIndicatorPainter( - color: _useCodeTextColor(context), - ) + ..painter = + painter ?? + DefaultCodeChunkIndicatorPainter(color: _useCodeTextColor(context)) ..collapseIndicatorVisible = collapseIndicatorVisible ..expandIndicatorVisible = expandIndicatorVisible; super.updateRenderObject(context, renderObject); } Color? _useCodeTextColor(BuildContext context) { - final _CodeEditable? editor = context.findAncestorWidgetOfExactType<_CodeEditable>(); - assert(editor != null); + final _CodeEditable? editor = + context.findAncestorWidgetOfExactType<_CodeEditable>(); + assert(editor != null, 'editor is null'); + return editor!.textStyle.color?.withAlpha(128); } - } abstract class CodeChunkIndicatorPainter { - void paintCollapseIndicator(Canvas canvas, Size container); void paintExpandIndicator(Canvas canvas, Size container); - } class DefaultCodeChunkIndicatorPainter implements CodeChunkIndicatorPainter { - - final Color? color; - final Size size; - - late final Paint _paint; - DefaultCodeChunkIndicatorPainter({ this.color, - this.size = _kDefaultChunkIndicatorSize + this.size = _kDefaultChunkIndicatorSize, }) { _paint = Paint(); if (color != null) { _paint.color = color!; } } + final Color? color; + final Size size; + + late final Paint _paint; @override void paintCollapseIndicator(Canvas canvas, Size container) { @@ -179,10 +177,19 @@ class DefaultCodeChunkIndicatorPainter implements CodeChunkIndicatorPainter { return; } final Path path = Path(); - path.moveTo((container.width - size.width) / 2, (container.height - size.height) / 2); - path.lineTo((container.width + size.width) / 2, (container.height - size.height) / 2); + path.moveTo( + (container.width - size.width) / 2, + (container.height - size.height) / 2, + ); + path.lineTo( + (container.width + size.width) / 2, + (container.height - size.height) / 2, + ); path.lineTo(container.width / 2, (container.height + size.height) / 2); - path.lineTo((container.width - size.width) / 2, (container.height - size.height) / 2); + path.lineTo( + (container.width - size.width) / 2, + (container.height - size.height) / 2, + ); canvas.drawPath(path, _paint); } @@ -192,11 +199,19 @@ class DefaultCodeChunkIndicatorPainter implements CodeChunkIndicatorPainter { return; } final Path path = Path(); - path.moveTo((container.width - size.width) / 2, (container.height - size.height) / 2); + path.moveTo( + (container.width - size.width) / 2, + (container.height - size.height) / 2, + ); path.lineTo((container.width + size.width) / 2, container.height / 2); - path.lineTo((container.width - size.width) / 2, (container.height + size.height) / 2); - path.lineTo((container.width - size.width) / 2, (container.height - size.height) / 2); + path.lineTo( + (container.width - size.width) / 2, + (container.height + size.height) / 2, + ); + path.lineTo( + (container.width - size.width) / 2, + (container.height - size.height) / 2, + ); canvas.drawPath(path, _paint); } - } diff --git a/lib/src/code_line.dart b/lib/src/code_line.dart index 63e86a8..dd2c5c6 100644 --- a/lib/src/code_line.dart +++ b/lib/src/code_line.dart @@ -1,12 +1,13 @@ -part of re_editor; +part of 're_editor.dart'; -typedef CodeLineSpanBuilder = TextSpan Function({ - required BuildContext context, - required int index, - required CodeLine codeLine, - required TextSpan textSpan, - required TextStyle style, -}); +typedef CodeLineSpanBuilder = + TextSpan Function({ + required BuildContext context, + required int index, + required CodeLine codeLine, + required TextSpan textSpan, + required TextStyle style, + }); /// A controller for an editor field. /// @@ -38,8 +39,8 @@ typedef CodeLineSpanBuilder = TextSpan Function({ /// Remember to [dispose] of the [CodeLineEditingController] when it is no longer /// needed. This will ensure we discard any resources used by the object. /// -abstract class CodeLineEditingController extends ValueNotifier { - +abstract class CodeLineEditingController + extends ValueNotifier { /// Creates a controller for an editor field. /// /// This constructor treats an empty [codeLines] argument as if it were the empty @@ -60,13 +61,15 @@ abstract class CodeLineEditingController extends ValueNotifier _CodeLineEditingControllerImpl.fromText(text, options); /// Creates a controller for a given file path. The file content will read async. - factory CodeLineEditingController.fromTextAsync(String? text, [ - CodeLineOptions options = const CodeLineOptions() + factory CodeLineEditingController.fromTextAsync( + String? text, [ + CodeLineOptions options = const CodeLineOptions(), ]) => _CodeLineEditingControllerImpl.fromTextAsync(text, options); /// Set the current editor codes. @@ -217,10 +220,10 @@ abstract class CodeLineEditingController extends ValueNotifier chunks; - const CodeLine(this.text, [this.chunks = const[]]); - @override bool operator ==(Object other) { if (identical(this, other)) { return true; } - return other is CodeLine - && other.text == text - && listEquals(other.chunks, chunks); + + return other is CodeLine && + other.text == text && + listEquals(other.chunks, chunks); } @override @@ -421,6 +422,7 @@ class CodeLine { for (final CodeLine codeLine in chunks) { count += codeLine.lineCount; } + return count; } @@ -429,6 +431,7 @@ class CodeLine { for (final CodeLine codeLine in chunks) { count += codeLine.charCount; } + return count; } @@ -445,6 +448,7 @@ class CodeLine { end = length; } } + return start >= length ? '' : text.substring(start, end); } @@ -474,18 +478,15 @@ class CodeLine { int codeUnitAt(int index) => text.codeUnitAt(index); - CodeLine copyWith({ - String? text, - List? chunks - }) { - return CodeLine( - text ?? this.text, - chunks ?? this.chunks - ); + CodeLine copyWith({String? text, List? chunks}) { + return CodeLine(text ?? this.text, chunks ?? this.chunks); } String asString(int start, TextLineBreak lineBreak) { - return [substring(start), ...chunks.map((e) => e.asString(0, lineBreak))].join(lineBreak.value); + return [ + substring(start), + ...chunks.map((e) => e.asString(0, lineBreak)), + ].join(lineBreak.value); } List flat() { @@ -493,14 +494,13 @@ class CodeLine { for (final CodeLine child in chunks) { codeLines.addAll(child.flat()); } + return codeLines; } - } /// The current codes, selection, and composing state for editing a run of text. class CodeLineEditingValue { - /// Creates information for editing a run of codes. /// /// The selection and composing range must be within the codes. This is not @@ -514,9 +514,7 @@ class CodeLineEditingValue { this.composing = TextRange.empty, }); - const CodeLineEditingValue.empty() : this( - codeLines: _kInitialCodeLines - ); + const CodeLineEditingValue.empty() : this(codeLines: _kInitialCodeLines); /// The current codes being edited. final CodeLines codeLines; @@ -559,7 +557,7 @@ class CodeLineEditingValue { return CodeLineEditingValue( codeLines: codeLines ?? this.codeLines, selection: selection ?? this.selection, - composing: composing ?? this.composing + composing: composing ?? this.composing, ); } @@ -570,10 +568,11 @@ class CodeLineEditingValue { if (identical(this, other)) { return true; } - return other is CodeLineEditingValue - && other.codeLines.equals(codeLines) - && other.selection == selection - && other.composing == composing; + + return other is CodeLineEditingValue && + other.codeLines.equals(codeLines) && + other.selection == selection && + other.composing == composing; } @override @@ -583,42 +582,10 @@ class CodeLineEditingValue { String toString() { return 'codeLines: $codeLines, selection: $selection, composing: $composing'; } - } /// A range of code lines that represents a selection. class CodeLineSelection { - - /// The line index at which the selection originates. - final int baseIndex; - - /// The line index at which the selection terminates. - final int extentIndex; - - /// The offset at which the selection originates. - /// - /// Might be larger than, smaller than, or equal to extent. - final int baseOffset; - - /// The offset at which the selection terminates. - /// - /// When the user uses the arrow keys to adjust the selection, this is the - /// value that changes. Similarly, if the current theme paints a caret on one - /// side of the selection, this is the location at which to paint the caret. - /// - /// Might be larger than, smaller than, or equal to base. - final int extentOffset; - - /// If the code range is collapsed and has more than one visual location - /// (e.g., occurs at a line break), which of the two locations to use when - /// painting the caret. - final TextAffinity baseAffinity; - - /// If the code range is collapsed and has more than one visual location - /// (e.g., occurs at a line break), which of the two locations to use when - /// painting the caret. - final TextAffinity extentAffinity; - /// Creates a code selection. const CodeLineSelection({ required this.baseIndex, @@ -639,64 +606,88 @@ class CodeLineSelection { required int offset, TextAffinity affinity = TextAffinity.downstream, }) : this( - baseIndex: index, - baseOffset: offset, - extentIndex: index, - extentOffset: offset, - baseAffinity: affinity, - extentAffinity: affinity - ); + baseIndex: index, + baseOffset: offset, + extentIndex: index, + extentOffset: offset, + baseAffinity: affinity, + extentAffinity: affinity, + ); /// Creates a collapsed selection at the given code position. /// /// A collapsed selection starts and ends at the same offset, which means it /// contains zero characters but instead serves as an insertion point in the /// text. - CodeLineSelection.fromPosition({ - required CodeLinePosition position - }) : this.collapsed( - index: position.index, - offset: position.offset, - affinity: position.affinity, - ); + CodeLineSelection.fromPosition({required CodeLinePosition position}) + : this.collapsed( + index: position.index, + offset: position.offset, + affinity: position.affinity, + ); /// Creates a selection at the given line index and range. - CodeLineSelection.fromRange({ - required CodeLineRange range - }) : this( - baseIndex: range.index, - baseOffset: range.start, - extentIndex: range.index, - extentOffset: range.end, - ); + CodeLineSelection.fromRange({required CodeLineRange range}) + : this( + baseIndex: range.index, + baseOffset: range.start, + extentIndex: range.index, + extentOffset: range.end, + ); /// Creates a selection at the given line index and selection. CodeLineSelection.fromTextSelection({ required int index, - required TextSelection selection + required TextSelection selection, }) : this( - baseIndex: index, - baseOffset: selection.baseOffset, - baseAffinity: selection.affinity, - extentIndex: index, - extentOffset: selection.extentOffset, - extentAffinity: selection.affinity, - ); + baseIndex: index, + baseOffset: selection.baseOffset, + baseAffinity: selection.affinity, + extentIndex: index, + extentOffset: selection.extentOffset, + extentAffinity: selection.affinity, + ); /// Creates a collapsed selection at the beginning. - const CodeLineSelection.zero() : this( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 0, - ); + const CodeLineSelection.zero() + : this(baseIndex: 0, baseOffset: 0, extentIndex: 0, extentOffset: 0); + + /// The line index at which the selection originates. + final int baseIndex; + + /// The line index at which the selection terminates. + final int extentIndex; + + /// The offset at which the selection originates. + /// + /// Might be larger than, smaller than, or equal to extent. + final int baseOffset; + + /// The offset at which the selection terminates. + /// + /// When the user uses the arrow keys to adjust the selection, this is the + /// value that changes. Similarly, if the current theme paints a caret on one + /// side of the selection, this is the location at which to paint the caret. + /// + /// Might be larger than, smaller than, or equal to base. + final int extentOffset; + + /// If the code range is collapsed and has more than one visual location + /// (e.g., occurs at a line break), which of the two locations to use when + /// painting the caret. + final TextAffinity baseAffinity; + + /// If the code range is collapsed and has more than one visual location + /// (e.g., occurs at a line break), which of the two locations to use when + /// painting the caret. + final TextAffinity extentAffinity; /// The position at which the selection originates. CodeLinePosition get base { return CodeLinePosition( index: baseIndex, offset: baseOffset, - affinity: baseAffinity + affinity: baseAffinity, ); } @@ -705,7 +696,7 @@ class CodeLineSelection { return CodeLinePosition( index: extentIndex, offset: extentOffset, - affinity: extentAffinity + affinity: extentAffinity, ); } @@ -777,6 +768,7 @@ class CodeLineSelection { } else { endInside = true; } + return startInside && endInside; } @@ -806,17 +798,25 @@ class CodeLineSelection { if (other is! CodeLineSelection) { return false; } - return other.baseIndex == baseIndex - && other.extentIndex == extentIndex - && other.baseOffset == baseOffset - && other.extentOffset == extentOffset - && other.baseAffinity == baseAffinity - && other.extentAffinity == extentAffinity; + + return other.baseIndex == baseIndex && + other.extentIndex == extentIndex && + other.baseOffset == baseOffset && + other.extentOffset == extentOffset && + other.baseAffinity == baseAffinity && + other.extentAffinity == extentAffinity; } @override int get hashCode { - return Object.hash(baseIndex, extentIndex, baseOffset, extentOffset, baseAffinity, extentAffinity); + return Object.hash( + baseIndex, + extentIndex, + baseOffset, + extentOffset, + baseAffinity, + extentAffinity, + ); } @override @@ -824,7 +824,6 @@ class CodeLineSelection { return 'CodeLineSelection(baseIndex: $baseIndex, baseOffset: $baseOffset, baseAffinity: $baseAffinity, ' 'extentIndex: $extentIndex, extentOffset: $extentOffset, extentAffinity: $extentAffinity)'; } - } /// A position in a string of code. @@ -835,7 +834,6 @@ class CodeLineSelection { /// and the [affinity] is used to describe which character this position affiliates /// with. class CodeLinePosition extends TextPosition { - /// Creates an object representing a particular position in a code. const CodeLinePosition({ required this.index, @@ -843,24 +841,14 @@ class CodeLinePosition extends TextPosition { super.affinity = TextAffinity.downstream, }); + /// Creates the CodeLinePosition with the line index and text position. + CodeLinePosition.from({required int index, required TextPosition position}) + : this(index: index, offset: position.offset, affinity: position.affinity); + /// Line index in the codes. final int index; - /// Creates the CodeLinePosition with the line index and text position. - CodeLinePosition.from({ - required int index, - required TextPosition position - }) : this( - index: index, - offset: position.offset, - affinity: position.affinity - ); - - CodeLinePosition copyWith({ - int? index, - int? offset, - TextAffinity? affinity - }) { + CodeLinePosition copyWith({int? index, int? offset, TextAffinity? affinity}) { return CodeLinePosition( index: index ?? this.index, offset: offset ?? this.offset, @@ -869,7 +857,8 @@ class CodeLinePosition extends TextPosition { } /// Get the text position withou line index. - TextPosition get textPosition => TextPosition(offset: offset, affinity: affinity); + TextPosition get textPosition => + TextPosition(offset: offset, affinity: affinity); /// Whether the current code position is before the given position. bool isBefore(CodeLinePosition position) { @@ -879,6 +868,7 @@ class CodeLinePosition extends TextPosition { if (index > position.index) { return false; } + return offset < position.offset; } @@ -890,6 +880,7 @@ class CodeLinePosition extends TextPosition { if (index < position.index) { return false; } + return offset > position.offset; } @@ -898,10 +889,11 @@ class CodeLinePosition extends TextPosition { if (identical(this, other)) { return true; } - return other is CodeLinePosition - && other.index == index - && other.offset == offset - && other.affinity == affinity; + + return other is CodeLinePosition && + other.index == index && + other.offset == offset && + other.affinity == affinity; } @override @@ -911,12 +903,10 @@ class CodeLinePosition extends TextPosition { String toString() { return 'CodeLinePosition(index: $index, offset: $offset, affinity: $affinity)'; } - } /// A range of code that represents a selection. class CodeLineRange extends TextRange { - /// Creates a code range. const CodeLineRange({ required this.index, @@ -924,19 +914,9 @@ class CodeLineRange extends TextRange { required super.end, }); - /// Line index in the codes. - final int index; - /// Creates a code range at the given line index and text range. - factory CodeLineRange.from({ - required int index, - required TextRange range - }) { - return CodeLineRange( - index: index, - start: range.start, - end: range.end - ); + factory CodeLineRange.from({required int index, required TextRange range}) { + return CodeLineRange(index: index, start: range.start, end: range.end); } /// Creates a collapsed range at the given offset. @@ -944,29 +924,18 @@ class CodeLineRange extends TextRange { /// A collapsed range starts and ends at the same offset, which means it /// contains zero characters but instead serves as an insertion point in the /// text. - const CodeLineRange.collapsed({ - required int index, - required int offset - }) : this( - index: index, - start: offset, - end: offset - ); + const CodeLineRange.collapsed({required int index, required int offset}) + : this(index: index, start: offset, end: offset); /// Creates a collapsed range with negative offset. - const CodeLineRange.empty() : this( - index: 0, - start: -1, - end: -1 - ); + const CodeLineRange.empty() : this(index: 0, start: -1, end: -1); + + /// Line index in the codes. + final int index; /// Creates a new [CodeLineRange] based on the current selection, with the /// provided parameters overridden. - CodeLineRange copyWith({ - int? index, - int? start, - int? end - }) { + CodeLineRange copyWith({int? index, int? start, int? end}) { return CodeLineRange( index: index ?? this.index, start: start ?? this.start, @@ -982,26 +951,24 @@ class CodeLineRange extends TextRange { if (identical(this, other)) { return true; } - return other is CodeLineRange - && other.index == index - && other.start == start - && other.end == end; + + return other is CodeLineRange && + other.index == index && + other.start == start && + other.end == end; } @override String toString() => 'CodeLineRange(index: $index start: $start, end: $end)'; - } /// Some options of the code lines. class CodeLineOptions { - - static const int _defaultIndentSize = 2; - const CodeLineOptions({ this.lineBreak = TextLineBreak.lf, - this.indentSize = _defaultIndentSize + this.indentSize = _defaultIndentSize, }); + static const int _defaultIndentSize = 2; /// Line break symbols, like LF, CRLF. /// @@ -1011,10 +978,7 @@ class CodeLineOptions { /// Indent length, default value is 2. final int indentSize; - CodeLineOptions copyWith({ - TextLineBreak? lineBreak, - int? indentSize, - }) { + CodeLineOptions copyWith({TextLineBreak? lineBreak, int? indentSize}) { return CodeLineOptions( lineBreak: lineBreak ?? this.lineBreak, indentSize: indentSize ?? this.indentSize, @@ -1029,22 +993,20 @@ class CodeLineOptions { if (identical(this, other)) { return true; } - return other is CodeLineOptions - && other.lineBreak == lineBreak - && other.indentSize == indentSize; + + return other is CodeLineOptions && + other.lineBreak == lineBreak && + other.indentSize == indentSize; } String get indent => ' ' * indentSize; - } class CodeLineIndex { - + const CodeLineIndex(this.index, this.chunkIndex); final int index; final int chunkIndex; - const CodeLineIndex(this.index, this.chunkIndex); - @override int get hashCode => Object.hash(index, chunkIndex); @@ -1053,9 +1015,10 @@ class CodeLineIndex { if (identical(this, other)) { return true; } - return other is CodeLineIndex - && other.index == index - && other.chunkIndex == chunkIndex; + + return other is CodeLineIndex && + other.index == index && + other.chunkIndex == chunkIndex; } @override @@ -1063,15 +1026,6 @@ class CodeLineIndex { } class CodeLineRenderParagraph { - - static const double _chunkIndicatorWidth = 15; - - final int index; - final IParagraph paragraph; - final Offset offset; - final bool chunkParent; - final bool chunkLongText; - const CodeLineRenderParagraph({ required this.index, required this.paragraph, @@ -1079,6 +1033,13 @@ class CodeLineRenderParagraph { required this.chunkParent, required this.chunkLongText, }); + static const double _chunkIndicatorWidth = 15; + + final int index; + final IParagraph paragraph; + final Offset offset; + final bool chunkParent; + final bool chunkLongText; double get preferredLineHeight => paragraph.preferredLineHeight; @@ -1086,25 +1047,26 @@ class CodeLineRenderParagraph { double get bottom => offset.dy + height; - double get width => paragraph.width + (chunkParent ? _chunkIndicatorWidth : 0); + double get width => + paragraph.width + (chunkParent ? _chunkIndicatorWidth : 0); double get height => paragraph.height; int get length => paragraph.length; - bool inVerticalRange(Offset coordinate) => coordinate.dy >= top && coordinate.dy < bottom; + bool inVerticalRange(Offset coordinate) => + coordinate.dy >= top && coordinate.dy < bottom; CodeLinePosition getPosition(Offset offset) => CodeLinePosition.from( index: index, - position: paragraph.getPosition(offset) + position: paragraph.getPosition(offset), ); - CodeLineRange getWord(Offset offset) => CodeLineRange.from( - index: index, - range: paragraph.getWord(offset) - ); + CodeLineRange getWord(Offset offset) => + CodeLineRange.from(index: index, range: paragraph.getWord(offset)); - InlineSpan? getSpanForPosition(Offset offset) => paragraph.getSpanForPosition(getPosition(offset)); + InlineSpan? getSpanForPosition(Offset offset) => + paragraph.getSpanForPosition(getPosition(offset)); TextRange getRangeForSpan(InlineSpan span) => paragraph.getRangeForSpan(span); @@ -1124,11 +1086,12 @@ class CodeLineRenderParagraph { if (identical(this, other)) { return true; } - return other is CodeLineRenderParagraph - && other.index == index - && other.paragraph == paragraph - && other.offset == offset - && other.chunkParent == chunkParent; + + return other is CodeLineRenderParagraph && + other.index == index && + other.paragraph == paragraph && + other.offset == offset && + other.chunkParent == chunkParent; } CodeLineRenderParagraph copyWith({ @@ -1146,27 +1109,15 @@ class CodeLineRenderParagraph { chunkLongText: chunkLongText ?? this.chunkLongText, ); } - } -enum TextLineBreak { - - crlf, - - cr, - - lf, - -} +enum TextLineBreak { crlf, cr, lf } extension TextLineBreakExtension on TextLineBreak { - String get value => const ['\r\n', '\r', '\n'][index]; - } class CodeLineUtils { - static List toTextLines(String text) { return text.replaceAll('\r\n', '\n').replaceAll('\r', '\n').split('\n'); } @@ -1179,7 +1130,7 @@ class CodeLineUtils { if (text.isEmpty) { return _kInitialCodeLines; } + return compute((message) => toCodeLines(message), text); } - -} \ No newline at end of file +} diff --git a/lib/src/code_lines.dart b/lib/src/code_lines.dart index cd53fad..9c998b1 100644 --- a/lib/src/code_lines.dart +++ b/lib/src/code_lines.dart @@ -1,11 +1,8 @@ -part of re_editor; +part of 're_editor.dart'; const int _kCodeLineSegamentDefaultSize = 256; class CodeLines { - - final List segments; - const CodeLines(this.segments); factory CodeLines.empty() { @@ -22,10 +19,9 @@ class CodeLines { if (segment.isEmpty) { continue; } - segments.add(segment.copyWith( - dirty: true - )); + segments.add(segment.copyWith(dirty: true)); } + return CodeLines(segments); } @@ -42,20 +38,28 @@ class CodeLines { count = 0; } } + return CodeLines(segments); } + final List segments; CodeLine get first => segments.first.first; CodeLine get last => segments.last.last; - int get length => segments.fold(0, (previousValue, element) => previousValue += element.length); + int get length => segments.fold( + 0, + (previousValue, element) => previousValue += element.length, + ); bool get isEmpty => segments.isEmpty || length == 0; bool get isNotEmpty => !isEmpty; - int get lineCount => segments.fold(0, (previousValue, element) => previousValue += element.lineCount); + int get lineCount => segments.fold( + 0, + (previousValue, element) => previousValue += element.lineCount, + ); CodeLine operator [](int index) { int offset = 0; @@ -81,6 +85,7 @@ class CodeLines { segments[i] = segment; } segment[index - offset] = value; + return; } } @@ -89,11 +94,7 @@ class CodeLines { void add(CodeLine value) { if (isEmpty || segments.last.length >= _kCodeLineSegamentDefaultSize) { - segments.add(CodeLineSegment.of( - codeLines: [ - value - ] - )); + segments.add(CodeLineSegment.of(codeLines: [value])); } else { CodeLineSegment segment = segments.last; if (segment.dirty) { @@ -107,6 +108,7 @@ class CodeLines { void addAll(Iterable iterable) { if (isEmpty) { segments.addAll(CodeLines.of(iterable).segments); + return; } final CodeLineSegment segment = segments.last; @@ -138,6 +140,7 @@ class CodeLines { } if (isEmpty) { segments.addAll(sub.segments); + return; } final List appendSegments = sub.segments; @@ -181,7 +184,10 @@ class CodeLines { if (length1 != length2) { return false; } - final int minSegmentLength = min(segments.length, codeLines.segments.length); + final int minSegmentLength = min( + segments.length, + codeLines.segments.length, + ); int offset = 0; for (int i = 0; i < minSegmentLength; i++) { if (segments[i].length != codeLines.segments[i].length) { @@ -198,6 +204,7 @@ class CodeLines { return false; } } + return true; } @@ -221,9 +228,7 @@ class CodeLines { } if (start <= offset) { if (end - offset >= segment.length) { - newSegments.add(segment.copyWith( - dirty: true - )); + newSegments.add(segment.copyWith(dirty: true)); offset += segment.length; continue; } else { @@ -243,6 +248,7 @@ class CodeLines { } } } + return CodeLines(newSegments); } @@ -267,6 +273,7 @@ class CodeLines { } } } + return sb.toString(); } @@ -287,6 +294,7 @@ class CodeLines { break; } } + return lineIndex; } @@ -294,14 +302,17 @@ class CodeLines { if (lineIndex < 0) { return const CodeLineIndex(-1, -1); } + + int lIndex = lineIndex; + // Find the segment first int segmentIndex = -1; int lineCount = 0; for (int i = 0, start = 0; i < segments.length; i++) { final int end = start + segments[i].lineCount; - if (lineIndex >= start && lineIndex < end) { + if (lIndex >= start && lIndex < end) { segmentIndex = i; - lineIndex -= start; + lIndex -= start; break; } start = end; @@ -316,7 +327,7 @@ class CodeLines { int start = 0; for (int i = 0; i < codeLines.length; i++) { final int end = start + codeLines[i].lineCount; - if (lineIndex >= start && lineIndex < end) { + if (lIndex >= start && lIndex < end) { index = i; start++; break; @@ -331,12 +342,13 @@ class CodeLines { final List chunks = codeLines[index].chunks; for (int i = 0; i < chunks.length; i++) { final int end = start + chunks[i].lineCount; - if (lineIndex >= start && lineIndex < end) { + if (lIndex >= start && lIndex < end) { chunkIndex = i; break; } start = end; } + return CodeLineIndex(index + lineCount, chunkIndex); } @@ -345,6 +357,7 @@ class CodeLines { for (final CodeLineSegment segment in segments) { codeLines.addAll(segment.codeLines); } + return codeLines; } @@ -356,39 +369,33 @@ class CodeLines { if (identical(this, other)) { return true; } - return other is CodeLines - && listEquals(other.segments, segments); + + return other is CodeLines && listEquals(other.segments, segments); } @override String toString() { return '[ ${segments.join(',')} ]'; } - } class CodeLineSegment with ListMixin { - - final List codeLines; - final bool dirty; - - const CodeLineSegment({ - required this.codeLines, - this.dirty = false - }); + const CodeLineSegment({required this.codeLines, this.dirty = false}); factory CodeLineSegment.of({ required List codeLines, - bool dirty = false - }) => _CodeLineSegmentQuckLineCount( - codeLines: codeLines, - dirty: dirty - ); + bool dirty = false, + }) => _CodeLineSegmentQuckLineCount(codeLines: codeLines, dirty: dirty); + final List codeLines; + final bool dirty; @override - int get length => codeLines.length; + int get length => codeLines.length; - int get lineCount => codeLines.fold(0, (previousValue, element) => previousValue += element.lineCount); + int get lineCount => codeLines.fold( + 0, + (previousValue, element) => previousValue += element.lineCount, + ); @override CodeLine operator [](int index) { @@ -425,17 +432,13 @@ class CodeLineSegment with ListMixin { } } - CodeLineSegment clone([int start = 0, int? end]) => CodeLineSegment.of( - codeLines: codeLines.sublist(start, end) - ); + CodeLineSegment clone([int start = 0, int? end]) => + CodeLineSegment.of(codeLines: codeLines.sublist(start, end)); - CodeLineSegment copyWith({ - List? codeLines, - bool? dirty, - }) { + CodeLineSegment copyWith({List? codeLines, bool? dirty}) { return CodeLineSegment.of( codeLines: codeLines ?? this.codeLines, - dirty: dirty ?? this.dirty + dirty: dirty ?? this.dirty, ); } @@ -447,15 +450,15 @@ class CodeLineSegment with ListMixin { if (identical(this, other)) { return true; } - return other is CodeLineSegment - && listEquals(other.codeLines, codeLines) - && other.lineCount == lineCount - && other.dirty == dirty; + + return other is CodeLineSegment && + listEquals(other.codeLines, codeLines) && + other.lineCount == lineCount && + other.dirty == dirty; } @override String toString() { return '[ ${join(',')} ]'; } - -} \ No newline at end of file +} diff --git a/lib/src/code_paragraph.dart b/lib/src/code_paragraph.dart index 67021ed..224c0e4 100644 --- a/lib/src/code_paragraph.dart +++ b/lib/src/code_paragraph.dart @@ -1,7 +1,6 @@ -part of re_editor; +part of 're_editor.dart'; abstract class IParagraph { - double get width; double get height; double get preferredLineHeight; @@ -14,7 +13,7 @@ abstract class IParagraph { TextPosition getPosition(Offset offset); TextRange getWord(Offset offset); - + InlineSpan? getSpanForPosition(TextPosition position); TextRange getRangeForSpan(InlineSpan span); @@ -24,5 +23,4 @@ abstract class IParagraph { Offset? getOffset(TextPosition position); List getRangeRects(TextRange range); - -} \ No newline at end of file +} diff --git a/lib/src/code_scroll.dart b/lib/src/code_scroll.dart index a8d15e7..c97fa93 100644 --- a/lib/src/code_scroll.dart +++ b/lib/src/code_scroll.dart @@ -1,19 +1,22 @@ -part of re_editor; +part of 're_editor.dart'; -typedef CodeScrollbarBuilder = Widget Function(BuildContext context, Widget child, ScrollableDetails details); +typedef CodeScrollbarBuilder = + Widget Function( + BuildContext context, + Widget child, + ScrollableDetails details, + ); class CodeScrollController { - - final ScrollController verticalScroller; - final ScrollController horizontalScroller; - - GlobalKey? _editorKey; - CodeScrollController({ ScrollController? verticalScroller, ScrollController? horizontalScroller, }) : verticalScroller = verticalScroller ?? ScrollController(), - horizontalScroller = horizontalScroller ?? ScrollController(); + horizontalScroller = horizontalScroller ?? ScrollController(); + final ScrollController verticalScroller; + final ScrollController horizontalScroller; + + GlobalKey? _editorKey; void makeCenterIfInvisible(CodeLinePosition position) { _render?.makePositionCenterIfInvisible(position); @@ -23,14 +26,14 @@ class CodeScrollController { _render?.makePositionVisible(position); } - void bindEditor(GlobalKey key) { + set bindEditor(GlobalKey key) { _editorKey = key; } - _CodeFieldRender? get _render => _editorKey?.currentContext?.findRenderObject() as _CodeFieldRender?; + _CodeFieldRender? get _render => + _editorKey?.currentContext?.findRenderObject() as _CodeFieldRender?; void dispose() { _editorKey = null; } - -} \ No newline at end of file +} diff --git a/lib/src/code_shortcuts.dart b/lib/src/code_shortcuts.dart index d53930b..280a045 100644 --- a/lib/src/code_shortcuts.dart +++ b/lib/src/code_shortcuts.dart @@ -1,4 +1,4 @@ -part of re_editor; +part of 're_editor.dart'; enum CodeShortcutType { selectAll, @@ -54,23 +54,21 @@ enum CodeShortcutType { } abstract class CodeShortcutsActivatorsBuilder { - const CodeShortcutsActivatorsBuilder(); List? build(CodeShortcutType type); - } -class DefaultCodeShortcutsActivatorsBuilder extends CodeShortcutsActivatorsBuilder { - +class DefaultCodeShortcutsActivatorsBuilder + extends CodeShortcutsActivatorsBuilder { const DefaultCodeShortcutsActivatorsBuilder(); @override List? build(CodeShortcutType type) { - return kIsMacOS ? _kDefaultMacCodeShortcutsActivators[type] : - _kDefaultCommonCodeShortcutsActivators[type]; + return kIsMacOS + ? _kDefaultMacCodeShortcutsActivators[type] + : _kDefaultCommonCodeShortcutsActivators[type]; } - } abstract class CodeShortcutEditableIntent extends Intent { @@ -110,13 +108,13 @@ class ShortcutLineDeleteIntent extends CodeShortcutEditableIntent { } class ShortcutLineMoveIntent extends CodeShortcutEditableIntent { - final VerticalDirection direction; const ShortcutLineMoveIntent(this.direction); + final VerticalDirection direction; } class ShortcutLineDeleteDirectionIntent extends CodeShortcutEditableIntent { - final bool forward; const ShortcutLineDeleteDirectionIntent(this.forward); + final bool forward; } class CodeShortcutIndentIntent extends CodeShortcutEditableIntent { @@ -128,63 +126,63 @@ class CodeShortcutOutdentIntent extends CodeShortcutEditableIntent { } class CodeShortcutCommentIntent extends CodeShortcutEditableIntent { - final bool single; const CodeShortcutCommentIntent(this.single); + final bool single; } class CodeShortcutCursorMoveIntent extends Intent { - final AxisDirection direction; const CodeShortcutCursorMoveIntent(this.direction); + final AxisDirection direction; } class CodeShortcutCursorMoveLineEdgeIntent extends Intent { - final bool forward; const CodeShortcutCursorMoveLineEdgeIntent(this.forward); + final bool forward; } class CodeShortcutCursorMoveDocEdgeIntent extends Intent { - final bool forward; const CodeShortcutCursorMoveDocEdgeIntent(this.forward); + final bool forward; } class CodeShortcutCursorMovePageIntent extends Intent { - final bool forward; const CodeShortcutCursorMovePageIntent(this.forward); + final bool forward; } class CodeShortcutCursorMoveWordBoundaryIntent extends Intent { - final bool forward; const CodeShortcutCursorMoveWordBoundaryIntent(this.forward); + final bool forward; } class CodeShortcutSelectionExtendIntent extends Intent { - final AxisDirection direction; const CodeShortcutSelectionExtendIntent(this.direction); + final AxisDirection direction; } class CodeShortcutSelectionExtendLineEdgeIntent extends Intent { - final bool forward; const CodeShortcutSelectionExtendLineEdgeIntent(this.forward); + final bool forward; } class CodeShortcutSelectionExtendPageEdgeIntent extends Intent { - final bool forward; const CodeShortcutSelectionExtendPageEdgeIntent(this.forward); + final bool forward; } class CodeShortcutSelectionExtendWordBoundaryIntent extends Intent { - final bool forward; const CodeShortcutSelectionExtendWordBoundaryIntent(this.forward); + final bool forward; } class ShortcutWordDeleteDirectionIntent extends CodeShortcutEditableIntent { - final bool forward; const ShortcutWordDeleteDirectionIntent(this.forward); + final bool forward; } class CodeShortcutDeleteIntent extends CodeShortcutEditableIntent { - final bool forward; const CodeShortcutDeleteIntent(this.forward); + final bool forward; } class CodeShortcutNewLineIntent extends CodeShortcutEditableIntent { @@ -235,27 +233,55 @@ const Map kCodeShortcutIntents = { CodeShortcutType.lineMoveUp: ShortcutLineMoveIntent(VerticalDirection.up), CodeShortcutType.lineMoveDown: ShortcutLineMoveIntent(VerticalDirection.down), CodeShortcutType.cursorMoveUp: CodeShortcutCursorMoveIntent(AxisDirection.up), - CodeShortcutType.cursorMoveDown: CodeShortcutCursorMoveIntent(AxisDirection.down), - CodeShortcutType.cursorMoveForward: CodeShortcutCursorMoveIntent(AxisDirection.right), - CodeShortcutType.cursorMoveBackward: CodeShortcutCursorMoveIntent(AxisDirection.left), - CodeShortcutType.cursorMoveLineStart: CodeShortcutCursorMoveLineEdgeIntent(false), - CodeShortcutType.cursorMoveLineEnd: CodeShortcutCursorMoveLineEdgeIntent(true), - CodeShortcutType.cursorMovePageStart: CodeShortcutCursorMoveDocEdgeIntent(false), + CodeShortcutType.cursorMoveDown: CodeShortcutCursorMoveIntent( + AxisDirection.down, + ), + CodeShortcutType.cursorMoveForward: CodeShortcutCursorMoveIntent( + AxisDirection.right, + ), + CodeShortcutType.cursorMoveBackward: CodeShortcutCursorMoveIntent( + AxisDirection.left, + ), + CodeShortcutType.cursorMoveLineStart: CodeShortcutCursorMoveLineEdgeIntent( + false, + ), + CodeShortcutType.cursorMoveLineEnd: CodeShortcutCursorMoveLineEdgeIntent( + true, + ), + CodeShortcutType.cursorMovePageStart: CodeShortcutCursorMoveDocEdgeIntent( + false, + ), CodeShortcutType.cursorMovePageEnd: CodeShortcutCursorMoveDocEdgeIntent(true), CodeShortcutType.cursorMovePageUp: CodeShortcutCursorMovePageIntent(false), CodeShortcutType.cursorMovePageDown: CodeShortcutCursorMovePageIntent(true), - CodeShortcutType.cursorMoveWordBoundaryForward: CodeShortcutCursorMoveWordBoundaryIntent(true), - CodeShortcutType.cursorMoveWordBoundaryBackward: CodeShortcutCursorMoveWordBoundaryIntent(false), - CodeShortcutType.selectionExtendUp: CodeShortcutSelectionExtendIntent(AxisDirection.up), - CodeShortcutType.selectionExtendDown: CodeShortcutSelectionExtendIntent(AxisDirection.down), - CodeShortcutType.selectionExtendForward: CodeShortcutSelectionExtendIntent(AxisDirection.right), - CodeShortcutType.selectionExtendBackward: CodeShortcutSelectionExtendIntent(AxisDirection.left), - CodeShortcutType.selectionExtendLineStart: CodeShortcutSelectionExtendLineEdgeIntent(false), - CodeShortcutType.selectionExtendLineEnd: CodeShortcutSelectionExtendLineEdgeIntent(true), - CodeShortcutType.selectionExtendPageStart: CodeShortcutSelectionExtendPageEdgeIntent(false), - CodeShortcutType.selectionExtendPageEnd: CodeShortcutSelectionExtendPageEdgeIntent(true), - CodeShortcutType.selectionExtendWordBoundaryForward: CodeShortcutSelectionExtendWordBoundaryIntent(true), - CodeShortcutType.selectionExtendWordBoundaryBackward: CodeShortcutSelectionExtendWordBoundaryIntent(false), + CodeShortcutType.cursorMoveWordBoundaryForward: + CodeShortcutCursorMoveWordBoundaryIntent(true), + CodeShortcutType.cursorMoveWordBoundaryBackward: + CodeShortcutCursorMoveWordBoundaryIntent(false), + CodeShortcutType.selectionExtendUp: CodeShortcutSelectionExtendIntent( + AxisDirection.up, + ), + CodeShortcutType.selectionExtendDown: CodeShortcutSelectionExtendIntent( + AxisDirection.down, + ), + CodeShortcutType.selectionExtendForward: CodeShortcutSelectionExtendIntent( + AxisDirection.right, + ), + CodeShortcutType.selectionExtendBackward: CodeShortcutSelectionExtendIntent( + AxisDirection.left, + ), + CodeShortcutType.selectionExtendLineStart: + CodeShortcutSelectionExtendLineEdgeIntent(false), + CodeShortcutType + .selectionExtendLineEnd: CodeShortcutSelectionExtendLineEdgeIntent(true), + CodeShortcutType.selectionExtendPageStart: + CodeShortcutSelectionExtendPageEdgeIntent(false), + CodeShortcutType + .selectionExtendPageEnd: CodeShortcutSelectionExtendPageEdgeIntent(true), + CodeShortcutType.selectionExtendWordBoundaryForward: + CodeShortcutSelectionExtendWordBoundaryIntent(true), + CodeShortcutType.selectionExtendWordBoundaryBackward: + CodeShortcutSelectionExtendWordBoundaryIntent(false), CodeShortcutType.wordDeleteForward: ShortcutWordDeleteDirectionIntent(true), CodeShortcutType.wordDeleteBackward: ShortcutWordDeleteDirectionIntent(false), CodeShortcutType.indent: CodeShortcutIndentIntent(), @@ -272,66 +298,59 @@ const Map kCodeShortcutIntents = { CodeShortcutType.esc: CodeShortcutEscIntent(), }; -const Map> _kDefaultMacCodeShortcutsActivators = { +const Map> +_kDefaultMacCodeShortcutsActivators = { CodeShortcutType.selectAll: [ - SingleActivator(LogicalKeyboardKey.keyA, meta: true) - ], - CodeShortcutType.cut: [ - SingleActivator(LogicalKeyboardKey.keyX, meta: true) - ], - CodeShortcutType.copy: [ - SingleActivator(LogicalKeyboardKey.keyC, meta: true) + SingleActivator(LogicalKeyboardKey.keyA, meta: true), ], + CodeShortcutType.cut: [SingleActivator(LogicalKeyboardKey.keyX, meta: true)], + CodeShortcutType.copy: [SingleActivator(LogicalKeyboardKey.keyC, meta: true)], CodeShortcutType.paste: [ - SingleActivator(LogicalKeyboardKey.keyV, meta: true) + SingleActivator(LogicalKeyboardKey.keyV, meta: true), ], CodeShortcutType.delete: [ - SingleActivator(LogicalKeyboardKey.delete,), + SingleActivator(LogicalKeyboardKey.delete), SingleActivator(LogicalKeyboardKey.delete, shift: true), ], CodeShortcutType.backspace: [ - SingleActivator(LogicalKeyboardKey.backspace,), + SingleActivator(LogicalKeyboardKey.backspace), SingleActivator(LogicalKeyboardKey.backspace, shift: true), ], - CodeShortcutType.undo: [ - SingleActivator(LogicalKeyboardKey.keyZ, meta: true) - ], + CodeShortcutType.undo: [SingleActivator(LogicalKeyboardKey.keyZ, meta: true)], CodeShortcutType.redo: [ - SingleActivator(LogicalKeyboardKey.keyZ, meta: true, shift: true) + SingleActivator(LogicalKeyboardKey.keyZ, meta: true, shift: true), ], CodeShortcutType.lineSelect: [ - SingleActivator(LogicalKeyboardKey.keyL, meta: true) + SingleActivator(LogicalKeyboardKey.keyL, meta: true), ], CodeShortcutType.lineDelete: [ - SingleActivator(LogicalKeyboardKey.keyD, meta: true) + SingleActivator(LogicalKeyboardKey.keyD, meta: true), ], CodeShortcutType.lineDeleteForward: [ - SingleActivator(LogicalKeyboardKey.delete, meta: true) + SingleActivator(LogicalKeyboardKey.delete, meta: true), ], CodeShortcutType.lineDeleteBackward: [ - SingleActivator(LogicalKeyboardKey.backspace, meta: true) + SingleActivator(LogicalKeyboardKey.backspace, meta: true), ], CodeShortcutType.lineMoveUp: [ - SingleActivator(LogicalKeyboardKey.arrowUp, alt: true) + SingleActivator(LogicalKeyboardKey.arrowUp, alt: true), ], CodeShortcutType.lineMoveDown: [ - SingleActivator(LogicalKeyboardKey.arrowDown, alt: true) - ], - CodeShortcutType.cursorMoveUp: [ - SingleActivator(LogicalKeyboardKey.arrowUp) + SingleActivator(LogicalKeyboardKey.arrowDown, alt: true), ], + CodeShortcutType.cursorMoveUp: [SingleActivator(LogicalKeyboardKey.arrowUp)], CodeShortcutType.cursorMoveDown: [ - SingleActivator(LogicalKeyboardKey.arrowDown) + SingleActivator(LogicalKeyboardKey.arrowDown), ], CodeShortcutType.cursorMoveForward: [ - SingleActivator(LogicalKeyboardKey.arrowRight) + SingleActivator(LogicalKeyboardKey.arrowRight), ], CodeShortcutType.cursorMoveBackward: [ - SingleActivator(LogicalKeyboardKey.arrowLeft) + SingleActivator(LogicalKeyboardKey.arrowLeft), ], CodeShortcutType.cursorMoveLineStart: [ SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true), - SingleActivator(LogicalKeyboardKey.home) + SingleActivator(LogicalKeyboardKey.home), ], CodeShortcutType.cursorMoveLineEnd: [ SingleActivator(LogicalKeyboardKey.arrowRight, meta: true), @@ -339,211 +358,214 @@ const Map> _kDefaultMacCodeShortcutsAc ], CodeShortcutType.cursorMovePageStart: [ SingleActivator(LogicalKeyboardKey.arrowUp, meta: true), - SingleActivator(LogicalKeyboardKey.home, control: true) + SingleActivator(LogicalKeyboardKey.home, control: true), + ], + CodeShortcutType.cursorMovePageUp: [ + SingleActivator(LogicalKeyboardKey.arrowUp, control: true), + ], + CodeShortcutType.cursorMovePageDown: [ + SingleActivator(LogicalKeyboardKey.arrowDown, control: true), ], CodeShortcutType.cursorMovePageEnd: [ SingleActivator(LogicalKeyboardKey.arrowDown, meta: true), - SingleActivator(LogicalKeyboardKey.end, control: true) + SingleActivator(LogicalKeyboardKey.end, control: true), ], CodeShortcutType.cursorMoveWordBoundaryBackward: [ - SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true) + SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true), ], CodeShortcutType.cursorMoveWordBoundaryForward: [ - SingleActivator(LogicalKeyboardKey.arrowRight, alt: true) + SingleActivator(LogicalKeyboardKey.arrowRight, alt: true), ], CodeShortcutType.selectionExtendUp: [ - SingleActivator(LogicalKeyboardKey.arrowUp, shift: true) + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true), ], CodeShortcutType.selectionExtendDown: [ - SingleActivator(LogicalKeyboardKey.arrowDown, shift: true) + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true), ], CodeShortcutType.selectionExtendForward: [ - SingleActivator(LogicalKeyboardKey.arrowRight, shift: true) + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true), ], CodeShortcutType.selectionExtendBackward: [ - SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true) + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true), ], CodeShortcutType.selectionExtendPageStart: [ SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, meta: true), - SingleActivator(LogicalKeyboardKey.home, shift: true, meta: true) + SingleActivator(LogicalKeyboardKey.home, shift: true, meta: true), ], CodeShortcutType.selectionExtendPageEnd: [ SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, meta: true), - SingleActivator(LogicalKeyboardKey.end, shift: true, meta: true) + SingleActivator(LogicalKeyboardKey.end, shift: true, meta: true), ], CodeShortcutType.selectionExtendLineStart: [ SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, meta: true), - SingleActivator(LogicalKeyboardKey.home, shift: true) + SingleActivator(LogicalKeyboardKey.home, shift: true), ], CodeShortcutType.selectionExtendLineEnd: [ SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, meta: true), - SingleActivator(LogicalKeyboardKey.end, shift: true) + SingleActivator(LogicalKeyboardKey.end, shift: true), ], CodeShortcutType.selectionExtendWordBoundaryForward: [ - SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true) + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true), ], CodeShortcutType.selectionExtendWordBoundaryBackward: [ - SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true) + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true), ], CodeShortcutType.wordDeleteForward: [ SingleActivator(LogicalKeyboardKey.delete, alt: true), SingleActivator(LogicalKeyboardKey.delete, alt: true, shift: true), - SingleActivator(LogicalKeyboardKey.delete, meta: true, shift: true) + SingleActivator(LogicalKeyboardKey.delete, meta: true, shift: true), ], CodeShortcutType.wordDeleteBackward: [ SingleActivator(LogicalKeyboardKey.backspace, alt: true), SingleActivator(LogicalKeyboardKey.backspace, alt: true, shift: true), - SingleActivator(LogicalKeyboardKey.backspace, meta: true, shift: true) - ], - CodeShortcutType.indent: [ - SingleActivator(LogicalKeyboardKey.tab) + SingleActivator(LogicalKeyboardKey.backspace, meta: true, shift: true), ], + CodeShortcutType.indent: [SingleActivator(LogicalKeyboardKey.tab)], CodeShortcutType.outdent: [ - SingleActivator(LogicalKeyboardKey.tab, shift: true) + SingleActivator(LogicalKeyboardKey.tab, shift: true), ], CodeShortcutType.newLine: [ SingleActivator(LogicalKeyboardKey.enter), SingleActivator(LogicalKeyboardKey.enter, shift: true), SingleActivator(LogicalKeyboardKey.enter, meta: true), - SingleActivator(LogicalKeyboardKey.enter, meta: true, shift: true) + SingleActivator(LogicalKeyboardKey.enter, meta: true, shift: true), ], CodeShortcutType.transposeCharacters: [ - SingleActivator(LogicalKeyboardKey.keyT, control: true) + SingleActivator(LogicalKeyboardKey.keyT, control: true), ], CodeShortcutType.singleLineComment: [ - SingleActivator(LogicalKeyboardKey.slash, meta: true) + SingleActivator(LogicalKeyboardKey.slash, meta: true), ], CodeShortcutType.multiLineComment: [ - SingleActivator(LogicalKeyboardKey.slash, meta: true, shift: true) - ], - CodeShortcutType.find: [ - SingleActivator(LogicalKeyboardKey.keyF, meta: true) + SingleActivator(LogicalKeyboardKey.slash, meta: true, shift: true), ], + CodeShortcutType.find: [SingleActivator(LogicalKeyboardKey.keyF, meta: true)], CodeShortcutType.findToggleMatchCase: [ - SingleActivator(LogicalKeyboardKey.keyC, meta: true, alt: true) + SingleActivator(LogicalKeyboardKey.keyC, meta: true, alt: true), ], CodeShortcutType.findToggleRegex: [ - SingleActivator(LogicalKeyboardKey.keyR, meta: true, alt: true) + SingleActivator(LogicalKeyboardKey.keyR, meta: true, alt: true), ], CodeShortcutType.replace: [ - SingleActivator(LogicalKeyboardKey.keyF, meta: true, alt: true) - ], - CodeShortcutType.save: [ - SingleActivator(LogicalKeyboardKey.keyS, meta: true) - ], - CodeShortcutType.esc: [ - SingleActivator(LogicalKeyboardKey.escape) + SingleActivator(LogicalKeyboardKey.keyF, meta: true, alt: true), ], + CodeShortcutType.save: [SingleActivator(LogicalKeyboardKey.keyS, meta: true)], + CodeShortcutType.esc: [SingleActivator(LogicalKeyboardKey.escape)], }; -const Map> _kDefaultCommonCodeShortcutsActivators = { +const Map> +_kDefaultCommonCodeShortcutsActivators = { CodeShortcutType.selectAll: [ - SingleActivator(LogicalKeyboardKey.keyA, control: true) + SingleActivator(LogicalKeyboardKey.keyA, control: true), ], CodeShortcutType.cut: [ - SingleActivator(LogicalKeyboardKey.keyX, control: true) + SingleActivator(LogicalKeyboardKey.keyX, control: true), ], CodeShortcutType.copy: [ - SingleActivator(LogicalKeyboardKey.keyC, control: true) + SingleActivator(LogicalKeyboardKey.keyC, control: true), ], CodeShortcutType.paste: [ - SingleActivator(LogicalKeyboardKey.keyV, control: true) + SingleActivator(LogicalKeyboardKey.keyV, control: true), ], CodeShortcutType.delete: [ - SingleActivator(LogicalKeyboardKey.delete,), + SingleActivator(LogicalKeyboardKey.delete), SingleActivator(LogicalKeyboardKey.delete, shift: true), ], CodeShortcutType.backspace: [ - SingleActivator(LogicalKeyboardKey.backspace,), + SingleActivator(LogicalKeyboardKey.backspace), SingleActivator(LogicalKeyboardKey.backspace, shift: true), ], CodeShortcutType.undo: [ - SingleActivator(LogicalKeyboardKey.keyZ, control: true) + SingleActivator(LogicalKeyboardKey.keyZ, control: true), ], CodeShortcutType.redo: [ - SingleActivator(LogicalKeyboardKey.keyZ, control: true, shift: true) + SingleActivator(LogicalKeyboardKey.keyZ, control: true, shift: true), ], CodeShortcutType.lineSelect: [ - SingleActivator(LogicalKeyboardKey.keyL, control: true) + SingleActivator(LogicalKeyboardKey.keyL, control: true), ], CodeShortcutType.lineDelete: [ - SingleActivator(LogicalKeyboardKey.keyD, control: true) + SingleActivator(LogicalKeyboardKey.keyD, control: true), ], CodeShortcutType.lineDeleteForward: [ - SingleActivator(LogicalKeyboardKey.delete, control: true) + SingleActivator(LogicalKeyboardKey.delete, control: true), ], CodeShortcutType.lineDeleteBackward: [ - SingleActivator(LogicalKeyboardKey.backspace, control: true) + SingleActivator(LogicalKeyboardKey.backspace, control: true), ], CodeShortcutType.lineMoveUp: [ - SingleActivator(LogicalKeyboardKey.arrowUp, alt: true) + SingleActivator(LogicalKeyboardKey.arrowUp, alt: true), ], CodeShortcutType.lineMoveDown: [ - SingleActivator(LogicalKeyboardKey.arrowDown, alt: true) - ], - CodeShortcutType.cursorMoveUp: [ - SingleActivator(LogicalKeyboardKey.arrowUp) + SingleActivator(LogicalKeyboardKey.arrowDown, alt: true), ], + CodeShortcutType.cursorMoveUp: [SingleActivator(LogicalKeyboardKey.arrowUp)], CodeShortcutType.cursorMoveDown: [ - SingleActivator(LogicalKeyboardKey.arrowDown) + SingleActivator(LogicalKeyboardKey.arrowDown), ], CodeShortcutType.cursorMoveForward: [ - SingleActivator(LogicalKeyboardKey.arrowRight) + SingleActivator(LogicalKeyboardKey.arrowRight), ], CodeShortcutType.cursorMoveBackward: [ - SingleActivator(LogicalKeyboardKey.arrowLeft) + SingleActivator(LogicalKeyboardKey.arrowLeft), ], CodeShortcutType.cursorMoveLineStart: [ SingleActivator(LogicalKeyboardKey.arrowLeft, control: true), - SingleActivator(LogicalKeyboardKey.home) + SingleActivator(LogicalKeyboardKey.home), ], CodeShortcutType.cursorMoveLineEnd: [ SingleActivator(LogicalKeyboardKey.arrowRight, control: true), - SingleActivator(LogicalKeyboardKey.end) + SingleActivator(LogicalKeyboardKey.end), ], CodeShortcutType.cursorMovePageStart: [ SingleActivator(LogicalKeyboardKey.arrowUp, control: true), - SingleActivator(LogicalKeyboardKey.home, control: true) + SingleActivator(LogicalKeyboardKey.home, control: true), + ], + CodeShortcutType.cursorMovePageUp: [ + SingleActivator(LogicalKeyboardKey.arrowUp, control: true), + ], + CodeShortcutType.cursorMovePageDown: [ + SingleActivator(LogicalKeyboardKey.arrowDown, control: true), ], CodeShortcutType.cursorMovePageEnd: [ SingleActivator(LogicalKeyboardKey.arrowDown, control: true), - SingleActivator(LogicalKeyboardKey.end, control: true) + SingleActivator(LogicalKeyboardKey.end, control: true), ], CodeShortcutType.cursorMoveWordBoundaryBackward: [ - SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true) + SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true), ], CodeShortcutType.cursorMoveWordBoundaryForward: [ - SingleActivator(LogicalKeyboardKey.arrowRight, alt: true) + SingleActivator(LogicalKeyboardKey.arrowRight, alt: true), ], CodeShortcutType.selectionExtendUp: [ - SingleActivator(LogicalKeyboardKey.arrowUp, shift: true) + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true), ], CodeShortcutType.selectionExtendDown: [ - SingleActivator(LogicalKeyboardKey.arrowDown, shift: true) + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true), ], CodeShortcutType.selectionExtendForward: [ - SingleActivator(LogicalKeyboardKey.arrowRight, shift: true) + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true), ], CodeShortcutType.selectionExtendBackward: [ - SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true) + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true), ], CodeShortcutType.selectionExtendPageStart: [ - SingleActivator(LogicalKeyboardKey.home, shift: true, control: true) + SingleActivator(LogicalKeyboardKey.home, shift: true, control: true), ], CodeShortcutType.selectionExtendPageEnd: [ - SingleActivator(LogicalKeyboardKey.end, shift: true, control: true) + SingleActivator(LogicalKeyboardKey.end, shift: true, control: true), ], CodeShortcutType.selectionExtendLineStart: [ - SingleActivator(LogicalKeyboardKey.home, shift: true) + SingleActivator(LogicalKeyboardKey.home, shift: true), ], CodeShortcutType.selectionExtendLineEnd: [ - SingleActivator(LogicalKeyboardKey.end, shift: true) + SingleActivator(LogicalKeyboardKey.end, shift: true), ], CodeShortcutType.selectionExtendWordBoundaryForward: [ - SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true) + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true), ], CodeShortcutType.selectionExtendWordBoundaryBackward: [ - SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true) + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true), ], CodeShortcutType.wordDeleteForward: [ SingleActivator(LogicalKeyboardKey.delete, alt: true), @@ -555,43 +577,39 @@ const Map> _kDefaultCommonCodeShortcut SingleActivator(LogicalKeyboardKey.backspace, alt: true, shift: true), SingleActivator(LogicalKeyboardKey.backspace, control: true), ], - CodeShortcutType.indent: [ - SingleActivator(LogicalKeyboardKey.tab) - ], + CodeShortcutType.indent: [SingleActivator(LogicalKeyboardKey.tab)], CodeShortcutType.outdent: [ - SingleActivator(LogicalKeyboardKey.tab, shift: true) + SingleActivator(LogicalKeyboardKey.tab, shift: true), ], CodeShortcutType.newLine: [ SingleActivator(LogicalKeyboardKey.enter), SingleActivator(LogicalKeyboardKey.enter, shift: true), SingleActivator(LogicalKeyboardKey.enter, control: true), - SingleActivator(LogicalKeyboardKey.enter, control: true, shift: true) + SingleActivator(LogicalKeyboardKey.enter, control: true, shift: true), ], CodeShortcutType.transposeCharacters: [ - SingleActivator(LogicalKeyboardKey.keyT, control: true) + SingleActivator(LogicalKeyboardKey.keyT, control: true), ], CodeShortcutType.singleLineComment: [ - SingleActivator(LogicalKeyboardKey.slash, control: true) + SingleActivator(LogicalKeyboardKey.slash, control: true), ], CodeShortcutType.multiLineComment: [ - SingleActivator(LogicalKeyboardKey.slash, control: true, shift: true) + SingleActivator(LogicalKeyboardKey.slash, control: true, shift: true), ], CodeShortcutType.find: [ - SingleActivator(LogicalKeyboardKey.keyF, control: true) + SingleActivator(LogicalKeyboardKey.keyF, control: true), ], CodeShortcutType.findToggleMatchCase: [ - SingleActivator(LogicalKeyboardKey.keyC, control: true, alt: true) + SingleActivator(LogicalKeyboardKey.keyC, control: true, alt: true), ], CodeShortcutType.findToggleRegex: [ - SingleActivator(LogicalKeyboardKey.keyR, control: true, alt: true) + SingleActivator(LogicalKeyboardKey.keyR, control: true, alt: true), ], CodeShortcutType.replace: [ - SingleActivator(LogicalKeyboardKey.keyF, control: true, alt: true) + SingleActivator(LogicalKeyboardKey.keyF, control: true, alt: true), ], CodeShortcutType.save: [ - SingleActivator(LogicalKeyboardKey.keyS, control: true) - ], - CodeShortcutType.esc: [ - SingleActivator(LogicalKeyboardKey.escape) + SingleActivator(LogicalKeyboardKey.keyS, control: true), ], -}; \ No newline at end of file + CodeShortcutType.esc: [SingleActivator(LogicalKeyboardKey.escape)], +}; diff --git a/lib/src/code_span.dart b/lib/src/code_span.dart index f01d9a3..76fa7a7 100644 --- a/lib/src/code_span.dart +++ b/lib/src/code_span.dart @@ -1,16 +1,16 @@ -part of re_editor; +part of 're_editor.dart'; -typedef PointerEnterEventWithRectListener = void Function(PointerEnterEvent event, int id, List rects); +typedef PointerEnterEventWithRectListener = + void Function(PointerEnterEvent event, int id, List rects); -typedef PointerExitEventWithRectListener = void Function(PointerExitEvent event, int id, List rects); +typedef PointerExitEventWithRectListener = + void Function(PointerExitEvent event, int id, List rects); @immutable class MouseTrackerAnnotationTextSpan extends TextSpan { - - final PointerEnterEventWithRectListener onEnterWithRect; - final PointerExitEventWithRectListener onExitWithRect; - const MouseTrackerAnnotationTextSpan({ + required this.onEnterWithRect, + required this.onExitWithRect, super.text, super.children, super.style, @@ -19,8 +19,7 @@ class MouseTrackerAnnotationTextSpan extends TextSpan { super.semanticsLabel, super.locale, super.spellOut, - required this.onEnterWithRect, - required this.onExitWithRect, }); - -} \ No newline at end of file + final PointerEnterEventWithRectListener onEnterWithRect; + final PointerExitEventWithRectListener onExitWithRect; +} diff --git a/lib/src/code_theme.dart b/lib/src/code_theme.dart index 545d531..8dbf742 100644 --- a/lib/src/code_theme.dart +++ b/lib/src/code_theme.dart @@ -1,4 +1,4 @@ -part of re_editor; +part of 're_editor.dart'; /// The code syntax highlighting theme. We use Re-Highlight as the syntax highlighting rule. /// Re-Highlight provides some built-in syntax highlighting rules for dozens of programming languages, @@ -6,7 +6,6 @@ part of re_editor; /// /// Please see [Re-Highlight](https://reqable/re-highlight). class CodeHighlightTheme { - const CodeHighlightTheme({ required this.languages, required this.theme, @@ -30,12 +29,12 @@ class CodeHighlightTheme { if (identical(this, other)) { return true; } - return other is CodeHighlightTheme - && mapEquals(other.languages, languages) - && mapEquals(other.theme, theme) - && listEquals(other.plugins, plugins); - } + return other is CodeHighlightTheme && + mapEquals(other.languages, languages) && + mapEquals(other.theme, theme) && + listEquals(other.plugins, plugins); + } } /// Define language rules and restrictions for highlighting. @@ -46,7 +45,6 @@ class CodeHighlightTheme { /// /// The issue see https://github.com/dart-lang/sdk/issues/48425 class CodeHighlightThemeMode { - const CodeHighlightThemeMode({ required this.mode, this.maxSize = 4 * 1024 * 1024, @@ -76,15 +74,14 @@ class CodeHighlightThemeMode { if (identical(this, other)) { return true; } - return other is CodeHighlightThemeMode - && mode == other.mode && maxSize == other.maxSize - && maxLineLength == other.maxLineLength; - } + return other is CodeHighlightThemeMode && + mode == other.mode && + maxSize == other.maxSize && + maxLineLength == other.maxLineLength; + } } extension CodeHighlightThemeModeExtension on Mode { - CodeHighlightThemeMode get themeMode => CodeHighlightThemeMode(mode: this); - -} \ No newline at end of file +} diff --git a/lib/src/code_toolbar.dart b/lib/src/code_toolbar.dart index 5b2948f..1de1356 100644 --- a/lib/src/code_toolbar.dart +++ b/lib/src/code_toolbar.dart @@ -1,34 +1,30 @@ -part of re_editor; +part of 're_editor.dart'; -typedef ToolbarMenuBuilder = Widget Function({ - required BuildContext context, - required TextSelectionToolbarAnchors anchors, - required CodeLineEditingController controller, - required VoidCallback onDismiss, - required VoidCallback onRefresh, -}); +typedef ToolbarMenuBuilder = + Widget Function({ + required BuildContext context, + required TextSelectionToolbarAnchors anchors, + required CodeLineEditingController controller, + required VoidCallback onDismiss, + required VoidCallback onRefresh, + }); abstract class SelectionToolbarController { - void show({ required BuildContext context, required CodeLineEditingController controller, required TextSelectionToolbarAnchors anchors, - Rect? renderRect, required LayerLink layerLink, required ValueNotifier visibility, + Rect? renderRect, }); void hide(BuildContext context); - } -abstract class MobileSelectionToolbarController implements SelectionToolbarController { - +abstract class MobileSelectionToolbarController + implements SelectionToolbarController { factory MobileSelectionToolbarController({ - required ToolbarMenuBuilder builder - }) => _MobileSelectionToolbarController( - builder: builder - ); - -} \ No newline at end of file + required ToolbarMenuBuilder builder, + }) => _MobileSelectionToolbarController(builder: builder); +} diff --git a/lib/src/debug/_trace.dart b/lib/src/debug/_trace.dart index 496ed30..7fa1baa 100644 --- a/lib/src/debug/_trace.dart +++ b/lib/src/debug/_trace.dart @@ -1,7 +1,6 @@ -part of re_editor; +part of 're_editor.dart'; class _Trace { - static final Map _timestamps = {}; static void begin(String name) { @@ -12,11 +11,14 @@ class _Trace { final DateTime? time = _timestamps.remove(name); if (time != null) { if (microsecond) { - print('[${DateTime.now()}] $name costs ${DateTime.now().microsecondsSinceEpoch - time.microsecondsSinceEpoch} us'); + print( + '[${DateTime.now()}] $name costs ${DateTime.now().microsecondsSinceEpoch - time.microsecondsSinceEpoch} us', + ); } else { - print('[${DateTime.now()}] $name costs ${DateTime.now().millisecondsSinceEpoch - time.millisecondsSinceEpoch} ms'); + print( + '[${DateTime.now()}] $name costs ${DateTime.now().millisecondsSinceEpoch - time.millisecondsSinceEpoch} ms', + ); } } } - -} \ No newline at end of file +} diff --git a/lib/src/re_editor.dart b/lib/src/re_editor.dart index 72a8a90..f19242c 100644 --- a/lib/src/re_editor.dart +++ b/lib/src/re_editor.dart @@ -1,9 +1,7 @@ -library re_editor; - import 'dart:async'; +import 'dart:collection'; import 'dart:math'; import 'dart:ui' as ui; -import 'dart:collection'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; @@ -12,16 +10,15 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; - -import 'package:re_highlight/re_highlight.dart'; import 'package:isolate_manager/isolate_manager.dart'; +import 'package:re_highlight/re_highlight.dart'; -part '_code_floating_cursor.dart'; part '_code_autocomplete.dart'; part '_code_editable.dart'; part '_code_extensions.dart'; part '_code_field.dart'; part '_code_find.dart'; +part '_code_floating_cursor.dart'; part '_code_formatter.dart'; part '_code_highlight.dart'; part '_code_indicator.dart'; @@ -44,9 +41,10 @@ part 'code_indicator.dart'; part 'code_line.dart'; part 'code_lines.dart'; part 'code_paragraph.dart'; -part 'code_shortcuts.dart'; part 'code_scroll.dart'; +part 'code_shortcuts.dart'; part 'code_span.dart'; part 'code_theme.dart'; part 'code_toolbar.dart'; -part 'debug/_trace.dart'; \ No newline at end of file + +// part 'debug/_trace.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 2cc4b24..c9bc9ae 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,18 +3,24 @@ description: Re-Editor is a powerful lightweight text and code editor widget. version: 0.7.0 homepage: https://reqable.com repository: https://github.com/reqable/re-editor +publish_to: 'none' environment: - sdk: ">=2.17.3 <4.0.0" + sdk: ^3.7.2 dependencies: flutter: sdk: flutter - re_highlight: ^0.0.3 - isolate_manager: ^4.1.5+1 + isolate_manager: ^6.0.0+2 + re_highlight: + git: https://github.com/sgehrman/re-highlight dev_dependencies: + dart_code_metrics: + git: https://github.com/JonasWanke/dart-code-metrics + dfc_lints: + git: https://github.com/sgehrman/dfc_lints + flutter_lints: ^5.0.0 flutter_test: sdk: flutter - flutter_lints: ^2.0.1 - path: ^1.8.2 \ No newline at end of file + path: ^1.9.1 diff --git a/test/code_chunk_default_analyzer_test.dart b/test/code_chunk_default_analyzer_test.dart index 24efa81..7bf147a 100644 --- a/test/code_chunk_default_analyzer_test.dart +++ b/test/code_chunk_default_analyzer_test.dart @@ -9,110 +9,74 @@ void main() { group('DefaultCodeChunkAnalyzer.parse()', () { test('A single code line with empty content', () { { - final CodeLines codeLines = CodeLines.of([ - CodeLine.empty - ]); + final CodeLines codeLines = CodeLines.of([CodeLine.empty]); expect(analyzer.parse(codeLines), const []); } }); test('A single code line without quota', () { { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('(') - ]); - expect(analyzer.parse(codeLines), const [ - CodeChunkSymbol('(', 0) - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('(')]); + expect(analyzer.parse(codeLines), const [CodeChunkSymbol('(', 0)]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine(')') - ]); - expect(analyzer.parse(codeLines), const [ - CodeChunkSymbol(')', 0) - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine(')')]); + expect(analyzer.parse(codeLines), const [CodeChunkSymbol(')', 0)]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('[') - ]); - expect(analyzer.parse(codeLines), const [ - CodeChunkSymbol('[', 0) - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('[')]); + expect(analyzer.parse(codeLines), const [CodeChunkSymbol('[', 0)]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine(']') - ]); - expect(analyzer.parse(codeLines), const [ - CodeChunkSymbol(']', 0) - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine(']')]); + expect(analyzer.parse(codeLines), const [CodeChunkSymbol(']', 0)]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('{') - ]); - expect(analyzer.parse(codeLines), const [ - CodeChunkSymbol('{', 0) - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('{')]); + expect(analyzer.parse(codeLines), const [CodeChunkSymbol('{', 0)]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('}') - ]); - expect(analyzer.parse(codeLines), const [ - CodeChunkSymbol('}', 0) - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('}')]); + expect(analyzer.parse(codeLines), const [CodeChunkSymbol('}', 0)]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('()') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('()')]); expect(analyzer.parse(codeLines), const [ CodeChunkSymbol('(', 0), - CodeChunkSymbol(')', 0) + CodeChunkSymbol(')', 0), ]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('[]') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('[]')]); expect(analyzer.parse(codeLines), const [ CodeChunkSymbol('[', 0), - CodeChunkSymbol(']', 0) + CodeChunkSymbol(']', 0), ]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('{}') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('{}')]); expect(analyzer.parse(codeLines), const [ CodeChunkSymbol('{', 0), - CodeChunkSymbol('}', 0) + CodeChunkSymbol('}', 0), ]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('()[]{}') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('()[]{}')]); expect(analyzer.parse(codeLines), const [ CodeChunkSymbol('(', 0), CodeChunkSymbol(')', 0), CodeChunkSymbol('[', 0), CodeChunkSymbol(']', 0), CodeChunkSymbol('{', 0), - CodeChunkSymbol('}', 0) + CodeChunkSymbol('}', 0), ]); } { final CodeLines codeLines = CodeLines.of(const [ - CodeLine('123{[foo]((abc))[[]]{{bar}}()}') + CodeLine('123{[foo]((abc))[[]]{{bar}}()}'), ]); expect(analyzer.parse(codeLines), const [ CodeChunkSymbol('{', 0), @@ -139,127 +103,89 @@ void main() { test('A single code line with quotas', () { { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('"') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('"')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\'') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('\'')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\\"\\"') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine(r'\"\"')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\\\'\\\'') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('\\\'\\\'')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('"abc"') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('"abc"')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\'abc\'') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('\'abc\'')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('"\'abc\'"') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('"\'abc\'"')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('"("') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('"("')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\'(\'') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('\'(\'')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('"()[]{}"') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('"()[]{}"')]); expect(analyzer.parse(codeLines), const []); } { final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\'()[]{}\'') + CodeLine('\'()[]{}\''), ]); expect(analyzer.parse(codeLines), const []); } { final CodeLines codeLines = CodeLines.of(const [ - CodeLine('"\'()[]{}\'"') + CodeLine('"\'()[]{}\'"'), ]); expect(analyzer.parse(codeLines), const []); } { final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\\"\'()[]{}\'\\"') + CodeLine('\\"\'()[]{}\'\\"'), ]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('""(') - ]); - expect(analyzer.parse(codeLines), const [ - CodeChunkSymbol('(', 0), - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('""(')]); + expect(analyzer.parse(codeLines), const [CodeChunkSymbol('(', 0)]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('""(""') - ]); - expect(analyzer.parse(codeLines), const [ - CodeChunkSymbol('(', 0), - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('""(""')]); + expect(analyzer.parse(codeLines), const [CodeChunkSymbol('(', 0)]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('""("")') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('""("")')]); expect(analyzer.parse(codeLines), const [ CodeChunkSymbol('(', 0), CodeChunkSymbol(')', 0), ]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\'\'(') - ]); - expect(analyzer.parse(codeLines), const [ - CodeChunkSymbol('(', 0), - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('\'\'(')]); + expect(analyzer.parse(codeLines), const [CodeChunkSymbol('(', 0)]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\'\'(\'\'') - ]); - expect(analyzer.parse(codeLines), const [ - CodeChunkSymbol('(', 0), - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('\'\'(\'\'')]); + expect(analyzer.parse(codeLines), const [CodeChunkSymbol('(', 0)]); } { final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\'\'(\'\')') + CodeLine('\'\'(\'\')'), ]); expect(analyzer.parse(codeLines), const [ CodeChunkSymbol('(', 0), @@ -270,51 +196,37 @@ void main() { test('A single code line with unbalanced quotas', () { { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\'(') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('\'(')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('"(') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('"(')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\'(\'\')') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('\'(\'\')')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('"\'()[]{}') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('"\'()[]{}')]); expect(analyzer.parse(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('"\'()"[]') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('"\'()"[]')]); expect(analyzer.parse(codeLines), const [ CodeChunkSymbol('[', 0), CodeChunkSymbol(']', 0), ]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('"\\"()"[]') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine(r'"\"()"[]')]); expect(analyzer.parse(codeLines), const [ CodeChunkSymbol('[', 0), CodeChunkSymbol(']', 0), ]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('\\"()"[]') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine(r'\"()"[]')]); expect(analyzer.parse(codeLines), const []); } }); @@ -393,7 +305,7 @@ void main() { CodeLine('inner1'), CodeLine('inner2'), CodeLine('inner3'), - ]) + ]), ]), CodeLine(']'), CodeLine('{', [ @@ -402,7 +314,7 @@ void main() { CodeLine('inner5'), CodeLine('inner6'), CodeLine('inner7'), - ]) + ]), ]), CodeLine('}'), CodeLine('}'), @@ -418,7 +330,9 @@ void main() { test('Parse a json string', () { { - final CodeLines codeLines = CodeLineUtils.toCodeLines(File(join('test', 'data', 'json_pretty.json')).readAsStringSync()); + final CodeLines codeLines = CodeLineUtils.toCodeLines( + File(join('test', 'data', 'json_pretty.json')).readAsStringSync(), + ); expect(analyzer.parse(codeLines), const [ CodeChunkSymbol('{', 0), CodeChunkSymbol('{', 1), @@ -435,7 +349,9 @@ void main() { ]); } { - final CodeLines codeLines = CodeLineUtils.toCodeLines(File(join('test', 'data', 'json_flatted.json')).readAsStringSync()); + final CodeLines codeLines = CodeLineUtils.toCodeLines( + File(join('test', 'data', 'json_flatted.json')).readAsStringSync(), + ); expect(analyzer.parse(codeLines), const [ CodeChunkSymbol('{', 0), CodeChunkSymbol('{', 0), @@ -457,21 +373,15 @@ void main() { group('DefaultCodeChunkAnalyzer.run()', () { test('A single code line', () { { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine.empty - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine.empty]); expect(analyzer.run(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); expect(analyzer.run(codeLines), const []); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc(){}[]') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc(){}[]')]); expect(analyzer.run(codeLines), const []); } }); @@ -514,9 +424,7 @@ void main() { CodeLine('abc'), CodeLine('abc)'), ]); - expect(analyzer.run(codeLines), const [ - CodeChunk(0, 4) - ]); + expect(analyzer.run(codeLines), const [CodeChunk(0, 4)]); } { final CodeLines codeLines = CodeLines.of(const [ @@ -528,7 +436,7 @@ void main() { ]); expect(analyzer.run(codeLines), const [ CodeChunk(0, 4), - CodeChunk(1, 3) + CodeChunk(1, 3), ]); } { @@ -543,7 +451,7 @@ void main() { expect(analyzer.run(codeLines), const [ CodeChunk(0, 1), CodeChunk(2, 3), - CodeChunk(4, 5) + CodeChunk(4, 5), ]); } { @@ -556,7 +464,7 @@ void main() { ]); expect(analyzer.run(codeLines), const [ CodeChunk(0, 4), - CodeChunk(1, 3) + CodeChunk(1, 3), ]); } { @@ -572,7 +480,7 @@ void main() { ]); expect(analyzer.run(codeLines), const [ CodeChunk(0, 7), - CodeChunk(1, 3) + CodeChunk(1, 3), ]); } { @@ -583,27 +491,29 @@ void main() { CodeLine('abc['), CodeLine('abc)'), ]); - expect(analyzer.run(codeLines), const [ - CodeChunk(0, 4), - ]); + expect(analyzer.run(codeLines), const [CodeChunk(0, 4)]); } }); test('Parse a json string', () { { - final CodeLines codeLines = CodeLineUtils.toCodeLines(File(join('test', 'data', 'json_pretty.json')).readAsStringSync()); + final CodeLines codeLines = CodeLineUtils.toCodeLines( + File(join('test', 'data', 'json_pretty.json')).readAsStringSync(), + ); expect(analyzer.run(codeLines), const [ CodeChunk(0, 17), CodeChunk(1, 5), CodeChunk(2, 4), CodeChunk(6, 15), CodeChunk(7, 10), - CodeChunk(11, 14) + CodeChunk(11, 14), ]); } { - final CodeLines codeLines = CodeLineUtils.toCodeLines(File(join('test', 'data', 'json_flatted.json')).readAsStringSync()); + final CodeLines codeLines = CodeLineUtils.toCodeLines( + File(join('test', 'data', 'json_flatted.json')).readAsStringSync(), + ); expect(analyzer.run(codeLines), const []); } }); }); -} \ No newline at end of file +} diff --git a/test/code_chunk_test.dart b/test/code_chunk_test.dart index 5e67ee9..adb54f1 100644 --- a/test/code_chunk_test.dart +++ b/test/code_chunk_test.dart @@ -5,32 +5,35 @@ void main() { group('CodeChunkController constructor', () { test('CodeChunkController()', () async { { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController(), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController(), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200), () { expect(controller.value, const []); controller.dispose(); }); } { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController.fromText('{\n\n}'), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController.fromText('{\n\n}'), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); - expect(controller.value, const [ - CodeChunk(0, 2) - ]); + expect(controller.value, const [CodeChunk(0, 2)]); controller.dispose(); } }); }); group('CodeChunkController method', () { - test('collapse()', () async { // Empty content, and no chunk { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController(), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController(), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); controller.collapse(0); expect(controller.value, const []); @@ -38,8 +41,10 @@ void main() { } // Non-Empty content, but no chunk { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController.fromText('abc'), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController.fromText('abc'), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); controller.collapse(0); expect(controller.value, const []); @@ -47,44 +52,47 @@ void main() { } // Have a chunk, but nothing to collapse { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController.fromText('{\n}'), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController.fromText('{\n}'), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); - expect(controller.value, const [ - CodeChunk(0, 1) - ]); + expect(controller.value, const [CodeChunk(0, 1)]); controller.collapse(0); - expect(controller.value, const [ - CodeChunk(0, 1) - ]); + expect(controller.value, const [CodeChunk(0, 1)]); controller.dispose(); } // Have only a chunk { - final CodeLineEditingController editingController = CodeLineEditingController.fromText('{\nabc\n}'); - final CodeChunkController controller = CodeChunkController(editingController, - const DefaultCodeChunkAnalyzer()); + final CodeLineEditingController editingController = + CodeLineEditingController.fromText('{\nabc\n}'); + final CodeChunkController controller = CodeChunkController( + editingController, + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); - expect(controller.value, const [ - CodeChunk(0, 2) - ]); + expect(controller.value, const [CodeChunk(0, 2)]); controller.collapse(0); - expect(controller.value, const [ - CodeChunk(0, 1) - ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('abc') + expect(controller.value, const [CodeChunk(0, 1)]); + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine('abc')]), + CodeLine('}'), ]), - CodeLine('}') - ])); + ); controller.dispose(); } // Have multi chunks, collapse from inside one by one { - final CodeLineEditingController editingController = CodeLineEditingController.fromText('{\n\n{\n[\nabc\n(foo)\nbar\n]\n}\n\n}'); - final CodeChunkController controller = CodeChunkController(editingController, - const DefaultCodeChunkAnalyzer()); + final CodeLineEditingController editingController = + CodeLineEditingController.fromText( + '{\n\n{\n[\nabc\n(foo)\nbar\n]\n}\n\n}', + ); + final CodeChunkController controller = CodeChunkController( + editingController, + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.value, const [ CodeChunk(0, 10), @@ -97,68 +105,75 @@ void main() { CodeChunk(2, 5), CodeChunk(3, 4), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('{'), - CodeLine('[', [ - CodeLine('abc'), - CodeLine('(foo)'), - CodeLine('bar'), - ]), - CodeLine(']'), - CodeLine('}'), - CodeLine(''), - CodeLine('}') - ])); - controller.collapse(2); - expect(controller.value, const [ - CodeChunk(0, 5), - CodeChunk(2, 3) - ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('{', [ + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('{'), CodeLine('[', [ CodeLine('abc'), CodeLine('(foo)'), CodeLine('bar'), ]), - CodeLine(']') + CodeLine(']'), + CodeLine('}'), + CodeLine.empty, + CodeLine('}'), ]), - CodeLine('}'), - CodeLine(''), - CodeLine('}') - ])); - controller.collapse(0); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine(''), + ); + controller.collapse(2); + expect(controller.value, const [CodeChunk(0, 5), CodeChunk(2, 3)]); + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, CodeLine('{', [ CodeLine('[', [ CodeLine('abc'), CodeLine('(foo)'), CodeLine('bar'), ]), - CodeLine(']') + CodeLine(']'), ]), CodeLine('}'), - CodeLine(''), + CodeLine.empty, + CodeLine('}'), + ]), + ); + controller.collapse(0); + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{', [ + CodeLine.empty, + CodeLine('{', [ + CodeLine('[', [ + CodeLine('abc'), + CodeLine('(foo)'), + CodeLine('bar'), + ]), + CodeLine(']'), + ]), + CodeLine('}'), + CodeLine.empty, ]), - CodeLine('}') - ])); + CodeLine('}'), + ]), + ); controller.collapse(0); - expect(controller.value, const [ - CodeChunk(0, 1) - ]); + expect(controller.value, const [CodeChunk(0, 1)]); controller.dispose(); } // Have multi chunks, collapse from top one by one { - final CodeLineEditingController editingController = CodeLineEditingController.fromText('{\n\n}{\n\n}{\n\n}{\n\n}'); - final CodeChunkController controller = CodeChunkController(editingController, - const DefaultCodeChunkAnalyzer()); + final CodeLineEditingController editingController = + CodeLineEditingController.fromText('{\n\n}{\n\n}{\n\n}{\n\n}'); + final CodeChunkController controller = CodeChunkController( + editingController, + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.value, const [ CodeChunk(0, 2), @@ -173,18 +188,19 @@ void main() { CodeChunk(3, 5), CodeChunk(5, 7), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('') + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine.empty]), + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}'), ]), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}'), - ])); + ); controller.collapse(1); expect(controller.value, const [ CodeChunk(0, 1), @@ -192,19 +208,18 @@ void main() { CodeChunk(2, 4), CodeChunk(4, 6), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}'), ]), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}'), - ])); + ); controller.collapse(2); expect(controller.value, const [ CodeChunk(0, 1), @@ -212,20 +227,17 @@ void main() { CodeChunk(2, 3), CodeChunk(3, 5), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{'), + CodeLine.empty, + CodeLine('}'), ]), - CodeLine('}{'), - CodeLine(''), - CodeLine('}'), - ])); + ); controller.collapse(3); expect(controller.value, const [ CodeChunk(0, 1), @@ -233,27 +245,25 @@ void main() { CodeChunk(2, 3), CodeChunk(3, 4), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}'), ]), - CodeLine('}'), - ])); + ); } // Have multi chunks, collapse from bottom one by one { - final CodeLineEditingController editingController = CodeLineEditingController.fromText('{\n\n}{\n\n}{\n\n}{\n\n}'); - final CodeChunkController controller = CodeChunkController(editingController, - const DefaultCodeChunkAnalyzer()); + final CodeLineEditingController editingController = + CodeLineEditingController.fromText('{\n\n}{\n\n}{\n\n}{\n\n}'); + final CodeChunkController controller = CodeChunkController( + editingController, + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.value, const [ CodeChunk(0, 2), @@ -268,18 +278,19 @@ void main() { CodeChunk(4, 6), CodeChunk(6, 7), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{', [ - CodeLine(''), + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{', [CodeLine.empty]), + CodeLine('}'), ]), - CodeLine('}'), - ])); + ); controller.collapse(4); expect(controller.value, const [ CodeChunk(0, 2), @@ -287,19 +298,18 @@ void main() { CodeChunk(4, 5), CodeChunk(5, 6), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{', [ - CodeLine(''), - ]), - CodeLine('}{', [ - CodeLine(''), + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}'), ]), - CodeLine('}'), - ])); + ); controller.collapse(2); expect(controller.value, const [ CodeChunk(0, 2), @@ -307,20 +317,17 @@ void main() { CodeChunk(3, 4), CodeChunk(4, 5), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('}{', [ - CodeLine(''), - ]), - CodeLine('}{', [ - CodeLine(''), - ]), - CodeLine('}{', [ - CodeLine(''), + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}'), ]), - CodeLine('}'), - ])); + ); controller.collapse(0); expect(controller.value, const [ CodeChunk(0, 1), @@ -328,29 +335,26 @@ void main() { CodeChunk(2, 3), CodeChunk(3, 4), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}'), ]), - CodeLine('}'), - ])); + ); } }); test('expand()', () async { // Empty content, and no chunk { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController(), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController(), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); controller.expand(0); expect(controller.value, const []); @@ -358,8 +362,10 @@ void main() { } // Non-Empty content, but no chunk { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController.fromText('abc'), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController.fromText('abc'), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); controller.expand(0); expect(controller.value, const []); @@ -367,150 +373,145 @@ void main() { } // Have a chunk, but nothing to expand { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController.fromText('{\n}'), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController.fromText('{\n}'), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); - expect(controller.value, const [ - CodeChunk(0, 1) - ]); + expect(controller.value, const [CodeChunk(0, 1)]); controller.expand(0); - expect(controller.value, const [ - CodeChunk(0, 1) - ]); + expect(controller.value, const [CodeChunk(0, 1)]); controller.dispose(); } // Have only a collapsed chunk { - final CodeLineEditingController editingController = CodeLineEditingController( - codeLines: CodeLines.of(const [ - CodeLine('{', [ - CodeLine('abc'), - ]), - CodeLine('}'), - ] - )); - final CodeChunkController controller = CodeChunkController(editingController, const DefaultCodeChunkAnalyzer()); + final CodeLineEditingController editingController = + CodeLineEditingController( + codeLines: CodeLines.of(const [ + CodeLine('{', [CodeLine('abc')]), + CodeLine('}'), + ]), + ); + final CodeChunkController controller = CodeChunkController( + editingController, + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); - expect(controller.value, const [ - CodeChunk(0, 1), - ]); + expect(controller.value, const [CodeChunk(0, 1)]); controller.expand(0); - expect(controller.value, const [ - CodeChunk(0, 2) - ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine('abc'), - CodeLine('}'), - ])); + expect(controller.value, const [CodeChunk(0, 2)]); + expect( + editingController.codeLines, + CodeLines.of(const [CodeLine('{'), CodeLine('abc'), CodeLine('}')]), + ); controller.dispose(); } // Have multi collapsed chunks, expand from outside one by one { - final CodeLineEditingController editingController = CodeLineEditingController( - codeLines: CodeLines.of(const [ - CodeLine('{', [ - CodeLine(''), - CodeLine('{', [ - CodeLine('[', [ - CodeLine('abc'), - CodeLine('(foo)'), - CodeLine('bar'), + final CodeLineEditingController editingController = + CodeLineEditingController( + codeLines: CodeLines.of(const [ + CodeLine('{', [ + CodeLine.empty, + CodeLine('{', [ + CodeLine('[', [ + CodeLine('abc'), + CodeLine('(foo)'), + CodeLine('bar'), + ]), + CodeLine(']'), + ]), + CodeLine('}'), + CodeLine.empty, ]), - CodeLine(']') - ]), - CodeLine('}'), - CodeLine(''), + CodeLine('}'), ]), - CodeLine('}') - ] - )); - final CodeChunkController controller = CodeChunkController(editingController, - const DefaultCodeChunkAnalyzer()); + ); + final CodeChunkController controller = CodeChunkController( + editingController, + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); - expect(controller.value, const [ - CodeChunk(0, 1), - ]); + expect(controller.value, const [CodeChunk(0, 1)]); controller.expand(0); - expect(controller.value, const [ - CodeChunk(0, 5), - ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('{', [ + expect(controller.value, const [CodeChunk(0, 5)]); + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('{', [ + CodeLine('[', [ + CodeLine('abc'), + CodeLine('(foo)'), + CodeLine('bar'), + ]), + CodeLine(']'), + ]), + CodeLine('}'), + CodeLine.empty, + CodeLine('}'), + ]), + ); + controller.expand(2); + expect(controller.value, const [CodeChunk(0, 7), CodeChunk(2, 5)]); + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('{'), CodeLine('[', [ CodeLine('abc'), CodeLine('(foo)'), CodeLine('bar'), ]), - CodeLine(']') - ]), - CodeLine('}'), - CodeLine(''), - CodeLine('}') - ])); - controller.expand(2); - expect(controller.value, const [ - CodeChunk(0, 7), - CodeChunk(2, 5), - ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('{'), - CodeLine('[', [ - CodeLine('abc'), - CodeLine('(foo)'), - CodeLine('bar'), + CodeLine(']'), + CodeLine('}'), + CodeLine.empty, + CodeLine('}'), ]), - CodeLine(']'), - CodeLine('}'), - CodeLine(''), - CodeLine('}') - ])); + ); controller.expand(3); expect(controller.value, const [ CodeChunk(0, 10), CodeChunk(2, 8), CodeChunk(3, 7), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('{'), - CodeLine('['), - CodeLine('abc'), - CodeLine('(foo)'), - CodeLine('bar'), - CodeLine(']'), - CodeLine('}'), - CodeLine(''), - CodeLine('}') - ])); + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('{'), + CodeLine('['), + CodeLine('abc'), + CodeLine('(foo)'), + CodeLine('bar'), + CodeLine(']'), + CodeLine('}'), + CodeLine.empty, + CodeLine('}'), + ]), + ); controller.dispose(); } // Have multi collapsed chunks, expand from top one by one { - final CodeLineEditingController editingController = CodeLineEditingController( - codeLines: CodeLines.of(const [ - CodeLine('{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}'), - ] - )); - final CodeChunkController controller = CodeChunkController(editingController, - const DefaultCodeChunkAnalyzer()); + final CodeLineEditingController editingController = + CodeLineEditingController( + codeLines: CodeLines.of(const [ + CodeLine('{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}'), + ]), + ); + final CodeChunkController controller = CodeChunkController( + editingController, + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.value, const [ CodeChunk(0, 1), @@ -525,20 +526,17 @@ void main() { CodeChunk(3, 4), CodeChunk(4, 5), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}'), ]), - CodeLine('}'), - ])); + ); controller.expand(2); expect(controller.value, const [ CodeChunk(0, 2), @@ -546,19 +544,18 @@ void main() { CodeChunk(4, 5), CodeChunk(5, 6), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}'), ]), - CodeLine('}'), - ])); + ); controller.expand(4); expect(controller.value, const [ CodeChunk(0, 2), @@ -566,18 +563,19 @@ void main() { CodeChunk(4, 6), CodeChunk(6, 7), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{', [ - CodeLine('') + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{', [CodeLine.empty]), + CodeLine('}'), ]), - CodeLine('}'), - ])); + ); controller.expand(6); expect(controller.value, const [ CodeChunk(0, 2), @@ -585,40 +583,38 @@ void main() { CodeChunk(4, 6), CodeChunk(6, 8), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}'), - ])); + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}'), + ]), + ); controller.dispose(); } // Have multi collapsed chunks, expand from bottom one by one { - final CodeLineEditingController editingController = CodeLineEditingController( - codeLines: CodeLines.of(const [ - CodeLine('{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}'), - ] - )); - final CodeChunkController controller = CodeChunkController(editingController, - const DefaultCodeChunkAnalyzer()); + final CodeLineEditingController editingController = + CodeLineEditingController( + codeLines: CodeLines.of(const [ + CodeLine('{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}'), + ]), + ); + final CodeChunkController controller = CodeChunkController( + editingController, + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.value, const [ CodeChunk(0, 1), @@ -633,20 +629,17 @@ void main() { CodeChunk(2, 3), CodeChunk(3, 5), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{'), + CodeLine.empty, + CodeLine('}'), ]), - CodeLine('}{',), - CodeLine(''), - CodeLine('}'), - ])); + ); controller.expand(2); expect(controller.value, const [ CodeChunk(0, 1), @@ -654,19 +647,18 @@ void main() { CodeChunk(2, 4), CodeChunk(4, 6), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('') - ]), - CodeLine('}{', [ - CodeLine('') + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}'), ]), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{',), - CodeLine(''), - CodeLine('}'), - ])); + ); controller.expand(1); expect(controller.value, const [ CodeChunk(0, 1), @@ -674,18 +666,19 @@ void main() { CodeChunk(3, 5), CodeChunk(5, 7), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('') + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine.empty]), + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}'), ]), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{',), - CodeLine(''), - CodeLine('}'), - ])); + ); controller.expand(0); expect(controller.value, const [ CodeChunk(0, 2), @@ -693,25 +686,31 @@ void main() { CodeChunk(4, 6), CodeChunk(6, 8), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}'), - ])); + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}'), + ]), + ); controller.dispose(); } }); test('collapse() and expand()', () async { - final CodeLineEditingController editingController = CodeLineEditingController.fromText('{\n\n}{\n\n}{\n\n}{\n\n}'); - final CodeChunkController controller = CodeChunkController(editingController, - const DefaultCodeChunkAnalyzer()); + final CodeLineEditingController editingController = + CodeLineEditingController.fromText('{\n\n}{\n\n}{\n\n}{\n\n}'); + final CodeChunkController controller = CodeChunkController( + editingController, + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); controller.collapse(2); expect(controller.value, const [ @@ -720,18 +719,19 @@ void main() { CodeChunk(3, 5), CodeChunk(5, 7), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('}{', [ - CodeLine(''), + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}'), ]), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}'), - ])); + ); controller.collapse(3); expect(controller.value, const [ CodeChunk(0, 2), @@ -739,19 +739,18 @@ void main() { CodeChunk(3, 4), CodeChunk(4, 6), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('}{', [ - CodeLine(''), - ]), - CodeLine('}{', [ - CodeLine(''), + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{'), + CodeLine.empty, + CodeLine('}'), ]), - CodeLine('}{'), - CodeLine(''), - CodeLine('}'), - ])); + ); controller.expand(2); expect(controller.value, const [ CodeChunk(0, 2), @@ -759,18 +758,19 @@ void main() { CodeChunk(4, 5), CodeChunk(5, 7), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{', [ - CodeLine(''), + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{', [CodeLine.empty]), + CodeLine('}{'), + CodeLine.empty, + CodeLine('}'), ]), - CodeLine('}{'), - CodeLine(''), - CodeLine('}'), - ])); + ); controller.expand(4); expect(controller.value, const [ CodeChunk(0, 2), @@ -778,40 +778,49 @@ void main() { CodeChunk(4, 6), CodeChunk(6, 8), ]); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}{'), - CodeLine(''), - CodeLine('}'), - ])); + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}{'), + CodeLine.empty, + CodeLine('}'), + ]), + ); controller.dispose(); }); test('findByIndex()', () async { { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController(), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController(), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.findByIndex(0), null); expect(controller.findByIndex(1), null); controller.dispose(); } { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController.fromText('{\n\n}'), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController.fromText('{\n\n}'), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.findByIndex(0), const CodeChunk(0, 2)); expect(controller.findByIndex(1), null); controller.dispose(); } { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController.fromText('{\n{\n{\n\n}\n}\n}'), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController.fromText('{\n{\n{\n\n}\n}\n}'), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.findByIndex(0), const CodeChunk(0, 6)); expect(controller.findByIndex(1), const CodeChunk(1, 5)); @@ -825,23 +834,29 @@ void main() { test('canCollapse()', () async { { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController.fromText('{\n}'), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController.fromText('{\n}'), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.canCollapse(0), false); controller.dispose(); } { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController.fromText('{\n\n}'), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController.fromText('{\n\n}'), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.canCollapse(0), true); expect(controller.canCollapse(1), false); controller.dispose(); } { - final CodeChunkController controller = CodeChunkController(CodeLineEditingController.fromText('{\n{\n{\n\n}\n}\n}'), - const DefaultCodeChunkAnalyzer()); + final CodeChunkController controller = CodeChunkController( + CodeLineEditingController.fromText('{\n{\n{\n\n}\n}\n}'), + const DefaultCodeChunkAnalyzer(), + ); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.canCollapse(0), true); expect(controller.canCollapse(1), true); @@ -853,84 +868,71 @@ void main() { test('auto expand invalid collapsed chunks()', () async { { - final CodeLineEditingController editingController = CodeLineEditingController( - codeLines: CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]), - CodeLine('123'), - ]) + final CodeLineEditingController editingController = + CodeLineEditingController( + codeLines: CodeLines.of(const [ + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('123'), + ]), + ); + final CodeChunkController controller = CodeChunkController( + editingController, + const DefaultCodeChunkAnalyzer(), ); - final CodeChunkController controller = CodeChunkController(editingController, const DefaultCodeChunkAnalyzer()); await Future.delayed(const Duration(milliseconds: 200)); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - CodeLine('123'), - ])); - // Edit the code line to create invalid chunks - editingController.codeLines = CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]), - CodeLine('abc', [ + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), + CodeLine('123'), ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]) + ); + // Edit the code line to create invalid chunks + editingController.codeLines = CodeLines.of(const [ + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), ]); await Future.delayed(const Duration(milliseconds: 200)); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - ])); - // Edit the code line to create two invalid chunks and one valid chunk - editingController.codeLines = CodeLines.of(const [ - CodeLine('abc', [ + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), - ]), - CodeLine('{', [ + CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), - ]), - CodeLine('}'), - CodeLine('abc', [ + CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), - ]) + ]), + ); + // Edit the code line to create two invalid chunks and one valid chunk + editingController.codeLines = CodeLines.of(const [ + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), ]); await Future.delayed(const Duration(milliseconds: 200)); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - CodeLine('{', [ + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('abc'), + CodeLine('foo'), + CodeLine('bar'), + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), + CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), ]), - CodeLine('}'), - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - ])); + ); controller.dispose(); } }); - }); - -} \ No newline at end of file +} diff --git a/test/code_line_editing_controller_test.dart b/test/code_line_editing_controller_test.dart index db11b19..ff01aa1 100644 --- a/test/code_line_editing_controller_test.dart +++ b/test/code_line_editing_controller_test.dart @@ -7,7 +7,8 @@ void main() { group('CodeLineEditingController constructor ', () { test('`CodeLineEditingController()`', () { { - final CodeLineEditingController controller = CodeLineEditingController(); + final CodeLineEditingController controller = + CodeLineEditingController(); expect(controller.value, const CodeLineEditingValue.empty()); expect(controller.options, const CodeLineOptions()); } @@ -17,29 +18,32 @@ void main() { CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), - ]) + ]), + ); + expect( + controller.value, + CodeLineEditingValue( + codeLines: CodeLines.of(const [ + CodeLine('abc'), + CodeLine('foo'), + CodeLine('bar'), + ]), + ), ); - expect(controller.value, CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - ]) - )); expect(controller.options, const CodeLineOptions()); } { final CodeLineEditingController controller = CodeLineEditingController( options: const CodeLineOptions( lineBreak: TextLineBreak.crlf, - indentSize: 4 - ) + indentSize: 4, + ), ); expect(controller.value, const CodeLineEditingValue.empty()); - expect(controller.options, const CodeLineOptions( - lineBreak: TextLineBreak.crlf, - indentSize: 4 - )); + expect( + controller.options, + const CodeLineOptions(lineBreak: TextLineBreak.crlf, indentSize: 4), + ); } { final CodeLineEditingController controller = CodeLineEditingController( @@ -50,45 +54,56 @@ void main() { ]), options: const CodeLineOptions( lineBreak: TextLineBreak.crlf, - indentSize: 4 - ) + indentSize: 4, + ), + ); + expect( + controller.value, + CodeLineEditingValue( + codeLines: CodeLines.of(const [ + CodeLine('abc'), + CodeLine('foo'), + CodeLine('bar'), + ]), + ), + ); + expect( + controller.options, + const CodeLineOptions(lineBreak: TextLineBreak.crlf, indentSize: 4), ); - expect(controller.value, CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - ]) - )); - expect(controller.options, const CodeLineOptions( - lineBreak: TextLineBreak.crlf, - indentSize: 4 - )); } }); test('`CodeLineEditingController.fromText()`', () { { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); expect(controller.value, const CodeLineEditingValue.empty()); expect(controller.options, const CodeLineOptions()); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar', const CodeLineOptions( - lineBreak: TextLineBreak.crlf, - indentSize: 4 - )); - expect(controller.value, CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - ]) - )); - expect(controller.options, const CodeLineOptions( - lineBreak: TextLineBreak.crlf, - indentSize: 4 - )); + final CodeLineEditingController controller = + CodeLineEditingController.fromText( + 'abc\nfoo\nbar', + const CodeLineOptions( + lineBreak: TextLineBreak.crlf, + indentSize: 4, + ), + ); + expect( + controller.value, + CodeLineEditingValue( + codeLines: CodeLines.of(const [ + CodeLine('abc'), + CodeLine('foo'), + CodeLine('bar'), + ]), + ), + ); + expect( + controller.options, + const CodeLineOptions(lineBreak: TextLineBreak.crlf, indentSize: 4), + ); } }); }); @@ -102,7 +117,7 @@ void main() { CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), - ]) + ]), ); controller.value = value; expect(controller.value, value); @@ -110,9 +125,7 @@ void main() { test('`codeLines`', () { final CodeLineEditingController controller = CodeLineEditingController(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); final CodeLines codeLines = CodeLines.of(const [ CodeLine('abc'), CodeLine('foo'), @@ -123,18 +136,20 @@ void main() { }); test('`selection`', () { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); expect(controller.selection, const CodeLineSelection.zero()); const CodeLineSelection selection = CodeLineSelection.collapsed( index: 0, - offset: 1 + offset: 1, ); controller.selection = selection; expect(controller.selection, selection); }); test('`composing`', () { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); expect(controller.composing, TextRange.empty); const TextRange composing = TextRange.collapsed(1); controller.composing = composing; @@ -143,16 +158,18 @@ void main() { test('`baseLine`', () { { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); expect(controller.baseLine, controller.codeLines[0]); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 2, - extentOffset: 0 + extentOffset: 0, ); expect(controller.baseLine, controller.codeLines[1]); } @@ -160,16 +177,18 @@ void main() { test('`extentLine`', () { { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); expect(controller.extentLine, controller.codeLines[0]); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 2, - extentOffset: 0 + extentOffset: 0, ); expect(controller.extentLine, controller.codeLines[2]); } @@ -177,26 +196,29 @@ void main() { test('`startLine`', () { { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); expect(controller.startLine, controller.codeLines[0]); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 2, - extentOffset: 0 + extentOffset: 0, ); expect(controller.startLine, controller.codeLines[1]); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection( baseIndex: 2, baseOffset: 0, extentIndex: 1, - extentOffset: 0 + extentOffset: 0, ); expect(controller.startLine, controller.codeLines[1]); } @@ -204,26 +226,29 @@ void main() { test('`endLine`', () { { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); expect(controller.endLine, controller.codeLines[0]); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 2, - extentOffset: 0 + extentOffset: 0, ); expect(controller.endLine, controller.codeLines[2]); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection( baseIndex: 2, baseOffset: 0, extentIndex: 1, - extentOffset: 0 + extentOffset: 0, ); expect(controller.endLine, controller.codeLines[2]); } @@ -231,37 +256,41 @@ void main() { test('`isComposing`', () { { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); expect(controller.isComposing, false); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.composing = const TextRange.collapsed(0); expect(controller.isComposing, false); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); - controller.composing = const TextRange( - start: 0, - end: 1 - ); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); + controller.composing = const TextRange(start: 0, end: 1); expect(controller.isComposing, true); } }); test('`text`', () { { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); expect(controller.text, 'abc'); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); expect(controller.text, 'abc\nfoo\nbar'); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar', const CodeLineOptions( - lineBreak: TextLineBreak.crlf - )); + final CodeLineEditingController controller = + CodeLineEditingController.fromText( + 'abc\nfoo\nbar', + const CodeLineOptions(lineBreak: TextLineBreak.crlf), + ); expect(controller.text, 'abc\r\nfoo\r\nbar'); } }); @@ -269,47 +298,38 @@ void main() { test('`selectedText`', () { // Empty { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); expect(controller.selectedText, ''); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); expect(controller.selectedText, ''); controller.selection = CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 0, - start: 0, - end: 1 - ) + range: const CodeLineRange(index: 0, start: 0, end: 1), ); expect(controller.selectedText, 'a'); controller.selection = CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 0, - start: 0, - end: 3 - ) + range: const CodeLineRange(index: 0, start: 0, end: 3), ); expect(controller.selectedText, 'abc'); } // Multi code lines and LF linebreak { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); expect(controller.selectedText, ''); controller.selection = CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 1, - start: 0, - end: 1 - ) + range: const CodeLineRange(index: 1, start: 0, end: 1), ); expect(controller.selectedText, 'f'); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 1, - extentOffset: 3 + extentOffset: 3, ); expect(controller.selectedText, 'foo'); controller.selection = const CodeLineSelection( @@ -336,9 +356,11 @@ void main() { } // Multi code lines and CRLF linebreak { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar', const CodeLineOptions( - lineBreak: TextLineBreak.crlf - )); + final CodeLineEditingController controller = + CodeLineEditingController.fromText( + 'abc\nfoo\nbar', + const CodeLineOptions(lineBreak: TextLineBreak.crlf), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 0, @@ -356,28 +378,30 @@ void main() { } }); - test('`unforldLineSelection`', () { // Empty { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); expect(controller.unforldLineSelection, controller.selection); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selection = const CodeLineSelection.collapsed( - index: 0, - offset: 1 + index: 0, + offset: 1, ); expect(controller.unforldLineSelection, controller.selection); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection.collapsed( - index: 1, - offset: 1 + index: 1, + offset: 1, ); expect(controller.unforldLineSelection, controller.selection); controller.selection = const CodeLineSelection( @@ -392,15 +416,12 @@ void main() { { final CodeLineEditingController controller = CodeLineEditingController( codeLines: CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]), - ]) + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + ]), ); controller.selection = const CodeLineSelection.collapsed( - index: 0, - offset: 1 + index: 0, + offset: 1, ); expect(controller.unforldLineSelection, controller.selection); } @@ -423,7 +444,7 @@ void main() { CodeLine('456'), CodeLine('789'), ]), - ]) + ]), ); controller.selection = const CodeLineSelection( baseIndex: 1, @@ -431,12 +452,15 @@ void main() { extentIndex: 2, extentOffset: 3, ); - expect(controller.unforldLineSelection, const CodeLineSelection( - baseIndex: 4, - baseOffset: 0, - extentIndex: 8, - extentOffset: 3, - )); + expect( + controller.unforldLineSelection, + const CodeLineSelection( + baseIndex: 4, + baseOffset: 0, + extentIndex: 8, + extentOffset: 3, + ), + ); } }); }); @@ -445,140 +469,119 @@ void main() { test('`edit()`', () { // Starts with empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); // Input a letter 'a' - controller.edit(const TextEditingValue( - text: 'a', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('a') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + controller.edit( + const TextEditingValue( + text: 'a', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect(controller.codeLines, CodeLines.of(const [CodeLine('a')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); expect(controller.composing, TextRange.empty); // Replace with a letter 'b' - controller.edit(const TextEditingValue( - text: 'b', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('b') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + controller.edit( + const TextEditingValue( + text: 'b', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect(controller.codeLines, CodeLines.of(const [CodeLine('b')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); expect(controller.composing, TextRange.empty); // Replace with letters 'abc' - controller.edit(const TextEditingValue( - text: 'abc', - selection: TextSelection.collapsed( - offset: 3 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + controller.edit( + const TextEditingValue( + text: 'abc', + selection: TextSelection.collapsed(offset: 3), + ), + ); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); expect(controller.composing, TextRange.empty); // Input a letter 'd' and select letter 'd' - controller.edit(const TextEditingValue( - text: 'abcd', - selection: TextSelection( + controller.edit( + const TextEditingValue( + text: 'abcd', + selection: TextSelection(baseOffset: 3, extentOffset: 4), + ), + ); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abcd')])); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, baseOffset: 3, - extentOffset: 4 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcd') - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 3, - extentIndex: 0, - extentOffset: 4 - )); + extentIndex: 0, + extentOffset: 4, + ), + ); expect(controller.composing, TextRange.empty); // Have a composing - controller.edit(const TextEditingValue( - text: 'abca a a a a', - selection: TextSelection.collapsed( - offset: 12 + controller.edit( + const TextEditingValue( + text: 'abca a a a a', + selection: TextSelection.collapsed(offset: 12), + composing: TextRange(start: 3, end: 12), ), - composing: TextRange( - start: 3, - end: 12 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abca a a a a') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 12 - )); - expect(controller.composing, const TextRange( - start: 3, - end: 12 - )); + ); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('abca a a a a')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 12), + ); + expect(controller.composing, const TextRange(start: 3, end: 12)); } // Starts with a single line and has a selection range { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selection = CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 0, - start: 0, - end: 1 - ) + range: const CodeLineRange(index: 0, start: 0, end: 1), ); // Replace selection 'a' with a letter 'c' - controller.edit(const TextEditingValue( - text: 'cbc', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('cbc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + controller.edit( + const TextEditingValue( + text: 'cbc', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect(controller.codeLines, CodeLines.of(const [CodeLine('cbc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); expect(controller.composing, TextRange.empty); // Select all controller.selection = CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 0, - start: 0, - end: 3 - ) + range: const CodeLineRange(index: 0, start: 0, end: 3), ); // Replace selection 'cbc' with a letter 'a' - controller.edit(const TextEditingValue( - text: 'a', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('a') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + controller.edit( + const TextEditingValue( + text: 'a', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect(controller.codeLines, CodeLines.of(const [CodeLine('a')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); expect(controller.composing, TextRange.empty); } // Starts with multi lines @@ -588,118 +591,126 @@ void main() { CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), - ]) + ]), ); // Edit line index 0 controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 3 - ); - controller.edit(const TextEditingValue( - text: 'abc1', - selection: TextSelection.collapsed( - offset: 4 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc1'), - CodeLine('foo'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 4 - )); + offset: 3, + ); + controller.edit( + const TextEditingValue( + text: 'abc1', + selection: TextSelection.collapsed(offset: 4), + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc1'), + CodeLine('foo'), + CodeLine('bar'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 4), + ); expect(controller.composing, TextRange.empty); // Edit line index 1 controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 3 - ); - controller.edit(const TextEditingValue( - text: 'foo1', - selection: TextSelection.collapsed( - offset: 4 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc1'), - CodeLine('foo1'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 4 - )); - expect(controller.composing, const TextRange( - start: -1, - end: -1 - )); + offset: 3, + ); + controller.edit( + const TextEditingValue( + text: 'foo1', + selection: TextSelection.collapsed(offset: 4), + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc1'), + CodeLine('foo1'), + CodeLine('bar'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 4), + ); + expect(controller.composing, TextRange.empty); // Edit line index 2 controller.selection = const CodeLineSelection.collapsed( index: 2, - offset: 3 - ); - controller.edit(const TextEditingValue( - text: 'bar1', - selection: TextSelection.collapsed( - offset: 4 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc1'), - CodeLine('foo1'), - CodeLine('bar1'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 4 - )); + offset: 3, + ); + controller.edit( + const TextEditingValue( + text: 'bar1', + selection: TextSelection.collapsed(offset: 4), + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc1'), + CodeLine('foo1'), + CodeLine('bar1'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 4), + ); expect(controller.composing, TextRange.empty); // Edit line index 2 and select the input - controller.edit(const TextEditingValue( - text: 'bar2', - selection: TextSelection( + controller.edit( + const TextEditingValue( + text: 'bar2', + selection: TextSelection(baseOffset: 3, extentOffset: 4), + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc1'), + CodeLine('foo1'), + CodeLine('bar2'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 2, baseOffset: 3, - extentOffset: 4 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc1'), - CodeLine('foo1'), - CodeLine('bar2'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 2, - baseOffset: 3, - extentIndex: 2, - extentOffset: 4 - )); + extentIndex: 2, + extentOffset: 4, + ), + ); expect(controller.composing, TextRange.empty); // Have a composing - controller.edit(const TextEditingValue( - text: 'bara a a a a', - selection: TextSelection.collapsed( - offset: 12 + controller.edit( + const TextEditingValue( + text: 'bara a a a a', + selection: TextSelection.collapsed(offset: 12), + composing: TextRange(start: 3, end: 12), ), - composing: TextRange( - start: 3, - end: 12 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc1'), - CodeLine('foo1'), - CodeLine('bara a a a a'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 12 - )); - expect(controller.composing, const TextRange( - start: 3, - end: 12 - )); + ); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc1'), + CodeLine('foo1'), + CodeLine('bara a a a a'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 12), + ); + expect(controller.composing, const TextRange(start: 3, end: 12)); } // Starts with multi lines and has a selection range { @@ -708,53 +719,51 @@ void main() { CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), - ]) + ]), ); // Replace 'abc' with '1' controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 0, extentIndex: 0, - extentOffset: 3 - ); - controller.edit(const TextEditingValue( - text: '1', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('1'), - CodeLine('foo'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + extentOffset: 3, + ); + controller.edit( + const TextEditingValue( + text: '1', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('1'), CodeLine('foo'), CodeLine('bar')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); expect(controller.composing, TextRange.empty); // Replace 'foo' with '2' controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 1, - extentOffset: 3 - ); - controller.edit(const TextEditingValue( - text: '2', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('1'), - CodeLine('2'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 1 - )); + extentOffset: 3, + ); + controller.edit( + const TextEditingValue( + text: '2', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('1'), CodeLine('2'), CodeLine('bar')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 1), + ); expect(controller.composing, TextRange.empty); // Reset codeLines controller.codeLines = CodeLines.of(const [ @@ -767,22 +776,22 @@ void main() { baseIndex: 0, baseOffset: 0, extentIndex: 1, - extentOffset: 3 - ); - controller.edit(const TextEditingValue( - text: 'a', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('a'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + extentOffset: 3, + ); + controller.edit( + const TextEditingValue( + text: 'a', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('a'), CodeLine('bar')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); expect(controller.composing, TextRange.empty); // Reset codeLines controller.codeLines = CodeLines.of(const [ @@ -795,22 +804,20 @@ void main() { baseIndex: 0, baseOffset: 2, extentIndex: 2, - extentOffset: 1 + extentOffset: 1, ); // Input 'a' - controller.edit(const TextEditingValue( - text: 'ab1', - selection: TextSelection.collapsed( - offset: 3 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ab1ar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + controller.edit( + const TextEditingValue( + text: 'ab1', + selection: TextSelection.collapsed(offset: 3), + ), + ); + expect(controller.codeLines, CodeLines.of(const [CodeLine('ab1ar')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); expect(controller.composing, TextRange.empty); // Reset codeLines controller.codeLines = CodeLines.of(const [ @@ -823,22 +830,20 @@ void main() { baseIndex: 2, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ); // Input '1' - controller.edit(const TextEditingValue( - text: '1ar', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ab1ar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + controller.edit( + const TextEditingValue( + text: '1ar', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect(controller.codeLines, CodeLines.of(const [CodeLine('ab1ar')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); expect(controller.composing, TextRange.empty); // Reset codeLines controller.codeLines = CodeLines.of(const [ @@ -851,30 +856,22 @@ void main() { baseIndex: 0, baseOffset: 2, extentIndex: 2, - extentOffset: 1 + extentOffset: 1, ); // Input 'a' with a composing - controller.edit(const TextEditingValue( - text: 'aba ', - selection: TextSelection.collapsed( - offset: 4 + controller.edit( + const TextEditingValue( + text: 'aba ', + selection: TextSelection.collapsed(offset: 4), + composing: TextRange(start: 2, end: 4), ), - composing: TextRange( - start: 2, - end: 4 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('aba ar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 4 - )); - expect(controller.composing, const TextRange( - start: 2, - end: 4 - )); + ); + expect(controller.codeLines, CodeLines.of(const [CodeLine('aba ar')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 4), + ); + expect(controller.composing, const TextRange(start: 2, end: 4)); // Reset codeLines controller.codeLines = CodeLines.of(const [ CodeLine('abc'), @@ -886,247 +883,214 @@ void main() { baseIndex: 2, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ); // Input 'a' - controller.edit(const TextEditingValue( - text: 'a ar', - selection: TextSelection.collapsed( - offset: 2 + controller.edit( + const TextEditingValue( + text: 'a ar', + selection: TextSelection.collapsed(offset: 2), + composing: TextRange(start: 0, end: 2), ), - composing: TextRange( - start: 0, - end: 2 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('aba ar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 4 - )); - expect(controller.composing, const TextRange( - start: 2, - end: 4 - )); + ); + expect(controller.codeLines, CodeLines.of(const [CodeLine('aba ar')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 4), + ); + expect(controller.composing, const TextRange(start: 2, end: 4)); } // Starts with multi lines and has collapsed chunks { final CodeLineEditingController controller = CodeLineEditingController( codeLines: CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('123'), - CodeLine('456') - ]), + CodeLine('abc', [CodeLine('123'), CodeLine('456')]), CodeLine('foo'), CodeLine('bar'), - ]) + ]), ); // Replace 'abc' with '1' controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 0, extentIndex: 0, - extentOffset: 3 - ); - controller.edit(const TextEditingValue( - text: '1', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('1', [ - CodeLine('123'), - CodeLine('456') + extentOffset: 3, + ); + controller.edit( + const TextEditingValue( + text: '1', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('1', [CodeLine('123'), CodeLine('456')]), + CodeLine('foo'), + CodeLine('bar'), ]), - CodeLine('foo'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); expect(controller.composing, TextRange.empty); // Replace 'foo' with '2' controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 1, - extentOffset: 3 - ); - controller.edit(const TextEditingValue( - text: '2', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('1', [ - CodeLine('123'), - CodeLine('456') + extentOffset: 3, + ); + controller.edit( + const TextEditingValue( + text: '2', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('1', [CodeLine('123'), CodeLine('456')]), + CodeLine('2'), + CodeLine('bar'), ]), - CodeLine('2'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 1 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 1), + ); expect(controller.composing, TextRange.empty); // Select line '1' and '2' and replace with '3' controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 0, extentIndex: 1, - extentOffset: 1 - ); - controller.edit(const TextEditingValue( - text: '3', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('3'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + extentOffset: 1, + ); + controller.edit( + const TextEditingValue( + text: '3', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('3'), CodeLine('bar')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); expect(controller.composing, TextRange.empty); // Reset code lines controller.value = CodeLineEditingValue( codeLines: CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('123'), - CodeLine('456') - ]), + CodeLine('abc', [CodeLine('123'), CodeLine('456')]), CodeLine('foo'), CodeLine('bar'), - ]) + ]), ); // Select three line, and base before extent controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, extentIndex: 2, - extentOffset: 1 - ); - controller.edit(const TextEditingValue( - text: 'ab1', - selection: TextSelection.collapsed( - offset: 3 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ab1ar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + extentOffset: 1, + ); + controller.edit( + const TextEditingValue( + text: 'ab1', + selection: TextSelection.collapsed(offset: 3), + ), + ); + expect(controller.codeLines, CodeLines.of(const [CodeLine('ab1ar')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); expect(controller.composing, TextRange.empty); // Reset code lines controller.value = CodeLineEditingValue( codeLines: CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('123'), - CodeLine('456') - ]), + CodeLine('abc', [CodeLine('123'), CodeLine('456')]), CodeLine('foo'), CodeLine('bar'), - ]) + ]), ); // Select three line, and extent before base controller.selection = const CodeLineSelection( baseIndex: 2, baseOffset: 1, extentIndex: 0, - extentOffset: 2 - ); - controller.edit(const TextEditingValue( - text: '1ar', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ab1ar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + extentOffset: 2, + ); + controller.edit( + const TextEditingValue( + text: '1ar', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect(controller.codeLines, CodeLines.of(const [CodeLine('ab1ar')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); expect(controller.composing, TextRange.empty); // Test more chunks controller.value = CodeLineEditingValue( codeLines: CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('123'), - CodeLine('123') - ]), - CodeLine('foo', [ - CodeLine('456'), - CodeLine('456') - ]), - CodeLine('bar', [ - CodeLine('789'), - CodeLine('789') - ]), - ]) + CodeLine('abc', [CodeLine('123'), CodeLine('123')]), + CodeLine('foo', [CodeLine('456'), CodeLine('456')]), + CodeLine('bar', [CodeLine('789'), CodeLine('789')]), + ]), ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, extentIndex: 1, - extentOffset: 1 - ); - controller.edit(const TextEditingValue( - text: 'ab1', - selection: TextSelection.collapsed( - offset: 3 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ab1oo', [ - CodeLine('456'), - CodeLine('456') - ]), - CodeLine('bar', [ - CodeLine('789'), - CodeLine('789') + extentOffset: 1, + ); + controller.edit( + const TextEditingValue( + text: 'ab1', + selection: TextSelection.collapsed(offset: 3), + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('ab1oo', [CodeLine('456'), CodeLine('456')]), + CodeLine('bar', [CodeLine('789'), CodeLine('789')]), ]), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); expect(controller.composing, TextRange.empty); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 1, extentIndex: 0, - extentOffset: 1 - ); - controller.edit(const TextEditingValue( - text: '2ar', - selection: TextSelection.collapsed( - offset: 1 - ) - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('a2ar', [ - CodeLine('789'), - CodeLine('789') + extentOffset: 1, + ); + controller.edit( + const TextEditingValue( + text: '2ar', + selection: TextSelection.collapsed(offset: 1), + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('a2ar', [CodeLine('789'), CodeLine('789')]), ]), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); expect(controller.composing, TextRange.empty); } }); @@ -1134,47 +1098,46 @@ void main() { test('`selectLine()`', () { // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selectLine(0); - expect(controller.selection, CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 0, - start: 0, - end: 3 - ) - )); + expect( + controller.selection, + CodeLineSelection.fromRange( + range: const CodeLineRange(index: 0, start: 0, end: 3), + ), + ); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selectLine(0); - expect(controller.selection, CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 0, - start: 0, - end: 3 - ) - )); + expect( + controller.selection, + CodeLineSelection.fromRange( + range: const CodeLineRange(index: 0, start: 0, end: 3), + ), + ); controller.selectLine(1); - expect(controller.selection, CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 1, - start: 0, - end: 3 - ) - )); + expect( + controller.selection, + CodeLineSelection.fromRange( + range: const CodeLineRange(index: 1, start: 0, end: 3), + ), + ); controller.selectLine(2); - expect(controller.selection, CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 2, - start: 0, - end: 3 - ) - )); + expect( + controller.selection, + CodeLineSelection.fromRange( + range: const CodeLineRange(index: 2, start: 0, end: 3), + ), + ); } // Out of range { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selectLine(-1); expect(controller.selection, const CodeLineSelection.zero()); controller.selectLine(3); @@ -1184,653 +1147,724 @@ void main() { test('`selectLines()`', () { { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selectLines(0, 1); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 1, - extentOffset: 3 - )); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 1, + extentOffset: 3, + ), + ); controller.selectLines(1, 0); - expect(controller.selection, const CodeLineSelection( - baseIndex: 1, - baseOffset: 3, - extentIndex: 0, - extentOffset: 0 - )); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 1, + baseOffset: 3, + extentIndex: 0, + extentOffset: 0, + ), + ); // Out of range controller.selectLines(0, 3); - expect(controller.selection, const CodeLineSelection( - baseIndex: 1, - baseOffset: 3, - extentIndex: 0, - extentOffset: 0 - )); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 1, + baseOffset: 3, + extentIndex: 0, + extentOffset: 0, + ), + ); } }); test('`selectAll()`', () { { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.selectAll(); expect(controller.selection, const CodeLineSelection.zero()); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selectAll(); - expect(controller.selection, CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 0, - start: 0, - end: 3 - ) - )); + expect( + controller.selection, + CodeLineSelection.fromRange( + range: const CodeLineRange(index: 0, start: 0, end: 3), + ), + ); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selectAll(); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 2, - extentOffset: 3 - )); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 2, + extentOffset: 3, + ), + ); } }); test('`cancelSelection()`', () { { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.cancelSelection(); expect(controller.selection, const CodeLineSelection.zero()); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selectAll(); controller.cancelSelection(); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3, - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ); controller.cancelSelection(); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, extentIndex: 0, - extentOffset: 1 + extentOffset: 1, ); controller.cancelSelection(); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1, - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selectAll(); controller.cancelSelection(); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 3, - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 3), + ); } }); test('`moveSelectionLinesUp()`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.moveSelectionLinesUp(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.moveSelectionLinesUp(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc') - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abc')])); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 0 + offset: 0, ); controller.moveSelectionLinesUp(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('foo'), - CodeLine('abc'), - CodeLine('bar'), - ])); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('foo'), + CodeLine('abc'), + CodeLine('bar'), + ]), + ); controller.selection = const CodeLineSelection.collapsed( index: 2, - offset: 0 + offset: 0, ); controller.moveSelectionLinesUp(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('foo'), - CodeLine('bar'), - CodeLine('abc'), - ])); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('foo'), + CodeLine('bar'), + CodeLine('abc'), + ]), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 1, extentIndex: 2, - extentOffset: 1 + extentOffset: 1, ); controller.moveSelectionLinesUp(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('bar'), - CodeLine('abc'), - CodeLine('foo'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 1, - extentOffset: 1 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('bar'), + CodeLine('abc'), + CodeLine('foo'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 1, + extentOffset: 1, + ), + ); controller.selection = const CodeLineSelection( baseIndex: 2, baseOffset: 2, extentIndex: 1, - extentOffset: 1 + extentOffset: 1, ); controller.moveSelectionLinesUp(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 1, - baseOffset: 2, - extentIndex: 0, - extentOffset: 1 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc'), + CodeLine('foo'), + CodeLine('bar'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 1, + baseOffset: 2, + extentIndex: 0, + extentOffset: 1, + ), + ); } }); test('`moveSelectionLinesDown()`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.moveSelectionLinesDown(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.moveSelectionLinesDown(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc') - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abc')])); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.moveSelectionLinesDown(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('foo'), - CodeLine('abc'), - CodeLine('bar'), - ])); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('foo'), + CodeLine('abc'), + CodeLine('bar'), + ]), + ); controller.selection = const CodeLineSelection.collapsed( index: 2, - offset: 0 + offset: 0, ); controller.moveSelectionLinesDown(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('foo'), - CodeLine('abc'), - CodeLine('bar'), - ])); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('foo'), + CodeLine('abc'), + CodeLine('bar'), + ]), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 1, - extentOffset: 1 + extentOffset: 1, ); controller.moveSelectionLinesDown(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('bar'), - CodeLine('foo'), - CodeLine('abc'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 2, - extentOffset: 1 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('bar'), + CodeLine('foo'), + CodeLine('abc'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 2, + extentOffset: 1, + ), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 2, extentIndex: 0, - extentOffset: 1 + extentOffset: 1, ); controller.moveSelectionLinesDown(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('bar'), - CodeLine('foo'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 2, - baseOffset: 2, - extentIndex: 1, - extentOffset: 1 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc'), + CodeLine('bar'), + CodeLine('foo'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 2, + baseOffset: 2, + extentIndex: 1, + extentOffset: 1, + ), + ); } }); test('`moveCursor(left)`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.moveCursor(AxisDirection.left); expect(controller.selection, const CodeLineSelection.zero()); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 1 + offset: 1, ); controller.moveCursor(AxisDirection.left); expect(controller.selection, const CodeLineSelection.zero()); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 2 + offset: 2, ); controller.moveCursor(AxisDirection.left); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ); controller.moveCursor(AxisDirection.left); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, extentIndex: 0, - extentOffset: 1 + extentOffset: 1, ); controller.moveCursor(AxisDirection.left); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\bar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\bar'); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 1 + offset: 1, ); controller.moveCursor(AxisDirection.left); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); controller.moveCursor(AxisDirection.left); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 1, extentIndex: 1, - extentOffset: 2 + extentOffset: 2, ); controller.moveCursor(AxisDirection.left); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 1, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 1), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, extentIndex: 1, - extentOffset: 1 + extentOffset: 1, ); controller.moveCursor(AxisDirection.left); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ); controller.moveCursor(AxisDirection.left); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); } // Affinity change { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selection = const CodeLineSelection.collapsed( index: 0, offset: 2, - affinity: TextAffinity.upstream + affinity: TextAffinity.upstream, ); controller.moveCursor(AxisDirection.left); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, - baseAffinity: TextAffinity.downstream, extentIndex: 0, extentOffset: 2, extentAffinity: TextAffinity.upstream, ); controller.moveCursor(AxisDirection.left); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - affinity: TextAffinity.upstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed( + index: 0, + offset: 2, + affinity: TextAffinity.upstream, + ), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, baseAffinity: TextAffinity.upstream, extentIndex: 0, extentOffset: 2, - extentAffinity: TextAffinity.downstream, ); controller.moveCursor(AxisDirection.left); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - affinity: TextAffinity.upstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed( + index: 0, + offset: 2, + affinity: TextAffinity.upstream, + ), + ); } - }); test('`moveCursor(right)`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.moveCursor(AxisDirection.right); expect(controller.selection, const CodeLineSelection.zero()); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 0 + offset: 0, ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1, - affinity: TextAffinity.upstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed( + index: 0, + offset: 1, + affinity: TextAffinity.upstream, + ), + ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - affinity: TextAffinity.upstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed( + index: 0, + offset: 2, + affinity: TextAffinity.upstream, + ), + ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3, - affinity: TextAffinity.upstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed( + index: 0, + offset: 3, + affinity: TextAffinity.upstream, + ), + ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3, - affinity: TextAffinity.upstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed( + index: 0, + offset: 3, + affinity: TextAffinity.upstream, + ), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, extentIndex: 0, - extentOffset: 1 + extentOffset: 1, ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nar'); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 1 + offset: 1, ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 2, - affinity: TextAffinity.upstream - )); - controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 3, - affinity: TextAffinity.upstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed( + index: 1, + offset: 2, + affinity: TextAffinity.upstream, + ), + ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 0, - affinity: TextAffinity.upstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed( + index: 1, + offset: 3, + affinity: TextAffinity.upstream, + ), + ); + controller.moveCursor(AxisDirection.right); + expect( + controller.selection, + const CodeLineSelection.collapsed( + index: 2, + offset: 0, + affinity: TextAffinity.upstream, + ), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 1, extentIndex: 1, - extentOffset: 2 + extentOffset: 2, ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 2, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 2), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, extentIndex: 1, - extentOffset: 1 + extentOffset: 1, ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 1, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 1), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 1, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 1), + ); } // Affinity change { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selection = const CodeLineSelection.collapsed( index: 0, offset: 2, - affinity: TextAffinity.downstream ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3, - affinity: TextAffinity.upstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed( + index: 0, + offset: 3, + affinity: TextAffinity.upstream, + ), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, - baseAffinity: TextAffinity.downstream, extentIndex: 0, extentOffset: 2, extentAffinity: TextAffinity.upstream, ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, baseAffinity: TextAffinity.upstream, extentIndex: 0, extentOffset: 2, - extentAffinity: TextAffinity.downstream, ); controller.moveCursor(AxisDirection.right); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - affinity: TextAffinity.downstream - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); } }); test('`moveCursor(up)`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.moveCursor(AxisDirection.up); expect(controller.selection, const CodeLineSelection.zero()); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 1 + offset: 1, ); controller.moveCursor(AxisDirection.up); expect(controller.selection, const CodeLineSelection.zero()); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoofoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoofoo\nbar'); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 1 + offset: 1, ); controller.moveCursor(AxisDirection.up); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); controller.moveCursor(AxisDirection.up); expect(controller.selection, const CodeLineSelection.zero()); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 6 + offset: 6, ); controller.moveCursor(AxisDirection.up); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 1, extentIndex: 1, - extentOffset: 2 + extentOffset: 2, ); controller.moveCursor(AxisDirection.up); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); controller.selection = const CodeLineSelection( baseIndex: 2, baseOffset: 1, extentIndex: 1, - extentOffset: 1 + extentOffset: 1, ); controller.moveCursor(AxisDirection.up); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 1, - extentOffset: 1 + extentOffset: 1, ); controller.moveCursor(AxisDirection.up); expect(controller.selection, const CodeLineSelection.zero()); @@ -1840,1290 +1874,1212 @@ void main() { test('`moveCursor(down)`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.moveCursor(AxisDirection.down); expect(controller.selection, const CodeLineSelection.zero()); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 1 + offset: 1, ); controller.moveCursor(AxisDirection.down); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoofoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoofoo\nbar'); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 2 + offset: 2, ); controller.moveCursor(AxisDirection.down); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 2 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 2), + ); controller.moveCursor(AxisDirection.down); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 3 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 3), + ); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 6 + offset: 6, ); controller.moveCursor(AxisDirection.down); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 3 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 3), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 1, extentIndex: 1, - extentOffset: 2 + extentOffset: 2, ); controller.moveCursor(AxisDirection.down); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 2 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 2), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 2, extentIndex: 1, - extentOffset: 1 + extentOffset: 1, ); controller.moveCursor(AxisDirection.down); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 2 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 2), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 2, extentIndex: 2, - extentOffset: 1 + extentOffset: 1, ); controller.moveCursor(AxisDirection.down); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 3 - )); - } - }); - - test('`moveCursorToLineStart() & moveCursorToLineEnd() & moveCursorToPageStart() & moveCursorToPageEnd()`', () { - // Empty content - { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); - controller.moveCursorToLineStart(); - expect(controller.selection, const CodeLineSelection.zero()); - controller.moveCursorToLineEnd(); - expect(controller.selection, const CodeLineSelection.zero()); - controller.moveCursorToPageStart(); - expect(controller.selection, const CodeLineSelection.zero()); - controller.moveCursorToPageEnd(); - expect(controller.selection, const CodeLineSelection.zero()); - } - // Single code line - { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); - controller.moveCursorToLineEnd(); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); - controller.moveCursorToLineStart(); - expect(controller.selection, const CodeLineSelection.zero()); - controller.moveCursorToPageEnd(); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); - controller.moveCursorToPageStart(); - expect(controller.selection, const CodeLineSelection.zero()); - } - // Multi code lines - { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); - controller.selection = const CodeLineSelection.collapsed( - index: 1, - offset: 1 + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 3), ); - controller.moveCursorToLineEnd(); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 3 - )); - controller.moveCursorToLineStart(); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0 - )); - controller.moveCursorToPageEnd(); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 3 - )); - controller.moveCursorToPageStart(); - expect(controller.selection, const CodeLineSelection.zero()); } }); + test( + '`moveCursorToLineStart() & moveCursorToLineEnd() & moveCursorToPageStart() & moveCursorToPageEnd()`', + () { + // Empty content + { + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); + controller.moveCursorToLineStart(); + expect(controller.selection, const CodeLineSelection.zero()); + controller.moveCursorToLineEnd(); + expect(controller.selection, const CodeLineSelection.zero()); + controller.moveCursorToPageStart(); + expect(controller.selection, const CodeLineSelection.zero()); + controller.moveCursorToPageEnd(); + expect(controller.selection, const CodeLineSelection.zero()); + } + // Single code line + { + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); + controller.moveCursorToLineEnd(); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); + controller.moveCursorToLineStart(); + expect(controller.selection, const CodeLineSelection.zero()); + controller.moveCursorToPageEnd(); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); + controller.moveCursorToPageStart(); + expect(controller.selection, const CodeLineSelection.zero()); + } + // Multi code lines + { + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); + controller.selection = const CodeLineSelection.collapsed( + index: 1, + offset: 1, + ); + controller.moveCursorToLineEnd(); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 3), + ); + controller.moveCursorToLineStart(); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); + controller.moveCursorToPageEnd(); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 3), + ); + controller.moveCursorToPageStart(); + expect(controller.selection, const CodeLineSelection.zero()); + } + }, + ); + test('`deleteSelectionLines()`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.deleteSelectionLines(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.deleteSelectionLines(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.deleteSelectionLines(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('foo'), - CodeLine('bar'), - ])); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('foo'), CodeLine('bar')]), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 0, extentIndex: 1, - extentOffset: 0 + extentOffset: 0, ); controller.deleteSelectionLines(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); controller.deleteSelectionLines(); } // Multi code lines, keep extent offset { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 1 + offset: 1, ); controller.deleteSelectionLines(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('foo'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('foo'), CodeLine('bar')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); } // Multi code lines, failed to keep extent offset { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo123\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo123\nbar'); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 0, extentIndex: 1, - extentOffset: 6 + extentOffset: 6, ); controller.deleteSelectionLines(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine('bar')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); } }); test('`deleteSelection()`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.deleteSelection(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.deleteSelection(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc') - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abc')])); expect(controller.selection, const CodeLineSelection.zero()); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ); controller.deleteSelection(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ac') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine('ac')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 1, extentIndex: 1, - extentOffset: 2 + extentOffset: 2, ); controller.deleteSelection(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('fo'), - CodeLine('bar') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 1 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc'), + CodeLine('fo'), + CodeLine('bar'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 1), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 1, - extentOffset: 1 + extentOffset: 1, ); controller.deleteSelection(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ao'), - CodeLine('bar') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('ao'), CodeLine('bar')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); controller.selectAll(); controller.deleteSelection(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); expect(controller.selection, const CodeLineSelection.zero()); } // Multi code lines (have chunks) { - final CodeLineEditingController controller = CodeLineEditingController(); + final CodeLineEditingController controller = + CodeLineEditingController(); controller.codeLines = CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('123') - ]), - CodeLine('foo', [ - CodeLine('456') - ]), - CodeLine('bar', [ - CodeLine('789') - ]) + CodeLine('abc', [CodeLine('123')]), + CodeLine('foo', [CodeLine('456')]), + CodeLine('bar', [CodeLine('789')]), ]); controller.deleteSelection(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('123') - ]), - CodeLine('foo', [ - CodeLine('456') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc', [CodeLine('123')]), + CodeLine('foo', [CodeLine('456')]), + CodeLine('bar', [CodeLine('789')]), ]), - CodeLine('bar', [ - CodeLine('789') - ]) - ])); + ); expect(controller.selection, const CodeLineSelection.zero()); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ); controller.deleteSelection(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ac', [ - CodeLine('123') - ]), - CodeLine('foo', [ - CodeLine('456') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('ac', [CodeLine('123')]), + CodeLine('foo', [CodeLine('456')]), + CodeLine('bar', [CodeLine('789')]), ]), - CodeLine('bar', [ - CodeLine('789') - ]) - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 1, extentIndex: 2, - extentOffset: 1 + extentOffset: 1, ); controller.deleteSelection(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ac', [ - CodeLine('123') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('ac', [CodeLine('123')]), + CodeLine('far', [CodeLine('789')]), ]), - CodeLine('far', [ - CodeLine('789') - ]) - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 1 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 1), + ); } }); test('`deleteBackward()`', () { - // Empty content + // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.deleteBackward(); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 3 + offset: 3, ); controller.deleteBackward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ab') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine('ab')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); controller.deleteBackward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('a') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine('a')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); controller.deleteBackward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); expect(controller.selection, const CodeLineSelection.zero()); controller.deleteBackward(); // Rest code lines - controller.codeLines = CodeLines.of(const [ - CodeLine('abc{}') - ]); + controller.codeLines = CodeLines.of(const [CodeLine('abc{}')]); // Delete the {} at same time controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 4 + offset: 4, ); controller.deleteBackward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); // Rest code lines controller.codeLines = CodeLines.of([ - CodeLine('${controller.options.indent}${controller.options.indent}abc') + CodeLine( + '${controller.options.indent}${controller.options.indent}abc', + ), ]); // Delete an indent controller.selection = CodeLineSelection.collapsed( index: 0, - offset: controller.options.indentSize + offset: controller.options.indentSize, ); controller.deleteBackward(); - expect(controller.codeLines, CodeLines.of([ - CodeLine('${controller.options.indent}abc') - ])); + expect( + controller.codeLines, + CodeLines.of([CodeLine('${controller.options.indent}abc')]), + ); expect(controller.selection, const CodeLineSelection.zero()); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 0 + offset: 0, ); controller.deleteBackward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcfoo'), - CodeLine('bar') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('abcfoo'), CodeLine('bar')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); } // Multi code lines (have chunks) { - final CodeLineEditingController controller = CodeLineEditingController(); + final CodeLineEditingController controller = + CodeLineEditingController(); controller.codeLines = CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('123') - ]), - CodeLine('foo', [ - CodeLine('456') - ]), - CodeLine('bar', [ - CodeLine('789') - ]) + CodeLine('abc', [CodeLine('123')]), + CodeLine('foo', [CodeLine('456')]), + CodeLine('bar', [CodeLine('789')]), ]); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 3 + offset: 3, ); controller.deleteBackward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ab', [ - CodeLine('123') - ]), - CodeLine('foo', [ - CodeLine('456') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('ab', [CodeLine('123')]), + CodeLine('foo', [CodeLine('456')]), + CodeLine('bar', [CodeLine('789')]), ]), - CodeLine('bar', [ - CodeLine('789') - ]) - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 0 + offset: 0, ); controller.deleteBackward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ab'), - CodeLine('123foo', [ - CodeLine('456') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('ab'), + CodeLine('123foo', [CodeLine('456')]), + CodeLine('bar', [CodeLine('789')]), ]), - CodeLine('bar', [ - CodeLine('789') - ]) - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 3 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 3), + ); } // Multi code lines (have nested chunks) { - final CodeLineEditingController controller = CodeLineEditingController(); + final CodeLineEditingController controller = + CodeLineEditingController(); controller.codeLines = CodeLines.of(const [ CodeLine('abc', [ - CodeLine('{', [ - CodeLine('123') - ]), - CodeLine('}') + CodeLine('{', [CodeLine('123')]), + CodeLine('}'), ]), CodeLine('foo', [ - CodeLine('{', [ - CodeLine('456') - ]), - CodeLine('}') + CodeLine('{', [CodeLine('456')]), + CodeLine('}'), ]), CodeLine('bar', [ - CodeLine('{', [ - CodeLine('789') - ]), - CodeLine('}') - ]) + CodeLine('{', [CodeLine('789')]), + CodeLine('}'), + ]), ]); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 0 + offset: 0, ); controller.deleteBackward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('{', [ - CodeLine('123') - ]), - CodeLine('}foo', [ - CodeLine('{', [ - CodeLine('456') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc'), + CodeLine('{', [CodeLine('123')]), + CodeLine('}foo', [ + CodeLine('{', [CodeLine('456')]), + CodeLine('}'), ]), - CodeLine('}') - ]), - CodeLine('bar', [ - CodeLine('{', [ - CodeLine('789') + CodeLine('bar', [ + CodeLine('{', [CodeLine('789')]), + CodeLine('}'), ]), - CodeLine('}') - ]) - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 1 - )); + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 1), + ); controller.deleteBackward(); controller.deleteBackward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('{'), - CodeLine('123foo', [ - CodeLine('{', [ - CodeLine('456') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc'), + CodeLine('{'), + CodeLine('123foo', [ + CodeLine('{', [CodeLine('456')]), + CodeLine('}'), ]), - CodeLine('}') - ]), - CodeLine('bar', [ - CodeLine('{', [ - CodeLine('789') + CodeLine('bar', [ + CodeLine('{', [CodeLine('789')]), + CodeLine('}'), ]), - CodeLine('}') - ]) - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 3 - )); + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 3), + ); } }); test('`deleteForward()`', () { - // Empty content + // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.deleteForward(); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 3 + offset: 3, ); controller.deleteForward(); controller.selection = const CodeLineSelection.zero(); controller.deleteForward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('bc') - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine('bc')])); expect(controller.selection, const CodeLineSelection.zero()); controller.deleteForward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('c') - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine('c')])); expect(controller.selection, const CodeLineSelection.zero()); controller.deleteForward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); expect(controller.selection, const CodeLineSelection.zero()); controller.deleteForward(); // Rest code lines - controller.codeLines = CodeLines.of(const [ - CodeLine('abc{}') - ]); + controller.codeLines = CodeLines.of(const [CodeLine('abc{}')]); // Delete the {} at same time controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 4 + offset: 4, ); controller.deleteForward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); // Rest code lines controller.codeLines = CodeLines.of([ - CodeLine('${controller.options.indent}${controller.options.indent}abc') + CodeLine( + '${controller.options.indent}${controller.options.indent}abc', + ), ]); // Delete an indent controller.selection = CodeLineSelection.collapsed( index: 0, - offset: controller.options.indentSize + offset: controller.options.indentSize, ); controller.deleteForward(); - expect(controller.codeLines, CodeLines.of([ - CodeLine('${controller.options.indent}abc') - ])); - expect(controller.selection, CodeLineSelection.collapsed( - index: 0, - offset: controller.options.indentSize - )); + expect( + controller.codeLines, + CodeLines.of([CodeLine('${controller.options.indent}abc')]), + ); + expect( + controller.selection, + CodeLineSelection.collapsed( + index: 0, + offset: controller.options.indentSize, + ), + ); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 3 + offset: 3, ); controller.deleteForward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcfoo'), - CodeLine('bar') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('abcfoo'), CodeLine('bar')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 0 + offset: 0, ); controller.deleteForward(); controller.deleteForward(); controller.deleteForward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcfoo'), - CodeLine.empty - ])); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('abcfoo'), CodeLine.empty]), + ); controller.deleteForward(); } // Multi code lines (have chunks) { - final CodeLineEditingController controller = CodeLineEditingController(); + final CodeLineEditingController controller = + CodeLineEditingController(); controller.codeLines = CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('123') - ]), - CodeLine('foo', [ - CodeLine('456') - ]), - CodeLine('bar', [ - CodeLine('789') - ]) + CodeLine('abc', [CodeLine('123')]), + CodeLine('foo', [CodeLine('456')]), + CodeLine('bar', [CodeLine('789')]), ]); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 2 + offset: 2, ); controller.deleteForward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ab', [ - CodeLine('123') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('ab', [CodeLine('123')]), + CodeLine('foo', [CodeLine('456')]), + CodeLine('bar', [CodeLine('789')]), ]), - CodeLine('foo', [ - CodeLine('456') - ]), - CodeLine('bar', [ - CodeLine('789') - ]) - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); controller.deleteForward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ab123'), - CodeLine('foo', [ - CodeLine('456') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('ab123'), + CodeLine('foo', [CodeLine('456')]), + CodeLine('bar', [CodeLine('789')]), ]), - CodeLine('bar', [ - CodeLine('789') - ]) - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); } // Multi code lines (have nested chunks) { - final CodeLineEditingController controller = CodeLineEditingController(); + final CodeLineEditingController controller = + CodeLineEditingController(); controller.codeLines = CodeLines.of(const [ CodeLine('abc', [ - CodeLine('{', [ - CodeLine('123') - ]), - CodeLine('}') + CodeLine('{', [CodeLine('123')]), + CodeLine('}'), ]), CodeLine('foo', [ - CodeLine('{', [ - CodeLine('456') - ]), - CodeLine('}') + CodeLine('{', [CodeLine('456')]), + CodeLine('}'), ]), CodeLine('bar', [ - CodeLine('{', [ - CodeLine('789') - ]), - CodeLine('}') - ]) + CodeLine('{', [CodeLine('789')]), + CodeLine('}'), + ]), ]); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 3 + offset: 3, ); controller.deleteForward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc{', [ - CodeLine('123') - ]), - CodeLine('}'), - CodeLine('foo', [ - CodeLine('{', [ - CodeLine('456') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc{', [CodeLine('123')]), + CodeLine('}'), + CodeLine('foo', [ + CodeLine('{', [CodeLine('456')]), + CodeLine('}'), ]), - CodeLine('}') - ]), - CodeLine('bar', [ - CodeLine('{', [ - CodeLine('789') + CodeLine('bar', [ + CodeLine('{', [CodeLine('789')]), + CodeLine('}'), ]), - CodeLine('}') - ]) - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); controller.deleteForward(); controller.deleteForward(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc123'), - CodeLine('}'), - CodeLine('foo', [ - CodeLine('{', [ - CodeLine('456') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc123'), + CodeLine('}'), + CodeLine('foo', [ + CodeLine('{', [CodeLine('456')]), + CodeLine('}'), ]), - CodeLine('}') - ]), - CodeLine('bar', [ - CodeLine('{', [ - CodeLine('789') + CodeLine('bar', [ + CodeLine('{', [CodeLine('789')]), + CodeLine('}'), ]), - CodeLine('}') - ]) - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); } }); test('`applyNewLine()`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty, - CodeLine.empty - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine.empty, CodeLine.empty]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); controller.applyNewLine(); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 0 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 0), + ); } // Single code line, cursor at begin { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty, - CodeLine('abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine.empty, CodeLine('abc')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); } // Single code line, cursor at end { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 3 + offset: 3, ); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine.empty, - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('abc'), CodeLine.empty]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); } // Single code line, has a selection { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('a'), - CodeLine('c'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('a'), CodeLine('c')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); } // Single code line, all have selected { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.selectAll(); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty, - CodeLine.empty, - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine.empty, CodeLine.empty]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); } // Multi code lines, select lines 0 - 1 { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, extentIndex: 1, - extentOffset: 2 + extentOffset: 2, ); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ab'), - CodeLine('o'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('ab'), CodeLine('o'), CodeLine('bar')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); } // Multi code lines, have a chunk { final CodeLineEditingController controller = CodeLineEditingController( codeLines: CodeLines.of(const [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('}') - ]) + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), + ]), ); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty, - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine.empty, + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), ]), - CodeLine('}') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); } // Multi code lines, have a few of chunks { final CodeLineEditingController controller = CodeLineEditingController( codeLines: CodeLines.of(const [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), CodeLine('}'), - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), CodeLine('}'), - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('}') - ]) + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), + ]), ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 4, - extentOffset: 1 + extentOffset: 1, ); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine('', [ - CodeLine('foo'), - CodeLine('bar'), + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine('', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), ]), - CodeLine('}') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); } // Test auto indent { - final CodeLineEditingController controller = CodeLineEditingController.fromText(' abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(' abc'); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 5 + offset: 5, ); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' abc'), - CodeLine(' ') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 2 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine(' abc'), CodeLine(' ')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 2), + ); } // Test auto indent in closure { - final CodeLineEditingController controller = CodeLineEditingController.fromText('{}'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('{}'); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 1 + offset: 1, ); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(' '), - CodeLine('}') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 2 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('{'), CodeLine(' '), CodeLine('}')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 2), + ); } // Test auto indent size in closure { - final CodeLineEditingController controller = CodeLineEditingController.fromText('{}', - const CodeLineOptions( - indentSize: 6 - ) - ); + final CodeLineEditingController controller = + CodeLineEditingController.fromText( + '{}', + const CodeLineOptions(indentSize: 6), + ); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 1 + offset: 1, ); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('{'), - CodeLine(' '), - CodeLine('}') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 6 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('{'), + CodeLine(' '), + CodeLine('}'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 6), + ); } // Test indent align { - final CodeLineEditingController controller = CodeLineEditingController.fromText(' {}'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(' {}'); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 3 + offset: 3, ); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' {'), - CodeLine(' '), - CodeLine(' }') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 4 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine(' {'), + CodeLine(' '), + CodeLine(' }'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 4), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 3, extentIndex: 2, - extentOffset: 2 + extentOffset: 2, ); controller.applyNewLine(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' {'), - CodeLine(' '), - CodeLine(' }') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 4 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine(' {'), + CodeLine(' '), + CodeLine(' }'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 4), + ); } }); test('`applyIndent()`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - CodeLine(controller.options.indent) - ])); - expect(controller.selection, CodeLineSelection.collapsed( - index: 0, - offset: controller.options.indentSize - )); + expect( + controller.codeLines, + CodeLines.of([CodeLine(controller.options.indent)]), + ); + expect( + controller.selection, + CodeLineSelection.collapsed( + index: 0, + offset: controller.options.indentSize, + ), + ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - CodeLine(controller.options.indent * 2) - ])); - expect(controller.selection, CodeLineSelection.collapsed( - index: 0, - offset: controller.options.indentSize * 2 - )); + expect( + controller.codeLines, + CodeLines.of([CodeLine(controller.options.indent * 2)]), + ); + expect( + controller.selection, + CodeLineSelection.collapsed( + index: 0, + offset: controller.options.indentSize * 2, + ), + ); } // Single code line { // Assign indent size is 2 - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc', - const CodeLineOptions( - indentSize: 2 - ) - ); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); // cursor at begin controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine(' abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + expect(controller.codeLines, CodeLines.of([const CodeLine(' abc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); // cursor at end controller.selection = CodeLineSelection.collapsed( index: 0, - offset: controller.codeLines.first.length + offset: controller.codeLines.first.length, ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine(' abc ') - ])); - expect(controller.selection, CodeLineSelection.collapsed( - index: 0, - offset: controller.codeLines.first.length - )); + expect(controller.codeLines, CodeLines.of([const CodeLine(' abc ')])); + expect( + controller.selection, + CodeLineSelection.collapsed( + index: 0, + offset: controller.codeLines.first.length, + ), + ); // cursor at mid (after 'a') controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 3 + offset: 3, ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine(' a bc ') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 4 - )); + expect(controller.codeLines, CodeLines.of([const CodeLine(' a bc ')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 4), + ); // Reset code lines, and select 'a' - controller.codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + controller.codeLines = CodeLines.of(const [CodeLine('abc')]); controller.selection = CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 0, - start: 0, - end: 1 - ) + range: const CodeLineRange(index: 0, start: 0, end: 1), ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine(' bc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + expect(controller.codeLines, CodeLines.of([const CodeLine(' bc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); // Reset code lines, and select 'b' - controller.codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + controller.codeLines = CodeLines.of(const [CodeLine('abc')]); controller.selection = CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 0, - start: 1, - end: 2 - ) + range: const CodeLineRange(index: 0, start: 1, end: 2), ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine('a c') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + expect(controller.codeLines, CodeLines.of([const CodeLine('a c')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); // Reset code lines, and select 'c' - controller.codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + controller.codeLines = CodeLines.of(const [CodeLine('abc')]); controller.selection = CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 0, - start: 2, - end: 3 - ) + range: const CodeLineRange(index: 0, start: 2, end: 3), ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine('ab ') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 4 - )); + expect(controller.codeLines, CodeLines.of([const CodeLine('ab ')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 4), + ); // Reset code lines, and select all - controller.codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + controller.codeLines = CodeLines.of(const [CodeLine('abc')]); controller.selectAll(); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' abc') - ])); - expect(controller.selection, CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 0, - start: 0, - end: 5 - ) - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine(' abc')])); + expect( + controller.selection, + CodeLineSelection.fromRange( + range: const CodeLineRange(index: 0, start: 0, end: 5), + ), + ); // Reset code lines, with a whitespace as prefix and selection offset is at 0 - controller.codeLines = CodeLines.of(const [ - CodeLine(' abc') - ]); + controller.codeLines = CodeLines.of(const [CodeLine(' abc')]); controller.selection = const CodeLineSelection.zero(); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine(' abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - )); + expect(controller.codeLines, CodeLines.of([const CodeLine(' abc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); // Reset code lines, with a whitespace as prefix and selection offset is at 1 - controller.codeLines = CodeLines.of(const [ - CodeLine(' abc') - ]); + controller.codeLines = CodeLines.of(const [CodeLine(' abc')]); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 1 + offset: 1, ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine(' abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - )); + expect(controller.codeLines, CodeLines.of([const CodeLine(' abc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); // Reset code lines, with a whitespace as prefix and selected - controller.codeLines = CodeLines.of(const [ - CodeLine(' abc') - ]); + controller.codeLines = CodeLines.of(const [CodeLine(' abc')]); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 0, extentIndex: 0, - extentOffset: 1 + extentOffset: 1, ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine(' abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2, - )); + expect(controller.codeLines, CodeLines.of([const CodeLine(' abc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); // Reset code lines, with a whitespace as prefix and select all - controller.codeLines = CodeLines.of(const [ - CodeLine(' abc') - ]); + controller.codeLines = CodeLines.of(const [CodeLine(' abc')]); controller.selectAll(); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine(' abc') - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 5 - )); + expect(controller.codeLines, CodeLines.of([const CodeLine(' abc')])); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: 5, + ), + ); } // Multi code lines { // Assign indent size is 2 - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar', - const CodeLineOptions( - indentSize: 2 - ) - ); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' abc'), - CodeLine('foo'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine(' abc'), + CodeLine('foo'), + CodeLine('bar'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); // select line 1-2 (all letters) controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 2, - extentOffset: 3 + extentOffset: 3, ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' abc'), - CodeLine(' foo'), - CodeLine(' bar'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 1, - baseOffset: 0, - extentIndex: 2, - extentOffset: 5 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine(' abc'), + CodeLine(' foo'), + CodeLine(' bar'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 1, + baseOffset: 0, + extentIndex: 2, + extentOffset: 5, + ), + ); // Reset code lines controller.codeLines = CodeLines.of(const [ CodeLine('abc'), @@ -3135,20 +3091,26 @@ void main() { baseIndex: 1, baseOffset: 1, extentIndex: 2, - extentOffset: 2 + extentOffset: 2, ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine(' foo'), - CodeLine(' bar'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 1, - baseOffset: 3, - extentIndex: 2, - extentOffset: 4 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc'), + CodeLine(' foo'), + CodeLine(' bar'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 1, + baseOffset: 3, + extentIndex: 2, + extentOffset: 4, + ), + ); // Reset code lines controller.codeLines = CodeLines.of(const [ CodeLine('abc'), @@ -3160,20 +3122,26 @@ void main() { baseIndex: 2, baseOffset: 2, extentIndex: 1, - extentOffset: 1 + extentOffset: 1, ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine(' foo'), - CodeLine(' bar'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 2, - baseOffset: 4, - extentIndex: 1, - extentOffset: 3 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc'), + CodeLine(' foo'), + CodeLine(' bar'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 2, + baseOffset: 4, + extentIndex: 1, + extentOffset: 3, + ), + ); // Reset code lines controller.codeLines = CodeLines.of(const [ CodeLine('abc'), @@ -3185,20 +3153,26 @@ void main() { baseIndex: 1, baseOffset: 1, extentIndex: 2, - extentOffset: 0 + extentOffset: 0, ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine(' foo'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 1, - baseOffset: 3, - extentIndex: 2, - extentOffset: 0 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc'), + CodeLine(' foo'), + CodeLine('bar'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 1, + baseOffset: 3, + extentIndex: 2, + extentOffset: 0, + ), + ); // Reset code lines, add one whitespace at begin controller.codeLines = CodeLines.of(const [ CodeLine(' abc'), @@ -3210,22 +3184,28 @@ void main() { baseIndex: 0, baseOffset: 1, extentIndex: 2, - extentOffset: 1 + extentOffset: 1, ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' abc'), - CodeLine(' foo'), - CodeLine(' bar'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 2, - extentOffset: 1 - )); - // Reset code lines, add three whitespace at begin - controller.codeLines = CodeLines.of(const [ + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine(' abc'), + CodeLine(' foo'), + CodeLine(' bar'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 2, + extentOffset: 1, + ), + ); + // Reset code lines, add three whitespace at begin + controller.codeLines = CodeLines.of(const [ CodeLine(' abc'), CodeLine(' foo'), CodeLine(' bar'), @@ -3235,150 +3215,138 @@ void main() { baseIndex: 0, baseOffset: 1, extentIndex: 2, - extentOffset: 1 + extentOffset: 1, ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' abc'), - CodeLine(' foo'), - CodeLine(' bar'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 2, - extentOffset: 1 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine(' abc'), + CodeLine(' foo'), + CodeLine(' bar'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 2, + extentOffset: 1, + ), + ); } // Multi code lines, have a chunk. { final CodeLineEditingController controller = CodeLineEditingController( codeLines: CodeLines.of(const [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('}') + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), ]), - options: const CodeLineOptions( - indentSize: 2 - ) ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' {', [ - CodeLine('foo'), - CodeLine('bar') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine(' {', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), ]), - CodeLine('}') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 3 + offset: 3, ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' { ', [ - CodeLine('foo'), - CodeLine('bar') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine(' { ', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), ]), - CodeLine('}') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 4 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 4), + ); // Reset code lines and select all controller.codeLines = CodeLines.of(const [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('}') + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), ]); controller.selectAll(); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' {', [ - CodeLine(' foo'), - CodeLine(' bar') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine(' {', [CodeLine(' foo'), CodeLine(' bar')]), + CodeLine(' }'), ]), - CodeLine(' }') - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 1, - extentOffset: 3 - )); + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 1, + extentOffset: 3, + ), + ); } // Multi code lines, have a few of chunks { final CodeLineEditingController controller = CodeLineEditingController( codeLines: CodeLines.of(const [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), CodeLine('}'), - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), CodeLine('}'), - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('}') - ]) + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), + ]), ); controller.selectAll(); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - CodeLine('${controller.options.indent}{', [ - CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') - ]), - CodeLine('${controller.options.indent}}'), - CodeLine('${controller.options.indent}{', [ - CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') - ]), - CodeLine('${controller.options.indent}}'), - CodeLine('${controller.options.indent}{', [ - CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') + expect( + controller.codeLines, + CodeLines.of([ + CodeLine('${controller.options.indent}{', [ + CodeLine('${controller.options.indent}foo'), + CodeLine('${controller.options.indent}bar'), + ]), + CodeLine('${controller.options.indent}}'), + CodeLine('${controller.options.indent}{', [ + CodeLine('${controller.options.indent}foo'), + CodeLine('${controller.options.indent}bar'), + ]), + CodeLine('${controller.options.indent}}'), + CodeLine('${controller.options.indent}{', [ + CodeLine('${controller.options.indent}foo'), + CodeLine('${controller.options.indent}bar'), + ]), + CodeLine('${controller.options.indent}}'), ]), - CodeLine('${controller.options.indent}}') - ])); - expect(controller.selection, CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 5, - extentOffset: controller.options.indentSize + 1 - )); + ); + expect( + controller.selection, + CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 5, + extentOffset: controller.options.indentSize + 1, + ), + ); // Reset code lines controller.codeLines = CodeLines.of(const [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), CodeLine('}'), - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), CodeLine('}'), - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('}') ]); controller.selection = const CodeLineSelection( baseIndex: 0, @@ -3387,29 +3355,35 @@ void main() { extentOffset: 1, ); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - CodeLine('${controller.options.indent}{', [ - CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') - ]), - CodeLine('${controller.options.indent}}'), - CodeLine('${controller.options.indent}{', [ - CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') - ]), - CodeLine('${controller.options.indent}}'), - CodeLine('${controller.options.indent}{', [ - const CodeLine('foo'), - const CodeLine('bar') + expect( + controller.codeLines, + CodeLines.of([ + CodeLine('${controller.options.indent}{', [ + CodeLine('${controller.options.indent}foo'), + CodeLine('${controller.options.indent}bar'), + ]), + CodeLine('${controller.options.indent}}'), + CodeLine('${controller.options.indent}{', [ + CodeLine('${controller.options.indent}foo'), + CodeLine('${controller.options.indent}bar'), + ]), + CodeLine('${controller.options.indent}}'), + CodeLine('${controller.options.indent}{', [ + const CodeLine('foo'), + const CodeLine('bar'), + ]), + const CodeLine('}'), ]), - const CodeLine('}') - ])); - expect(controller.selection, CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 4, - extentOffset: controller.options.indentSize + 1 - )); + ); + expect( + controller.selection, + CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 4, + extentOffset: controller.options.indentSize + 1, + ), + ); } // Multi code lines, have nested chunks { @@ -3418,220 +3392,233 @@ void main() { CodeLine('{', [ CodeLine('foo'), CodeLine('bar', [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('}') - ]) + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), + ]), ]), CodeLine('}'), - ]) + ]), ); controller.selectAll(); controller.applyIndent(); - expect(controller.codeLines, CodeLines.of([ - CodeLine('${controller.options.indent}{', [ - CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar', [ - CodeLine('${controller.options.indent}{', [ - CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') + expect( + controller.codeLines, + CodeLines.of([ + CodeLine('${controller.options.indent}{', [ + CodeLine('${controller.options.indent}foo'), + CodeLine('${controller.options.indent}bar', [ + CodeLine('${controller.options.indent}{', [ + CodeLine('${controller.options.indent}foo'), + CodeLine('${controller.options.indent}bar'), + ]), + CodeLine('${controller.options.indent}}'), ]), - CodeLine('${controller.options.indent}}') - ]) + ]), + CodeLine('${controller.options.indent}}'), ]), - CodeLine('${controller.options.indent}}'), - ])); - expect(controller.selection, CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 1, - extentOffset: controller.options.indentSize + 1 - )); + ); + expect( + controller.selection, + CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 1, + extentOffset: controller.options.indentSize + 1, + ), + ); } }); test('`applyOutdent()`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); expect(controller.selection, const CodeLineSelection.zero()); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc') - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abc')])); expect(controller.selection, const CodeLineSelection.zero()); // have one whitespace - controller.codeLines = CodeLines.of(const [ - CodeLine(' abc') - ]); + controller.codeLines = CodeLines.of(const [CodeLine(' abc')]); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc') - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abc')])); expect(controller.selection, const CodeLineSelection.zero()); // have one whitespace + one indent controller.codeLines = CodeLines.of([ - CodeLine(' ${controller.options.indent}abc') + CodeLine(' ${controller.options.indent}abc'), ]); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of([ - CodeLine('${controller.options.indent}abc') - ])); + expect( + controller.codeLines, + CodeLines.of([CodeLine('${controller.options.indent}abc')]), + ); expect(controller.selection, const CodeLineSelection.zero()); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc') - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abc')])); expect(controller.selection, const CodeLineSelection.zero()); // have one whitespace + one indent and selection position is after 'a' controller.codeLines = CodeLines.of([ - CodeLine(' ${controller.options.indent}abc') + CodeLine(' ${controller.options.indent}abc'), ]); controller.selection = CodeLineSelection.collapsed( index: 0, - offset: 2 + controller.options.indentSize + offset: 2 + controller.options.indentSize, ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of([ - CodeLine('${controller.options.indent}abc') - ])); - expect(controller.selection, CodeLineSelection.collapsed( - index: 0, - offset: 1 + controller.options.indentSize - )); + expect( + controller.codeLines, + CodeLines.of([CodeLine('${controller.options.indent}abc')]), + ); + expect( + controller.selection, + CodeLineSelection.collapsed( + index: 0, + offset: 1 + controller.options.indentSize, + ), + ); // have two indent and selection position is in the mid of intents controller.codeLines = CodeLines.of([ - CodeLine('${controller.options.indent}${controller.options.indent}abc') + CodeLine( + '${controller.options.indent}${controller.options.indent}abc', + ), ]); controller.selection = CodeLineSelection.collapsed( index: 0, - offset: controller.options.indentSize + offset: controller.options.indentSize, ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of([ - CodeLine('${controller.options.indent}abc') - ])); - expect(controller.selection, CodeLineSelection.collapsed( - index: 0, - offset: controller.options.indentSize - )); + expect( + controller.codeLines, + CodeLines.of([CodeLine('${controller.options.indent}abc')]), + ); + expect( + controller.selection, + CodeLineSelection.collapsed( + index: 0, + offset: controller.options.indentSize, + ), + ); // have two indent and have selected the first controller.codeLines = CodeLines.of([ - CodeLine('${controller.options.indent}${controller.options.indent}abc') + CodeLine( + '${controller.options.indent}${controller.options.indent}abc', + ), ]); controller.selection = CodeLineSelection( baseIndex: 0, baseOffset: 0, extentIndex: 0, - extentOffset: controller.options.indentSize + extentOffset: controller.options.indentSize, ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of([ - CodeLine('${controller.options.indent}abc') - ])); - expect(controller.selection, CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: controller.options.indentSize - )); + expect( + controller.codeLines, + CodeLines.of([CodeLine('${controller.options.indent}abc')]), + ); + expect( + controller.selection, + CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: controller.options.indentSize, + ), + ); // have two indent and have selected the second controller.codeLines = CodeLines.of([ - CodeLine('${controller.options.indent}${controller.options.indent}abc') + CodeLine( + '${controller.options.indent}${controller.options.indent}abc', + ), ]); controller.selection = CodeLineSelection( baseIndex: 0, baseOffset: controller.options.indentSize, extentIndex: 0, - extentOffset: controller.options.indentSize * 2 + extentOffset: controller.options.indentSize * 2, ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of([ - CodeLine('${controller.options.indent}abc') - ])); - expect(controller.selection, CodeLineSelection.collapsed( - index: 0, - offset: controller.options.indentSize - )); + expect( + controller.codeLines, + CodeLines.of([CodeLine('${controller.options.indent}abc')]), + ); + expect( + controller.selection, + CodeLineSelection.collapsed( + index: 0, + offset: controller.options.indentSize, + ), + ); // have three whitespace and have selected the first (one indent = two whitespace) - controller.codeLines = CodeLines.of(const [ - CodeLine(' abc') - ]); + controller.codeLines = CodeLines.of(const [CodeLine(' abc')]); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 0, extentIndex: 0, - extentOffset: 1 + extentOffset: 1, ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' abc') - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 1 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine(' abc')])); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: 1, + ), + ); // have three whitespace and have selected the second (one indent = two whitespace) - controller.codeLines = CodeLines.of(const [ - CodeLine(' abc') - ]); + controller.codeLines = CodeLines.of(const [CodeLine(' abc')]); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' abc') - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine(' abc')])); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + ); // have three whitespace and have selected the third (one indent = two whitespace) - controller.codeLines = CodeLines.of(const [ - CodeLine(' abc') - ]); + controller.codeLines = CodeLines.of(const [CodeLine(' abc')]); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 2, extentIndex: 0, - extentOffset: 3 + extentOffset: 3, ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(' abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine(' abc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); } // Multi code lines without indent { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.applyOutdent(); // select line 1-2 (all letters) controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 2, - extentOffset: 3 + extentOffset: 3, ); controller.applyOutdent(); // select all @@ -3640,33 +3627,43 @@ void main() { } // Multi code lines with indents { - final CodeLineEditingController controller = CodeLineEditingController.fromText(' abc \n foo \n bar '); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(' abc \n foo \n bar '); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc '), - CodeLine(' foo '), - CodeLine(' bar '), - ])); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc '), + CodeLine(' foo '), + CodeLine(' bar '), + ]), + ); expect(controller.selection, const CodeLineSelection.zero()); // select line 1-2 (all letters) controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 2, - extentOffset: 5 + extentOffset: 5, ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc '), - CodeLine('foo '), - CodeLine('bar '), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 1, - baseOffset: 0, - extentIndex: 2, - extentOffset: 4 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc '), + CodeLine('foo '), + CodeLine('bar '), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 1, + baseOffset: 0, + extentIndex: 2, + extentOffset: 4, + ), + ); // Rest code lines controller.codeLines = CodeLines.of(const [ CodeLine(' abc '), @@ -3676,231 +3673,266 @@ void main() { // select all controller.selectAll(); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc '), - CodeLine('foo '), - CodeLine('bar '), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 2, - extentOffset: 4 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc '), + CodeLine('foo '), + CodeLine('bar '), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 2, + extentOffset: 4, + ), + ); // Rest code lines controller.codeLines = CodeLines.of([ CodeLine(' ${controller.options.indent}abc'), - CodeLine(' ${controller.options.indent}${controller.options.indent}foo'), - CodeLine(' ${controller.options.indent}${controller.options.indent}${controller.options.indent}bar'), + CodeLine( + ' ${controller.options.indent}${controller.options.indent}foo', + ), + CodeLine( + ' ${controller.options.indent}${controller.options.indent}${controller.options.indent}bar', + ), ]); controller.selectAll(); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of([ - CodeLine('${controller.options.indent}abc'), - CodeLine('${controller.options.indent}${controller.options.indent}foo'), - CodeLine('${controller.options.indent}${controller.options.indent}${controller.options.indent}bar'), - ])); - expect(controller.selection, CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 2, - extentOffset: 3 + controller.options.indentSize * 3 - )); + expect( + controller.codeLines, + CodeLines.of([ + CodeLine('${controller.options.indent}abc'), + CodeLine( + '${controller.options.indent}${controller.options.indent}foo', + ), + CodeLine( + '${controller.options.indent}${controller.options.indent}${controller.options.indent}bar', + ), + ]), + ); + expect( + controller.selection, + CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 2, + extentOffset: 3 + controller.options.indentSize * 3, + ), + ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine('abc'), - CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}${controller.options.indent}bar'), - ])); - expect(controller.selection, CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 2, - extentOffset: 3 + controller.options.indentSize * 2 - )); + expect( + controller.codeLines, + CodeLines.of([ + const CodeLine('abc'), + CodeLine('${controller.options.indent}foo'), + CodeLine( + '${controller.options.indent}${controller.options.indent}bar', + ), + ]), + ); + expect( + controller.selection, + CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 2, + extentOffset: 3 + controller.options.indentSize * 2, + ), + ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine('abc'), - const CodeLine('foo'), - CodeLine('${controller.options.indent}bar'), - ])); - expect(controller.selection, CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 2, - extentOffset: 3 + controller.options.indentSize - )); + expect( + controller.codeLines, + CodeLines.of([ + const CodeLine('abc'), + const CodeLine('foo'), + CodeLine('${controller.options.indent}bar'), + ]), + ); + expect( + controller.selection, + CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 2, + extentOffset: 3 + controller.options.indentSize, + ), + ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 2, - extentOffset: 3 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abc'), + CodeLine('foo'), + CodeLine('bar'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 2, + extentOffset: 3, + ), + ); } // Multi code lines, have a chunk. { final CodeLineEditingController controller = CodeLineEditingController( codeLines: CodeLines.of(const [ - CodeLine(' {', [ - CodeLine(' foo'), - CodeLine(' bar') - ]), - CodeLine('}') - ]) + CodeLine(' {', [CodeLine(' foo'), CodeLine(' bar')]), + CodeLine('}'), + ]), ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine(' foo'), - CodeLine(' bar') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine(' foo'), CodeLine(' bar')]), + CodeLine('}'), ]), - CodeLine('}') - ])); + ); expect(controller.selection, const CodeLineSelection.zero()); // Rest code lines controller.codeLines = CodeLines.of(const [ - CodeLine(' {', [ - CodeLine(' foo'), - CodeLine(' bar') - ]), - CodeLine(' }') + CodeLine(' {', [CodeLine(' foo'), CodeLine(' bar')]), + CodeLine(' }'), ]); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 0, extentIndex: 1, - extentOffset: 0 + extentOffset: 0, ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine(' }'), ]), - CodeLine(' }') - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 1, - extentOffset: 0 - )); + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 1, + extentOffset: 0, + ), + ); // Rest code lines controller.codeLines = CodeLines.of(const [ - CodeLine(' {', [ - CodeLine(' foo'), - CodeLine(' bar') - ]), - CodeLine(' }') + CodeLine(' {', [CodeLine(' foo'), CodeLine(' bar')]), + CodeLine(' }'), ]); controller.selectAll(); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), ]), - CodeLine('}') - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 1, - extentOffset: 1 - )); + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 1, + extentOffset: 1, + ), + ); controller.applyOutdent(); // Rest code lines controller.codeLines = CodeLines.of(const [ - CodeLine('{', [ - CodeLine(' foo'), - CodeLine(' bar') - ]), - CodeLine('}') + CodeLine('{', [CodeLine(' foo'), CodeLine(' bar')]), + CodeLine('}'), ]); controller.selectAll(); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), ]), - CodeLine('}') - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 1, - extentOffset: 1 - )); + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 1, + extentOffset: 1, + ), + ); } // Multi code lines, have a few of chunks { - final CodeLineEditingController controller = CodeLineEditingController(); + final CodeLineEditingController controller = + CodeLineEditingController(); controller.codeLines = CodeLines.of([ CodeLine('${controller.options.indent}{', [ CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') + CodeLine('${controller.options.indent}bar'), ]), CodeLine('${controller.options.indent}}'), CodeLine('${controller.options.indent}{', [ CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') + CodeLine('${controller.options.indent}bar'), ]), CodeLine('${controller.options.indent}}'), CodeLine('${controller.options.indent}{', [ CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') - ]), - CodeLine('${controller.options.indent}}') - ]); - controller.selectAll(); - controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('}'), - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('}'), - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') + CodeLine('${controller.options.indent}bar'), ]), - CodeLine('}') - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 5, - extentOffset: 1 - )); + CodeLine('${controller.options.indent}}'), + ]); + controller.selectAll(); + controller.applyOutdent(); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 5, + extentOffset: 1, + ), + ); // Reset code lines controller.codeLines = CodeLines.of([ CodeLine('${controller.options.indent}{', [ CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') + CodeLine('${controller.options.indent}bar'), ]), CodeLine('${controller.options.indent}}'), CodeLine('${controller.options.indent}{', [ CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') + CodeLine('${controller.options.indent}bar'), ]), CodeLine('${controller.options.indent}}'), CodeLine('${controller.options.indent}{', [ CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') + CodeLine('${controller.options.indent}bar'), ]), - CodeLine('${controller.options.indent}}') + CodeLine('${controller.options.indent}}'), ]); controller.selection = const CodeLineSelection( baseIndex: 0, @@ -3909,124 +3941,120 @@ void main() { extentOffset: 1, ); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of([ - const CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), - const CodeLine('}'), - const CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') - ]), - const CodeLine('}'), - CodeLine('{', [ - CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') + expect( + controller.codeLines, + CodeLines.of([ + const CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + const CodeLine('}'), + const CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + const CodeLine('}'), + CodeLine('{', [ + CodeLine('${controller.options.indent}foo'), + CodeLine('${controller.options.indent}bar'), + ]), + CodeLine('${controller.options.indent}}'), ]), - CodeLine('${controller.options.indent}}') - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 4, - extentOffset: 0 - )); + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 4, + extentOffset: 0, + ), + ); controller.applyOutdent(); } // Multi code lines, have nested chunks { - final CodeLineEditingController controller = CodeLineEditingController(); + final CodeLineEditingController controller = + CodeLineEditingController(); controller.codeLines = CodeLines.of([ CodeLine('${controller.options.indent}{', [ CodeLine('${controller.options.indent}foo'), CodeLine('${controller.options.indent}bar', [ CodeLine('${controller.options.indent}{', [ CodeLine('${controller.options.indent}foo'), - CodeLine('${controller.options.indent}bar') + CodeLine('${controller.options.indent}bar'), ]), - CodeLine('${controller.options.indent}}') - ]) + CodeLine('${controller.options.indent}}'), + ]), ]), CodeLine('${controller.options.indent}}'), ]); controller.selectAll(); controller.applyOutdent(); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar', [ - CodeLine('{', [ - CodeLine('foo'), - CodeLine('bar') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('{', [ + CodeLine('foo'), + CodeLine('bar', [ + CodeLine('{', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('}'), ]), - CodeLine('}') - ]) + ]), + CodeLine('}'), ]), - CodeLine('}'), - ])); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 1, - extentOffset: 1 - )); + ); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 1, + extentOffset: 1, + ), + ); } }); test('`collapseChunk() && expandChunk()`', () { { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.collapseChunk(0, 3); - expect(controller.value, CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc', [ + expect( + controller.value, + CodeLineEditingValue( + codeLines: CodeLines.of(const [ + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + ]), + ), + ); + controller.expandChunk(0); + expect( + controller.value, + CodeLineEditingValue( + codeLines: CodeLines.of(const [ + CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), ]), - ]) - )); - controller.expandChunk(0); - expect(controller.value, CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - ]) - )); + ), + ); } { - const String json = '{\n' - ' "start": "foo",\n' - ' "abc": [\n' - ' 0,\n' - ' 1,\n' - ' 2,\n' - ' ],\n' - ' "end": "bar"\n' - '}'; - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + const String json = + '{\n' + ' "start": "foo",\n' + ' "abc": [\n' + ' 0,\n' + ' 1,\n' + ' 2,\n' + ' ],\n' + ' "end": "bar"\n' + '}'; + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); // Collapse inner array controller.collapseChunk(2, 6); - expect(controller.value, CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('{'), - CodeLine(' "start": "foo",'), - CodeLine(' "abc": [', [ - CodeLine(' 0,'), - CodeLine(' 1,'), - CodeLine(' 2,'), - ]), - CodeLine(' ],'), - CodeLine(' "end": "bar"'), - CodeLine('}'), - ]) - )); - // Collapse the root object - controller.collapseChunk(0, 5); - expect(controller.value, CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('{', [ + expect( + controller.value, + CodeLineEditingValue( + codeLines: CodeLines.of(const [ + CodeLine('{'), CodeLine(' "start": "foo",'), CodeLine(' "abc": [', [ CodeLine(' 0,'), @@ -4035,280 +4063,359 @@ void main() { ]), CodeLine(' ],'), CodeLine(' "end": "bar"'), + CodeLine('}'), ]), - CodeLine('}'), - ]) - )); + ), + ); + // Collapse the root object + controller.collapseChunk(0, 5); + expect( + controller.value, + CodeLineEditingValue( + codeLines: CodeLines.of(const [ + CodeLine('{', [ + CodeLine(' "start": "foo",'), + CodeLine(' "abc": [', [ + CodeLine(' 0,'), + CodeLine(' 1,'), + CodeLine(' 2,'), + ]), + CodeLine(' ],'), + CodeLine(' "end": "bar"'), + ]), + CodeLine('}'), + ]), + ), + ); // Expand the root object controller.expandChunk(0); - expect(controller.value, CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('{'), - CodeLine(' "start": "foo",'), - CodeLine(' "abc": [', [ - CodeLine(' 0,'), - CodeLine(' 1,'), - CodeLine(' 2,'), + expect( + controller.value, + CodeLineEditingValue( + codeLines: CodeLines.of(const [ + CodeLine('{'), + CodeLine(' "start": "foo",'), + CodeLine(' "abc": [', [ + CodeLine(' 0,'), + CodeLine(' 1,'), + CodeLine(' 2,'), + ]), + CodeLine(' ],'), + CodeLine(' "end": "bar"'), + CodeLine('}'), ]), - CodeLine(' ],'), - CodeLine(' "end": "bar"'), - CodeLine('}'), - ]) - )); + ), + ); // Expand the inner array controller.expandChunk(2); - expect(controller.value, CodeLineEditingController.fromText(json).value); + expect( + controller.value, + CodeLineEditingController.fromText(json).value, + ); } // Test selection { - const String json = '{\n' - ' "start": "foo",\n' - ' "abc": [\n' - ' 0,\n' - ' 1,\n' - ' 2,\n' - ' ],\n' - ' "end": "bar"\n' - '}'; + const String json = + '{\n' + ' "start": "foo",\n' + ' "abc": [\n' + ' 0,\n' + ' 1,\n' + ' 2,\n' + ' ],\n' + ' "end": "bar"\n' + '}'; // Selection position before array { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 0 + offset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); } // Selection range before array (base before extent) { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 0, extentIndex: 1, - extentOffset: 0 + extentOffset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 1, - extentOffset: 0 - )); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 1, + extentOffset: 0, + ), + ); } // Selection range before array (base after extent) { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 0, - extentOffset: 0 + extentOffset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, const CodeLineSelection( - baseIndex: 1, - baseOffset: 0, - extentIndex: 0, - extentOffset: 0 - )); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 1, + baseOffset: 0, + extentIndex: 0, + extentOffset: 0, + ), + ); } // Selection position is inside the collapse region, should move position to parent end. { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection.collapsed( index: 3, - offset: 0 + offset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, CodeLineSelection.collapsed( - index: 2, - offset: controller.codeLines[2].text.length - )); + expect( + controller.selection, + CodeLineSelection.collapsed( + index: 2, + offset: controller.codeLines[2].text.length, + ), + ); } // Selection range is included in collapse region, should move position to parent end. { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection( baseIndex: 3, baseOffset: 0, extentIndex: 5, - extentOffset: 0 + extentOffset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, CodeLineSelection.collapsed( - index: 2, - offset: controller.codeLines[2].text.length - )); + expect( + controller.selection, + CodeLineSelection.collapsed( + index: 2, + offset: controller.codeLines[2].text.length, + ), + ); } // Selection base is before collapse region and extent is after collapse region { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 7, - extentOffset: 0 + extentOffset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, const CodeLineSelection( - baseIndex: 1, - baseOffset: 0, - extentIndex: 4, - extentOffset: 0 - )); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 1, + baseOffset: 0, + extentIndex: 4, + extentOffset: 0, + ), + ); } // Selection base is before collapse region and extent is inside collapse region { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 4, - extentOffset: 0 + extentOffset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, CodeLineSelection( - baseIndex: 1, - baseOffset: 0, - extentIndex: 2, - extentOffset: controller.codeLines[2].text.length - )); + expect( + controller.selection, + CodeLineSelection( + baseIndex: 1, + baseOffset: 0, + extentIndex: 2, + extentOffset: controller.codeLines[2].text.length, + ), + ); } // Selection base is inside collapse region and extent is after collapse region { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection( baseIndex: 4, baseOffset: 0, extentIndex: 7, - extentOffset: 0 + extentOffset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, CodeLineSelection( - baseIndex: 2, - baseOffset: controller.codeLines[2].text.length, - extentIndex: 4, - extentOffset: 0 - )); + expect( + controller.selection, + CodeLineSelection( + baseIndex: 2, + baseOffset: controller.codeLines[2].text.length, + extentIndex: 4, + extentOffset: 0, + ), + ); } // Selection extent is before collapse region and base is after collapse region { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection( baseIndex: 7, baseOffset: 0, extentIndex: 1, - extentOffset: 0 + extentOffset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, const CodeLineSelection( - baseIndex: 4, - baseOffset: 0, - extentIndex: 1, - extentOffset: 0 - )); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 4, + baseOffset: 0, + extentIndex: 1, + extentOffset: 0, + ), + ); } // Selection extent is before collapse region and base is inside collapse region { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection( baseIndex: 4, baseOffset: 0, extentIndex: 1, - extentOffset: 0 + extentOffset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, CodeLineSelection( - baseIndex: 2, - baseOffset: controller.codeLines[2].text.length, - extentIndex: 1, - extentOffset: 0 - )); + expect( + controller.selection, + CodeLineSelection( + baseIndex: 2, + baseOffset: controller.codeLines[2].text.length, + extentIndex: 1, + extentOffset: 0, + ), + ); } // Selection extent is inside collapse region and base is after collapse region { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection( baseIndex: 7, baseOffset: 0, extentIndex: 4, - extentOffset: 0 + extentOffset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, CodeLineSelection( - baseIndex: 4, - baseOffset: 0, - extentIndex: 2, - extentOffset: controller.codeLines[2].text.length, - )); + expect( + controller.selection, + CodeLineSelection( + baseIndex: 4, + baseOffset: 0, + extentIndex: 2, + extentOffset: controller.codeLines[2].text.length, + ), + ); } // Selection position after array { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection.collapsed( index: 7, - offset: 0 + offset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 4, - offset: 0 - )); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 4, offset: 0), + ); } // Selection range after array (base before extent) { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection( baseIndex: 7, baseOffset: 0, extentIndex: 8, - extentOffset: 0 + extentOffset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, const CodeLineSelection( - baseIndex: 4, - baseOffset: 0, - extentIndex: 5, - extentOffset: 0 - )); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 4, + baseOffset: 0, + extentIndex: 5, + extentOffset: 0, + ), + ); } // Selection range after array (base after extent) { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = const CodeLineSelection( baseIndex: 8, baseOffset: 0, extentIndex: 7, - extentOffset: 0 + extentOffset: 0, ); controller.collapseChunk(2, 6); - expect(controller.selection, const CodeLineSelection( - baseIndex: 5, - baseOffset: 0, - extentIndex: 4, - extentOffset: 0 - )); + expect( + controller.selection, + const CodeLineSelection( + baseIndex: 5, + baseOffset: 0, + extentIndex: 4, + extentOffset: 0, + ), + ); } } // Test composing { - const String json = '{\n' - ' "start": "foo",\n' - ' "abc": [\n' - ' 0,\n' - ' 1,\n' - ' 2,\n' - ' ],\n' - ' "end": "bar"\n' - '}'; + const String json = + '{\n' + ' "start": "foo",\n' + ' "abc": [\n' + ' 0,\n' + ' 1,\n' + ' 2,\n' + ' ],\n' + ' "end": "bar"\n' + '}'; // Composing is before the collapsed chunk { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.composing = TextRange.empty; controller.collapseChunk(2, 6); expect(controller.composing, TextRange.empty); @@ -4316,7 +4423,8 @@ void main() { expect(controller.composing, TextRange.empty); } { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.composing = const TextRange.collapsed(1); controller.collapseChunk(2, 6); expect(controller.composing, const TextRange.collapsed(1)); @@ -4325,12 +4433,10 @@ void main() { } // Composing is in the collapsed chunk { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = CodeLineSelection.fromPosition( - position: const CodeLinePosition( - index: 3, - offset: 0 - ) + position: const CodeLinePosition(index: 3, offset: 0), ); controller.composing = const TextRange.collapsed(1); controller.collapseChunk(2, 6); @@ -4338,12 +4444,10 @@ void main() { } // Composing is after the collapsed chunk { - final CodeLineEditingController controller = CodeLineEditingController.fromText(json); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(json); controller.selection = CodeLineSelection.fromPosition( - position: const CodeLinePosition( - index: 7, - offset: 0 - ) + position: const CodeLinePosition(index: 7, offset: 0), ); controller.composing = const TextRange.collapsed(1); controller.collapseChunk(2, 6); @@ -4357,331 +4461,339 @@ void main() { test('`replaceSelection()`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.replaceSelection('abc'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.replaceSelection('abc'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcabc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abcabc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); controller.replaceSelection('foo'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcfooabc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 6 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('abcfooabc')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 6), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 3, extentIndex: 0, - extentOffset: 6 + extentOffset: 6, ); controller.replaceSelection('bar'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcbarabc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 6 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('abcbarabc')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 6), + ); controller.replaceSelection(''); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcbarabc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 6 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('abcbarabc')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 6), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 3, extentIndex: 0, - extentOffset: 6 + extentOffset: 6, ); controller.replaceSelection(''); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcabc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 3 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine('abcabc')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 3), + ); controller.replaceSelection('foo\nbar'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcfoo'), - CodeLine('barabc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 3 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('abcfoo'), CodeLine('barabc')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 3), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 1, - extentOffset: 3 + extentOffset: 3, ); controller.replaceSelection('123\n456\n789'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcfoo'), - CodeLine('123'), - CodeLine('456'), - CodeLine('789abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 3, - offset: 3 - )); - controller.replaceSelection('456', const CodeLineSelection( - baseIndex: 1, - baseOffset: 0, - extentIndex: 1, - extentOffset: 3 - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcfoo'), - CodeLine('456'), - CodeLine('456'), - CodeLine('789abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 3 - )); - controller.replaceSelection('123\n123', const CodeLineSelection( - baseIndex: 1, - baseOffset: 0, - extentIndex: 2, - extentOffset: 3 - )); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('abcfoo'), - CodeLine('123'), - CodeLine('123'), - CodeLine('789abc') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 3 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abcfoo'), + CodeLine('123'), + CodeLine('456'), + CodeLine('789abc'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 3, offset: 3), + ); + controller.replaceSelection( + '456', + const CodeLineSelection( + baseIndex: 1, + baseOffset: 0, + extentIndex: 1, + extentOffset: 3, + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abcfoo'), + CodeLine('456'), + CodeLine('456'), + CodeLine('789abc'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 3), + ); + controller.replaceSelection( + '123\n123', + const CodeLineSelection( + baseIndex: 1, + baseOffset: 0, + extentIndex: 2, + extentOffset: 3, + ), + ); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('abcfoo'), + CodeLine('123'), + CodeLine('123'), + CodeLine('789abc'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 3), + ); } // Multi code lines { final CodeLineEditingController controller = CodeLineEditingController( codeLines: CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('123') - ]), - CodeLine('foo', [ - CodeLine('456') - ]), - CodeLine('bar', [ - CodeLine('789') - ]), - ]) + CodeLine('abc', [CodeLine('123')]), + CodeLine('foo', [CodeLine('456')]), + CodeLine('bar', [CodeLine('789')]), + ]), ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ); controller.replaceSelection(' '); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('a c', [ - CodeLine('123') - ]), - CodeLine('foo', [ - CodeLine('456') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('a c', [CodeLine('123')]), + CodeLine('foo', [CodeLine('456')]), + CodeLine('bar', [CodeLine('789')]), ]), - CodeLine('bar', [ - CodeLine('789') - ]), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); controller.selection = const CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 1, - extentOffset: 3 + extentOffset: 3, ); controller.replaceSelection('hello\nreqable\n'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('a c', [ - CodeLine('123') - ]), - CodeLine('hello'), - CodeLine('reqable'), - CodeLine('', [ - CodeLine('456') - ]), - CodeLine('bar', [ - CodeLine('789') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('a c', [CodeLine('123')]), + CodeLine('hello'), + CodeLine('reqable'), + CodeLine('', [CodeLine('456')]), + CodeLine('bar', [CodeLine('789')]), ]), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 3, - offset: 0 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 3, offset: 0), + ); controller.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 4, - extentOffset: 3 + extentOffset: 3, ); controller.replaceSelection('b'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('ab', [ - CodeLine('789') + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('ab', [CodeLine('789')]), ]), - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 2 - )); + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 2), + ); } }); test('`replaceAll()`', () { // Empty content { - final CodeLineEditingController controller = CodeLineEditingController.fromText(''); + final CodeLineEditingController controller = + CodeLineEditingController.fromText(''); controller.replaceAll('', 'abc'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); controller.replaceAll('abc', 'abc'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(controller.codeLines, CodeLines.of(const [CodeLine.empty])); } // Single code line { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); controller.replaceAll('abc', 'foo'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('foo') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 0 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine('foo')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 0), + ); controller.selection = const CodeLineSelection.collapsed( index: 0, - offset: 2 + offset: 2, ); controller.replaceAll('o', '123'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('f123123') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 4 - )); + expect(controller.codeLines, CodeLines.of(const [CodeLine('f123123')])); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 4), + ); controller.replaceAll('123', '123456789'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('f123456789123456789') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 10 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('f123456789123456789')]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 10), + ); controller.replaceAll('123456789', '\n'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('f'), - CodeLine(''), - CodeLine('') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0 - )); + expect( + controller.codeLines, + CodeLines.of(const [CodeLine('f'), CodeLine.empty, CodeLine.empty]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); } // Multi code lines { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc\nfoo\nbar'); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc\nfoo\nbar'); controller.replaceAll('a', '123'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('123bc'), - CodeLine('foo'), - CodeLine('b123r') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 0 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('123bc'), + CodeLine('foo'), + CodeLine('b123r'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 0, offset: 0), + ); controller.selection = const CodeLineSelection.collapsed( index: 1, - offset: 0 + offset: 0, ); controller.replaceAll('b', '456'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('123456c'), - CodeLine('foo'), - CodeLine('456123r') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 1, - offset: 0 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('123456c'), + CodeLine('foo'), + CodeLine('456123r'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 1, offset: 0), + ); controller.selection = const CodeLineSelection.collapsed( index: 2, - offset: 7 + offset: 7, + ); + controller.replaceAll(RegExp(r'\d'), 'zzz'); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine('zzzzzzzzzzzzzzzzzzc'), + CodeLine('foo'), + CodeLine('zzzzzzzzzzzzzzzzzzr'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 2, offset: 19), ); - controller.replaceAll(RegExp('\\d'), 'zzz'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine('zzzzzzzzzzzzzzzzzzc'), - CodeLine('foo'), - CodeLine('zzzzzzzzzzzzzzzzzzr') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 2, - offset: 19 - )); controller.replaceAll('zzzzz', '\n'); - expect(controller.codeLines, CodeLines.of(const [ - CodeLine(''), - CodeLine(''), - CodeLine(''), - CodeLine('zzzc'), - CodeLine('foo'), - CodeLine(''), - CodeLine(''), - CodeLine(''), - CodeLine('zzzr') - ])); - expect(controller.selection, const CodeLineSelection.collapsed( - index: 8, - offset: 4 - )); + expect( + controller.codeLines, + CodeLines.of(const [ + CodeLine.empty, + CodeLine.empty, + CodeLine.empty, + CodeLine('zzzc'), + CodeLine('foo'), + CodeLine.empty, + CodeLine.empty, + CodeLine.empty, + CodeLine('zzzr'), + ]), + ); + expect( + controller.selection, + const CodeLineSelection.collapsed(index: 8, offset: 4), + ); } }); test('`clearComposing()`', () { - final CodeLineEditingController controller = CodeLineEditingController.fromText('abc'); - const TextRange composing = TextRange( - start: 0, - end: 1 - ); + final CodeLineEditingController controller = + CodeLineEditingController.fromText('abc'); + const TextRange composing = TextRange(start: 0, end: 1); controller.composing = composing; expect(controller.composing, composing); expect(controller.isComposing, true); @@ -4689,6 +4801,5 @@ void main() { expect(controller.composing, TextRange.empty); expect(controller.isComposing, false); }); - }); -} \ No newline at end of file +} diff --git a/test/code_line_editing_value_test.dart b/test/code_line_editing_value_test.dart index 7743692..3651d6c 100644 --- a/test/code_line_editing_value_test.dart +++ b/test/code_line_editing_value_test.dart @@ -8,49 +8,30 @@ void main() { test('`CodeLineEditingValue()`', () { { final CodeLineEditingValue value = CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc') - ]) + codeLines: CodeLines.of(const [CodeLine('abc')]), ); - expect(value.codeLines, CodeLines.of(const [ - CodeLine('abc') - ])); + expect(value.codeLines, CodeLines.of(const [CodeLine('abc')])); expect(value.selection, const CodeLineSelection.zero()); expect(value.composing, TextRange.empty); } { final CodeLineEditingValue value = CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 1 - ), - composing: const TextRange( - start: 1, - end: 2 - ) + codeLines: CodeLines.of(const [CodeLine('abc')]), + selection: const CodeLineSelection.collapsed(index: 0, offset: 1), + composing: const TextRange(start: 1, end: 2), ); - expect(value.codeLines, CodeLines.of(const [ - CodeLine('abc') - ])); - expect(value.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); - expect(value.composing, const TextRange( - start: 1, - end: 2 - )); + expect(value.codeLines, CodeLines.of(const [CodeLine('abc')])); + expect( + value.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); + expect(value.composing, const TextRange(start: 1, end: 2)); } }); test('`CodeLineEditingValue.empty()`', () { const CodeLineEditingValue value = CodeLineEditingValue.empty(); - expect(value.codeLines, CodeLines.of(const [ - CodeLine.empty - ])); + expect(value.codeLines, CodeLines.of(const [CodeLine.empty])); expect(value.selection, const CodeLineSelection.zero()); expect(value.composing, TextRange.empty); }); @@ -59,74 +40,39 @@ void main() { group('CodeLineEditingValue method ', () { test('`copyWith()`', () { final CodeLineEditingValue value = CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 1 - ), - composing: const TextRange( - start: 1, - end: 2 - ) + codeLines: CodeLines.of(const [CodeLine('abc')]), + selection: const CodeLineSelection.collapsed(index: 0, offset: 1), + composing: const TextRange(start: 1, end: 2), ); expect(value.copyWith(), value); - expect(value.copyWith( - codeLines: CodeLines.of(const [ - CodeLine('foo'), - CodeLine('bar') - ]) - ), CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('foo'), - CodeLine('bar') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 1 + expect( + value.copyWith( + codeLines: CodeLines.of(const [CodeLine('foo'), CodeLine('bar')]), + ), + CodeLineEditingValue( + codeLines: CodeLines.of(const [CodeLine('foo'), CodeLine('bar')]), + selection: const CodeLineSelection.collapsed(index: 0, offset: 1), + composing: const TextRange(start: 1, end: 2), ), - composing: const TextRange( - start: 1, - end: 2 - ) - )); - expect(value.copyWith( - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 2 + ); + expect( + value.copyWith( + selection: const CodeLineSelection.collapsed(index: 0, offset: 2), ), - ), CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 2 + CodeLineEditingValue( + codeLines: CodeLines.of(const [CodeLine('abc')]), + selection: const CodeLineSelection.collapsed(index: 0, offset: 2), + composing: const TextRange(start: 1, end: 2), ), - composing: const TextRange( - start: 1, - end: 2 - ) - )); - expect(value.copyWith( - composing: const TextRange( - start: 2, - end: 3 - ) - ), CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 1 + ); + expect( + value.copyWith(composing: const TextRange(start: 2, end: 3)), + CodeLineEditingValue( + codeLines: CodeLines.of(const [CodeLine('abc')]), + selection: const CodeLineSelection.collapsed(index: 0, offset: 1), + composing: const TextRange(start: 2, end: 3), ), - composing: const TextRange( - start: 2, - end: 3 - ) - )); + ); }); }); @@ -134,120 +80,49 @@ void main() { test('`==`', () { { final CodeLineEditingValue value1 = CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 0 - ), - composing: const TextRange( - start: 0, - end: 0 - ) + codeLines: CodeLines.of(const [CodeLine('abc')]), + composing: const TextRange(start: 0, end: 0), ); final CodeLineEditingValue value2 = CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 0 - ), - composing: const TextRange( - start: 0, - end: 0 - ) + codeLines: CodeLines.of(const [CodeLine('abc')]), + composing: const TextRange(start: 0, end: 0), ); expect(value1, value2); } { final CodeLineEditingValue value1 = CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 0 - ), - composing: const TextRange( - start: 0, - end: 0 - ) + codeLines: CodeLines.of(const [CodeLine('abc')]), + composing: const TextRange(start: 0, end: 0), ); final CodeLineEditingValue value2 = CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('foobar') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 0 - ), - composing: const TextRange( - start: 0, - end: 0 - ) + codeLines: CodeLines.of(const [CodeLine('foobar')]), + composing: const TextRange(start: 0, end: 0), ); expect(value1 != value2, true); } { final CodeLineEditingValue value1 = CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 0 - ), - composing: const TextRange( - start: 0, - end: 0 - ) + codeLines: CodeLines.of(const [CodeLine('abc')]), + composing: const TextRange(start: 0, end: 0), ); final CodeLineEditingValue value2 = CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 1 - ), - composing: const TextRange( - start: 0, - end: 0 - ) + codeLines: CodeLines.of(const [CodeLine('abc')]), + selection: const CodeLineSelection.collapsed(index: 0, offset: 1), + composing: const TextRange(start: 0, end: 0), ); expect(value1 != value2, true); } { final CodeLineEditingValue value1 = CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 0 - ), - composing: const TextRange( - start: 0, - end: 0 - ) + codeLines: CodeLines.of(const [CodeLine('abc')]), + composing: const TextRange(start: 0, end: 0), ); final CodeLineEditingValue value2 = CodeLineEditingValue( - codeLines: CodeLines.of(const [ - CodeLine('abc') - ]), - selection: const CodeLineSelection.collapsed( - index: 0, - offset: 0 - ), - composing: const TextRange( - start: 1, - end: 0 - ) + codeLines: CodeLines.of(const [CodeLine('abc')]), + composing: const TextRange(start: 1, end: 0), ); expect(value1 != value2, true); } }); }); -} \ No newline at end of file +} diff --git a/test/code_line_position_test.dart b/test/code_line_position_test.dart index 7ba99cb..6d96292 100644 --- a/test/code_line_position_test.dart +++ b/test/code_line_position_test.dart @@ -8,7 +8,7 @@ void main() { const CodeLinePosition position = CodeLinePosition( index: 1, offset: 2, - affinity: TextAffinity.upstream + affinity: TextAffinity.upstream, ); expect(position.index, 1); expect(position.offset, 2); @@ -19,8 +19,8 @@ void main() { index: 1, position: const TextPosition( offset: 2, - affinity: TextAffinity.upstream - ) + affinity: TextAffinity.upstream, + ), ); expect(position.index, 1); expect(position.offset, 2); @@ -30,42 +30,32 @@ void main() { group('CodeLinePosition method ', () { test('`copyWith`', () { - const CodeLinePosition position = CodeLinePosition( - index: 1, - offset: 2, - affinity: TextAffinity.downstream - ); + const CodeLinePosition position = CodeLinePosition(index: 1, offset: 2); expect(position.copyWith(), position); - expect(position.copyWith( - index: 0 - ), const CodeLinePosition( - index: 0, - offset: 2, - affinity: TextAffinity.downstream - )); - expect(position.copyWith( - offset: 0 - ), const CodeLinePosition( - index: 1, - offset: 0, - affinity: TextAffinity.downstream - )); - expect(position.copyWith( - affinity: TextAffinity.upstream - ), const CodeLinePosition( - index: 1, - offset: 2, - affinity: TextAffinity.upstream - )); - expect(position.copyWith( - index: 0, - offset: 0, - affinity: TextAffinity.downstream - ), const CodeLinePosition( - index: 0, - offset: 0, - affinity: TextAffinity.downstream - )); + expect( + position.copyWith(index: 0), + const CodeLinePosition(index: 0, offset: 2), + ); + expect( + position.copyWith(offset: 0), + const CodeLinePosition(index: 1, offset: 0), + ); + expect( + position.copyWith(affinity: TextAffinity.upstream), + const CodeLinePosition( + index: 1, + offset: 2, + affinity: TextAffinity.upstream, + ), + ); + expect( + position.copyWith( + index: 0, + offset: 0, + affinity: TextAffinity.downstream, + ), + const CodeLinePosition(index: 0, offset: 0), + ); }); }); @@ -76,15 +66,15 @@ void main() { index: 1, position: const TextPosition( offset: 2, - affinity: TextAffinity.upstream - ) + affinity: TextAffinity.upstream, + ), ); final CodeLinePosition position2 = CodeLinePosition.from( index: 1, position: const TextPosition( offset: 2, - affinity: TextAffinity.upstream - ) + affinity: TextAffinity.upstream, + ), ); expect(position1, position2); } @@ -93,18 +83,18 @@ void main() { index: 1, position: const TextPosition( offset: 1, - affinity: TextAffinity.upstream - ) + affinity: TextAffinity.upstream, + ), ); final CodeLinePosition position2 = CodeLinePosition.from( index: 2, position: const TextPosition( offset: 2, - affinity: TextAffinity.upstream - ) + affinity: TextAffinity.upstream, + ), ); expect(position1 == position2, false); } }); }); -} \ No newline at end of file +} diff --git a/test/code_line_range_test.dart b/test/code_line_range_test.dart index 0558ce0..f4da1c5 100644 --- a/test/code_line_range_test.dart +++ b/test/code_line_range_test.dart @@ -5,11 +5,7 @@ import 'package:re_editor/re_editor.dart'; void main() { group('CodeLineRange constructor ', () { test('`CodeLineRange()`', () { - const CodeLineRange range = CodeLineRange( - index: 1, - start: 2, - end: 3 - ); + const CodeLineRange range = CodeLineRange(index: 1, start: 2, end: 3); expect(range.index, 1); expect(range.start, 2); expect(range.end, 3); @@ -18,10 +14,7 @@ void main() { test('`CodeLineRange.from()`', () { final CodeLineRange range = CodeLineRange.from( index: 1, - range: const TextRange( - start: 2, - end: 3 - ) + range: const TextRange(start: 2, end: 3), ); expect(range.index, 1); expect(range.start, 2); @@ -29,10 +22,7 @@ void main() { }); test('`CodeLineRange.collapsed()`', () { - const CodeLineRange range = CodeLineRange.collapsed( - index: 1, - offset: 2 - ); + const CodeLineRange range = CodeLineRange.collapsed(index: 1, offset: 2); expect(range.index, 1); expect(range.start, 2); expect(range.end, 2); @@ -48,42 +38,24 @@ void main() { group('CodeLineRange method ', () { test('`copyWith`', () { - const CodeLineRange range = CodeLineRange( - index: 1, - start: 2, - end: 3 - ); + const CodeLineRange range = CodeLineRange(index: 1, start: 2, end: 3); expect(range.copyWith(), range); - expect(range.copyWith( - index: 0 - ), const CodeLineRange( - index: 0, - start: 2, - end: 3 - )); - expect(range.copyWith( - start: 0 - ), const CodeLineRange( - index: 1, - start: 0, - end: 3 - )); - expect(range.copyWith( - end: 0 - ), const CodeLineRange( - index: 1, - start: 2, - end: 0 - )); - expect(range.copyWith( - index: 0, - start: 0, - end: 0 - ), const CodeLineRange( - index: 0, - start: 0, - end: 0 - )); + expect( + range.copyWith(index: 0), + const CodeLineRange(index: 0, start: 2, end: 3), + ); + expect( + range.copyWith(start: 0), + const CodeLineRange(index: 1, start: 0, end: 3), + ); + expect( + range.copyWith(end: 0), + const CodeLineRange(index: 1, start: 2, end: 0), + ); + expect( + range.copyWith(index: 0, start: 0, end: 0), + const CodeLineRange(index: 0, start: 0, end: 0), + ); }); }); @@ -92,37 +64,25 @@ void main() { { final CodeLineRange range1 = CodeLineRange.from( index: 1, - range: const TextRange( - start: 2, - end: 3 - ) + range: const TextRange(start: 2, end: 3), ); final CodeLineRange range2 = CodeLineRange.from( index: 1, - range: const TextRange( - start: 2, - end: 3 - ) + range: const TextRange(start: 2, end: 3), ); expect(range1, range2); } { final CodeLineRange range1 = CodeLineRange.from( index: 1, - range: const TextRange( - start: 2, - end: 3 - ) + range: const TextRange(start: 2, end: 3), ); final CodeLineRange range2 = CodeLineRange.from( index: 2, - range: const TextRange( - start: 2, - end: 3 - ) + range: const TextRange(start: 2, end: 3), ); expect(range1 == range2, false); } }); }); -} \ No newline at end of file +} diff --git a/test/code_line_selection_test.dart b/test/code_line_selection_test.dart index 69920e8..20532c8 100644 --- a/test/code_line_selection_test.dart +++ b/test/code_line_selection_test.dart @@ -10,7 +10,7 @@ void main() { baseOffset: 2, extentIndex: 3, extentOffset: 4, - baseAffinity: TextAffinity.upstream + baseAffinity: TextAffinity.upstream, ); expect(selection.baseIndex, 1); expect(selection.baseOffset, 2); @@ -22,7 +22,7 @@ void main() { const CodeLineSelection selection = CodeLineSelection.collapsed( index: 1, offset: 2, - affinity: TextAffinity.upstream + affinity: TextAffinity.upstream, ); expect(selection.baseIndex, 1); expect(selection.baseOffset, 2); @@ -35,8 +35,8 @@ void main() { position: const CodeLinePosition( index: 1, offset: 2, - affinity: TextAffinity.upstream - ) + affinity: TextAffinity.upstream, + ), ); expect(selection.baseIndex, 1); expect(selection.baseOffset, 2); @@ -46,11 +46,7 @@ void main() { }); test('`CodeLineSelection.fromRange()`', () { final CodeLineSelection selection = CodeLineSelection.fromRange( - range: const CodeLineRange( - index: 1, - start: 2, - end: 3 - ) + range: const CodeLineRange(index: 1, start: 2, end: 3), ); expect(selection.baseIndex, 1); expect(selection.baseOffset, 2); @@ -64,8 +60,8 @@ void main() { selection: const TextSelection( baseOffset: 2, extentOffset: 3, - affinity: TextAffinity.upstream - ) + affinity: TextAffinity.upstream, + ), ); expect(selection.baseIndex, 1); expect(selection.baseOffset, 2); @@ -93,11 +89,7 @@ void main() { extentIndex: 1, extentOffset: 1, ); - expect(selection.base, const CodeLinePosition( - index: 0, - offset: 0, - affinity: TextAffinity.downstream - )); + expect(selection.base, const CodeLinePosition(index: 0, offset: 0)); } // Multi code line selected and base after extent { @@ -107,11 +99,7 @@ void main() { baseIndex: 1, baseOffset: 1, ); - expect(selection.base, const CodeLinePosition( - index: 1, - offset: 1, - affinity: TextAffinity.downstream - )); + expect(selection.base, const CodeLinePosition(index: 1, offset: 1)); } // Single code line selected and base before extent { @@ -121,11 +109,7 @@ void main() { extentIndex: 0, extentOffset: 1, ); - expect(selection.base, const CodeLinePosition( - index: 0, - offset: 0, - affinity: TextAffinity.downstream - )); + expect(selection.base, const CodeLinePosition(index: 0, offset: 0)); } // Single code line selected and base after extent { @@ -135,37 +119,31 @@ void main() { baseIndex: 0, baseOffset: 1, ); - expect(selection.base, const CodeLinePosition( - index: 0, - offset: 1, - affinity: TextAffinity.downstream - )); + expect(selection.base, const CodeLinePosition(index: 0, offset: 1)); } // collapsed and upstream { const CodeLineSelection selection = CodeLineSelection.collapsed( index: 0, offset: 0, - affinity: TextAffinity.upstream + affinity: TextAffinity.upstream, + ); + expect( + selection.base, + const CodeLinePosition( + index: 0, + offset: 0, + affinity: TextAffinity.upstream, + ), ); - expect(selection.base, const CodeLinePosition( - index: 0, - offset: 0, - affinity: TextAffinity.upstream - )); } // collapsed and downstream { const CodeLineSelection selection = CodeLineSelection.collapsed( index: 0, offset: 0, - affinity: TextAffinity.downstream ); - expect(selection.base, const CodeLinePosition( - index: 0, - offset: 0, - affinity: TextAffinity.downstream - )); + expect(selection.base, const CodeLinePosition(index: 0, offset: 0)); } }); @@ -178,11 +156,7 @@ void main() { extentIndex: 1, extentOffset: 1, ); - expect(selection.extent, const CodeLinePosition( - index: 1, - offset: 1, - affinity: TextAffinity.downstream - )); + expect(selection.extent, const CodeLinePosition(index: 1, offset: 1)); } // Multi code line selected and base after extent { @@ -192,11 +166,7 @@ void main() { baseIndex: 1, baseOffset: 1, ); - expect(selection.extent, const CodeLinePosition( - index: 0, - offset: 0, - affinity: TextAffinity.downstream - )); + expect(selection.extent, const CodeLinePosition(index: 0, offset: 0)); } // Single code line selected and base before extent { @@ -206,11 +176,7 @@ void main() { extentIndex: 0, extentOffset: 1, ); - expect(selection.extent, const CodeLinePosition( - index: 0, - offset: 1, - affinity: TextAffinity.downstream - )); + expect(selection.extent, const CodeLinePosition(index: 0, offset: 1)); } // Single code line selected and base after extent { @@ -220,37 +186,31 @@ void main() { baseIndex: 0, baseOffset: 1, ); - expect(selection.extent, const CodeLinePosition( - index: 0, - offset: 0, - affinity: TextAffinity.downstream - )); + expect(selection.extent, const CodeLinePosition(index: 0, offset: 0)); } // collapsed and upstream { const CodeLineSelection selection = CodeLineSelection.collapsed( index: 0, offset: 0, - affinity: TextAffinity.upstream + affinity: TextAffinity.upstream, + ); + expect( + selection.extent, + const CodeLinePosition( + index: 0, + offset: 0, + affinity: TextAffinity.upstream, + ), ); - expect(selection.extent, const CodeLinePosition( - index: 0, - offset: 0, - affinity: TextAffinity.upstream - )); } // collapsed and downstream { const CodeLineSelection selection = CodeLineSelection.collapsed( index: 0, offset: 0, - affinity: TextAffinity.downstream ); - expect(selection.extent, const CodeLinePosition( - index: 0, - offset: 0, - affinity: TextAffinity.downstream - )); + expect(selection.extent, const CodeLinePosition(index: 0, offset: 0)); } }); @@ -509,13 +469,15 @@ void main() { { const CodeLineSelection selection = CodeLineSelection.collapsed( index: 0, - offset: 0 + offset: 0, ); expect(selection.contains(selection), true); - expect(selection.contains(const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )), false); + expect( + selection.contains( + const CodeLineSelection.collapsed(index: 0, offset: 1), + ), + false, + ); } // Single code line { @@ -526,20 +488,29 @@ void main() { extentOffset: 3, ); expect(selection.contains(selection), true); - expect(selection.contains(const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )), true); - expect(selection.contains(const CodeLineSelection.collapsed( - index: 0, - offset: 4 - )), false); - expect(selection.contains(const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 1 - )), true); + expect( + selection.contains( + const CodeLineSelection.collapsed(index: 0, offset: 1), + ), + true, + ); + expect( + selection.contains( + const CodeLineSelection.collapsed(index: 0, offset: 4), + ), + false, + ); + expect( + selection.contains( + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: 1, + ), + ), + true, + ); } // Multi code line { @@ -550,32 +521,51 @@ void main() { extentOffset: 3, ); expect(selection.contains(selection), true); - expect(selection.contains(const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )), true); - expect(selection.contains(const CodeLineSelection.collapsed( - index: 0, - offset: 4 - )), true); - expect(selection.contains(const CodeLineSelection( - baseIndex: 1, - baseOffset: 0, - extentIndex: 1, - extentOffset: 1000 - )), true); - expect(selection.contains(const CodeLineSelection( - baseIndex: 1, - baseOffset: 0, - extentIndex: 2, - extentOffset: 1000 - )), true); - expect(selection.contains(const CodeLineSelection( - baseIndex: 1, - baseOffset: 0, - extentIndex: 3, - extentOffset: 1000 - )), false); + expect( + selection.contains( + const CodeLineSelection.collapsed(index: 0, offset: 1), + ), + true, + ); + expect( + selection.contains( + const CodeLineSelection.collapsed(index: 0, offset: 4), + ), + true, + ); + expect( + selection.contains( + const CodeLineSelection( + baseIndex: 1, + baseOffset: 0, + extentIndex: 1, + extentOffset: 1000, + ), + ), + true, + ); + expect( + selection.contains( + const CodeLineSelection( + baseIndex: 1, + baseOffset: 0, + extentIndex: 2, + extentOffset: 1000, + ), + ), + true, + ); + expect( + selection.contains( + const CodeLineSelection( + baseIndex: 1, + baseOffset: 0, + extentIndex: 3, + extentOffset: 1000, + ), + ), + false, + ); } }); @@ -587,61 +577,70 @@ void main() { extentOffset: 3, ); expect(selection.copyWith(), selection); - expect(selection.copyWith( - baseIndex: 3, - baseOffset: 3, - extentIndex: 0, - extentOffset: 0, - baseAffinity: TextAffinity.upstream, - extentAffinity: TextAffinity.upstream - ), const CodeLineSelection( - baseIndex: 3, - baseOffset: 3, - extentIndex: 0, - extentOffset: 0, - baseAffinity: TextAffinity.upstream, - extentAffinity: TextAffinity.upstream - )); - expect(selection.copyWith( - baseIndex: 3, - baseAffinity: TextAffinity.upstream - ), const CodeLineSelection( - baseIndex: 3, - baseOffset: 0, - extentIndex: 3, - extentOffset: 3, - baseAffinity: TextAffinity.upstream - )); - expect(selection.copyWith( - baseOffset: 3, - baseAffinity: TextAffinity.upstream - ), const CodeLineSelection( - baseIndex: 0, - baseOffset: 3, - extentIndex: 3, - extentOffset: 3, - baseAffinity: TextAffinity.upstream - )); - expect(selection.copyWith( - extentIndex: 0, - extentAffinity: TextAffinity.upstream - ), const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 3, - extentAffinity: TextAffinity.upstream - )); - expect(selection.copyWith( - extentOffset: 0, - extentAffinity: TextAffinity.upstream - ), const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 3, - extentOffset: 0, - extentAffinity: TextAffinity.upstream - )); + expect( + selection.copyWith( + baseIndex: 3, + baseOffset: 3, + extentIndex: 0, + extentOffset: 0, + baseAffinity: TextAffinity.upstream, + extentAffinity: TextAffinity.upstream, + ), + const CodeLineSelection( + baseIndex: 3, + baseOffset: 3, + extentIndex: 0, + extentOffset: 0, + baseAffinity: TextAffinity.upstream, + extentAffinity: TextAffinity.upstream, + ), + ); + expect( + selection.copyWith(baseIndex: 3, baseAffinity: TextAffinity.upstream), + const CodeLineSelection( + baseIndex: 3, + baseOffset: 0, + extentIndex: 3, + extentOffset: 3, + baseAffinity: TextAffinity.upstream, + ), + ); + expect( + selection.copyWith(baseOffset: 3, baseAffinity: TextAffinity.upstream), + const CodeLineSelection( + baseIndex: 0, + baseOffset: 3, + extentIndex: 3, + extentOffset: 3, + baseAffinity: TextAffinity.upstream, + ), + ); + expect( + selection.copyWith( + extentIndex: 0, + extentAffinity: TextAffinity.upstream, + ), + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: 3, + extentAffinity: TextAffinity.upstream, + ), + ); + expect( + selection.copyWith( + extentOffset: 0, + extentAffinity: TextAffinity.upstream, + ), + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 3, + extentOffset: 0, + extentAffinity: TextAffinity.upstream, + ), + ); }); }); -} \ No newline at end of file +} diff --git a/test/code_line_test.dart b/test/code_line_test.dart index 0a31e5a..2bb9059 100644 --- a/test/code_line_test.dart +++ b/test/code_line_test.dart @@ -15,7 +15,7 @@ void main() { { const CodeLine codeLine = CodeLine('abc', [ CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLine.length, 3); } @@ -29,7 +29,7 @@ void main() { { const CodeLine codeLine = CodeLine('abc', [ CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLine.chunkParent, true); } @@ -47,7 +47,7 @@ void main() { { const CodeLine codeLine = CodeLine('abc', [ CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLine.lineCount, 3); } @@ -58,7 +58,7 @@ void main() { CodeLine('inner1'), CodeLine('inner2'), CodeLine('inner3'), - ]) + ]), ]), CodeLine('bar', [ CodeLine('inner', [ @@ -66,7 +66,7 @@ void main() { CodeLine('inner5'), CodeLine('inner6'), CodeLine('inner7'), - ]) + ]), ]), ]); expect(codeLine.lineCount, 12); @@ -85,7 +85,7 @@ void main() { { const CodeLine codeLine = CodeLine('abc', [ CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLine.charCount, 9); } @@ -96,7 +96,7 @@ void main() { CodeLine('inner1'), CodeLine('inner2'), CodeLine('inner3'), - ]) + ]), ]), CodeLine('bar', [ CodeLine('inner', [ @@ -104,7 +104,7 @@ void main() { CodeLine('inner5'), CodeLine('inner6'), CodeLine('inner7'), - ]) + ]), ]), ]); expect(codeLine.charCount, 61); @@ -121,7 +121,7 @@ void main() { { const CodeLine codeLine = CodeLine('abc', [ CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLine.toString(), 'abc'); } @@ -137,7 +137,7 @@ void main() { { const CodeLine codeLine = CodeLine('abc', [ CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLine.asString(0, TextLineBreak.lf), 'abc\nfoo\nbar'); expect(codeLine.asString(0, TextLineBreak.crlf), 'abc\r\nfoo\r\nbar'); @@ -148,12 +148,12 @@ void main() { const CodeLine codeLine = CodeLine('abc', [ CodeLine('foo'), CodeLine('bar'), - CodeLine('123', [ - CodeLine('foo'), - CodeLine('bar'), - ]) + CodeLine('123', [CodeLine('foo'), CodeLine('bar')]), ]); - expect(codeLine.asString(0, TextLineBreak.lf), 'abc\nfoo\nbar\n123\nfoo\nbar'); + expect( + codeLine.asString(0, TextLineBreak.lf), + 'abc\nfoo\nbar\n123\nfoo\nbar', + ); } }); @@ -165,7 +165,7 @@ void main() { { const CodeLine codeLine = CodeLine('abc', [ CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLine.flat(), const ['abc', 'foo', 'bar']); } @@ -173,12 +173,16 @@ void main() { const CodeLine codeLine = CodeLine('abc', [ CodeLine('foo'), CodeLine('bar'), - CodeLine('123', [ - CodeLine('foo'), - CodeLine('bar'), - ]) + CodeLine('123', [CodeLine('foo'), CodeLine('bar')]), + ]); + expect(codeLine.flat(), const [ + 'abc', + 'foo', + 'bar', + '123', + 'foo', + 'bar', ]); - expect(codeLine.flat(), const ['abc', 'foo', 'bar', '123', 'foo', 'bar']); } }); @@ -190,31 +194,23 @@ void main() { { const CodeLine codeLine = CodeLine('abc', [ CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLine.copyWith(), codeLine); } { final CodeLine codeLine = const CodeLine('abc', [ CodeLine('foo'), - CodeLine('bar') - ]).copyWith( - text: '123', - ); + CodeLine('bar'), + ]).copyWith(text: '123'); expect(codeLine.text, '123'); - expect(codeLine.chunks, const [ - CodeLine('foo'), - CodeLine('bar') - ]); + expect(codeLine.chunks, const [CodeLine('foo'), CodeLine('bar')]); } { final CodeLine codeLine = const CodeLine('abc', [ CodeLine('foo'), - CodeLine('bar') - ]).copyWith( - text: '123', - chunks: const [] - ); + CodeLine('bar'), + ]).copyWith(text: '123', chunks: const []); expect(codeLine.text, '123'); expect(codeLine.chunks, const []); } @@ -231,36 +227,36 @@ void main() { { final CodeLine codeLine1 = CodeLine('abc' * 1, [ CodeLine('foo' * 1), - CodeLine('bar' * 1) + CodeLine('bar' * 1), ]); final CodeLine codeLine2 = CodeLine('abc' * 1, [ CodeLine('foo' * 1), - CodeLine('bar' * 1) + CodeLine('bar' * 1), ]); expect(codeLine1, codeLine2); } { final CodeLine codeLine1 = CodeLine('abc' * 1, [ const CodeLine('foo'), - const CodeLine('bar') + const CodeLine('bar'), ]); final CodeLine codeLine2 = CodeLine('abc' * 2, [ const CodeLine('foo'), - const CodeLine('bar') + const CodeLine('bar'), ]); expect(codeLine1 == codeLine2, false); } { final CodeLine codeLine1 = CodeLine('abc' * 1, [ CodeLine('foo' * 1), - CodeLine('bar' * 1) + CodeLine('bar' * 1), ]); final CodeLine codeLine2 = CodeLine('abc' * 1, [ CodeLine('foo' * 2), - CodeLine('bar' * 2) + CodeLine('bar' * 2), ]); expect(codeLine1 == codeLine2, false); } }); }); -} \ No newline at end of file +} diff --git a/test/code_lines_test.dart b/test/code_lines_test.dart index 44e1f38..8ddc019 100644 --- a/test/code_lines_test.dart +++ b/test/code_lines_test.dart @@ -12,22 +12,17 @@ void main() { { const CodeLines codeLines = CodeLines([ CodeLineSegment( - codeLines: [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar') - ] - ) + codeLines: [CodeLine('abc'), CodeLine('foo'), CodeLine('bar')], + ), ]); - expect(listEquals(codeLines.segments, const [ - CodeLineSegment( - codeLines: [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar') - ] - ) - ]), true); + expect( + listEquals(codeLines.segments, const [ + CodeLineSegment( + codeLines: [CodeLine('abc'), CodeLine('foo'), CodeLine('bar')], + ), + ]), + true, + ); } }); @@ -45,20 +40,21 @@ void main() { final CodeLines codeLines = CodeLines.of(const [ CodeLine('abc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); - expect(listEquals(codeLines.segments, const [ - CodeLineSegment( - codeLines: [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar') - ] - ) - ]), true); + expect( + listEquals(codeLines.segments, const [ + CodeLineSegment( + codeLines: [CodeLine('abc'), CodeLine('foo'), CodeLine('bar')], + ), + ]), + true, + ); } { - final CodeLines codeLines = CodeLines.of(List.generate(512, (index) => CodeLine('$index'))); + final CodeLines codeLines = CodeLines.of( + List.generate(512, (index) => CodeLine('$index')), + ); expect(codeLines.segments.length, 2); for (int i = 0; i < codeLines.segments.length; i++) { expect(codeLines.segments[i].dirty, false); @@ -74,64 +70,39 @@ void main() { expect(listEquals(codeLines.segments, const []), true); } { - final CodeLines codeLines = CodeLines.from(const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar') - ] - ) - ])); - expect(listEquals(codeLines.segments, const [ - CodeLineSegment( - codeLines: [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar') - ], - dirty: true - ) - ]), true); + final CodeLines codeLines = CodeLines.from( + const CodeLines([ + CodeLineSegment( + codeLines: [CodeLine('abc'), CodeLine('foo'), CodeLine('bar')], + ), + ]), + ); + expect( + listEquals(codeLines.segments, const [ + CodeLineSegment( + codeLines: [CodeLine('abc'), CodeLine('foo'), CodeLine('bar')], + dirty: true, + ), + ]), + true, + ); } { - final CodeLines codeLines = CodeLines.from(const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc'), - ] - ), - CodeLineSegment( - codeLines: [ - CodeLine('foo'), - ] - ), - CodeLineSegment( - codeLines: [ - CodeLine('bar'), - ] - ) - ])); - expect(listEquals(codeLines.segments, const [ - CodeLineSegment( - codeLines: [ - CodeLine('abc'), - ], - dirty: true - ), - CodeLineSegment( - codeLines: [ - CodeLine('foo'), - ], - dirty: true - ), - CodeLineSegment( - codeLines: [ - CodeLine('bar'), - ], - dirty: true - ) - ]), true); + final CodeLines codeLines = CodeLines.from( + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('abc')]), + CodeLineSegment(codeLines: [CodeLine('foo')]), + CodeLineSegment(codeLines: [CodeLine('bar')]), + ]), + ); + expect( + listEquals(codeLines.segments, const [ + CodeLineSegment(codeLines: [CodeLine('abc')], dirty: true), + CodeLineSegment(codeLines: [CodeLine('foo')], dirty: true), + CodeLineSegment(codeLines: [CodeLine('bar')], dirty: true), + ]), + true, + ); } }); }); @@ -144,9 +115,7 @@ void main() { expect(() => codeLines.last, throwsA(isA())); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); expect(codeLines.first, const CodeLine('abc')); expect(codeLines.last, const CodeLine('abc')); } @@ -154,13 +123,15 @@ void main() { final CodeLines codeLines = CodeLines.of(const [ CodeLine('abc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLines.first, const CodeLine('abc')); expect(codeLines.last, const CodeLine('bar')); } { - final CodeLines codeLines = CodeLines.of(List.generate(3000, (index) => CodeLine('$index'))); + final CodeLines codeLines = CodeLines.of( + List.generate(3000, (index) => CodeLine('$index')), + ); expect(codeLines.first, const CodeLine('0')); expect(codeLines.last, const CodeLine('2999')); } @@ -172,21 +143,21 @@ void main() { expect(codeLines.length, 0); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); expect(codeLines.length, 1); } { final CodeLines codeLines = CodeLines.of(const [ CodeLine('abc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLines.length, 3); } { - final CodeLines codeLines = CodeLines.of(List.generate(3000, (index) => CodeLine('$index'))); + final CodeLines codeLines = CodeLines.of( + List.generate(3000, (index) => CodeLine('$index')), + ); expect(codeLines.length, 3000); } }); @@ -198,9 +169,7 @@ void main() { expect(codeLines.isNotEmpty, false); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); expect(codeLines.isEmpty, false); expect(codeLines.isNotEmpty, true); } @@ -208,13 +177,15 @@ void main() { final CodeLines codeLines = CodeLines.of(const [ CodeLine('abc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLines.isEmpty, false); expect(codeLines.isNotEmpty, true); } { - final CodeLines codeLines = CodeLines.of(List.generate(3000, (index) => CodeLine('$index'))); + final CodeLines codeLines = CodeLines.of( + List.generate(3000, (index) => CodeLine('$index')), + ); expect(codeLines.isEmpty, false); expect(codeLines.isNotEmpty, true); } @@ -226,41 +197,29 @@ void main() { expect(codeLines.lineCount, 0); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); expect(codeLines.lineCount, 1); } { final CodeLines codeLines = CodeLines.of(const [ CodeLine('abc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLines.lineCount, 3); } { final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('123'), - CodeLine('456'), - CodeLine('789'), - ]), - CodeLine('foo', [ - CodeLine('123'), - CodeLine('456'), - CodeLine('789'), - ]), - CodeLine('bar', [ - CodeLine('123'), - CodeLine('456'), - CodeLine('789'), - ]) + CodeLine('abc', [CodeLine('123'), CodeLine('456'), CodeLine('789')]), + CodeLine('foo', [CodeLine('123'), CodeLine('456'), CodeLine('789')]), + CodeLine('bar', [CodeLine('123'), CodeLine('456'), CodeLine('789')]), ]); expect(codeLines.lineCount, 12); } { - final CodeLines codeLines = CodeLines.of(List.generate(3000, (index) => CodeLine('$index'))); + final CodeLines codeLines = CodeLines.of( + List.generate(3000, (index) => CodeLine('$index')), + ); expect(codeLines.lineCount, 3000); } }); @@ -273,9 +232,7 @@ void main() { expect(() => codeLines[0], throwsA(isA())); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); expect(codeLines[0], const CodeLine('abc')); expect(() => codeLines[1], throwsA(isA())); } @@ -283,7 +240,7 @@ void main() { final CodeLines codeLines = CodeLines.of(const [ CodeLine('abc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLines[0], const CodeLine('abc')); expect(codeLines[1], const CodeLine('foo')); @@ -291,7 +248,9 @@ void main() { expect(() => codeLines[3], throwsA(isA())); } { - final CodeLines codeLines = CodeLines.of(List.generate(3000, (index) => CodeLine('$index'))); + final CodeLines codeLines = CodeLines.of( + List.generate(3000, (index) => CodeLine('$index')), + ); expect(codeLines[0], const CodeLine('0')); expect(codeLines[1024], const CodeLine('1024')); expect(codeLines[2047], const CodeLine('2047')); @@ -303,21 +262,25 @@ void main() { test('`[]=`', () { { final CodeLines codeLines = CodeLines.empty(); - expect(() => codeLines[0] = const CodeLine('abc'), throwsA(isA())); + expect( + () => codeLines[0] = const CodeLine('abc'), + throwsA(isA()), + ); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); codeLines[0] = const CodeLine('foo'); expect(codeLines[0], const CodeLine('foo')); - expect(() => codeLines[1] = const CodeLine('abc'), throwsA(isA())); + expect( + () => codeLines[1] = const CodeLine('abc'), + throwsA(isA()), + ); } { final CodeLines codeLines = CodeLines.of(const [ CodeLine('abc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); codeLines[0] = const CodeLine('123'); expect(codeLines[0], const CodeLine('123')); @@ -327,7 +290,9 @@ void main() { expect(codeLines[2], const CodeLine('789')); } { - final CodeLines codeLines = CodeLines.of(List.generate(3000, (index) => CodeLine('$index'))); + final CodeLines codeLines = CodeLines.of( + List.generate(3000, (index) => CodeLine('$index')), + ); codeLines[0] = const CodeLine('a'); expect(codeLines[0], const CodeLine('a')); codeLines[1024] = const CodeLine('b'); @@ -343,10 +308,10 @@ void main() { codeLines: List.of(const [ CodeLine('abc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]), - dirty: true - ) + dirty: true, + ), ]); codeLines[0] = const CodeLine('a'); expect(codeLines.segments.last.dirty, false); @@ -355,8 +320,8 @@ void main() { final CodeLines codeLines = CodeLines([ CodeLineSegment( codeLines: List.generate(1024, (index) => CodeLine('$index')), - dirty: true - ) + dirty: true, + ), ]); codeLines[1023] = const CodeLine('a'); expect(codeLines[1023], const CodeLine('a')); @@ -366,99 +331,52 @@ void main() { test('`==`', () { expect(CodeLines.empty() == CodeLines.empty(), true); - expect(CodeLines.empty() == CodeLines.of(const [ - CodeLine('abc') - ]), false); - expect(CodeLines.of(const [ - CodeLine('abc') - ]) == CodeLines.of(const [ - CodeLine('abc') - ]), true); - expect(CodeLines.of(const [ - CodeLine('foo') - ]) == CodeLines.of(const [ - CodeLine('abc') - ]), false); - expect(const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc') - ] - ) - ]) == const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc') - ] - ) - ]), true); - expect(const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc') - ] - ), - CodeLineSegment( - codeLines: [ - CodeLine('foo') - ] - ), - CodeLineSegment( - codeLines: [ - CodeLine('bar') - ] - ) - ]) == const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc') - ] - ), - CodeLineSegment( - codeLines: [ - CodeLine('foo') - ] - ), - CodeLineSegment( - codeLines: [ - CodeLine('bar') - ] - ) - ]), true); - expect(const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc') - ], - dirty: true - ), - CodeLineSegment( - codeLines: [ - CodeLine('foo') - ] - ), - CodeLineSegment( - codeLines: [ - CodeLine('bar') - ] - ) - ]) == const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc') - ] - ), - CodeLineSegment( - codeLines: [ - CodeLine('foo') - ] - ), - CodeLineSegment( - codeLines: [ - CodeLine('bar') - ] - ) - ]), false); + expect(CodeLines.empty() == CodeLines.of(const [CodeLine('abc')]), false); + expect( + CodeLines.of(const [CodeLine('abc')]) == + CodeLines.of(const [CodeLine('abc')]), + true, + ); + expect( + CodeLines.of(const [CodeLine('foo')]) == + CodeLines.of(const [CodeLine('abc')]), + false, + ); + expect( + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('abc')]), + ]) == + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('abc')]), + ]), + true, + ); + expect( + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('abc')]), + CodeLineSegment(codeLines: [CodeLine('foo')]), + CodeLineSegment(codeLines: [CodeLine('bar')]), + ]) == + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('abc')]), + CodeLineSegment(codeLines: [CodeLine('foo')]), + CodeLineSegment(codeLines: [CodeLine('bar')]), + ]), + true, + ); + expect( + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('abc')], dirty: true), + CodeLineSegment(codeLines: [CodeLine('foo')]), + CodeLineSegment(codeLines: [CodeLine('bar')]), + ]) == + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('abc')]), + CodeLineSegment(codeLines: [CodeLine('foo')]), + CodeLineSegment(codeLines: [CodeLine('bar')]), + ]), + false, + ); }); }); @@ -480,25 +398,24 @@ void main() { expect(codeLines.last, const CodeLine('bar')); } { - final CodeLines codeLines = CodeLines.of(List.generate(1024, (index) => CodeLine('$index'))); + final CodeLines codeLines = CodeLines.of( + List.generate(1024, (index) => CodeLine('$index')), + ); codeLines.add(const CodeLine('abc')); expect(codeLines.length, 1025); expect(codeLines.last, const CodeLine('abc')); expect(codeLines.segments.length, 5); - expect(codeLines.segments.last, const CodeLineSegment( - codeLines: [ - CodeLine('abc') - ] - )); + expect( + codeLines.segments.last, + const CodeLineSegment(codeLines: [CodeLine('abc')]), + ); } { final CodeLines codeLines = CodeLines([ CodeLineSegment( - codeLines: List.of(const [ - CodeLine('abc') - ]), - dirty: true - ) + codeLines: List.of(const [CodeLine('abc')]), + dirty: true, + ), ]); codeLines.add(const CodeLine('foo')); codeLines.add(const CodeLine('bar')); @@ -512,44 +429,35 @@ void main() { test('`addAll()`', () { { final CodeLines codeLines = CodeLines.empty(); - codeLines.addAll(const [ - CodeLine('abc') - ]); + codeLines.addAll(const [CodeLine('abc')]); expect(codeLines.length, 1); expect(codeLines.first, const CodeLine('abc')); expect(codeLines.last, const CodeLine('abc')); - codeLines.addAll(const [ - CodeLine('foo'), - CodeLine('bar') - ]); + codeLines.addAll(const [CodeLine('foo'), CodeLine('bar')]); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); codeLines.addAll(List.generate(512, (index) => CodeLine('$index'))); expect(codeLines.length, 513); expect(codeLines.last, const CodeLine('511')); expect(codeLines.segments.length, 3); - expect(codeLines.segments[0].length, 256); + expect(codeLines.segments.first.length, 256); expect(codeLines.segments[1].length, 256); expect(codeLines.segments[2].length, 1); } { final CodeLines codeLines = CodeLines([ CodeLineSegment( - codeLines: List.of(const [ - CodeLine('abc') - ]), - dirty: true - ) + codeLines: List.of(const [CodeLine('abc')]), + dirty: true, + ), ]); codeLines.addAll(List.generate(512, (index) => CodeLine('$index'))); expect(codeLines.length, 513); expect(codeLines.last, const CodeLine('511')); expect(codeLines.segments.length, 3); - expect(codeLines.segments[0].length, 256); - expect(codeLines.segments[0].dirty, false); + expect(codeLines.segments.first.length, 256); + expect(codeLines.segments.first.dirty, false); expect(codeLines.segments[1].length, 256); expect(codeLines.segments[1].dirty, false); expect(codeLines.segments[2].length, 1); @@ -560,124 +468,95 @@ void main() { test('`addFrom()`', () { { final CodeLines codeLines1 = CodeLines.empty(); - final CodeLines codeLines2 = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines2 = CodeLines.of(const [CodeLine('abc')]); codeLines1.addFrom(codeLines2, 0); - expect(listEquals(codeLines1.segments, const [ - CodeLineSegment( - codeLines: [ - CodeLine('abc') - ], - dirty: true - ) - ]), true); + expect( + listEquals(codeLines1.segments, const [ + CodeLineSegment(codeLines: [CodeLine('abc')], dirty: true), + ]), + true, + ); } { const CodeLines codeLines1 = CodeLines([ CodeLineSegment( - codeLines: [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar') - ], - ) + codeLines: [CodeLine('abc'), CodeLine('foo'), CodeLine('bar')], + ), ]); final CodeLines codeLines2 = CodeLines([ - CodeLineSegment( - codeLines: List.of([ - const CodeLine('123'), - ]), - ) + CodeLineSegment(codeLines: List.of([const CodeLine('123')])), ]); codeLines2.addFrom(codeLines1, 1, 2); - expect(listEquals(codeLines2.segments, const [ - CodeLineSegment( - codeLines: [ - CodeLine('123'), - CodeLine('foo') - ], - ), - ]), true); + expect( + listEquals(codeLines2.segments, const [ + CodeLineSegment(codeLines: [CodeLine('123'), CodeLine('foo')]), + ]), + true, + ); codeLines2.addFrom(codeLines1, 0); - expect(listEquals(codeLines2.segments, const [ - CodeLineSegment( - codeLines: [ - CodeLine('123'), - CodeLine('foo'), - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar') - ], - ), - ]), true); + expect( + listEquals(codeLines2.segments, const [ + CodeLineSegment( + codeLines: [ + CodeLine('123'), + CodeLine('foo'), + CodeLine('abc'), + CodeLine('foo'), + CodeLine('bar'), + ], + ), + ]), + true, + ); } { - final CodeLines codeLines1 = CodeLines.of(const [ - CodeLine('abc') - ]); - final CodeLines codeLines2 = CodeLines.of(List.generate(512, (index) => CodeLine('$index'))); + final CodeLines codeLines1 = CodeLines.of(const [CodeLine('abc')]); + final CodeLines codeLines2 = CodeLines.of( + List.generate(512, (index) => CodeLine('$index')), + ); codeLines1.addFrom(codeLines2, 0); - expect(listEquals(codeLines1.segments, [ - const CodeLineSegment( - codeLines: [ - CodeLine('abc') - ], - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('$index')), - dirty: true - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 256}')), - dirty: true - ), - ]), true); + expect( + listEquals(codeLines1.segments, [ + const CodeLineSegment(codeLines: [CodeLine('abc')]), + CodeLineSegment( + codeLines: List.generate(256, (index) => CodeLine('$index')), + dirty: true, + ), + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 256}'), + ), + dirty: true, + ), + ]), + true, + ); } { - final CodeLines codeLines1 = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines1 = CodeLines.of(const [CodeLine('abc')]); final CodeLines codeLines2 = CodeLines([ - const CodeLineSegment( - codeLines: [ - CodeLine('foo') - ], - ), - const CodeLineSegment( - codeLines: [ - CodeLine('bar') - ], - ), + const CodeLineSegment(codeLines: [CodeLine('foo')]), + const CodeLineSegment(codeLines: [CodeLine('bar')]), CodeLineSegment( codeLines: List.generate(256, (index) => CodeLine('$index')), ), - const CodeLineSegment( - codeLines: [ - CodeLine('abc') - ], - ), + const CodeLineSegment(codeLines: [CodeLine('abc')]), ]); codeLines1.addFrom(codeLines2, 0); - expect(listEquals(codeLines1.segments, [ - const CodeLineSegment( - codeLines: [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - ], - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('$index')), - dirty: true - ), - const CodeLineSegment( - codeLines: [ - CodeLine('abc') - ], - dirty: true - ), - ]), true); + expect( + listEquals(codeLines1.segments, [ + const CodeLineSegment( + codeLines: [CodeLine('abc'), CodeLine('foo'), CodeLine('bar')], + ), + CodeLineSegment( + codeLines: List.generate(256, (index) => CodeLine('$index')), + dirty: true, + ), + const CodeLineSegment(codeLines: [CodeLine('abc')], dirty: true), + ]), + true, + ); } }); @@ -687,16 +566,14 @@ void main() { expect(codeLines.asString(TextLineBreak.lf), ''); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); expect(codeLines.asString(TextLineBreak.lf), 'abc'); } { final CodeLines codeLines = CodeLines.of(const [ CodeLine('abc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLines.asString(TextLineBreak.lf), 'abc\nfoo\nbar'); expect(codeLines.asString(TextLineBreak.crlf), 'abc\r\nfoo\r\nbar'); @@ -704,81 +581,84 @@ void main() { } { final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('123'), - CodeLine('456'), - CodeLine('789'), - ]), - CodeLine('foo', [ - CodeLine('123'), - CodeLine('456'), - CodeLine('789'), - ]), - CodeLine('bar', [ - CodeLine('123'), - CodeLine('456'), - CodeLine('789'), - ]) - ]); - expect(codeLines.asString(TextLineBreak.lf), 'abc\n123\n456\n789\nfoo\n123\n456\n789\nbar\n123\n456\n789'); - expect(codeLines.asString(TextLineBreak.crlf), 'abc\r\n123\r\n456\r\n789\r\nfoo\r\n123\r\n456\r\n789\r\nbar\r\n123\r\n456\r\n789'); - expect(codeLines.asString(TextLineBreak.cr), 'abc\r123\r456\r789\rfoo\r123\r456\r789\rbar\r123\r456\r789'); + CodeLine('abc', [CodeLine('123'), CodeLine('456'), CodeLine('789')]), + CodeLine('foo', [CodeLine('123'), CodeLine('456'), CodeLine('789')]), + CodeLine('bar', [CodeLine('123'), CodeLine('456'), CodeLine('789')]), + ]); + expect( + codeLines.asString(TextLineBreak.lf), + 'abc\n123\n456\n789\nfoo\n123\n456\n789\nbar\n123\n456\n789', + ); + expect( + codeLines.asString(TextLineBreak.crlf), + 'abc\r\n123\r\n456\r\n789\r\nfoo\r\n123\r\n456\r\n789\r\nbar\r\n123\r\n456\r\n789', + ); + expect( + codeLines.asString(TextLineBreak.cr), + 'abc\r123\r456\r789\rfoo\r123\r456\r789\rbar\r123\r456\r789', + ); expect(codeLines.asString(TextLineBreak.lf, false), 'abc\nfoo\nbar'); } }); test('`equals()`', () { expect(CodeLines.empty().equals(CodeLines.empty()), true); - expect(CodeLines.empty().equals(CodeLines.of(const [ - CodeLine('abc') - ])), false); - expect(CodeLines.of(const [ - CodeLine('abc') - ]).equals(CodeLines.empty()), false); - expect(CodeLines.of(const [ - CodeLine('abc') - ]).equals(CodeLines.of(const [ - CodeLine('abc') - ])), true); - expect(CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar') - ]).equals(CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar') - ])), true); - expect(CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar') - ]).equals(CodeLines.of(const [ - CodeLine('abc'), - CodeLine('bar'), - CodeLine('foo'), - ])), false); - expect(const CodeLines([ - CodeLineSegment( - codeLines: [ + expect( + CodeLines.empty().equals(CodeLines.of(const [CodeLine('abc')])), + false, + ); + expect( + CodeLines.of(const [CodeLine('abc')]).equals(CodeLines.empty()), + false, + ); + expect( + CodeLines.of(const [ + CodeLine('abc'), + ]).equals(CodeLines.of(const [CodeLine('abc')])), + true, + ); + expect( + CodeLines.of(const [ + CodeLine('abc'), + CodeLine('foo'), + CodeLine('bar'), + ]).equals( + CodeLines.of(const [ CodeLine('abc'), - ], + CodeLine('foo'), + CodeLine('bar'), + ]), ), - CodeLineSegment( - codeLines: [ + true, + ); + expect( + CodeLines.of(const [ + CodeLine('abc'), + CodeLine('foo'), + CodeLine('bar'), + ]).equals( + CodeLines.of(const [ + CodeLine('abc'), + CodeLine('bar'), CodeLine('foo'), - ], + ]), ), - CodeLineSegment( - codeLines: [ + false, + ); + expect( + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('abc')]), + CodeLineSegment(codeLines: [CodeLine('foo')]), + CodeLineSegment(codeLines: [CodeLine('bar')]), + ]).equals( + CodeLines.of(const [ + CodeLine('abc'), + CodeLine('foo'), CodeLine('bar'), - ], - ) - ]).equals(CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - ])), true); + ]), + ), + true, + ); }); test('`sublines()`', () { @@ -789,9 +669,7 @@ void main() { expect(() => codeLines.sublines(0, 1), throwsA(isA())); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); expect(codeLines.sublines(0).equals(codeLines), true); expect(codeLines.sublines(0) != codeLines, true); expect(codeLines.sublines(1), CodeLines.empty()); @@ -805,113 +683,149 @@ void main() { final CodeLines codeLines = CodeLines.of(const [ CodeLine('abc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); expect(codeLines.sublines(0).equals(codeLines), true); expect(codeLines.sublines(0) != codeLines, true); - expect(codeLines.sublines(1), const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('foo'), - CodeLine('bar') - ], - ) - ])); - expect(codeLines.sublines(0, 1), const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc'), - ], - ) - ])); - expect(codeLines.sublines(0, 2), const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc'), - CodeLine('foo'), - ], - ) - ])); - expect(codeLines.sublines(1, 2), const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('foo'), - ], - ) - ])); - expect(codeLines.sublines(2, 3), const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('bar'), - ], - ) - ])); - expect(codeLines.sublines(0, 3), const CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar') - ], - dirty: true - ) - ])); + expect( + codeLines.sublines(1), + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('foo'), CodeLine('bar')]), + ]), + ); + expect( + codeLines.sublines(0, 1), + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('abc')]), + ]), + ); + expect( + codeLines.sublines(0, 2), + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('abc'), CodeLine('foo')]), + ]), + ); + expect( + codeLines.sublines(1, 2), + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('foo')]), + ]), + ); + expect( + codeLines.sublines(2, 3), + const CodeLines([ + CodeLineSegment(codeLines: [CodeLine('bar')]), + ]), + ); + expect( + codeLines.sublines(0, 3), + const CodeLines([ + CodeLineSegment( + codeLines: [CodeLine('abc'), CodeLine('foo'), CodeLine('bar')], + dirty: true, + ), + ]), + ); expect(() => codeLines.sublines(4), throwsA(isA())); } { - final CodeLines codeLines = CodeLines.of(List.generate(3000, (index) => CodeLine('$index'))); - expect(codeLines.sublines(512, 1024 + 512), CodeLines([ - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 512}')), - dirty: true - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 512 + 256 * 1}')), - dirty: true - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 512 + 256 * 2}')), - dirty: true - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 512 + 256 * 3}')), - dirty: true - ) - ])); - expect(codeLines.sublines(512, 2048 + 512), CodeLines([ - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 512}')), - dirty: true - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 512 + 256 * 1}')), - dirty: true - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 512 + 256 * 2}')), - dirty: true - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 512 + 256 * 3}')), - dirty: true - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 512 + 256 * 4}')), - dirty: true - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 512 + 256 * 5}')), - dirty: true - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 512 + 256 * 6}')), - dirty: true - ), - CodeLineSegment( - codeLines: List.generate(256, (index) => CodeLine('${index + 512 + 256 * 7}')), - dirty: true - ) - ])); + final CodeLines codeLines = CodeLines.of( + List.generate(3000, (index) => CodeLine('$index')), + ); + expect( + codeLines.sublines(512, 1024 + 512), + CodeLines([ + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 512}'), + ), + dirty: true, + ), + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 512 + 256 * 1}'), + ), + dirty: true, + ), + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 512 + 256 * 2}'), + ), + dirty: true, + ), + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 512 + 256 * 3}'), + ), + dirty: true, + ), + ]), + ); + expect( + codeLines.sublines(512, 2048 + 512), + CodeLines([ + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 512}'), + ), + dirty: true, + ), + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 512 + 256 * 1}'), + ), + dirty: true, + ), + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 512 + 256 * 2}'), + ), + dirty: true, + ), + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 512 + 256 * 3}'), + ), + dirty: true, + ), + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 512 + 256 * 4}'), + ), + dirty: true, + ), + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 512 + 256 * 5}'), + ), + dirty: true, + ), + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 512 + 256 * 6}'), + ), + dirty: true, + ), + CodeLineSegment( + codeLines: List.generate( + 256, + (index) => CodeLine('${index + 512 + 256 * 7}'), + ), + dirty: true, + ), + ]), + ); } }); @@ -922,9 +836,7 @@ void main() { expect(codeLines.isEmpty, true); } { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); codeLines.clear(); expect(codeLines.isEmpty, true); } @@ -932,19 +844,17 @@ void main() { final CodeLines codeLines = CodeLines.of(const [ CodeLine('abc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), ]); codeLines.clear(); expect(codeLines.isEmpty, true); } }); - + test('`index2lineIndex()`', () { // Single code line { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); expect(codeLines.index2lineIndex(0), 0); expect(codeLines.index2lineIndex(1), -1); expect(codeLines.index2lineIndex(-1), -1); @@ -963,21 +873,9 @@ void main() { // Multi code lines in different segments { const CodeLines codeLines = CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc'), - ], - ), - CodeLineSegment( - codeLines: [ - CodeLine('foo'), - ], - ), - CodeLineSegment( - codeLines: [ - CodeLine('bar') - ], - ) + CodeLineSegment(codeLines: [CodeLine('abc')]), + CodeLineSegment(codeLines: [CodeLine('foo')]), + CodeLineSegment(codeLines: [CodeLine('bar')]), ]); expect(codeLines.index2lineIndex(0), 0); expect(codeLines.index2lineIndex(1), 1); @@ -1006,9 +904,7 @@ void main() { test('`lineIndex2index()`', () { // Single code line { - final CodeLines codeLines = CodeLines.of(const [ - CodeLine('abc') - ]); + final CodeLines codeLines = CodeLines.of(const [CodeLine('abc')]); expect(codeLines.lineIndex2Index(0), const CodeLineIndex(0, -1)); expect(codeLines.lineIndex2Index(1), const CodeLineIndex(-1, -1)); expect(codeLines.lineIndex2Index(-1), const CodeLineIndex(-1, -1)); @@ -1027,21 +923,9 @@ void main() { // Multi code lines in different segments { const CodeLines codeLines = CodeLines([ - CodeLineSegment( - codeLines: [ - CodeLine('abc'), - ], - ), - CodeLineSegment( - codeLines: [ - CodeLine('foo'), - ], - ), - CodeLineSegment( - codeLines: [ - CodeLine('bar') - ], - ) + CodeLineSegment(codeLines: [CodeLine('abc')]), + CodeLineSegment(codeLines: [CodeLine('foo')]), + CodeLineSegment(codeLines: [CodeLine('bar')]), ]); expect(codeLines.lineIndex2Index(0), const CodeLineIndex(0, -1)); expect(codeLines.lineIndex2Index(1), const CodeLineIndex(1, -1)); @@ -1071,5 +955,4 @@ void main() { } }); }); - -} \ No newline at end of file +} diff --git a/test/code_search_controller_test.dart b/test/code_search_controller_test.dart index 0e5eecb..791a58f 100644 --- a/test/code_search_controller_test.dart +++ b/test/code_search_controller_test.dart @@ -6,19 +6,24 @@ void main() { group('CodeFindController getter ', () { test('`allMatchSelections`', () async { { - final CodeFindController controller = CodeFindController(CodeLineEditingController()); + final CodeFindController controller = CodeFindController( + CodeLineEditingController(), + ); expect(controller.allMatchSelections, null); controller.close(); } { - final CodeFindController controller = CodeFindController(CodeLineEditingController.fromText('abc'), const CodeFindValue( - option: CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false + final CodeFindController controller = CodeFindController( + CodeLineEditingController.fromText('abc'), + const CodeFindValue( + option: CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, + ), + replaceMode: false, ), - replaceMode: false - )); + ); expect(controller.allMatchSelections, null); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.allMatchSelections, const [ @@ -26,20 +31,23 @@ void main() { baseIndex: 0, baseOffset: 0, extentIndex: 0, - extentOffset: 1 - ) + extentOffset: 1, + ), ]); controller.close(); } { - final CodeFindController controller = CodeFindController(CodeLineEditingController.fromText('abc\nfoo\nbar'), const CodeFindValue( - option: CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false + final CodeFindController controller = CodeFindController( + CodeLineEditingController.fromText('abc\nfoo\nbar'), + const CodeFindValue( + option: CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, + ), + replaceMode: false, ), - replaceMode: false - )); + ); expect(controller.allMatchSelections, null); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.allMatchSelections, const [ @@ -47,41 +55,35 @@ void main() { baseIndex: 0, baseOffset: 0, extentIndex: 0, - extentOffset: 1 + extentOffset: 1, ), CodeLineSelection( baseIndex: 2, baseOffset: 1, extentIndex: 2, - extentOffset: 2 - ) + extentOffset: 2, + ), ]); controller.close(); } { - final CodeFindController controller = CodeFindController(CodeLineEditingController( - codeLines: CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar') + final CodeFindController controller = CodeFindController( + CodeLineEditingController( + codeLines: CodeLines.of(const [ + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar') - ]) - ]) - ), const CodeFindValue( - option: CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false ), - replaceMode: false - )); + const CodeFindValue( + option: CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, + ), + replaceMode: false, + ), + ); expect(controller.allMatchSelections, null); await Future.delayed(const Duration(milliseconds: 200)); expect(controller.allMatchSelections, const [ @@ -89,19 +91,19 @@ void main() { baseIndex: 0, baseOffset: 0, extentIndex: 0, - extentOffset: 1 + extentOffset: 1, ), CodeLineSelection( baseIndex: 1, baseOffset: 0, extentIndex: 1, - extentOffset: 1 + extentOffset: 1, ), CodeLineSelection( baseIndex: 2, baseOffset: 0, extentIndex: 2, - extentOffset: 1 + extentOffset: 1, ), ]); controller.close(); @@ -110,87 +112,101 @@ void main() { test('`currentMatchSelection`', () async { { - final CodeFindController controller = CodeFindController(CodeLineEditingController()); + final CodeFindController controller = CodeFindController( + CodeLineEditingController(), + ); expect(controller.currentMatchSelection, null); controller.close(); } { - final CodeFindController controller = CodeFindController(CodeLineEditingController.fromText('abc'), const CodeFindValue( - option: CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false + final CodeFindController controller = CodeFindController( + CodeLineEditingController.fromText('abc'), + const CodeFindValue( + option: CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, + ), + replaceMode: false, ), - replaceMode: false - )); + ); expect(controller.currentMatchSelection, null); await Future.delayed(const Duration(milliseconds: 200)); - expect(controller.currentMatchSelection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 1 - )); + expect( + controller.currentMatchSelection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: 1, + ), + ); controller.close(); } { - final CodeFindController controller = CodeFindController(CodeLineEditingController.fromText('abc\nfoo\nbar'), const CodeFindValue( - option: CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false + final CodeFindController controller = CodeFindController( + CodeLineEditingController.fromText('abc\nfoo\nbar'), + const CodeFindValue( + option: CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, + ), + replaceMode: false, ), - replaceMode: false - )); + ); expect(controller.currentMatchSelection, null); await Future.delayed(const Duration(milliseconds: 200)); - expect(controller.currentMatchSelection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 1 - )); + expect( + controller.currentMatchSelection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: 1, + ), + ); controller.nextMatch(); - expect(controller.currentMatchSelection, const CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - )); + expect( + controller.currentMatchSelection, + const CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ); controller.close(); } { - final CodeFindController controller = CodeFindController(CodeLineEditingController( - codeLines: CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar') + final CodeFindController controller = CodeFindController( + CodeLineEditingController( + codeLines: CodeLines.of(const [ + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar') - ]) - ]) - ), const CodeFindValue( - option: CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false ), - replaceMode: false - )); + const CodeFindValue( + option: CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, + ), + replaceMode: false, + ), + ); expect(controller.currentMatchSelection, null); await Future.delayed(const Duration(milliseconds: 200)); - expect(controller.currentMatchSelection, const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 1 - )); + expect( + controller.currentMatchSelection, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: 1, + ), + ); } }); }); @@ -198,168 +214,198 @@ void main() { group('CodeFindController method ', () { test('`findMode`', () async { { - final CodeFindController controller = CodeFindController(CodeLineEditingController.fromText('abc')); + final CodeFindController controller = CodeFindController( + CodeLineEditingController.fromText('abc'), + ); expect(controller.value, null); controller.findMode(); - expect(controller.value, const CodeFindValue( - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false + expect( + controller.value, + const CodeFindValue( + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + replaceMode: false, ), - replaceMode: false - )); + ); } { - final CodeLineEditingController editingController = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController editingController = + CodeLineEditingController.fromText('abc'); editingController.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, + ); + final CodeFindController controller = CodeFindController( + editingController, ); - final CodeFindController controller = CodeFindController(editingController); expect(controller.value, null); controller.findMode(); - expect(controller.value, const CodeFindValue( - option: CodeFindOption( - pattern: 'b', - caseSensitive: false, - regex: false + expect( + controller.value, + const CodeFindValue( + option: CodeFindOption( + pattern: 'b', + caseSensitive: false, + regex: false, + ), + replaceMode: false, + searching: true, ), - replaceMode: false, - searching: true - )); + ); expect(controller.findInputController.text, 'b'); - expect(controller.findInputController.selection, const TextSelection( - baseOffset: 0, - extentOffset: 1 - )); + expect( + controller.findInputController.selection, + const TextSelection(baseOffset: 0, extentOffset: 1), + ); await Future.delayed(const Duration(milliseconds: 200)); - expect(controller.value, CodeFindValue( - option: const CodeFindOption( - pattern: 'b', - caseSensitive: false, - regex: false - ), - replaceMode: false, - result: CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ) - ], + expect( + controller.value, + CodeFindValue( option: const CodeFindOption( pattern: 'b', caseSensitive: false, - regex: false + regex: false, ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: false - ) - )); + replaceMode: false, + result: CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: 'b', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: false, + ), + ), + ); } }); test('`replaceMode`', () async { { - final CodeFindController controller = CodeFindController(CodeLineEditingController.fromText('abc')); + final CodeFindController controller = CodeFindController( + CodeLineEditingController.fromText('abc'), + ); expect(controller.value, null); controller.replaceMode(); - expect(controller.value, const CodeFindValue( - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false + expect( + controller.value, + const CodeFindValue( + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + replaceMode: true, ), - replaceMode: true, - )); + ); } { - final CodeLineEditingController editingController = CodeLineEditingController.fromText('abc'); + final CodeLineEditingController editingController = + CodeLineEditingController.fromText('abc'); editingController.selection = const CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, + ); + final CodeFindController controller = CodeFindController( + editingController, ); - final CodeFindController controller = CodeFindController(editingController); expect(controller.value, null); controller.replaceMode(); - expect(controller.value, const CodeFindValue( - option: CodeFindOption( - pattern: 'b', - caseSensitive: false, - regex: false + expect( + controller.value, + const CodeFindValue( + option: CodeFindOption( + pattern: 'b', + caseSensitive: false, + regex: false, + ), + replaceMode: true, + searching: true, ), - replaceMode: true, - searching: true - )); + ); expect(controller.findInputController.text, 'b'); - expect(controller.findInputController.selection, const TextSelection( - baseOffset: 0, - extentOffset: 1 - )); + expect( + controller.findInputController.selection, + const TextSelection(baseOffset: 0, extentOffset: 1), + ); await Future.delayed(const Duration(milliseconds: 200)); - expect(controller.value, CodeFindValue( - option: const CodeFindOption( - pattern: 'b', - caseSensitive: false, - regex: false - ), - replaceMode: true, - result: CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ) - ], + expect( + controller.value, + CodeFindValue( option: const CodeFindOption( pattern: 'b', caseSensitive: false, - regex: false + regex: false, ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: false - ) - )); + replaceMode: true, + result: CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: 'b', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: false, + ), + ), + ); } }); test('`focusOnFindInput`', () { - final CodeFindController controller = CodeFindController(CodeLineEditingController()); + final CodeFindController controller = CodeFindController( + CodeLineEditingController(), + ); controller.findInputController.text = 'abc'; controller.focusOnFindInput(); - expect(controller.findInputController.selection, const TextSelection( - baseOffset: 0, - extentOffset: 3 - )); + expect( + controller.findInputController.selection, + const TextSelection(baseOffset: 0, extentOffset: 3), + ); }); test('`focusOnReplaceInput`', () { - final CodeFindController controller = CodeFindController(CodeLineEditingController()); + final CodeFindController controller = CodeFindController( + CodeLineEditingController(), + ); controller.replaceInputController.text = 'abc'; controller.focusOnReplaceInput(); - expect(controller.replaceInputController.selection, const TextSelection( - baseOffset: 0, - extentOffset: 3 - )); + expect( + controller.replaceInputController.selection, + const TextSelection(baseOffset: 0, extentOffset: 3), + ); }); test('`toggleMode`', () { - final CodeFindController controller = CodeFindController(CodeLineEditingController.fromText('abc')); + final CodeFindController controller = CodeFindController( + CodeLineEditingController.fromText('abc'), + ); controller.findMode(); expect(controller.value?.replaceMode, false); controller.toggleMode(); @@ -371,7 +417,9 @@ void main() { }); test('`close`', () { - final CodeFindController controller = CodeFindController(CodeLineEditingController.fromText('abc')); + final CodeFindController controller = CodeFindController( + CodeLineEditingController.fromText('abc'), + ); controller.findMode(); expect(controller.value != null, true); controller.close(); @@ -383,7 +431,9 @@ void main() { }); test('`toggleRegex`', () { - final CodeFindController controller = CodeFindController(CodeLineEditingController.fromText('abc')); + final CodeFindController controller = CodeFindController( + CodeLineEditingController.fromText('abc'), + ); controller.findMode(); expect(controller.value?.option.regex, false); controller.toggleRegex(); @@ -395,7 +445,9 @@ void main() { }); test('`toggleCaseSensitive`', () { - final CodeFindController controller = CodeFindController(CodeLineEditingController.fromText('abc')); + final CodeFindController controller = CodeFindController( + CodeLineEditingController.fromText('abc'), + ); controller.findMode(); expect(controller.value?.option.caseSensitive, false); controller.toggleCaseSensitive(); @@ -408,482 +460,444 @@ void main() { test('`previousMatch & nextMatch`', () async { { - final CodeFindController controller = CodeFindController(CodeLineEditingController.fromText('abcabcabc')); + final CodeFindController controller = CodeFindController( + CodeLineEditingController.fromText('abcabcabc'), + ); controller.findMode(); controller.findInputController.text = 'a'; await Future.delayed(const Duration(milliseconds: 200)); - expect(controller.value, CodeFindValue( - option: const CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false - ), - replaceMode: false, - result: CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 1 - ), - CodeLineSelection( - baseIndex: 0, - baseOffset: 3, - extentIndex: 0, - extentOffset: 4 - ), - CodeLineSelection( - baseIndex: 0, - baseOffset: 6, - extentIndex: 0, - extentOffset: 7 - ) - ], + expect( + controller.value, + CodeFindValue( option: const CodeFindOption( pattern: 'a', caseSensitive: false, - regex: false + regex: false, ), - codeLines: CodeLines.of([ - const CodeLine('abcabcabc') - ]), - dirty: false - ) - )); - controller.previousMatch(); - expect(controller.value, CodeFindValue( - option: const CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false - ), - replaceMode: false, - result: CodeFindResult( - index: 2, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 1 + replaceMode: false, + result: CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: 1, + ), + CodeLineSelection( + baseIndex: 0, + baseOffset: 3, + extentIndex: 0, + extentOffset: 4, + ), + CodeLineSelection( + baseIndex: 0, + baseOffset: 6, + extentIndex: 0, + extentOffset: 7, + ), + ], + option: const CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, ), - CodeLineSelection( - baseIndex: 0, - baseOffset: 3, - extentIndex: 0, - extentOffset: 4 - ), - CodeLineSelection( - baseIndex: 0, - baseOffset: 6, - extentIndex: 0, - extentOffset: 7 - ) - ], + codeLines: CodeLines.of([const CodeLine('abcabcabc')]), + dirty: false, + ), + ), + ); + controller.previousMatch(); + expect( + controller.value, + CodeFindValue( option: const CodeFindOption( pattern: 'a', caseSensitive: false, - regex: false + regex: false, ), - codeLines: CodeLines.of([ - const CodeLine('abcabcabc') - ]), - dirty: false - ) - )); - controller.previousMatch(); - expect(controller.value, CodeFindValue( - option: const CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false - ), - replaceMode: false, - result: CodeFindResult( - index: 1, - matches: [ - const CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 1 - ), - const CodeLineSelection( - baseIndex: 0, - baseOffset: 3, - extentIndex: 0, - extentOffset: 4 + replaceMode: false, + result: CodeFindResult( + index: 2, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: 1, + ), + CodeLineSelection( + baseIndex: 0, + baseOffset: 3, + extentIndex: 0, + extentOffset: 4, + ), + CodeLineSelection( + baseIndex: 0, + baseOffset: 6, + extentIndex: 0, + extentOffset: 7, + ), + ], + option: const CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, ), - const CodeLineSelection( - baseIndex: 0, - baseOffset: 6, - extentIndex: 0, - extentOffset: 7 - ) - ], + codeLines: CodeLines.of([const CodeLine('abcabcabc')]), + dirty: false, + ), + ), + ); + controller.previousMatch(); + expect( + controller.value, + CodeFindValue( option: const CodeFindOption( pattern: 'a', caseSensitive: false, - regex: false + regex: false, ), - codeLines: CodeLines.of([ - const CodeLine('abcabcabc') - ]), - dirty: false - ) - )); - controller.nextMatch(); - expect(controller.value, CodeFindValue( - option: const CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false - ), - replaceMode: false, - result: CodeFindResult( - index: 2, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 1 + replaceMode: false, + result: CodeFindResult( + index: 1, + matches: [ + const CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: 1, + ), + const CodeLineSelection( + baseIndex: 0, + baseOffset: 3, + extentIndex: 0, + extentOffset: 4, + ), + const CodeLineSelection( + baseIndex: 0, + baseOffset: 6, + extentIndex: 0, + extentOffset: 7, + ), + ], + option: const CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, ), - CodeLineSelection( - baseIndex: 0, - baseOffset: 3, - extentIndex: 0, - extentOffset: 4 - ), - CodeLineSelection( - baseIndex: 0, - baseOffset: 6, - extentIndex: 0, - extentOffset: 7 - ) - ], + codeLines: CodeLines.of([const CodeLine('abcabcabc')]), + dirty: false, + ), + ), + ); + controller.nextMatch(); + expect( + controller.value, + CodeFindValue( option: const CodeFindOption( pattern: 'a', caseSensitive: false, - regex: false + regex: false, ), - codeLines: CodeLines.of(const [ - CodeLine('abcabcabc') - ]), - dirty: false - ) - )); - controller.nextMatch(); - expect(controller.value, CodeFindValue( - option: const CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false - ), - replaceMode: false, - result: CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 0, - extentIndex: 0, - extentOffset: 1 + replaceMode: false, + result: CodeFindResult( + index: 2, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: 1, + ), + CodeLineSelection( + baseIndex: 0, + baseOffset: 3, + extentIndex: 0, + extentOffset: 4, + ), + CodeLineSelection( + baseIndex: 0, + baseOffset: 6, + extentIndex: 0, + extentOffset: 7, + ), + ], + option: const CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, ), - CodeLineSelection( - baseIndex: 0, - baseOffset: 3, - extentIndex: 0, - extentOffset: 4 - ), - CodeLineSelection( - baseIndex: 0, - baseOffset: 6, - extentIndex: 0, - extentOffset: 7 - ) - ], + codeLines: CodeLines.of(const [CodeLine('abcabcabc')]), + dirty: false, + ), + ), + ); + controller.nextMatch(); + expect( + controller.value, + CodeFindValue( option: const CodeFindOption( pattern: 'a', caseSensitive: false, - regex: false + regex: false, ), - codeLines: CodeLines.of(const [ - CodeLine('abcabcabc') - ]), - dirty: false - ) - )); + replaceMode: false, + result: CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 0, + extentIndex: 0, + extentOffset: 1, + ), + CodeLineSelection( + baseIndex: 0, + baseOffset: 3, + extentIndex: 0, + extentOffset: 4, + ), + CodeLineSelection( + baseIndex: 0, + baseOffset: 6, + extentIndex: 0, + extentOffset: 7, + ), + ], + option: const CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of(const [CodeLine('abcabcabc')]), + dirty: false, + ), + ), + ); } // Test auto expand chubnk { - final CodeLineEditingController editingController = CodeLineEditingController( - codeLines: CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]) - ] - )); - final CodeFindController controller = CodeFindController(editingController); + final CodeLineEditingController editingController = + CodeLineEditingController( + codeLines: CodeLines.of(const [ + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + ]), + ); + final CodeFindController controller = CodeFindController( + editingController, + ); controller.findMode(); controller.findInputController.text = 'a'; await Future.delayed(const Duration(milliseconds: 200)); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]) - ])); + ); controller.nextMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]), - CodeLine('abc', [ + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]) - ])); + ); controller.nextMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - CodeLine('abc', [ + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]) - ])); + ); controller.previousMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - CodeLine('abc', [ + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]) - ])); + ); controller.previousMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - CodeLine('abc', [ + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar'), - ]) - ])); + ); controller.previousMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - CodeLine('abc', [ + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), - ]), - CodeLine('abc', [ + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc'), CodeLine('foo'), CodeLine('bar'), ]), - CodeLine('abc'), - CodeLine('foo'), - CodeLine('bar'), - ])); + ); } }); test('`replaceMatch`', () async { { - final CodeLineEditingController editingController = CodeLineEditingController.fromText('abcabcabc'); - final CodeFindController controller = CodeFindController(editingController); + final CodeLineEditingController editingController = + CodeLineEditingController.fromText('abcabcabc'); + final CodeFindController controller = CodeFindController( + editingController, + ); controller.replaceMode(); controller.findInputController.text = 'a'; controller.replaceInputController.text = 'b'; await Future.delayed(const Duration(milliseconds: 200)); controller.replaceMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('bbcabcabc') - ])); + expect( + editingController.codeLines, + CodeLines.of(const [CodeLine('bbcabcabc')]), + ); await Future.delayed(const Duration(milliseconds: 200)); controller.replaceMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('bbcbbcabc') - ])); + expect( + editingController.codeLines, + CodeLines.of(const [CodeLine('bbcbbcabc')]), + ); await Future.delayed(const Duration(milliseconds: 200)); controller.replaceMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('bbcbbcbbc') - ])); + expect( + editingController.codeLines, + CodeLines.of(const [CodeLine('bbcbbcbbc')]), + ); } // replace with same text { - final CodeLineEditingController editingController = CodeLineEditingController.fromText('abcabcabc'); - final CodeFindController controller = CodeFindController(editingController); + final CodeLineEditingController editingController = + CodeLineEditingController.fromText('abcabcabc'); + final CodeFindController controller = CodeFindController( + editingController, + ); controller.replaceMode(); controller.findInputController.text = 'a'; controller.replaceInputController.text = 'a'; await Future.delayed(const Duration(milliseconds: 200)); controller.replaceMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('abcabcabc') - ])); - expect(editingController.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 1 - )); + expect( + editingController.codeLines, + CodeLines.of(const [CodeLine('abcabcabc')]), + ); + expect( + editingController.selection, + const CodeLineSelection.collapsed(index: 0, offset: 1), + ); expect(controller.value?.result?.index, 1); expect(controller.value?.result?.dirty, false); await Future.delayed(const Duration(milliseconds: 200)); controller.replaceMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('abcabcabc') - ])); - expect(editingController.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 4 - )); + expect( + editingController.codeLines, + CodeLines.of(const [CodeLine('abcabcabc')]), + ); + expect( + editingController.selection, + const CodeLineSelection.collapsed(index: 0, offset: 4), + ); expect(controller.value?.result?.index, 2); expect(controller.value?.result?.dirty, false); await Future.delayed(const Duration(milliseconds: 200)); controller.replaceMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('abcabcabc') - ])); - expect(editingController.selection, const CodeLineSelection.collapsed( - index: 0, - offset: 7 - )); + expect( + editingController.codeLines, + CodeLines.of(const [CodeLine('abcabcabc')]), + ); + expect( + editingController.selection, + const CodeLineSelection.collapsed(index: 0, offset: 7), + ); expect(controller.value?.result?.index, 0); expect(controller.value?.result?.dirty, false); } // Test code line chunks { - final CodeLineEditingController editingController = CodeLineEditingController( - codeLines: CodeLines.of(const [ - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar') - ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar') - ]) - ]) + final CodeLineEditingController editingController = + CodeLineEditingController( + codeLines: CodeLines.of(const [ + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + ]), + ); + final CodeFindController controller = CodeFindController( + editingController, ); - final CodeFindController controller = CodeFindController(editingController); controller.replaceMode(); controller.findInputController.text = 'a'; controller.replaceInputController.text = 'b'; await Future.delayed(const Duration(milliseconds: 200)); controller.replaceMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('bbc'), - CodeLine('foo'), - CodeLine('bar'), - CodeLine('abc', [ + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('bbc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bar'), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar') - ]) - ])); + ); await Future.delayed(const Duration(milliseconds: 200)); controller.replaceMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('bbc'), - CodeLine('foo'), - CodeLine('bbr'), - CodeLine('abc', [ + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('bbc'), CodeLine('foo'), - CodeLine('bar') + CodeLine('bbr'), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), ]), - CodeLine('abc', [ - CodeLine('foo'), - CodeLine('bar') - ]) - ])); + ); await Future.delayed(const Duration(milliseconds: 200)); controller.replaceMatch(); - expect(editingController.codeLines, CodeLines.of(const [ - CodeLine('bbc'), - CodeLine('foo'), - CodeLine('bbr'), - CodeLine('bbc'), - CodeLine('foo'), - CodeLine('bar'), - CodeLine('abc', [ + expect( + editingController.codeLines, + CodeLines.of(const [ + CodeLine('bbc'), + CodeLine('foo'), + CodeLine('bbr'), + CodeLine('bbc'), CodeLine('foo'), - CodeLine('bar') - ]) - ])); + CodeLine('bar'), + CodeLine('abc', [CodeLine('foo'), CodeLine('bar')]), + ]), + ); } }); }); -} \ No newline at end of file +} diff --git a/test/code_search_option_test.dart b/test/code_search_option_test.dart index c357f08..9333eac 100644 --- a/test/code_search_option_test.dart +++ b/test/code_search_option_test.dart @@ -3,119 +3,105 @@ import 'package:re_editor/re_editor.dart'; void main() { group('CodeFindOption getter ', () { - test('`regExp`', () async { + test('`regExp`', () { { const CodeFindOption option = CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false + pattern: 'a', + caseSensitive: false, + regex: false, ); expect(option.regExp, RegExp('a', caseSensitive: false)); } { const CodeFindOption option = CodeFindOption( - pattern: 'a', - caseSensitive: true, - regex: false + pattern: 'a', + caseSensitive: true, + regex: false, ); - expect(option.regExp, RegExp('a', caseSensitive: true)); + expect(option.regExp, RegExp('a')); } { const CodeFindOption option = CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: true + pattern: 'a', + caseSensitive: false, + regex: true, ); expect(option.regExp, RegExp('a', caseSensitive: false)); } { const CodeFindOption option = CodeFindOption( - pattern: '*', - caseSensitive: false, - regex: false + pattern: '*', + caseSensitive: false, + regex: false, ); - expect(option.regExp, RegExp('\\*', caseSensitive: false)); + expect(option.regExp, RegExp(r'\*', caseSensitive: false)); } }); }); group('CodeFindOption method ', () { - test('`copyWith`', () async { + test('`copyWith`', () { const CodeFindOption option = CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false + pattern: '', + caseSensitive: false, + regex: false, ); expect(option.copyWith(), option); - expect(option.copyWith( - pattern: 'a' - ), const CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false - )); - expect(option.copyWith( - caseSensitive: true, - ), const CodeFindOption( - pattern: '', - caseSensitive: true, - regex: false - )); - expect(option.copyWith( - regex: true, - ), const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: true - )); - expect(option.copyWith( - pattern: 'abc', - caseSensitive: true, - regex: true - ), const CodeFindOption( - pattern: 'abc', - caseSensitive: true, - regex: true - )); + expect( + option.copyWith(pattern: 'a'), + const CodeFindOption(pattern: 'a', caseSensitive: false, regex: false), + ); + expect( + option.copyWith(caseSensitive: true), + const CodeFindOption(pattern: '', caseSensitive: true, regex: false), + ); + expect( + option.copyWith(regex: true), + const CodeFindOption(pattern: '', caseSensitive: false, regex: true), + ); + expect( + option.copyWith(pattern: 'abc', caseSensitive: true, regex: true), + const CodeFindOption(pattern: 'abc', caseSensitive: true, regex: true), + ); }); }); group('CodeFindOption operator ', () { - test('`==`', () async { - expect(const CodeFindOption( - pattern: 'a', - caseSensitive: true, - regex: true - ) == const CodeFindOption( - pattern: 'a', - caseSensitive: true, - regex: true - ), true); - expect(const CodeFindOption( - pattern: 'a', - caseSensitive: true, - regex: true - ) == const CodeFindOption( - pattern: 'b', - caseSensitive: true, - regex: true - ), false); - expect(const CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: true - ) == const CodeFindOption( - pattern: 'a', - caseSensitive: true, - regex: true - ), false); - expect(const CodeFindOption( - pattern: 'a', - caseSensitive: true, - regex: false - ) == const CodeFindOption( - pattern: 'a', - caseSensitive: true, - regex: true - ), false); + test('`==`', () { + expect( + const CodeFindOption(pattern: 'a', caseSensitive: true, regex: true) == + const CodeFindOption( + pattern: 'a', + caseSensitive: true, + regex: true, + ), + true, + ); + expect( + const CodeFindOption(pattern: 'a', caseSensitive: true, regex: true) == + const CodeFindOption( + pattern: 'b', + caseSensitive: true, + regex: true, + ), + false, + ); + expect( + const CodeFindOption(pattern: 'a', caseSensitive: false, regex: true) == + const CodeFindOption( + pattern: 'a', + caseSensitive: true, + regex: true, + ), + false, + ); + expect( + const CodeFindOption(pattern: 'a', caseSensitive: true, regex: false) == + const CodeFindOption( + pattern: 'a', + caseSensitive: true, + regex: true, + ), + false, + ); }); }); -} \ No newline at end of file +} diff --git a/test/code_search_result_test.dart b/test/code_search_result_test.dart index 98b405a..ad6143a 100644 --- a/test/code_search_result_test.dart +++ b/test/code_search_result_test.dart @@ -3,7 +3,7 @@ import 'package:re_editor/re_editor.dart'; void main() { group('CodeFindResult getter ', () { - test('`previous & next & current`', () async { + test('`previous & next & current`', () { const CodeFindResult result = CodeFindResult( index: 0, matches: [ @@ -11,651 +11,655 @@ void main() { baseIndex: 0, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ), CodeLineSelection( baseIndex: 1, baseOffset: 1, extentIndex: 1, - extentOffset: 2 + extentOffset: 2, ), CodeLineSelection( baseIndex: 2, baseOffset: 1, extentIndex: 2, - extentOffset: 2 - ) + extentOffset: 2, + ), ], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), + option: CodeFindOption(pattern: '', caseSensitive: false, regex: false), codeLines: CodeLines([]), - dirty: false + dirty: false, ); - expect(result.currentMatch, const CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - )); - expect(result.next, result.copyWith( - index: 1 - )); - expect(result.next.currentMatch, const CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - )); - expect(result.next.next, result.copyWith( - index: 2 - )); - expect(result.next.next.currentMatch, const CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - )); - expect(result.next.next.next, result.copyWith( - index: 0 - )); - expect(result.next.next.next.currentMatch, const CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - )); - expect(result.previous, result.copyWith( - index: 2 - )); - expect(result.previous.currentMatch, const CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - )); - expect(result.previous.previous, result.copyWith( - index: 1 - )); - expect(result.previous.previous.currentMatch, const CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - )); - expect(result.previous.previous.previous, result.copyWith( - index: 0 - )); - expect(result.previous.previous.previous.currentMatch, const CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - )); - }); - }); - - group('CodeFindResult method ', () { - test('`copyWith`', () async { - const CodeFindResult result = CodeFindResult( - index: 0, - matches: [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, + expect( + result.currentMatch, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, ), - codeLines: CodeLines([]), - dirty: false ); - expect(result.copyWith(), result); - expect(result.copyWith( - index: 1 - ), const CodeFindResult( - index: 1, - matches: [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, + expect(result.next, result.copyWith(index: 1)); + expect( + result.next.currentMatch, + const CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, ), - codeLines: CodeLines([]), - dirty: false - )); - expect(result.copyWith( - matches: [] - ), const CodeFindResult( - index: 0, - matches: [], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, + ); + expect(result.next.next, result.copyWith(index: 2)); + expect( + result.next.next.currentMatch, + const CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, ), - codeLines: CodeLines([]), - dirty: false - )); - expect(result.copyWith( - option: const CodeFindOption( - pattern: 'a', - caseSensitive: true, - regex: true, + ); + expect(result.next.next.next, result.copyWith(index: 0)); + expect( + result.next.next.next.currentMatch, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, ), - ), const CodeFindResult( - index: 0, - matches: [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: CodeFindOption( - pattern: 'a', - caseSensitive: true, - regex: true, + ); + expect(result.previous, result.copyWith(index: 2)); + expect( + result.previous.currentMatch, + const CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, ), - codeLines: CodeLines([]), - dirty: false - )); - expect(result.copyWith( - codeLines: CodeLines.of([ - const CodeLine('abc') - ]) - ), CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, + ); + expect(result.previous.previous, result.copyWith(index: 1)); + expect( + result.previous.previous.currentMatch, + const CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: false - )); - expect(result.copyWith( - dirty: true - ), const CodeFindResult( - index: 0, - matches: [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, + ); + expect(result.previous.previous.previous, result.copyWith(index: 0)); + expect( + result.previous.previous.previous.currentMatch, + const CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, ), - codeLines: CodeLines([]), - dirty: true - )); + ); }); }); - group('CodeFindResult operator ', () { - test('`==`', () async { - expect(CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: true - ) == CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: true - ), true); - expect(CodeFindResult( - index: 1, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: true - ) == CodeFindResult( + group('CodeFindResult method ', () { + test('`copyWith`', () { + const CodeFindResult result = CodeFindResult( index: 0, - matches: const [ + matches: [ CodeLineSelection( baseIndex: 0, baseOffset: 1, extentIndex: 0, - extentOffset: 2 + extentOffset: 2, ), CodeLineSelection( baseIndex: 1, baseOffset: 1, extentIndex: 1, - extentOffset: 2 + extentOffset: 2, ), CodeLineSelection( baseIndex: 2, baseOffset: 1, extentIndex: 2, - extentOffset: 2 - ) - ], - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: true - ), false); - expect(CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 + extentOffset: 2, ), ], - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: true - ) == CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: true - ), false); - expect(CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: const CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false, + option: CodeFindOption(pattern: '', caseSensitive: false, regex: false), + codeLines: CodeLines([]), + dirty: false, + ); + expect(result.copyWith(), result); + expect( + result.copyWith(index: 1), + const CodeFindResult( + index: 1, + matches: [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines([]), + dirty: false, ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: true - ) == CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, + ); + expect( + result.copyWith(matches: []), + const CodeFindResult( + index: 0, + matches: [], + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines([]), + dirty: false, ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: true - ), false); - expect(CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 + ); + expect( + result.copyWith( + option: const CodeFindOption( + pattern: 'a', + caseSensitive: true, + regex: true, ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, ), - codeLines: CodeLines.of([ - const CodeLine('a') - ]), - dirty: true - ) == CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, + const CodeFindResult( + index: 0, + matches: [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: CodeFindOption( + pattern: 'a', + caseSensitive: true, + regex: true, + ), + codeLines: CodeLines([]), + dirty: false, ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: true - ), false); - expect(CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, + ); + expect( + result.copyWith(codeLines: CodeLines.of([const CodeLine('abc')])), + CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: false, ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: true - ) == CodeFindResult( - index: 0, - matches: const [ - CodeLineSelection( - baseIndex: 0, - baseOffset: 1, - extentIndex: 0, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 1, - baseOffset: 1, - extentIndex: 1, - extentOffset: 2 - ), - CodeLineSelection( - baseIndex: 2, - baseOffset: 1, - extentIndex: 2, - extentOffset: 2 - ) - ], - option: const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, + ); + expect( + result.copyWith(dirty: true), + const CodeFindResult( + index: 0, + matches: [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines([]), + dirty: true, ), - codeLines: CodeLines.of([ - const CodeLine('abc') - ]), - dirty: false - ), false); + ); + }); + }); + + group('CodeFindResult operator ', () { + test('`==`', () { + expect( + CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: true, + ) == + CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: true, + ), + true, + ); + expect( + CodeFindResult( + index: 1, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: true, + ) == + CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: true, + ), + false, + ); + expect( + CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: true, + ) == + CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: true, + ), + false, + ); + expect( + CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: true, + ) == + CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: true, + ), + false, + ); + expect( + CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('a')]), + dirty: true, + ) == + CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: true, + ), + false, + ); + expect( + CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: true, + ) == + CodeFindResult( + index: 0, + matches: const [ + CodeLineSelection( + baseIndex: 0, + baseOffset: 1, + extentIndex: 0, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 1, + baseOffset: 1, + extentIndex: 1, + extentOffset: 2, + ), + CodeLineSelection( + baseIndex: 2, + baseOffset: 1, + extentIndex: 2, + extentOffset: 2, + ), + ], + option: const CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines.of([const CodeLine('abc')]), + dirty: false, + ), + false, + ); }); }); -} \ No newline at end of file +} diff --git a/test/code_search_value_test.dart b/test/code_search_value_test.dart index 161f988..d3fe00b 100644 --- a/test/code_search_value_test.dart +++ b/test/code_search_value_test.dart @@ -3,219 +3,235 @@ import 'package:re_editor/re_editor.dart'; void main() { group('CodeFindValue constructor ', () { - test('`empty`', () async { + test('`empty`', () { const CodeFindValue value = CodeFindValue.empty(); - expect(value.option, const CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - )); + expect( + value.option, + const CodeFindOption(pattern: '', caseSensitive: false, regex: false), + ); expect(value.replaceMode, false); expect(value.result, null); }); }); group('CodeFindValue method ', () { - test('`copyWith`', () async { + test('`copyWith`', () { const CodeFindValue value = CodeFindValue.empty(); { final CodeFindValue newValue = value.copyWith( result: CodeFindResult( - index: 0, - matches: [], - option: value.option, + index: 0, + matches: [], + option: value.option, codeLines: const CodeLines([]), - dirty: false - ) + dirty: false, + ), + ); + expect( + newValue.result, + CodeFindResult( + index: 0, + matches: [], + option: value.option, + codeLines: const CodeLines([]), + dirty: false, + ), ); - expect(newValue.result, CodeFindResult( - index: 0, - matches: [], - option: value.option, - codeLines: const CodeLines([]), - dirty: false - )); - expect(newValue.replaceMode, value.replaceMode); - expect(newValue.option, value.option); + expect(newValue.replaceMode, value.replaceMode); + expect(newValue.option, value.option); } { final CodeFindValue newValue = value.copyWith( replaceMode: true, - result: null + result: null, ); expect(newValue.result, null); - expect(newValue.replaceMode, true); - expect(newValue.option, value.option); + expect(newValue.replaceMode, true); + expect(newValue.option, value.option); } { final CodeFindValue newValue = value.copyWith( option: const CodeFindOption( - pattern: 'a', - caseSensitive: true, - regex: true + pattern: 'a', + caseSensitive: true, + regex: true, ), - result: null + result: null, ); expect(newValue.result, null); - expect(newValue.replaceMode, value.replaceMode); - expect(newValue.option, const CodeFindOption( - pattern: 'a', - caseSensitive: true, - regex: true - )); + expect(newValue.replaceMode, value.replaceMode); + expect( + newValue.option, + const CodeFindOption(pattern: 'a', caseSensitive: true, regex: true), + ); } - }); }); group('CodeFindValue operator ', () { - test('`==`', () async { - expect(const CodeFindValue( - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - replaceMode: false, - result: CodeFindResult( - index: 0, - matches: [], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines([]), - dirty: false - ) - ) == const CodeFindValue( - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - replaceMode: false, - result: CodeFindResult( - index: 0, - matches: [], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines([]), - dirty: false - ) - ), true); - expect(const CodeFindValue( - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - replaceMode: false, - result: CodeFindResult( - index: 0, - matches: [], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines([]), - dirty: false - ) - ) == const CodeFindValue( - option: CodeFindOption( - pattern: 'a', - caseSensitive: false, - regex: false, - ), - replaceMode: false, - result: CodeFindResult( - index: 0, - matches: [], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines([]), - dirty: false - ) - ), false); - expect(const CodeFindValue( - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - replaceMode: false, - result: CodeFindResult( - index: 0, - matches: [], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines([]), - dirty: false - ) - ) == const CodeFindValue( - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - replaceMode: true, - result: CodeFindResult( - index: 0, - matches: [], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines([]), - dirty: false - ) - ), false); - expect(const CodeFindValue( - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - replaceMode: false, - result: CodeFindResult( - index: 0, - matches: [], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines([]), - dirty: false - ) - ) == const CodeFindValue( - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - replaceMode: false, - result: CodeFindResult( - index: 1, - matches: [], - option: CodeFindOption( - pattern: '', - caseSensitive: false, - regex: false, - ), - codeLines: CodeLines([]), - dirty: false - ) - ), false); + test('`==`', () { + expect( + const CodeFindValue( + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + replaceMode: false, + result: CodeFindResult( + index: 0, + matches: [], + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines([]), + dirty: false, + ), + ) == + const CodeFindValue( + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + replaceMode: false, + result: CodeFindResult( + index: 0, + matches: [], + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines([]), + dirty: false, + ), + ), + true, + ); + expect( + const CodeFindValue( + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + replaceMode: false, + result: CodeFindResult( + index: 0, + matches: [], + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines([]), + dirty: false, + ), + ) == + const CodeFindValue( + option: CodeFindOption( + pattern: 'a', + caseSensitive: false, + regex: false, + ), + replaceMode: false, + result: CodeFindResult( + index: 0, + matches: [], + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines([]), + dirty: false, + ), + ), + false, + ); + expect( + const CodeFindValue( + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + replaceMode: false, + result: CodeFindResult( + index: 0, + matches: [], + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines([]), + dirty: false, + ), + ) == + const CodeFindValue( + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + replaceMode: true, + result: CodeFindResult( + index: 0, + matches: [], + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines([]), + dirty: false, + ), + ), + false, + ); + expect( + const CodeFindValue( + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + replaceMode: false, + result: CodeFindResult( + index: 0, + matches: [], + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines([]), + dirty: false, + ), + ) == + const CodeFindValue( + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + replaceMode: false, + result: CodeFindResult( + index: 1, + matches: [], + option: CodeFindOption( + pattern: '', + caseSensitive: false, + regex: false, + ), + codeLines: CodeLines([]), + dirty: false, + ), + ), + false, + ); }); }); -} \ No newline at end of file +}