Skip to content

Commit

Permalink
feat: double asterisks to bold text
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasXu0 committed Sep 21, 2022
1 parent 6018200 commit 14b0ffd
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';

// convert **abc** to bold abc.
ShortcutEventHandler doubleAsterisksToBold = (editorState, event) {
final selectionService = editorState.service.selectionService;
final selection = selectionService.currentSelection.value;
final textNodes = selectionService.currentSelectedNodes.whereType<TextNode>();
if (selection == null || !selection.isSingle || textNodes.length != 1) {
return KeyEventResult.ignored;
}

final textNode = textNodes.first;
final text = textNode.toRawString().substring(0, selection.end.offset);

// make sure the last two characters are **.
if (text.length < 2 || text[selection.end.offset - 1] != '*') {
return KeyEventResult.ignored;
}

// find all the index of `*`.
final asteriskIndexes = <int>[];
for (var i = 0; i < text.length; i++) {
if (text[i] == '*') {
asteriskIndexes.add(i);
}
}

if (asteriskIndexes.length < 3) {
return KeyEventResult.ignored;
}

// make sure the second to last and third to last asterisks are connected.
final thirdToLastAsteriskIndex = asteriskIndexes[asteriskIndexes.length - 3];
final secondToLastAsteriskIndex = asteriskIndexes[asteriskIndexes.length - 2];
final lastAsterisIndex = asteriskIndexes[asteriskIndexes.length - 1];
if (secondToLastAsteriskIndex != thirdToLastAsteriskIndex + 1 ||
lastAsterisIndex == secondToLastAsteriskIndex + 1) {
return KeyEventResult.ignored;
}

// delete the last three asterisks.
// update the style of the text surround by `** **` to bold.
// and update the cursor position.
TransactionBuilder(editorState)
..deleteText(textNode, lastAsterisIndex, 1)
..deleteText(textNode, thirdToLastAsteriskIndex, 2)
..formatText(
textNode,
thirdToLastAsteriskIndex,
selection.end.offset - thirdToLastAsteriskIndex - 2,
{
BuiltInAttributeKey.bold: true,
},
)
..afterSelection = Selection.collapsed(
Position(
path: textNode.path,
offset: selection.end.offset - 3,
),
)
..commit();

return KeyEventResult.handled;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:appflowy_editor/src/service/internal_key_event_handlers/arrow_ke
import 'package:appflowy_editor/src/service/internal_key_event_handlers/backspace_handler.dart';
import 'package:appflowy_editor/src/service/internal_key_event_handlers/copy_paste_handler.dart';
import 'package:appflowy_editor/src/service/internal_key_event_handlers/enter_without_shift_in_text_node_handler.dart';
import 'package:appflowy_editor/src/service/internal_key_event_handlers/markdown_syntax_to_styled_text.dart';
import 'package:appflowy_editor/src/service/internal_key_event_handlers/page_up_down_handler.dart';
import 'package:appflowy_editor/src/service/internal_key_event_handlers/redo_undo_handler.dart';
import 'package:appflowy_editor/src/service/internal_key_event_handlers/select_all_handler.dart';
Expand Down Expand Up @@ -243,4 +244,9 @@ List<ShortcutEvent> builtInShortcutEvents = [
command: 'page down',
handler: pageDownHandler,
),
ShortcutEvent(
key: 'Double stars to bold',
command: 'shift+asterisk',
handler: doubleAsterisksToBold,
),
];
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ extension on LogicalKeyboardKey {
if (this == LogicalKeyboardKey.keyZ) {
return PhysicalKeyboardKey.keyZ;
}
if (this == LogicalKeyboardKey.asterisk) {
return PhysicalKeyboardKey.digit8;
}
throw UnimplementedError();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/extensions/text_node_extensions.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../infra/test_editor.dart';

void main() async {
setUpAll(() {
TestWidgetsFlutterBinding.ensureInitialized();
});

group('markdown_syntax_to_styled_text.dart', () {
group('convert double asterisks to bold', () {
Future<void> insertAsterisk(
EditorWidgetTester editor, {
int repeat = 1,
}) async {
for (var i = 0; i < repeat; i++) {
await editor.pressLogicKey(
LogicalKeyboardKey.asterisk,
isShiftPressed: true,
);
}
}

testWidgets('**AppFlowy** to bold AppFlowy', (tester) async {
const text = '**AppFlowy*';
final editor = tester.editor..insertTextNode('');
await editor.startTesting();
await editor.updateSelection(
Selection.single(path: [0], startOffset: 0),
);
final textNode = editor.nodeAtPath([0]) as TextNode;
for (var i = 0; i < text.length; i++) {
await editor.insertText(textNode, text[i], i);
}
await insertAsterisk(editor);
final allBold = textNode.allSatisfyBoldInSelection(
Selection.single(
path: [0],
startOffset: 0,
endOffset: textNode.toRawString().length,
),
);
expect(allBold, true);
expect(textNode.toRawString(), 'AppFlowy');
});

testWidgets('App**Flowy** to bold AppFlowy', (tester) async {
const text = 'App**Flowy*';
final editor = tester.editor..insertTextNode('');
await editor.startTesting();
await editor.updateSelection(
Selection.single(path: [0], startOffset: 0),
);
final textNode = editor.nodeAtPath([0]) as TextNode;
for (var i = 0; i < text.length; i++) {
await editor.insertText(textNode, text[i], i);
}
await insertAsterisk(editor);
final allBold = textNode.allSatisfyBoldInSelection(
Selection.single(
path: [0],
startOffset: 3,
endOffset: textNode.toRawString().length,
),
);
expect(allBold, true);
expect(textNode.toRawString(), 'AppFlowy');
});

testWidgets('***AppFlowy** to bold *AppFlowy', (tester) async {
const text = '***AppFlowy*';
final editor = tester.editor..insertTextNode('');
await editor.startTesting();
await editor.updateSelection(
Selection.single(path: [0], startOffset: 0),
);
final textNode = editor.nodeAtPath([0]) as TextNode;
for (var i = 0; i < text.length; i++) {
await editor.insertText(textNode, text[i], i);
}
await insertAsterisk(editor);
final allBold = textNode.allSatisfyBoldInSelection(
Selection.single(
path: [0],
startOffset: 1,
endOffset: textNode.toRawString().length,
),
);
expect(allBold, true);
expect(textNode.toRawString(), '*AppFlowy');
});

testWidgets('**** nothing changes', (tester) async {
const text = '***';
final editor = tester.editor..insertTextNode('');
await editor.startTesting();
await editor.updateSelection(
Selection.single(path: [0], startOffset: 0),
);
final textNode = editor.nodeAtPath([0]) as TextNode;
for (var i = 0; i < text.length; i++) {
await editor.insertText(textNode, text[i], i);
}
await insertAsterisk(editor);
final allBold = textNode.allSatisfyBoldInSelection(
Selection.single(
path: [0],
startOffset: 0,
endOffset: textNode.toRawString().length,
),
);
expect(allBold, false);
expect(textNode.toRawString(), text);
});
});
});
}

0 comments on commit 14b0ffd

Please sign in to comment.