chore: fully update match info after auto-accepting replacement, add more error handling in construct token span (#2865)

This commit is contained in:
ggurdin 2025-05-21 16:06:30 -04:00 committed by GitHub
parent 21d703d640
commit ddc60b0a4f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 98 additions and 28 deletions

View file

@ -453,11 +453,6 @@ class Choreographer {
if (!isNormalizationError) continue;
final match = igc.igcTextData!.matches[i];
choreoRecord.addRecord(
_textController.text,
match: match.copyWith..status = PangeaMatchStatus.automatic,
);
igc.igcTextData!.acceptReplacement(
i,
match.match.choices!.indexWhere(
@ -465,6 +460,19 @@ class Choreographer {
),
);
final newMatch = match.copyWith;
newMatch.status = PangeaMatchStatus.automatic;
newMatch.match.length = match.match.choices!
.firstWhere((c) => c.isBestCorrection)
.value
.characters
.length;
choreoRecord.addRecord(
_textController.text,
match: newMatch,
);
_textController.setSystemText(
igc.igcTextData!.originalInput,
EditType.igc,

View file

@ -65,7 +65,17 @@ class ErrorService {
return Duration(seconds: coolDownSeconds);
}
final List<String> _errorCache = [];
setError(ChoreoError? error, {Duration? duration}) {
if (_errorCache.contains(error?.raw.toString())) {
return;
}
if (error != null) {
_errorCache.add(error.raw.toString());
}
_error = error;
Future.delayed(duration ?? defaultCooldown, () {
clear();

View file

@ -295,6 +295,9 @@ class IgcController {
igcTextData = null;
spanDataController.clearCache();
spanDataController.dispose();
MatrixState.pAnyState.closeAllOverlays(
filter: RegExp(r'span_card_overlay_\d+'),
);
}
dispose() {

View file

@ -292,12 +292,45 @@ class IGCTextData {
// create a pointer to the current index in the original input
// and iterate until the pointer has reached the end of the input
int currentIndex = 0;
int loops = 0;
final List<PangeaMatch> addedMatches = [];
while (currentIndex < originalInput.characters.length) {
if (loops > 100) {
ErrorHandler.logError(
e: "In constructTokenSpan, infinite loop detected",
data: {
"currentIndex": currentIndex,
"matches": textSpanMatches.map((m) => m.toJson()).toList(),
},
);
throw "In constructTokenSpan, infinite loop detected";
}
// check if the pointer is at a match, and if so, get the index of the match
final int matchIndex = matchRanges.indexWhere(
(range) => currentIndex >= range[0] && currentIndex < range[1],
);
final bool inMatch = matchIndex != -1;
final bool inMatch = matchIndex != -1 &&
!addedMatches.contains(
textSpanMatches[matchIndex],
);
if (matchIndex != -1 &&
addedMatches.contains(
textSpanMatches[matchIndex],
)) {
ErrorHandler.logError(
e: "In constructTokenSpan, currentIndex is in match that has already been added",
data: {
"currentIndex": currentIndex,
"matchIndex": matchIndex,
"matches": textSpanMatches.map((m) => m.toJson()).toList(),
},
);
throw "In constructTokenSpan, currentIndex is in match that has already been added";
}
final prevIndex = currentIndex;
if (inMatch) {
// if the pointer is in a match, then add that match to items
@ -312,13 +345,7 @@ class IGCTextData {
final span = originalInput.characters
.getRange(
match.match.offset,
match.match.offset +
(match.match.choices
?.firstWhere((c) => c.isBestCorrection)
.value
.characters
.length ??
match.match.length),
match.match.offset + match.match.length,
)
.toString();
@ -364,12 +391,8 @@ class IGCTextData {
),
);
currentIndex = match.match.offset +
(match.match.choices
?.firstWhere((c) => c.isBestCorrection)
.value
.length ??
match.match.length);
addedMatches.add(match);
currentIndex = match.match.offset + match.match.length;
} else {
items.add(
getSpanItem(
@ -400,6 +423,20 @@ class IGCTextData {
);
currentIndex = nextIndex;
}
if (prevIndex >= currentIndex) {
ErrorHandler.logError(
e: "In constructTokenSpan, currentIndex is less than prevIndex",
data: {
"currentIndex": currentIndex,
"prevIndex": prevIndex,
"matches": textSpanMatches.map((m) => m.toJson()).toList(),
},
);
throw "In constructTokenSpan, currentIndex is less than prevIndex";
}
loops++;
}
return items;

View file

@ -3,6 +3,7 @@ import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:fluffychat/pangea/choreographer/controllers/error_service.dart';
import 'package:fluffychat/pangea/choreographer/models/igc_text_data_model.dart';
import 'package:fluffychat/pangea/choreographer/models/pangea_match_model.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/paywall_card.dart';
@ -174,18 +175,29 @@ class PangeaTextController extends TextEditingController {
final choreoSteps = choreographer.choreoRecord.choreoSteps;
List<InlineSpan> inlineSpans = [];
try {
inlineSpans = choreographer.igc.igcTextData!.constructTokenSpan(
choreoSteps: choreoSteps.isNotEmpty &&
choreoSteps.last.acceptedOrIgnoredMatch?.status ==
PangeaMatchStatus.automatic
? choreoSteps
: [],
defaultStyle: style,
onUndo: choreographer.onUndoReplacement,
);
} catch (e) {
choreographer.errorService.setError(
ChoreoError(type: ChoreoErrorType.unknown, raw: e),
);
inlineSpans = [TextSpan(text: text, style: style)];
choreographer.igc.clear();
}
return TextSpan(
style: style,
children: [
...choreographer.igc.igcTextData!.constructTokenSpan(
choreoSteps: choreoSteps.isNotEmpty &&
choreoSteps.last.acceptedOrIgnoredMatch?.status ==
PangeaMatchStatus.automatic
? choreoSteps
: [],
defaultStyle: style,
onUndo: choreographer.onUndoReplacement,
),
...inlineSpans,
TextSpan(text: parts[1], style: style),
],
);