* fix: [Bug] Code block jump skip blank line

* fix: auto completion interaction

* Revert "fix: [Bug] Code block jump skip blank line"

This reverts commit 5a252bcb18.

* fix: [Bug] Code block jump skip blank line

* fix: number list parse error
This commit is contained in:
Lucas.Xu
2023-03-09 10:10:31 +08:00
committed by GitHub
parent d3823eb076
commit 21199c04ac
7 changed files with 75 additions and 26 deletions

View File

@ -2,7 +2,6 @@ import 'dart:convert';
import 'package:appflowy/plugins/document/presentation/plugins/openai/service/text_edit.dart'; import 'package:appflowy/plugins/document/presentation/plugins/openai/service/text_edit.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'text_completion.dart'; import 'text_completion.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
@ -39,7 +38,7 @@ abstract class OpenAIRepository {
Future<Either<OpenAIError, TextCompletionResponse>> getCompletions({ Future<Either<OpenAIError, TextCompletionResponse>> getCompletions({
required String prompt, required String prompt,
String? suffix, String? suffix,
int maxTokens = 500, int maxTokens = 2048,
double temperature = .3, double temperature = .3,
}); });
@ -47,10 +46,10 @@ abstract class OpenAIRepository {
required String prompt, required String prompt,
required Future<void> Function() onStart, required Future<void> Function() onStart,
required Future<void> Function(TextCompletionResponse response) onProcess, required Future<void> Function(TextCompletionResponse response) onProcess,
required VoidCallback onEnd, required Future<void> Function() onEnd,
required void Function(OpenAIError error) onError, required void Function(OpenAIError error) onError,
String? suffix, String? suffix,
int maxTokens = 500, int maxTokens = 2048,
double temperature = 0.3, double temperature = 0.3,
}); });
@ -85,7 +84,7 @@ class HttpOpenAIRepository implements OpenAIRepository {
Future<Either<OpenAIError, TextCompletionResponse>> getCompletions({ Future<Either<OpenAIError, TextCompletionResponse>> getCompletions({
required String prompt, required String prompt,
String? suffix, String? suffix,
int maxTokens = 500, int maxTokens = 2048,
double temperature = 0.3, double temperature = 0.3,
}) async { }) async {
final parameters = { final parameters = {
@ -121,10 +120,10 @@ class HttpOpenAIRepository implements OpenAIRepository {
required String prompt, required String prompt,
required Future<void> Function() onStart, required Future<void> Function() onStart,
required Future<void> Function(TextCompletionResponse response) onProcess, required Future<void> Function(TextCompletionResponse response) onProcess,
required VoidCallback onEnd, required Future<void> Function() onEnd,
required void Function(OpenAIError error) onError, required void Function(OpenAIError error) onError,
String? suffix, String? suffix,
int maxTokens = 500, int maxTokens = 2048,
double temperature = 0.3, double temperature = 0.3,
}) async { }) async {
final parameters = { final parameters = {
@ -159,7 +158,9 @@ class HttpOpenAIRepository implements OpenAIRepository {
continue; continue;
} }
final data = chunk.trim().split('data: '); final data = chunk.trim().split('data: ');
if (data.length > 1 && data[1] != '[DONE]') { Log.editor.info(data.toString());
if (data.length > 1) {
if (data[1] != '[DONE]') {
final response = TextCompletionResponse.fromJson( final response = TextCompletionResponse.fromJson(
json.decode(data[1]), json.decode(data[1]),
); );
@ -170,12 +171,12 @@ class HttpOpenAIRepository implements OpenAIRepository {
} }
await onProcess(response); await onProcess(response);
previousSyntax = response.choices.first.text; previousSyntax = response.choices.first.text;
Log.editor.info(response.choices.first.text);
} }
} else { } else {
onEnd(); onEnd();
} }
} }
}
} else { } else {
final body = await response.stream.bytesToString(); final body = await response.stream.bytesToString();
onError( onError(

View File

@ -69,6 +69,8 @@ class _AutoCompletionInputState extends State<_AutoCompletionInput> {
void dispose() { void dispose() {
controller.dispose(); controller.dispose();
textFieldFocusNode.removeListener(_onFocusChanged); textFieldFocusNode.removeListener(_onFocusChanged);
widget.editorState.service.selectionService.currentSelection
.removeListener(_onCancelWhenSelectionChanged);
super.dispose(); super.dispose();
} }
@ -239,6 +241,7 @@ class _AutoCompletionInputState extends State<_AutoCompletionInput> {
final result = await UserBackendService.getCurrentUserProfile(); final result = await UserBackendService.getCurrentUserProfile();
result.fold((userProfile) async { result.fold((userProfile) async {
BarrierDialog? barrierDialog;
final openAIRepository = HttpOpenAIRepository( final openAIRepository = HttpOpenAIRepository(
client: http.Client(), client: http.Client(),
apiKey: userProfile.openaiKey, apiKey: userProfile.openaiKey,
@ -247,6 +250,8 @@ class _AutoCompletionInputState extends State<_AutoCompletionInput> {
prompt: controller.text, prompt: controller.text,
onStart: () async { onStart: () async {
loading.stop(); loading.stop();
barrierDialog = BarrierDialog(context);
barrierDialog?.show();
await _makeSurePreviousNodeIsEmptyTextNode(); await _makeSurePreviousNodeIsEmptyTextNode();
}, },
onProcess: (response) async { onProcess: (response) async {
@ -255,10 +260,15 @@ class _AutoCompletionInputState extends State<_AutoCompletionInput> {
await widget.editorState.autoInsertText( await widget.editorState.autoInsertText(
text, text,
inputType: TextRobotInputType.word, inputType: TextRobotInputType.word,
delay: Duration.zero,
); );
} }
}, },
onEnd: () {}, onEnd: () async {
await barrierDialog?.dismiss();
widget.editorState.service.selectionService.currentSelection
.addListener(_onCancelWhenSelectionChanged);
},
onError: (error) async { onError: (error) async {
loading.stop(); loading.stop();
await _showError(error.message); await _showError(error.message);
@ -353,4 +363,6 @@ class _AutoCompletionInputState extends State<_AutoCompletionInput> {
widget.editorState.service.keyboardService?.enable(); widget.editorState.service.keyboardService?.enable();
} }
} }
void _onCancelWhenSelectionChanged() {}
} }

View File

@ -32,3 +32,28 @@ class Loading {
return Navigator.of(loadingContext).pop(); return Navigator.of(loadingContext).pop();
} }
} }
class BarrierDialog {
BarrierDialog(
this.context,
);
late BuildContext loadingContext;
final BuildContext context;
Future<void> show() async {
return showDialog<void>(
context: context,
barrierDismissible: false,
barrierColor: Colors.transparent,
builder: (BuildContext context) {
loadingContext = context;
return Container();
},
);
}
Future<void> dismiss() async {
return Navigator.of(loadingContext).pop();
}
}

View File

@ -38,10 +38,10 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
flowy_infra_ui: c34d49d615ed9fe552cd47f90d7850815a74e9e9 flowy_infra_ui: c34d49d615ed9fe552cd47f90d7850815a74e9e9
FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811 FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811
path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852 path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9
rich_clipboard_macos: 43364b66b9dc69d203eb8dd6d758e2d12e02723c rich_clipboard_macos: 43364b66b9dc69d203eb8dd6d758e2d12e02723c
shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472
url_launcher_macos: c04e4fa86382d4f94f6b38f14625708be3ae52e2 url_launcher_macos: 5335912b679c073563f29d89d33d10d459f95451
PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c

View File

@ -95,11 +95,18 @@ class _FlowyRichTextState extends State<FlowyRichText> with SelectableMixin {
textPosition, Rect.zero) ?? textPosition, Rect.zero) ??
Offset.zero; Offset.zero;
} }
if (widget.cursorHeight != null && cursorHeight != null) {
cursorOffset = Offset(
cursorOffset.dx,
cursorOffset.dy + (cursorHeight - widget.cursorHeight!) / 2,
);
cursorHeight = widget.cursorHeight;
}
final rect = Rect.fromLTWH( final rect = Rect.fromLTWH(
cursorOffset.dx - (widget.cursorWidth / 2.0), cursorOffset.dx - (widget.cursorWidth / 2.0),
cursorOffset.dy, cursorOffset.dy,
widget.cursorWidth, widget.cursorWidth,
widget.cursorHeight ?? cursorHeight ?? 16.0, cursorHeight ?? 16.0,
); );
return rect; return rect;
} }

View File

@ -56,7 +56,9 @@ ShortcutEventHandler whiteSpaceHandler = (editorState, event) {
} else if (numberMatch != null) { } else if (numberMatch != null) {
final matchText = numberMatch.group(0); final matchText = numberMatch.group(0);
final numText = numberMatch.group(1); final numText = numberMatch.group(1);
if (matchText != null && numText != null) { if (matchText != null &&
numText != null &&
matchText.length == selection.startIndex) {
return _toNumberList(editorState, textNode, matchText, numText); return _toNumberList(editorState, textNode, matchText, numText);
} }
} }

View File

@ -102,6 +102,8 @@ class __CodeBlockNodeWidgeState extends State<_CodeBlockNodeWidge>
key: _richTextKey, key: _richTextKey,
textNode: widget.textNode, textNode: widget.textNode,
editorState: widget.editorState, editorState: widget.editorState,
lineHeight: 1.0,
cursorHeight: 15.0,
textSpanDecorator: (textSpan) => TextSpan( textSpanDecorator: (textSpan) => TextSpan(
style: widget.editorState.editorStyle.textStyle, style: widget.editorState.editorStyle.textStyle,
children: codeTextSpan, children: codeTextSpan,