Skip to content

Commit b0e893b

Browse files
MalargDzmitrySalauyeuAkvelon
authored andcommitted
Issues: #192 Paired Symbols, #199 YAML support (Dev: @Malarg)
1 parent 63b4691 commit b0e893b

File tree

9 files changed

+303
-6
lines changed

9 files changed

+303
-6
lines changed

example/lib/03.change_language_theme/constants.dart

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:highlight/languages/java.dart';
44
import 'package:highlight/languages/php.dart';
55
import 'package:highlight/languages/python.dart';
66
import 'package:highlight/languages/scala.dart';
7+
import 'package:highlight/languages/yaml.dart';
78

89
final builtinLanguages = {
910
'dart': dart,
@@ -12,6 +13,7 @@ final builtinLanguages = {
1213
'php': php,
1314
'python': python,
1415
'scala': scala,
16+
'yaml': yaml,
1517
};
1618

1719
const languageList = <String>[
@@ -21,6 +23,7 @@ const languageList = <String>[
2123
'php',
2224
'python',
2325
'scala',
26+
'yaml',
2427
];
2528

2629
const themeList = <String>[

lib/src/code_field/code_controller.dart

+14-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:meta/meta.dart';
1111
import '../../flutter_code_editor.dart';
1212
import '../autocomplete/autocompleter.dart';
1313
import '../code/code_edit_result.dart';
14+
import '../code_modifiers/insertion.dart';
1415
import '../code/key_event.dart';
1516
import '../history/code_history_controller.dart';
1617
import '../history/code_history_record.dart';
@@ -132,6 +133,18 @@ class CodeController extends TextEditingController {
132133
EnterKeyIntent: EnterKeyAction(controller: this),
133134
};
134135

136+
static const defaultCodeModifiers = [
137+
IndentModifier(),
138+
CloseBlockModifier(),
139+
TabModifier(),
140+
InsertionCodeModifier.backticks,
141+
InsertionCodeModifier.braces,
142+
InsertionCodeModifier.brackets,
143+
InsertionCodeModifier.doubleQuotes,
144+
InsertionCodeModifier.parentheses,
145+
InsertionCodeModifier.singleQuotes,
146+
];
147+
135148
CodeController({
136149
String? text,
137150
Mode? language,
@@ -143,11 +156,7 @@ class CodeController extends TextEditingController {
143156
this.patternMap,
144157
this.readOnly = false,
145158
this.params = const EditorParams(),
146-
this.modifiers = const [
147-
IndentModifier(),
148-
CloseBlockModifier(),
149-
TabModifier(),
150-
],
159+
this.modifiers = defaultCodeModifiers,
151160
}) : _analyzer = analyzer,
152161
_readOnlySectionNames = readOnlySectionNames,
153162
_code = Code.empty,

lib/src/code_modifiers/close_block_code_modifier.dart

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import 'package:flutter/widgets.dart';
55
import '../code_field/editor_params.dart';
66
import 'code_modifier.dart';
77

8+
/// [CloseBlockModifier] is an implementation of [CodeModifier]
9+
/// that remove spaces before the closing bracket, if required.
810
class CloseBlockModifier extends CodeModifier {
911
const CloseBlockModifier() : super('}');
1012

lib/src/code_modifiers/insertion.dart

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import 'package:flutter/services.dart';
2+
3+
import '../code_field/editor_params.dart';
4+
import 'code_modifier.dart';
5+
6+
class InsertionCodeModifier extends CodeModifier {
7+
final String openChar;
8+
final String closeString;
9+
10+
const InsertionCodeModifier({
11+
required this.openChar,
12+
required this.closeString,
13+
}) : super(openChar);
14+
15+
static const backticks =
16+
InsertionCodeModifier(openChar: '`', closeString: '`');
17+
18+
static const braces = InsertionCodeModifier(openChar: '{', closeString: '}');
19+
20+
static const brackets =
21+
InsertionCodeModifier(openChar: '[', closeString: ']');
22+
23+
static const doubleQuotes =
24+
InsertionCodeModifier(openChar: '"', closeString: '"');
25+
26+
static const parentheses =
27+
InsertionCodeModifier(openChar: '(', closeString: ')');
28+
29+
static const singleQuotes =
30+
InsertionCodeModifier(openChar: '\'', closeString: '\'');
31+
32+
@override
33+
TextEditingValue? updateString(
34+
String text,
35+
TextSelection sel,
36+
EditorParams params,
37+
) {
38+
final replaced = replace(text, sel.start, sel.end, '$openChar$closeString');
39+
40+
return replaced.copyWith(
41+
selection: TextSelection(
42+
baseOffset: replaced.selection.baseOffset - closeString.length,
43+
extentOffset: replaced.selection.extentOffset - closeString.length,
44+
),
45+
);
46+
}
47+
}

lib/src/folding/parsers/parser_factory.dart

+7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import 'package:highlight/highlight_core.dart';
22
import 'package:highlight/languages/java.dart';
33
import 'package:highlight/languages/python.dart';
4+
import 'package:highlight/languages/yaml.dart';
45

56
import 'abstract.dart';
67
import 'highlight.dart';
8+
import 'indent.dart';
79
import 'java.dart';
810
import 'python.dart';
911

@@ -15,6 +17,11 @@ class FoldableBlockParserFactory {
1517
if (mode == java) {
1618
return JavaFoldableBlockParser();
1719
}
20+
21+
if (mode == yaml) {
22+
return IndentFoldableBlockParser();
23+
}
24+
1825
return HighlightFoldableBlockParser();
1926
}
2027
}

lib/src/wip/autocomplete/popup.dart

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class PopupState extends State<Popup> {
4747
final pageStorageBucket = PageStorageBucket();
4848
@override
4949
void initState() {
50+
widget.controller.reset();
5051
widget.controller.addListener(rebuild);
5152
super.initState();
5253
}

lib/src/wip/autocomplete/popup_controller.dart

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class PopupController extends ChangeNotifier {
77
bool shouldShow = false;
88
bool enabled = true;
99

10-
final ItemScrollController itemScrollController = ItemScrollController();
10+
ItemScrollController itemScrollController = ItemScrollController();
1111
final ItemPositionsListener itemPositionsListener =
1212
ItemPositionsListener.create();
1313

@@ -23,6 +23,10 @@ class PopupController extends ChangeNotifier {
2323

2424
int get selectedIndex => _selectedIndex;
2525

26+
void reset() {
27+
itemScrollController = ItemScrollController();
28+
}
29+
2630
void show(List<String> suggestions) {
2731
if (enabled == false) {
2832
return;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_code_editor/flutter_code_editor.dart';
3+
import 'package:flutter_test/flutter_test.dart';
4+
5+
void main() {
6+
test('Insertion modifier test', () {
7+
const examples = [
8+
//
9+
_Example(
10+
'Add backticks',
11+
initialValue: TextEditingValue(
12+
text: 'dict',
13+
// \ cursor
14+
selection: TextSelection.collapsed(offset: 0),
15+
),
16+
expected: TextEditingValue(
17+
text: '``dict',
18+
// \ cursor
19+
selection: TextSelection.collapsed(offset: 1),
20+
),
21+
inputChar: '`',
22+
),
23+
24+
_Example(
25+
'Add char at the start of the string (braces)',
26+
initialValue: TextEditingValue(
27+
text: 'dict',
28+
// \ cursor
29+
selection: TextSelection.collapsed(offset: 0),
30+
),
31+
expected: TextEditingValue(
32+
text: '{}dict',
33+
// \ cursor
34+
selection: TextSelection.collapsed(offset: 1),
35+
),
36+
inputChar: '{',
37+
),
38+
39+
_Example(
40+
'Add char in the middle of the string (parentheses)',
41+
initialValue: TextEditingValue(
42+
text: 'print',
43+
// \ cursor
44+
selection: TextSelection.collapsed(offset: 3),
45+
),
46+
expected: TextEditingValue(
47+
text: 'pri()nt',
48+
// \ cursor
49+
selection: TextSelection.collapsed(offset: 4),
50+
),
51+
inputChar: '(',
52+
),
53+
54+
_Example(
55+
'Add char at the end of the string (brackets)',
56+
initialValue: TextEditingValue(
57+
text: 'print',
58+
// \ cursor
59+
selection: TextSelection.collapsed(offset: 5),
60+
),
61+
expected: TextEditingValue(
62+
text: 'print[]',
63+
// \ cursor
64+
selection: TextSelection.collapsed(offset: 6),
65+
),
66+
inputChar: '[',
67+
),
68+
69+
_Example(
70+
'Add close char before same close char (double quotes)',
71+
initialValue: TextEditingValue(
72+
text: 'string"',
73+
// \ cursor
74+
selection: TextSelection.collapsed(offset: 6),
75+
),
76+
expected: TextEditingValue(
77+
text: 'string"""',
78+
// \ cursor
79+
selection: TextSelection.collapsed(offset: 7),
80+
),
81+
inputChar: '"',
82+
),
83+
84+
_Example(
85+
'Empty initial string (single quotes)',
86+
initialValue: TextEditingValue(
87+
// ignore: avoid_redundant_argument_values
88+
text: '',
89+
// \ cursor
90+
selection: TextSelection.collapsed(offset: 0),
91+
),
92+
expected: TextEditingValue(
93+
text: '\'\'',
94+
// \ cursor
95+
selection: TextSelection.collapsed(offset: 1),
96+
),
97+
inputChar: '\'',
98+
),
99+
];
100+
101+
for (final example in examples) {
102+
final controller = CodeController();
103+
controller.value = example.initialValue;
104+
controller.value = _addCharToSelectedPosition(
105+
controller.value,
106+
example.inputChar,
107+
);
108+
109+
expect(
110+
controller.value,
111+
example.expected,
112+
reason: example.name,
113+
);
114+
}
115+
});
116+
}
117+
118+
TextEditingValue _addCharToSelectedPosition(
119+
TextEditingValue value,
120+
String char,
121+
) {
122+
final selection = value.selection;
123+
final text = value.text;
124+
125+
final newText = text.substring(0, selection.start) +
126+
char +
127+
text.substring(selection.start);
128+
129+
return TextEditingValue(
130+
text: newText,
131+
selection: TextSelection.collapsed(
132+
offset: selection.start + char.length,
133+
),
134+
);
135+
}
136+
137+
class _Example {
138+
final String name;
139+
final TextEditingValue initialValue;
140+
final TextEditingValue expected;
141+
final String inputChar;
142+
143+
const _Example(
144+
this.name, {
145+
required this.initialValue,
146+
required this.expected,
147+
required this.inputChar,
148+
});
149+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import 'package:flutter/services.dart';
2+
import 'package:flutter_code_editor/src/code_field/editor_params.dart';
3+
import 'package:flutter_code_editor/src/code_modifiers/insertion.dart';
4+
import 'package:flutter_test/flutter_test.dart';
5+
6+
void main() {
7+
test('inserts at the start of string correctly', () {
8+
const modifier = InsertionCodeModifier(openChar: '1', closeString: '23');
9+
const text = 'Hello World';
10+
final selection = TextSelection.fromPosition(const TextPosition(offset: 0));
11+
const editorParams = EditorParams();
12+
13+
final result = modifier.updateString(text, selection, editorParams);
14+
15+
expect(result!.text, '123Hello World');
16+
expect(result.selection.baseOffset, 1);
17+
expect(result.selection.extentOffset, 1);
18+
});
19+
20+
test('inserts in the middle of string correctly', () {
21+
const modifier = InsertionCodeModifier(openChar: '1', closeString: '23');
22+
const text = 'Hello World';
23+
final selection = TextSelection.fromPosition(const TextPosition(offset: 5));
24+
const editorParams = EditorParams();
25+
26+
final result = modifier.updateString(text, selection, editorParams);
27+
28+
expect(result!.text, 'Hello123 World');
29+
expect(result.selection.baseOffset, 6);
30+
expect(result.selection.extentOffset, 6);
31+
});
32+
33+
test('inserts at the end of string correctly', () {
34+
const modifier = InsertionCodeModifier(openChar: '1', closeString: '23');
35+
const text = 'Hello World';
36+
final selection =
37+
TextSelection.fromPosition(const TextPosition(offset: text.length));
38+
const editorParams = EditorParams();
39+
40+
final result = modifier.updateString(text, selection, editorParams);
41+
42+
expect(result!.text, 'Hello World123');
43+
expect(result.selection.baseOffset, text.length + 1);
44+
expect(result.selection.extentOffset, text.length + 1);
45+
});
46+
47+
test('inserts in the middle of string with selection correctly', () {
48+
const modifier = InsertionCodeModifier(openChar: '1', closeString: '23');
49+
const text = 'Hello World';
50+
const selection = TextSelection(
51+
baseOffset: 5,
52+
extentOffset: 7,
53+
);
54+
const editorParams = EditorParams();
55+
56+
final result = modifier.updateString(text, selection, editorParams);
57+
58+
expect(result!.text, 'Hello123orld');
59+
expect(result.selection.baseOffset, 6);
60+
expect(result.selection.extentOffset, 6);
61+
});
62+
63+
test('inserts at empty string correctly', () {
64+
const modifier = InsertionCodeModifier(openChar: '1', closeString: '23');
65+
const text = '';
66+
final selection = TextSelection.fromPosition(const TextPosition(offset: 0));
67+
const editorParams = EditorParams();
68+
69+
final result = modifier.updateString(text, selection, editorParams);
70+
71+
expect(result!.text, '123');
72+
expect(result.selection.baseOffset, 1);
73+
expect(result.selection.extentOffset, 1);
74+
});
75+
}

0 commit comments

Comments
 (0)