fix: backtick issue in French IME (#6408)

* fix: backtick doesn't format the text to code in french ime

* test: add backtick test

* fix: three backticks doesn't convert to code block in french ime

* chore: remove cache for docker ci
This commit is contained in:
Lucas 2024-09-26 20:16:49 +08:00 committed by GitHub
parent 1ffd653515
commit 1b0bb1d5ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 153 additions and 19 deletions

View File

@ -23,13 +23,14 @@ jobs:
uses: docker/setup-buildx-action@v3
# cache the docker layers
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
# don't cache anything temporarly, because it always triggers "no space left on device" error
# - name: Cache Docker layers
# uses: actions/cache@v3
# with:
# path: /tmp/.buildx-cache
# key: ${{ runner.os }}-buildx-${{ github.sha }}
# restore-keys: |
# ${{ runner.os }}-buildx-
- name: Build the app
uses: docker/build-push-action@v5
@ -37,10 +38,10 @@ jobs:
context: .
file: ./frontend/scripts/docker-buildfiles/Dockerfile
push: false
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
# cache-from: type=local,src=/tmp/.buildx-cache
# cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
# - name: Move cache
# run: |
# rm -rf /tmp/.buildx-cache
# mv /tmp/.buildx-cache-new /tmp/.buildx-cache

View File

@ -0,0 +1,61 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('customer:', () {
testWidgets('backtick issue - inline code', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
const pageName = 'backtick issue';
await tester.createNewPageWithNameUnderParent(name: pageName);
// focus on the editor
await tester.tap(find.byType(AppFlowyEditor));
// input backtick
const text = '`Hello` AppFlowy';
for (var i = 0; i < text.length; i++) {
await tester.ime.insertCharacter(text[i]);
}
final node = tester.editor.getNodeAtPath([0]);
expect(
node.delta?.toJson(),
equals([
{
"insert": "Hello",
"attributes": {"code": true},
},
{"insert": " AppFlowy"},
]),
);
});
testWidgets('backtick issue - inline code', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
const pageName = 'backtick issue';
await tester.createNewPageWithNameUnderParent(name: pageName);
// focus on the editor
await tester.tap(find.byType(AppFlowyEditor));
// input backtick
const text = '```';
for (var i = 0; i < text.length; i++) {
await tester.ime.insertCharacter(text[i]);
}
final node = tester.editor.getNodeAtPath([0]);
expect(node.type, equals(CodeBlockKeys.type));
});
});
}

View File

@ -270,9 +270,9 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
editorState.logConfiguration
..level = AppFlowyEditorLogLevel.all
..handler = (log) {
// if (enableDocumentInternalLog) {
Log.info(log);
// }
if (enableDocumentInternalLog) {
Log.info(log);
}
};
}

View File

@ -213,6 +213,8 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
late final ViewInfoBloc viewInfoBloc = context.read<ViewInfoBloc>();
final editorKeyboardInterceptor = EditorKeyboardInterceptor();
Future<bool> showSlashMenu(editorState) async => customSlashCommand(
slashMenuItems,
shouldInsertSlash: false,
@ -278,6 +280,10 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
if (widget.initialSelection != null) {
widget.editorState.updateSelectionWithReason(widget.initialSelection);
}
widget.editorState.service.keyboardService?.registerInterceptor(
editorKeyboardInterceptor,
);
});
}
@ -302,6 +308,9 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
@override
void dispose() {
widget.editorState.service.keyboardService?.unregisterInterceptor(
editorKeyboardInterceptor,
);
focusManager?.loseFocusNotifier.removeListener(_loseFocus);
if (widget.useViewInfoBloc && !viewInfoBloc.isClosed) {

View File

@ -0,0 +1,62 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
import 'package:flutter/services.dart';
class EditorKeyboardInterceptor extends AppFlowyKeyboardServiceInterceptor {
@override
Future<bool> interceptNonTextUpdate(
TextEditingDeltaNonTextUpdate nonTextUpdate,
EditorState editorState,
List<CharacterShortcutEvent> characterShortcutEvents,
) async {
return _checkIfBacktickPressed(
editorState,
nonTextUpdate,
);
}
/// Check if the backtick pressed event should be handled
Future<bool> _checkIfBacktickPressed(
EditorState editorState,
TextEditingDeltaNonTextUpdate nonTextUpdate,
) async {
// if the composing range is not empty, it means the user is typing a text,
// so we don't need to handle the backtick pressed event
if (!nonTextUpdate.composing.isCollapsed ||
!nonTextUpdate.selection.isCollapsed) {
return false;
}
final selection = editorState.selection;
if (selection == null || !selection.isCollapsed) {
AppFlowyEditorLog.input.debug('selection is null or not collapsed');
return false;
}
final node = editorState.getNodesInSelection(selection).firstOrNull;
if (node == null) {
AppFlowyEditorLog.input.debug('node is null');
return false;
}
// get last character of the node
final plainText = node.delta?.toPlainText();
// three backticks to code block
if (plainText != '```') {
return false;
}
final transaction = editorState.transaction;
transaction.insertNode(
selection.end.path,
codeBlockNode(),
);
transaction.deleteNode(node);
transaction.afterSelection = Selection.collapsed(
Position(path: selection.start.path),
);
await editorState.apply(transaction);
return true;
}
}

View File

@ -30,6 +30,7 @@ export 'image/mobile_image_toolbar_item.dart';
export 'image/multi_image_block_component/multi_image_menu.dart';
export 'inline_math_equation/inline_math_equation.dart';
export 'inline_math_equation/inline_math_equation_toolbar_item.dart';
export 'keyboard_interceptor/keyboard_interceptor.dart';
export 'link_preview/custom_link_preview.dart';
export 'link_preview/link_preview_cache.dart';
export 'link_preview/link_preview_menu.dart';

View File

@ -53,8 +53,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: "737681d"
resolved-ref: "737681dd97b501dd88c7c016c5c359f9ffff7d31"
ref: "6da7b4e"
resolved-ref: "6da7b4e5dc76dd6b9d4361c744359b04ddb5b983"
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
source: git
version: "3.3.0"

View File

@ -177,7 +177,7 @@ dependency_overrides:
appflowy_editor:
git:
url: https://github.com/AppFlowy-IO/appflowy-editor.git
ref: "737681d"
ref: "6da7b4e"
appflowy_editor_plugins:
git: