From f927042d801d993b5158310d5e19df411219e962 Mon Sep 17 00:00:00 2001 From: malarg Date: Tue, 25 Apr 2023 09:12:19 +0400 Subject: [PATCH 01/11] issue 192 paired symbols code modifier --- lib/src/code_field/code_controller.dart | 7 +++++ lib/src/code_modifiers/paired_symbols.dart | 30 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 lib/src/code_modifiers/paired_symbols.dart diff --git a/lib/src/code_field/code_controller.dart b/lib/src/code_field/code_controller.dart index 4e4ef7bd..ff099847 100644 --- a/lib/src/code_field/code_controller.dart +++ b/lib/src/code_field/code_controller.dart @@ -10,6 +10,7 @@ import 'package:highlight/highlight_core.dart'; import '../../flutter_code_editor.dart'; import '../autocomplete/autocompleter.dart'; import '../code/code_edit_result.dart'; +import '../code_modifiers/paired_symbols.dart'; import '../history/code_history_controller.dart'; import '../history/code_history_record.dart'; import '../single_line_comments/parser/single_line_comments.dart'; @@ -124,6 +125,12 @@ class CodeController extends TextEditingController { IndentModifier(), CloseBlockModifier(), TabModifier(), + PairedSymbolsCodeModifier(openChar: '(', closeChar: ')'), + PairedSymbolsCodeModifier(openChar: '{', closeChar: '}'), + PairedSymbolsCodeModifier(openChar: '[', closeChar: ']'), + PairedSymbolsCodeModifier(openChar: '"', closeChar: '"'), + PairedSymbolsCodeModifier(openChar: '`', closeChar: '`'), + PairedSymbolsCodeModifier(openChar: '\'', closeChar: '\''), ], }) : _analyzer = analyzer, _readOnlySectionNames = readOnlySectionNames, diff --git a/lib/src/code_modifiers/paired_symbols.dart b/lib/src/code_modifiers/paired_symbols.dart new file mode 100644 index 00000000..db840ee7 --- /dev/null +++ b/lib/src/code_modifiers/paired_symbols.dart @@ -0,0 +1,30 @@ +import 'package:flutter/services.dart'; + +import '../code_field/editor_params.dart'; +import 'code_modifier.dart'; + +class PairedSymbolsCodeModifier extends CodeModifier { + final String openChar; + final String closeChar; + + const PairedSymbolsCodeModifier({ + required this.openChar, + required this.closeChar, + }) : super(openChar); + + @override + TextEditingValue? updateString( + String text, + TextSelection sel, + EditorParams params, + ) { + final replaced = replace(text, sel.start, sel.end, '$openChar$closeChar'); + + return replaced.copyWith( + selection: TextSelection( + baseOffset: replaced.selection.baseOffset - closeChar.length, + extentOffset: replaced.selection.extentOffset - closeChar.length, + ), + ); + } +} From 4293fc066887253ba9fc69383f2ea60dbceddc09 Mon Sep 17 00:00:00 2001 From: malarg Date: Tue, 25 Apr 2023 10:09:47 +0400 Subject: [PATCH 02/11] yaml folding added --- example/lib/03.change_language_theme/constants.dart | 3 +++ lib/src/folding/parsers/parser_factory.dart | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/example/lib/03.change_language_theme/constants.dart b/example/lib/03.change_language_theme/constants.dart index 90dfbc2d..bb3b80d5 100644 --- a/example/lib/03.change_language_theme/constants.dart +++ b/example/lib/03.change_language_theme/constants.dart @@ -3,6 +3,7 @@ import 'package:highlight/languages/go.dart'; import 'package:highlight/languages/java.dart'; import 'package:highlight/languages/python.dart'; import 'package:highlight/languages/scala.dart'; +import 'package:highlight/languages/yaml.dart'; final builtinLanguages = { 'dart': dart, @@ -10,6 +11,7 @@ final builtinLanguages = { 'java': java, 'python': python, 'scala': scala, + 'yaml': yaml, }; const languageList = [ @@ -18,6 +20,7 @@ const languageList = [ 'java', 'python', 'scala', + 'yaml' ]; const themeList = [ diff --git a/lib/src/folding/parsers/parser_factory.dart b/lib/src/folding/parsers/parser_factory.dart index 6174775e..51d75ec6 100644 --- a/lib/src/folding/parsers/parser_factory.dart +++ b/lib/src/folding/parsers/parser_factory.dart @@ -1,9 +1,11 @@ import 'package:highlight/highlight_core.dart'; import 'package:highlight/languages/java.dart'; import 'package:highlight/languages/python.dart'; +import 'package:highlight/languages/yaml.dart'; import 'abstract.dart'; import 'highlight.dart'; +import 'indent.dart'; import 'java.dart'; import 'python.dart'; @@ -15,6 +17,11 @@ class FoldableBlockParserFactory { if (mode == java) { return JavaFoldableBlockParser(); } + + if (mode == yaml) { + return IndentFoldableBlockParser(); + } + return HighlightFoldableBlockParser(); } } From d8521ae82a2cce6dffdb9f2e199d393526f390e0 Mon Sep 17 00:00:00 2001 From: malarg Date: Thu, 11 May 2023 09:53:23 +0400 Subject: [PATCH 03/11] issue192 tests done --- lib/src/code_field/code_controller.dart | 12 +- lib/src/code_modifiers/paired_symbols.dart | 10 +- .../code_modifiers/paired_symbols_test.dart | 146 ++++++++++++++++++ 3 files changed, 157 insertions(+), 11 deletions(-) create mode 100644 test/src/code_modifiers/paired_symbols_test.dart diff --git a/lib/src/code_field/code_controller.dart b/lib/src/code_field/code_controller.dart index ff099847..b5ac3803 100644 --- a/lib/src/code_field/code_controller.dart +++ b/lib/src/code_field/code_controller.dart @@ -125,12 +125,12 @@ class CodeController extends TextEditingController { IndentModifier(), CloseBlockModifier(), TabModifier(), - PairedSymbolsCodeModifier(openChar: '(', closeChar: ')'), - PairedSymbolsCodeModifier(openChar: '{', closeChar: '}'), - PairedSymbolsCodeModifier(openChar: '[', closeChar: ']'), - PairedSymbolsCodeModifier(openChar: '"', closeChar: '"'), - PairedSymbolsCodeModifier(openChar: '`', closeChar: '`'), - PairedSymbolsCodeModifier(openChar: '\'', closeChar: '\''), + PairedSymbolsCodeModifier(openChar: '(', closeString: ')'), + PairedSymbolsCodeModifier(openChar: '{', closeString: '}'), + PairedSymbolsCodeModifier(openChar: '[', closeString: ']'), + PairedSymbolsCodeModifier(openChar: '"', closeString: '"'), + PairedSymbolsCodeModifier(openChar: '`', closeString: '`'), + PairedSymbolsCodeModifier(openChar: '\'', closeString: '\''), ], }) : _analyzer = analyzer, _readOnlySectionNames = readOnlySectionNames, diff --git a/lib/src/code_modifiers/paired_symbols.dart b/lib/src/code_modifiers/paired_symbols.dart index db840ee7..6b89f187 100644 --- a/lib/src/code_modifiers/paired_symbols.dart +++ b/lib/src/code_modifiers/paired_symbols.dart @@ -5,11 +5,11 @@ import 'code_modifier.dart'; class PairedSymbolsCodeModifier extends CodeModifier { final String openChar; - final String closeChar; + final String closeString; const PairedSymbolsCodeModifier({ required this.openChar, - required this.closeChar, + required this.closeString, }) : super(openChar); @override @@ -18,12 +18,12 @@ class PairedSymbolsCodeModifier extends CodeModifier { TextSelection sel, EditorParams params, ) { - final replaced = replace(text, sel.start, sel.end, '$openChar$closeChar'); + final replaced = replace(text, sel.start, sel.end, '$openChar$closeString'); return replaced.copyWith( selection: TextSelection( - baseOffset: replaced.selection.baseOffset - closeChar.length, - extentOffset: replaced.selection.extentOffset - closeChar.length, + baseOffset: replaced.selection.baseOffset - closeString.length, + extentOffset: replaced.selection.extentOffset - closeString.length, ), ); } diff --git a/test/src/code_modifiers/paired_symbols_test.dart b/test/src/code_modifiers/paired_symbols_test.dart new file mode 100644 index 00000000..aaaae959 --- /dev/null +++ b/test/src/code_modifiers/paired_symbols_test.dart @@ -0,0 +1,146 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_code_editor/flutter_code_editor.dart'; +import 'package:flutter_code_editor/src/code_modifiers/paired_symbols.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('Paired symbols modifier test', () { + const examples = [ + // + _Example( + 'Add paired symbols at the start of the string', + initialValue: TextEditingValue( + text: 'dict', + // \ cursor + selection: TextSelection.collapsed(offset: 0), + ), + expected: TextEditingValue( + text: '{}dict', + // \ cursor + selection: TextSelection.collapsed(offset: 1), + ), + openChar: '{', + closeString: '}', + ), + + _Example( + 'Add paired symbols in the middle of the string', + initialValue: TextEditingValue( + text: 'print', + // \ cursor + selection: TextSelection.collapsed(offset: 3), + ), + expected: TextEditingValue( + text: 'pri()nt', + // \ cursor + selection: TextSelection.collapsed(offset: 4), + ), + openChar: '(', + closeString: ')', + ), + + _Example( + 'Add paired symbols at the end of the string', + initialValue: TextEditingValue( + text: 'print', + // \ cursor + selection: TextSelection.collapsed(offset: 5), + ), + expected: TextEditingValue( + text: 'print[]', + // \ cursor + selection: TextSelection.collapsed(offset: 6), + ), + openChar: '[', + closeString: ']', + ), + + _Example( + 'Add paired symbols with several close chars', + initialValue: TextEditingValue( + text: 'string', + // \ cursor + selection: TextSelection.collapsed(offset: 6), + ), + expected: TextEditingValue( + text: 'string123', + // \ cursor + selection: TextSelection.collapsed(offset: 7), + ), + openChar: '1', + closeString: '23', + ), + + _Example( + 'Add paired symbols before same close char', + initialValue: TextEditingValue( + text: 'string)', + // \ cursor + selection: TextSelection.collapsed(offset: 6), + ), + expected: TextEditingValue( + text: 'string())', + // \ cursor + selection: TextSelection.collapsed(offset: 7), + ), + openChar: '(', + closeString: ')', + ), + + _Example( + 'Empty initial string', + initialValue: TextEditingValue( + // ignore: avoid_redundant_argument_values + text: '', + // \ cursor + selection: TextSelection.collapsed(offset: 0), + ), + expected: TextEditingValue( + text: '()', + // \ cursor + selection: TextSelection.collapsed(offset: 1), + ), + openChar: '(', + closeString: ')', + ), + ]; + + for (final example in examples) { + final controller = CodeController(); + final modifier = PairedSymbolsCodeModifier( + openChar: example.openChar, + closeString: example.closeString, + ); + + controller.value = example.initialValue; + + final updatedValue = modifier.updateString( + controller.text, + controller.selection, + const EditorParams(), + ); + + expect( + updatedValue, + example.expected, + reason: example.name, + ); + } + }); +} + +class _Example { + final String name; + final TextEditingValue initialValue; + final TextEditingValue expected; + final String openChar; + final String closeString; + + const _Example( + this.name, { + required this.initialValue, + required this.expected, + required this.openChar, + required this.closeString, + }); +} From 0e561b4e7105c9a87029bdbc1c1fab9370cc37f4 Mon Sep 17 00:00:00 2001 From: malarg Date: Thu, 11 May 2023 10:11:07 +0400 Subject: [PATCH 04/11] fixed tests --- .../code_modifiers/paired_symbols_test.dart | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/test/src/code_modifiers/paired_symbols_test.dart b/test/src/code_modifiers/paired_symbols_test.dart index aaaae959..1484cda6 100644 --- a/test/src/code_modifiers/paired_symbols_test.dart +++ b/test/src/code_modifiers/paired_symbols_test.dart @@ -106,22 +106,24 @@ void main() { ]; for (final example in examples) { - final controller = CodeController(); final modifier = PairedSymbolsCodeModifier( openChar: example.openChar, closeString: example.closeString, ); + final controller = CodeController( + modifiers: [modifier], + ); + controller.value = example.initialValue; - final updatedValue = modifier.updateString( - controller.text, - controller.selection, - const EditorParams(), + controller.value = _addCharToSelectedPosition( + controller.value, + example.openChar, ); expect( - updatedValue, + controller.value, example.expected, reason: example.name, ); @@ -129,6 +131,25 @@ void main() { }); } +TextEditingValue _addCharToSelectedPosition( + TextEditingValue value, + String char, +) { + final selection = value.selection; + final text = value.text; + + final newText = text.substring(0, selection.start) + + char + + text.substring(selection.start); + + return TextEditingValue( + text: newText, + selection: TextSelection.collapsed( + offset: selection.start + char.length, + ), + ); +} + class _Example { final String name; final TextEditingValue initialValue; From b82fe424075da6a526cb784697ac7d3551606126 Mon Sep 17 00:00:00 2001 From: malarg Date: Thu, 11 May 2023 10:16:30 +0400 Subject: [PATCH 05/11] formatting fixed --- example/lib/03.change_language_theme/constants.dart | 2 +- lib/src/folding/parsers/parser_factory.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/lib/03.change_language_theme/constants.dart b/example/lib/03.change_language_theme/constants.dart index bb3b80d5..02b93125 100644 --- a/example/lib/03.change_language_theme/constants.dart +++ b/example/lib/03.change_language_theme/constants.dart @@ -20,7 +20,7 @@ const languageList = [ 'java', 'python', 'scala', - 'yaml' + 'yaml', ]; const themeList = [ diff --git a/lib/src/folding/parsers/parser_factory.dart b/lib/src/folding/parsers/parser_factory.dart index 51d75ec6..586efcea 100644 --- a/lib/src/folding/parsers/parser_factory.dart +++ b/lib/src/folding/parsers/parser_factory.dart @@ -21,7 +21,7 @@ class FoldableBlockParserFactory { if (mode == yaml) { return IndentFoldableBlockParser(); } - + return HighlightFoldableBlockParser(); } } From 24cc6706b96cb39e38932932f20d922856d42a30 Mon Sep 17 00:00:00 2001 From: malarg Date: Thu, 11 May 2023 11:22:47 +0400 Subject: [PATCH 06/11] issue192 paired symbols -> insertion --- lib/src/code_field/code_controller.dart | 14 ++++++------- .../{paired_symbols.dart => insertion.dart} | 21 +++++++++++++++++-- ..._symbols_test.dart => insertion_test.dart} | 16 +++++++------- 3 files changed, 34 insertions(+), 17 deletions(-) rename lib/src/code_modifiers/{paired_symbols.dart => insertion.dart} (52%) rename test/src/code_modifiers/{paired_symbols_test.dart => insertion_test.dart} (89%) diff --git a/lib/src/code_field/code_controller.dart b/lib/src/code_field/code_controller.dart index b5ac3803..45b07fe8 100644 --- a/lib/src/code_field/code_controller.dart +++ b/lib/src/code_field/code_controller.dart @@ -10,7 +10,7 @@ import 'package:highlight/highlight_core.dart'; import '../../flutter_code_editor.dart'; import '../autocomplete/autocompleter.dart'; import '../code/code_edit_result.dart'; -import '../code_modifiers/paired_symbols.dart'; +import '../code_modifiers/insertion.dart'; import '../history/code_history_controller.dart'; import '../history/code_history_record.dart'; import '../single_line_comments/parser/single_line_comments.dart'; @@ -125,12 +125,12 @@ class CodeController extends TextEditingController { IndentModifier(), CloseBlockModifier(), TabModifier(), - PairedSymbolsCodeModifier(openChar: '(', closeString: ')'), - PairedSymbolsCodeModifier(openChar: '{', closeString: '}'), - PairedSymbolsCodeModifier(openChar: '[', closeString: ']'), - PairedSymbolsCodeModifier(openChar: '"', closeString: '"'), - PairedSymbolsCodeModifier(openChar: '`', closeString: '`'), - PairedSymbolsCodeModifier(openChar: '\'', closeString: '\''), + InsertionCodeModifier.backticks(), + InsertionCodeModifier.braces(), + InsertionCodeModifier.brackets(), + InsertionCodeModifier.doubleQuotes(), + InsertionCodeModifier.parentheses(), + InsertionCodeModifier.singleQuotes(), ], }) : _analyzer = analyzer, _readOnlySectionNames = readOnlySectionNames, diff --git a/lib/src/code_modifiers/paired_symbols.dart b/lib/src/code_modifiers/insertion.dart similarity index 52% rename from lib/src/code_modifiers/paired_symbols.dart rename to lib/src/code_modifiers/insertion.dart index 6b89f187..5361a4b5 100644 --- a/lib/src/code_modifiers/paired_symbols.dart +++ b/lib/src/code_modifiers/insertion.dart @@ -3,15 +3,32 @@ import 'package:flutter/services.dart'; import '../code_field/editor_params.dart'; import 'code_modifier.dart'; -class PairedSymbolsCodeModifier extends CodeModifier { +class InsertionCodeModifier extends CodeModifier { final String openChar; final String closeString; - const PairedSymbolsCodeModifier({ + const InsertionCodeModifier({ required this.openChar, required this.closeString, }) : super(openChar); + const InsertionCodeModifier.backticks() + : this(openChar: '`', closeString: '`'); + + const InsertionCodeModifier.braces() : this(openChar: '{', closeString: '}'); + + const InsertionCodeModifier.brackets() + : this(openChar: '[', closeString: ']'); + + const InsertionCodeModifier.doubleQuotes() + : this(openChar: '"', closeString: '"'); + + const InsertionCodeModifier.parentheses() + : this(openChar: '(', closeString: ')'); + + const InsertionCodeModifier.singleQuotes() + : this(openChar: '\'', closeString: '\''); + @override TextEditingValue? updateString( String text, diff --git a/test/src/code_modifiers/paired_symbols_test.dart b/test/src/code_modifiers/insertion_test.dart similarity index 89% rename from test/src/code_modifiers/paired_symbols_test.dart rename to test/src/code_modifiers/insertion_test.dart index 1484cda6..ac18ac13 100644 --- a/test/src/code_modifiers/paired_symbols_test.dart +++ b/test/src/code_modifiers/insertion_test.dart @@ -1,14 +1,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_code_editor/flutter_code_editor.dart'; -import 'package:flutter_code_editor/src/code_modifiers/paired_symbols.dart'; +import 'package:flutter_code_editor/src/code_modifiers/insertion.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { - test('Paired symbols modifier test', () { + test('Insertion modifier test', () { const examples = [ // _Example( - 'Add paired symbols at the start of the string', + 'Add close char at the start of the string', initialValue: TextEditingValue( text: 'dict', // \ cursor @@ -24,7 +24,7 @@ void main() { ), _Example( - 'Add paired symbols in the middle of the string', + 'Add close char in the middle of the string', initialValue: TextEditingValue( text: 'print', // \ cursor @@ -40,7 +40,7 @@ void main() { ), _Example( - 'Add paired symbols at the end of the string', + 'Add close char at the end of the string', initialValue: TextEditingValue( text: 'print', // \ cursor @@ -56,7 +56,7 @@ void main() { ), _Example( - 'Add paired symbols with several close chars', + 'Add close with several close chars', initialValue: TextEditingValue( text: 'string', // \ cursor @@ -72,7 +72,7 @@ void main() { ), _Example( - 'Add paired symbols before same close char', + 'Add close char before same close char', initialValue: TextEditingValue( text: 'string)', // \ cursor @@ -106,7 +106,7 @@ void main() { ]; for (final example in examples) { - final modifier = PairedSymbolsCodeModifier( + final modifier = InsertionCodeModifier( openChar: example.openChar, closeString: example.closeString, ); From 27e615666b49188391225004ab28c46286208bd0 Mon Sep 17 00:00:00 2001 From: malarg Date: Thu, 11 May 2023 19:12:26 +0400 Subject: [PATCH 07/11] issue 192 created default code modifier --- lib/src/code_field/code_controller.dart | 24 ++++---- test/src/code_modifiers/insertion_test.dart | 61 ++++++++++++--------- 2 files changed, 49 insertions(+), 36 deletions(-) diff --git a/lib/src/code_field/code_controller.dart b/lib/src/code_field/code_controller.dart index 6d983d99..fa24a92e 100644 --- a/lib/src/code_field/code_controller.dart +++ b/lib/src/code_field/code_controller.dart @@ -137,6 +137,18 @@ class CodeController extends TextEditingController { EnterKeyIntent: EnterKeyAction(controller: this), }; + static const defaultCodeModifiers = [ + IndentModifier(), + CloseBlockModifier(), + TabModifier(), + InsertionCodeModifier.backticks(), + InsertionCodeModifier.braces(), + InsertionCodeModifier.brackets(), + InsertionCodeModifier.doubleQuotes(), + InsertionCodeModifier.parentheses(), + InsertionCodeModifier.singleQuotes(), + ]; + CodeController({ String? text, Mode? language, @@ -151,17 +163,7 @@ class CodeController extends TextEditingController { this.readOnly = false, this.stringMap, this.params = const EditorParams(), - this.modifiers = const [ - IndentModifier(), - CloseBlockModifier(), - TabModifier(), - InsertionCodeModifier.backticks(), - InsertionCodeModifier.braces(), - InsertionCodeModifier.brackets(), - InsertionCodeModifier.doubleQuotes(), - InsertionCodeModifier.parentheses(), - InsertionCodeModifier.singleQuotes(), - ], + this.modifiers = defaultCodeModifiers, }) : _analyzer = analyzer, _readOnlySectionNames = readOnlySectionNames, _code = Code.empty, diff --git a/test/src/code_modifiers/insertion_test.dart b/test/src/code_modifiers/insertion_test.dart index ac18ac13..c4129e0e 100644 --- a/test/src/code_modifiers/insertion_test.dart +++ b/test/src/code_modifiers/insertion_test.dart @@ -19,8 +19,7 @@ void main() { // \ cursor selection: TextSelection.collapsed(offset: 1), ), - openChar: '{', - closeString: '}', + inputChar: '{', ), _Example( @@ -35,8 +34,7 @@ void main() { // \ cursor selection: TextSelection.collapsed(offset: 4), ), - openChar: '(', - closeString: ')', + inputChar: '(', ), _Example( @@ -51,8 +49,7 @@ void main() { // \ cursor selection: TextSelection.collapsed(offset: 6), ), - openChar: '[', - closeString: ']', + inputChar: '[', ), _Example( @@ -67,8 +64,8 @@ void main() { // \ cursor selection: TextSelection.collapsed(offset: 7), ), - openChar: '1', - closeString: '23', + inputChar: '1', + insertedString: '23', ), _Example( @@ -83,8 +80,7 @@ void main() { // \ cursor selection: TextSelection.collapsed(offset: 7), ), - openChar: '(', - closeString: ')', + inputChar: '(', ), _Example( @@ -100,26 +96,41 @@ void main() { // \ cursor selection: TextSelection.collapsed(offset: 1), ), - openChar: '(', - closeString: ')', + inputChar: '(', ), ]; for (final example in examples) { - final modifier = InsertionCodeModifier( - openChar: example.openChar, - closeString: example.closeString, - ); - - final controller = CodeController( - modifiers: [modifier], - ); + final additionalModifier = example.insertedString != null + ? InsertionCodeModifier( + openChar: example.inputChar, + closeString: example.insertedString!, + ) + : null; + + if (additionalModifier != null && + CodeController.defaultCodeModifiers.any( + (e) => + e is InsertionCodeModifier && e.openChar == example.inputChar, + )) { + fail('Modifier for ${example.inputChar} already exists'); + } + + late CodeController controller; + + if (additionalModifier == null) { + controller = CodeController(); + } else { + controller = CodeController( + modifiers: CodeController.defaultCodeModifiers + [additionalModifier], + ); + } controller.value = example.initialValue; controller.value = _addCharToSelectedPosition( controller.value, - example.openChar, + example.inputChar, ); expect( @@ -154,14 +165,14 @@ class _Example { final String name; final TextEditingValue initialValue; final TextEditingValue expected; - final String openChar; - final String closeString; + final String inputChar; + final String? insertedString; const _Example( this.name, { required this.initialValue, required this.expected, - required this.openChar, - required this.closeString, + required this.inputChar, + this.insertedString, }); } From 4756920fa04c422e48285421504cb0fc1fd4409a Mon Sep 17 00:00:00 2001 From: malarg Date: Tue, 16 May 2023 10:25:22 +0400 Subject: [PATCH 08/11] insertion constructor replaced with static const variables --- lib/src/code_field/code_controller.dart | 12 ++++++------ lib/src/code_modifiers/insertion.dart | 22 +++++++++++----------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/src/code_field/code_controller.dart b/lib/src/code_field/code_controller.dart index fa24a92e..35e3bf00 100644 --- a/lib/src/code_field/code_controller.dart +++ b/lib/src/code_field/code_controller.dart @@ -141,12 +141,12 @@ class CodeController extends TextEditingController { IndentModifier(), CloseBlockModifier(), TabModifier(), - InsertionCodeModifier.backticks(), - InsertionCodeModifier.braces(), - InsertionCodeModifier.brackets(), - InsertionCodeModifier.doubleQuotes(), - InsertionCodeModifier.parentheses(), - InsertionCodeModifier.singleQuotes(), + InsertionCodeModifier.backticks, + InsertionCodeModifier.braces, + InsertionCodeModifier.brackets, + InsertionCodeModifier.doubleQuotes, + InsertionCodeModifier.parentheses, + InsertionCodeModifier.singleQuotes, ]; CodeController({ diff --git a/lib/src/code_modifiers/insertion.dart b/lib/src/code_modifiers/insertion.dart index 5361a4b5..ef967b9e 100644 --- a/lib/src/code_modifiers/insertion.dart +++ b/lib/src/code_modifiers/insertion.dart @@ -12,22 +12,22 @@ class InsertionCodeModifier extends CodeModifier { required this.closeString, }) : super(openChar); - const InsertionCodeModifier.backticks() - : this(openChar: '`', closeString: '`'); + static const backticks = + InsertionCodeModifier(openChar: '`', closeString: '`'); - const InsertionCodeModifier.braces() : this(openChar: '{', closeString: '}'); + static const braces = InsertionCodeModifier(openChar: '{', closeString: '}'); - const InsertionCodeModifier.brackets() - : this(openChar: '[', closeString: ']'); + static const brackets = + InsertionCodeModifier(openChar: '[', closeString: ']'); - const InsertionCodeModifier.doubleQuotes() - : this(openChar: '"', closeString: '"'); + static const doubleQuotes = + InsertionCodeModifier(openChar: '"', closeString: '"'); - const InsertionCodeModifier.parentheses() - : this(openChar: '(', closeString: ')'); + static const parentheses = + InsertionCodeModifier(openChar: '(', closeString: ')'); - const InsertionCodeModifier.singleQuotes() - : this(openChar: '\'', closeString: '\''); + static const singleQuotes = + InsertionCodeModifier(openChar: '\'', closeString: '\''); @override TextEditingValue? updateString( From da174e21eaeef1ea0e0eb72a7ea9d7ff28c10e16 Mon Sep 17 00:00:00 2001 From: malarg Date: Wed, 17 May 2023 10:19:40 +0400 Subject: [PATCH 09/11] fixed autocompleter error for iOS --- lib/src/wip/autocomplete/popup.dart | 1 + lib/src/wip/autocomplete/popup_controller.dart | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/src/wip/autocomplete/popup.dart b/lib/src/wip/autocomplete/popup.dart index 90e28945..5035d8f0 100644 --- a/lib/src/wip/autocomplete/popup.dart +++ b/lib/src/wip/autocomplete/popup.dart @@ -47,6 +47,7 @@ class PopupState extends State { final pageStorageBucket = PageStorageBucket(); @override void initState() { + widget.controller.reset(); widget.controller.addListener(rebuild); super.initState(); } diff --git a/lib/src/wip/autocomplete/popup_controller.dart b/lib/src/wip/autocomplete/popup_controller.dart index bbbc3886..cbfc05d8 100644 --- a/lib/src/wip/autocomplete/popup_controller.dart +++ b/lib/src/wip/autocomplete/popup_controller.dart @@ -7,7 +7,7 @@ class PopupController extends ChangeNotifier { bool shouldShow = false; bool enabled = true; - final ItemScrollController itemScrollController = ItemScrollController(); + ItemScrollController itemScrollController = ItemScrollController(); final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create(); @@ -23,6 +23,10 @@ class PopupController extends ChangeNotifier { int get selectedIndex => _selectedIndex; + void reset() { + itemScrollController = ItemScrollController(); + } + void show(List suggestions) { if (enabled == false) { return; From 523b72cd047b7496a3529a938385432f014534d0 Mon Sep 17 00:00:00 2001 From: malarg Date: Wed, 17 May 2023 10:19:40 +0400 Subject: [PATCH 10/11] tests fix --- .../controller_insertion_test.dart | 149 +++++++++++++ test/src/code_modifiers/insertion_test.dart | 211 +++++------------- 2 files changed, 203 insertions(+), 157 deletions(-) create mode 100644 test/src/code_modifiers/controller_insertion_test.dart diff --git a/test/src/code_modifiers/controller_insertion_test.dart b/test/src/code_modifiers/controller_insertion_test.dart new file mode 100644 index 00000000..9019e708 --- /dev/null +++ b/test/src/code_modifiers/controller_insertion_test.dart @@ -0,0 +1,149 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_code_editor/flutter_code_editor.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('Insertion modifier test', () { + const examples = [ + // + _Example( + 'Add backticks', + initialValue: TextEditingValue( + text: 'dict', + // \ cursor + selection: TextSelection.collapsed(offset: 0), + ), + expected: TextEditingValue( + text: '``dict', + // \ cursor + selection: TextSelection.collapsed(offset: 1), + ), + inputChar: '`', + ), + + _Example( + 'Add char at the start of the string (braces)', + initialValue: TextEditingValue( + text: 'dict', + // \ cursor + selection: TextSelection.collapsed(offset: 0), + ), + expected: TextEditingValue( + text: '{}dict', + // \ cursor + selection: TextSelection.collapsed(offset: 1), + ), + inputChar: '{', + ), + + _Example( + 'Add char in the middle of the string (parentheses)', + initialValue: TextEditingValue( + text: 'print', + // \ cursor + selection: TextSelection.collapsed(offset: 3), + ), + expected: TextEditingValue( + text: 'pri()nt', + // \ cursor + selection: TextSelection.collapsed(offset: 4), + ), + inputChar: '(', + ), + + _Example( + 'Add char at the end of the string (brackets)', + initialValue: TextEditingValue( + text: 'print', + // \ cursor + selection: TextSelection.collapsed(offset: 5), + ), + expected: TextEditingValue( + text: 'print[]', + // \ cursor + selection: TextSelection.collapsed(offset: 6), + ), + inputChar: '[', + ), + + _Example( + 'Add close char before same close char (double quotes)', + initialValue: TextEditingValue( + text: 'string"', + // \ cursor + selection: TextSelection.collapsed(offset: 6), + ), + expected: TextEditingValue( + text: 'string"""', + // \ cursor + selection: TextSelection.collapsed(offset: 7), + ), + inputChar: '"', + ), + + _Example( + 'Empty initial string (single quotes)', + initialValue: TextEditingValue( + // ignore: avoid_redundant_argument_values + text: '', + // \ cursor + selection: TextSelection.collapsed(offset: 0), + ), + expected: TextEditingValue( + text: '\'\'', + // \ cursor + selection: TextSelection.collapsed(offset: 1), + ), + inputChar: '\'', + ), + ]; + + for (final example in examples) { + final controller = CodeController(); + controller.value = example.initialValue; + controller.value = _addCharToSelectedPosition( + controller.value, + example.inputChar, + ); + + expect( + controller.value, + example.expected, + reason: example.name, + ); + } + }); +} + +TextEditingValue _addCharToSelectedPosition( + TextEditingValue value, + String char, +) { + final selection = value.selection; + final text = value.text; + + final newText = text.substring(0, selection.start) + + char + + text.substring(selection.start); + + return TextEditingValue( + text: newText, + selection: TextSelection.collapsed( + offset: selection.start + char.length, + ), + ); +} + +class _Example { + final String name; + final TextEditingValue initialValue; + final TextEditingValue expected; + final String inputChar; + + const _Example( + this.name, { + required this.initialValue, + required this.expected, + required this.inputChar, + }); +} diff --git a/test/src/code_modifiers/insertion_test.dart b/test/src/code_modifiers/insertion_test.dart index c4129e0e..5b7b338c 100644 --- a/test/src/code_modifiers/insertion_test.dart +++ b/test/src/code_modifiers/insertion_test.dart @@ -1,178 +1,75 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_code_editor/flutter_code_editor.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_code_editor/src/code_field/editor_params.dart'; import 'package:flutter_code_editor/src/code_modifiers/insertion.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { - test('Insertion modifier test', () { - const examples = [ - // - _Example( - 'Add close char at the start of the string', - initialValue: TextEditingValue( - text: 'dict', - // \ cursor - selection: TextSelection.collapsed(offset: 0), - ), - expected: TextEditingValue( - text: '{}dict', - // \ cursor - selection: TextSelection.collapsed(offset: 1), - ), - inputChar: '{', - ), + test('inserts at the start of string correctly', () { + const modifier = InsertionCodeModifier(openChar: '1', closeString: '23'); + const text = 'Hello World'; + final selection = TextSelection.fromPosition(const TextPosition(offset: 0)); + const editorParams = EditorParams(); - _Example( - 'Add close char in the middle of the string', - initialValue: TextEditingValue( - text: 'print', - // \ cursor - selection: TextSelection.collapsed(offset: 3), - ), - expected: TextEditingValue( - text: 'pri()nt', - // \ cursor - selection: TextSelection.collapsed(offset: 4), - ), - inputChar: '(', - ), + final result = modifier.updateString(text, selection, editorParams); - _Example( - 'Add close char at the end of the string', - initialValue: TextEditingValue( - text: 'print', - // \ cursor - selection: TextSelection.collapsed(offset: 5), - ), - expected: TextEditingValue( - text: 'print[]', - // \ cursor - selection: TextSelection.collapsed(offset: 6), - ), - inputChar: '[', - ), - - _Example( - 'Add close with several close chars', - initialValue: TextEditingValue( - text: 'string', - // \ cursor - selection: TextSelection.collapsed(offset: 6), - ), - expected: TextEditingValue( - text: 'string123', - // \ cursor - selection: TextSelection.collapsed(offset: 7), - ), - inputChar: '1', - insertedString: '23', - ), + expect(result!.text, '123Hello World'); + expect(result.selection.baseOffset, 1); + expect(result.selection.extentOffset, 1); + }); - _Example( - 'Add close char before same close char', - initialValue: TextEditingValue( - text: 'string)', - // \ cursor - selection: TextSelection.collapsed(offset: 6), - ), - expected: TextEditingValue( - text: 'string())', - // \ cursor - selection: TextSelection.collapsed(offset: 7), - ), - inputChar: '(', - ), + test('inserts in the middle of string correctly', () { + const modifier = InsertionCodeModifier(openChar: '1', closeString: '23'); + const text = 'Hello World'; + final selection = TextSelection.fromPosition(const TextPosition(offset: 5)); + const editorParams = EditorParams(); - _Example( - 'Empty initial string', - initialValue: TextEditingValue( - // ignore: avoid_redundant_argument_values - text: '', - // \ cursor - selection: TextSelection.collapsed(offset: 0), - ), - expected: TextEditingValue( - text: '()', - // \ cursor - selection: TextSelection.collapsed(offset: 1), - ), - inputChar: '(', - ), - ]; + final result = modifier.updateString(text, selection, editorParams); - for (final example in examples) { - final additionalModifier = example.insertedString != null - ? InsertionCodeModifier( - openChar: example.inputChar, - closeString: example.insertedString!, - ) - : null; + expect(result!.text, 'Hello123 World'); + expect(result.selection.baseOffset, 6); + expect(result.selection.extentOffset, 6); + }); - if (additionalModifier != null && - CodeController.defaultCodeModifiers.any( - (e) => - e is InsertionCodeModifier && e.openChar == example.inputChar, - )) { - fail('Modifier for ${example.inputChar} already exists'); - } + test('inserts at the end of string correctly', () { + const modifier = InsertionCodeModifier(openChar: '1', closeString: '23'); + const text = 'Hello World'; + final selection = + TextSelection.fromPosition(const TextPosition(offset: text.length)); + const editorParams = EditorParams(); - late CodeController controller; + final result = modifier.updateString(text, selection, editorParams); - if (additionalModifier == null) { - controller = CodeController(); - } else { - controller = CodeController( - modifiers: CodeController.defaultCodeModifiers + [additionalModifier], - ); - } + expect(result!.text, 'Hello World123'); + expect(result.selection.baseOffset, text.length + 1); + expect(result.selection.extentOffset, text.length + 1); + }); - controller.value = example.initialValue; + test('inserts in the middle of string with selection correctly', () { + const modifier = InsertionCodeModifier(openChar: '1', closeString: '23'); + const text = 'Hello World'; + const selection = TextSelection( + baseOffset: 5, + extentOffset: 7, + ); + const editorParams = EditorParams(); - controller.value = _addCharToSelectedPosition( - controller.value, - example.inputChar, - ); + final result = modifier.updateString(text, selection, editorParams); - expect( - controller.value, - example.expected, - reason: example.name, - ); - } + expect(result!.text, 'Hello123orld'); + expect(result.selection.baseOffset, 6); + expect(result.selection.extentOffset, 6); }); -} - -TextEditingValue _addCharToSelectedPosition( - TextEditingValue value, - String char, -) { - final selection = value.selection; - final text = value.text; - final newText = text.substring(0, selection.start) + - char + - text.substring(selection.start); - - return TextEditingValue( - text: newText, - selection: TextSelection.collapsed( - offset: selection.start + char.length, - ), - ); -} + test('inserts at empty string correctly', () { + const modifier = InsertionCodeModifier(openChar: '1', closeString: '23'); + const text = ''; + final selection = TextSelection.fromPosition(const TextPosition(offset: 0)); + const editorParams = EditorParams(); -class _Example { - final String name; - final TextEditingValue initialValue; - final TextEditingValue expected; - final String inputChar; - final String? insertedString; + final result = modifier.updateString(text, selection, editorParams); - const _Example( - this.name, { - required this.initialValue, - required this.expected, - required this.inputChar, - this.insertedString, + expect(result!.text, '123'); + expect(result.selection.baseOffset, 1); + expect(result.selection.extentOffset, 1); }); } From 962aae24370d075363e6aa30f231450fd222d734 Mon Sep 17 00:00:00 2001 From: malarg Date: Mon, 22 May 2023 11:29:38 +0400 Subject: [PATCH 11/11] commend added --- lib/src/code_modifiers/close_block_code_modifier.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/code_modifiers/close_block_code_modifier.dart b/lib/src/code_modifiers/close_block_code_modifier.dart index 7a719405..56699908 100644 --- a/lib/src/code_modifiers/close_block_code_modifier.dart +++ b/lib/src/code_modifiers/close_block_code_modifier.dart @@ -5,6 +5,8 @@ import 'package:flutter/widgets.dart'; import '../code_field/editor_params.dart'; import 'code_modifier.dart'; +/// [CloseBlockModifier] is an implementation of [CodeModifier] +/// that remove spaces before the closing bracket, if required. class CloseBlockModifier extends CodeModifier { const CloseBlockModifier() : super('}');