Skip to content

Commit 49b2161

Browse files
committed
feat: apply format and restore cursor after component results
1 parent f99ac65 commit 49b2161

File tree

11 files changed

+74
-41
lines changed

11 files changed

+74
-41
lines changed

.github/workflows/publish.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@ jobs:
1515
- uses: dart-lang/setup-dart@v1
1616
- name: Install dependencies
1717
run: dart pub get
18+
- name: Lint
19+
run: dart format .
1820
- name: Publish
1921
run: dart pub publish --force

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 1.1.0
2+
3+
- Implement password secure
4+
- Restore cursor after component result
5+
16
## 1.0.0
27

38
- Initial version.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ user input.
1010
To use Commander in your Dart project, add this to your `pubspec.yaml` file :
1111
```yaml
1212
dependencies:
13-
cli_commander: ^1.0.0
13+
commander_ui: ^1.1.0
1414
```
1515
1616
Then run `pub get` to install the dependencies.

example/input.dart

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:io';
2+
13
import 'package:commander_ui/commander_ui.dart';
24

35
final class Item {
@@ -13,20 +15,20 @@ Future<void> main() async {
1315
final input = Input(
1416
answer: 'Please give us your name',
1517
placeholder: 'firstname lastname',
16-
validate: (value) =>
17-
switch(value) {
18-
String value when value
19-
.trim()
20-
.isNotEmpty => Ok(null),
21-
_ => Err('Please provide a valid name')
22-
}
23-
);
24-
25-
final value = switch(await input.handle()) {
18+
secure:
19+
true, // 👈 Optional, ou can hide the input like html input with password type
20+
validate: (value) => switch (value) {
21+
String value when value.trim().isNotEmpty => Ok(null),
22+
_ => Err('Please provide a valid name')
23+
});
24+
25+
final value = switch (await input.handle()) {
2626
Ok(:final value) => 'My value is $value',
2727
Err(:final error) => Exception('Error: $error'),
2828
_ => 'Unknown',
2929
};
3030

3131
print(value);
32+
33+
exit(0);
3234
}

example/select.dart

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:io';
2+
13
import 'package:commander_ui/commander_ui.dart';
24

35
final class Item {
@@ -10,20 +12,27 @@ final class Item {
1012
Future<void> main() async {
1113
StdinBuffer.initialize();
1214

15+
final List<Item> items = List.generate(
16+
20, (index) => Item('${index + 1}. Hello World', index + 1));
17+
18+
String formatSelectedLine(String line) =>
19+
'${AsciiColors.green('❯')} ${AsciiColors.lightCyan(line)}';
20+
1321
final select = Select(
1422
answer: "Please select your best hello",
15-
options: List.generate(20, (index) => Item('${index + 1}. Hello World', index + 1)),
23+
options: items,
1624
placeholder: 'Type to filter',
17-
selectedLineStyle: (line) => '${AsciiColors.green('❯')} ${AsciiColors.lightCyan(line)}',
25+
selectedLineStyle: formatSelectedLine,
1826
unselectedLineStyle: (line) => ' $line',
19-
onDisplay: (item) => item.name
20-
);
27+
onDisplay: (item) => item.name);
2128

22-
final selected = switch(await select.handle()) {
29+
final selected = switch (await select.handle()) {
2330
Ok(:final value) => 'My value is ${value.value}',
2431
Err(:final error) => Exception('Error: $error'),
2532
_ => 'Unknown',
2633
};
2734

2835
print(selected);
36+
37+
exit(0);
2938
}

lib/commander_ui.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,3 @@ export '../src/commons/cli.dart';
1010
export '../src/commons/color.dart';
1111

1212
export '../src/application/stdin_buffer.dart';
13-
14-

lib/src/commons/cli.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ mixin Tools {
5252
throw Exception('Could not parse cursor position');
5353
}
5454

55-
return (
56-
int.parse(match.group(1)!),
57-
int.parse(match.group(2)!)
58-
);
55+
final line = int.parse(match.group(1)!);
56+
final column = int.parse(match.group(2)!);
57+
58+
return (line, column);
5959
}
6060

6161
Future<int> getAvailableLinesBelowCursor() async {

lib/src/components/select.dart

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import 'package:commander_ui/src/component.dart';
88
import 'package:commander_ui/src/key_down_event_listener.dart';
99
import 'package:commander_ui/src/result.dart';
1010

11-
final class Select<T, R extends dynamic> with Tools implements Component<Result<T>> {
11+
final class Select<T, R extends dynamic>
12+
with Tools
13+
implements Component<Result<T>> {
1214
String filter = '';
1315
int currentIndex = 0;
1416
bool isRendering = false;
@@ -35,10 +37,14 @@ final class Select<T, R extends dynamic> with Tools implements Component<Result<
3537
String Function(String)? selectedLineStyle,
3638
String Function(String)? unselectedLineStyle,
3739
}) {
38-
this.noResultFoundMessage = noResultFoundMessage ?? AsciiColors.dim('No result found');
39-
this.exitMessage = exitMessage ?? '${AsciiColors.red('✘')} Operation canceled by user';
40-
this.selectedLineStyle = selectedLineStyle ?? (line) => '${AsciiColors.green('❯')} $selectedLineStyle(line)';
41-
this.unselectedLineStyle = unselectedLineStyle ?? (line) => ' $unselectedLineStyle(line)';
40+
this.noResultFoundMessage =
41+
noResultFoundMessage ?? AsciiColors.dim('No result found');
42+
this.exitMessage =
43+
exitMessage ?? '${AsciiColors.red('✘')} Operation canceled by user';
44+
this.selectedLineStyle = selectedLineStyle ??
45+
(line) => '${AsciiColors.green('❯')} $selectedLineStyle(line)';
46+
this.unselectedLineStyle =
47+
unselectedLineStyle ?? (line) => ' $unselectedLineStyle(line)';
4248
}
4349

4450
@override
@@ -95,9 +101,11 @@ final class Select<T, R extends dynamic> with Tools implements Component<Result<
95101
return;
96102
}
97103

98-
final value = onDisplay?.call(options[currentIndex]) ?? options[currentIndex].toString();
104+
final value = onDisplay?.call(options[currentIndex]) ??
105+
options[currentIndex].toString();
99106

100-
stdout.writeln('${AsciiColors.green('✔')} $answer · ${AsciiColors.lightGreen(value)}');
107+
stdout.writeln(
108+
'${AsciiColors.green('✔')} $answer · ${AsciiColors.lightGreen(value)}');
101109
saveCursorPosition();
102110
showCursor();
103111
_completer.complete(Ok(options[currentIndex]));
@@ -139,11 +147,12 @@ final class Select<T, R extends dynamic> with Tools implements Component<Result<
139147
List<T> filteredArr = options.where((item) {
140148
final value = onDisplay?.call(item) ?? item.toString();
141149
return filter.isNotEmpty
142-
? value.toLowerCase().contains(filter.toLowerCase())
143-
: true;
150+
? value.toLowerCase().contains(filter.toLowerCase())
151+
: true;
144152
}).toList();
145153

146-
buffer.writeln('${AsciiColors.yellow('?')} $answer : ${filter.isEmpty ? AsciiColors.dim(placeholder ?? '') : filter}');
154+
buffer.writeln(
155+
'${AsciiColors.yellow('?')} $answer : ${filter.isEmpty ? AsciiColors.dim(placeholder ?? '') : filter}');
147156

148157
if (filteredArr.isEmpty) {
149158
buffer.writeln(noResultFoundMessage);
@@ -152,10 +161,12 @@ final class Select<T, R extends dynamic> with Tools implements Component<Result<
152161
if (currentIndex >= filteredArr.length - 2) {
153162
start = filteredArr.length - 5;
154163
}
155-
int end = start + 5 <= filteredArr.length ? start + 5 : filteredArr.length;
164+
int end =
165+
start + 5 <= filteredArr.length ? start + 5 : filteredArr.length;
156166

157167
for (int i = start; i < end; i++) {
158-
final value = onDisplay?.call(filteredArr[i]) ?? filteredArr[i].toString();
168+
final value =
169+
onDisplay?.call(filteredArr[i]) ?? filteredArr[i].toString();
159170
if (i == currentIndex) {
160171
copy.add(selectedLineStyle(value));
161172
} else {

lib/src/key_down_event_listener.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ class KeyDownEventListener {
1414

1515
KeyDownEventListener() {
1616
subscription = StdinBuffer.stream.transform(utf8.decoder).listen((data) {
17-
final listener = listeners.firstWhereOrNull((listener) => listener.key.value == data);
17+
final listener =
18+
listeners.firstWhereOrNull((listener) => listener.key.value == data);
1819
if (listener case KeyDownListener listener) {
1920
listener.callback(data, dispose);
2021
return;
@@ -26,11 +27,13 @@ class KeyDownEventListener {
2627
});
2728
}
2829

29-
void match(AnsiCharacter key, void Function(String, void Function() dispose) callback) {
30+
void match(AnsiCharacter key,
31+
void Function(String, void Function() dispose) callback) {
3032
listeners.add(KeyDownListener(key, callback));
3133
}
3234

33-
void catchAll(FutureOr<void> Function(String, void Function() dispose) callback) {
35+
void catchAll(
36+
FutureOr<void> Function(String, void Function() dispose) callback) {
3437
fallback = callback;
3538
}
3639

@@ -49,7 +52,6 @@ class KeyDownEventListener {
4952
}
5053
}
5154

52-
5355
final class KeyDownListener {
5456
final AnsiCharacter key;
5557
final void Function(String, void Function()) callback;

lib/src/result.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
abstract class Result<T> {
22
const Result();
33

4-
R when<R>({required R Function(T value) ok, required String Function(Object error) err});
4+
R when<R>(
5+
{required R Function(T value) ok,
6+
required String Function(Object error) err});
57
T unwrap();
68
}
79

@@ -19,7 +21,9 @@ class Err<T> extends Result<T> with ResultWhen {
1921

2022
mixin ResultWhen<T> on Result<T> {
2123
@override
22-
R when<R>({required R Function(T value) ok, required String Function(Object error) err}) {
24+
R when<R>(
25+
{required R Function(T value) ok,
26+
required String Function(Object error) err}) {
2327
if (this is Ok<T>) {
2428
return ok((this as Ok<T>).value);
2529
} else {

0 commit comments

Comments
 (0)