feat: backquote to code text

This commit is contained in:
He Linming 2022-09-23 18:05:57 +08:00
parent 882043ef96
commit 39bbfe109d
No known key found for this signature in database
GPG Key ID: CCD4C92A1475582F
3 changed files with 137 additions and 0 deletions
frontend/app_flowy/packages/appflowy_editor/lib/src

View File

@ -54,6 +54,11 @@ extension TextNodeExtension on TextNode {
return value == true;
});
bool allSatisfyCodeInSelection(Selection selection) =>
allSatisfyInSelection(selection, BuiltInAttributeKey.code, (value) {
return value == true;
});
bool allSatisfyInSelection(
Selection selection,
String styleKey,

View File

@ -0,0 +1,126 @@
import "dart:math";
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/extensions/text_node_extensions.dart';
import 'package:appflowy_editor/src/service/default_text_operations/format_rich_text_style.dart';
import 'package:flutter/material.dart';
bool _isCodeStyle(TextNode textNode, int index) {
return textNode.allSatisfyCodeInSelection(Selection.single(
path: textNode.path, startOffset: index, endOffset: index + 1));
}
// enter escape mode when start two backquote
bool _isEscapeBackquote(String text, List<int> backquoteIndexes) {
if (backquoteIndexes.length >= 2) {
final firstBackquoteIndex = backquoteIndexes[0];
final secondBackquoteIndex = backquoteIndexes[1];
return firstBackquoteIndex == secondBackquoteIndex - 1;
}
return false;
}
// find all the index of `, exclusion in code style.
List<int> _findBackquoteIndexes(String text, TextNode textNode) {
final backquoteIndexes = <int>[];
for (var i = 0; i < text.length; i++) {
if (text[i] == '`' && _isCodeStyle(textNode, i) == false) {
backquoteIndexes.add(i);
}
}
return backquoteIndexes;
}
/// To denote a word or phrase as code, enclose it in backticks (`).
/// If the word or phrase you want to denote as code includes one or more
/// backticks, you can escape it by enclosing the word or phrase in double
/// backticks (``).
ShortcutEventHandler backquoteToCodeHandler = (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 selectionText = textNode
.toRawString()
.substring(selection.start.offset, selection.end.offset);
// toggle code style when selected some text
if (selectionText.length > 0) {
formatEmbedCode(editorState);
return KeyEventResult.handled;
}
final text = textNode.toRawString().substring(0, selection.end.offset);
final backquoteIndexes = _findBackquoteIndexes(text, textNode);
if (backquoteIndexes.isEmpty) {
return KeyEventResult.ignored;
}
final endIndex = selection.end.offset;
if (_isEscapeBackquote(text, backquoteIndexes)) {
final firstBackquoteIndex = backquoteIndexes[0];
final secondBackquoteIndex = backquoteIndexes[1];
final lastBackquoteIndex = backquoteIndexes[backquoteIndexes.length - 1];
if (secondBackquoteIndex == lastBackquoteIndex ||
secondBackquoteIndex == lastBackquoteIndex - 1 ||
lastBackquoteIndex != endIndex - 1) {
// ``(`),```(`),``...`...(`) should ignored
return KeyEventResult.ignored;
}
TransactionBuilder(editorState)
..deleteText(textNode, lastBackquoteIndex, 1)
..deleteText(textNode, firstBackquoteIndex, 2)
..formatText(
textNode,
firstBackquoteIndex,
endIndex - firstBackquoteIndex - 3,
{
BuiltInAttributeKey.code: true,
},
)
..afterSelection = Selection.collapsed(
Position(
path: textNode.path,
offset: endIndex - 3,
),
)
..commit();
return KeyEventResult.handled;
}
// handle single backquote
final startIndex = backquoteIndexes[0];
if (startIndex == endIndex - 1) {
return KeyEventResult.ignored;
}
// delete the backquote.
// update the style of the text surround by ` ` to code.
// and update the cursor position.
TransactionBuilder(editorState)
..deleteText(textNode, startIndex, 1)
..formatText(
textNode,
startIndex,
endIndex - startIndex - 1,
{
BuiltInAttributeKey.code: true,
},
)
..afterSelection = Selection.collapsed(
Position(
path: textNode.path,
offset: endIndex - 1,
),
)
..commit();
return KeyEventResult.handled;
};

View File

@ -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';
@ -249,4 +250,9 @@ List<ShortcutEvent> builtInShortcutEvents = [
command: 'tab',
handler: tabHandler,
),
ShortcutEvent(
key: 'Backquote to code',
command: 'backquote',
handler: backquoteToCodeHandler,
),
];