chore(developer): further debugging for assertion failure

Adds breadcrumbs for debug memo to try and narrow down sequence of
events leading to assertion failure with backspace.

Relates-to: #11706
Test-bot: skip
Cherry-pick-of: #15056
This commit is contained in:
Marc Durdin 2025-10-30 13:22:27 +01:00
parent 82a8567845
commit ec57939f4d
3 changed files with 59 additions and 8 deletions

View file

@ -36,6 +36,7 @@ type
TMemoSelection = record
Start, Finish: Integer;
Anchor: Integer;
function ToString: string;
end;
TKeymanDeveloperDebuggerMemo = class(TRichEdit41)
@ -107,6 +108,8 @@ end;
function TKeymanDeveloperDebuggerMemo.GetSelection: TMemoSelection;
begin
Result.Anchor := 0;
// EM_GETSEL doesn't tell us the anchor position, but we can figure
// it out with this kludge. I am not aware of side effects from this
// at this time.
@ -170,4 +173,11 @@ begin
RegisterComponents('Keyman', [TKeymanDeveloperDebuggerMemo]);
end;
{ TMemoSelection }
function TMemoSelection.ToString: string;
begin
Result := Format('%d %d %d', [Start, Finish, Anchor]);
end;
end.

View file

@ -109,7 +109,7 @@ type
procedure ResetEvents;
procedure ExecuteEvent(n: Integer);
procedure ExecuteEventAction(n: Integer);
procedure ExecuteEventAction(EventNumber: Integer);
procedure ExecuteEventRule(n: Integer);
procedure SetExecutionPointLine(ALine: Integer);
procedure SetUIStatus(const Value: TDebugUIStatus);
@ -210,6 +210,7 @@ uses
dmActionsMain,
Glossary,
Keyman.Developer.System.Project.ProjectLog,
Keyman.System.KeymanSentryClient,
Keyman.UI.Debug.CharacterGridRenderer,
KeyNames,
kmxfile,
@ -462,6 +463,10 @@ begin
modifier := modifier and not KM_CORE_MODIFIER_LCTRL;
end;
TKeymanSentryClient.Instance.Breadcrumb('default',
Format('ProcessKeyEvent: vk=%x mod=%x scan=%x beforeText="%s" beforeSelection=%s',[vkey, modifier, scan, Copy(memo.GetTextCR, 1, 256), memo.Selection.ToString]),
'debugger');
if not SetKeyEventContext then
Exit(False);
@ -598,8 +603,14 @@ end;
procedure TfrmDebug.ExecuteEvent(n: Integer);
begin
TKeymanSentryClient.Instance.Breadcrumb('default',
Format('ExecuteEvent(%d/%d): [%s]; b:%s; s:%s',
[n, FEvents.Count, FEvents[n].ToString, memo.Selection.ToString, FSavedSelection.ToString]),
'debugger');
memo.ReadOnly := False;
memo.Selection := FSavedSelection;
if FEvents[n].EventType = etAction
then ExecuteEventAction(n)
else ExecuteEventRule(n);
@ -667,7 +678,7 @@ begin
end;
procedure TfrmDebug.ExecuteEventAction(n: Integer);
procedure TfrmDebug.ExecuteEventAction(EventNumber: Integer);
type
TMemoSelectionState = record
Selection: TMemoSelection;
@ -711,24 +722,25 @@ procedure TfrmDebug.ExecuteEventAction(n: Integer);
procedure DoBackspace(BackspaceType: km_core_backspace_type; ExpectedValue: NativeUInt);
var
t: string;
m, n: Integer;
m, m1: Integer;
dk: TDeadKeyInfo;
state: TMemoSelectionState;
function AssertionMessage: string;
begin
Result := 'Assertion failed. Extra data: '+
'EventNumber='+IntToStr(EventNumber)+'; '+
'BackspaceType='+IntToStr(Ord(BackspaceType))+'; '+
'ExpectedValue=U+'+IntToHex(ExpectedValue, 4)+'; '+
'memo.SelStart='+IntToStr(memo.SelStart)+'; '+
'memo.SelLength='+IntToStr(memo.SelLength)+'; '+
'memo.Text='+Copy(memo.GetTextCR, 1, 256);
'memo.Text="'+Copy(memo.GetTextCR, 1, 256)+'"';
end;
begin
// Offset is zero-based, but string is 1-based. Beware!
state := SaveMemoSelectionState;
n := memo.SelStart;
m := n;
m1 := memo.SelStart;
m := m1;
if memo.SelLength > 0 then
begin
@ -800,7 +812,7 @@ procedure TfrmDebug.ExecuteEventAction(n: Integer);
memo.Lines.BeginUpdate;
try
memo.Text := Copy(t, 1, m) + Copy(t, n+1, MaxInt);
memo.Text := Copy(t, 1, m) + Copy(t, m1+1, MaxInt);
memo.SelStart := m;
finally
memo.Lines.EndUpdate;
@ -894,7 +906,7 @@ procedure TfrmDebug.ExecuteEventAction(n: Integer);
begin
DisableUI;
frmDebugStatus.Elements.UpdateStores(nil);
with FEvents[n].Action do
with FEvents[EventNumber].Action do
begin
case ActionType of
KM_CORE_IT_EMIT_KEYSTROKE: DoEmitKeystroke(dwData);

View file

@ -62,6 +62,7 @@ type
public
constructor Create;
destructor Destroy; override;
function ToString: string; override;
property Action: TDebugEventActionData read FAction;
property Rule: TDebugEventRuleData read FRule;
property EventType: TDebugEventType read FEventType write SetEventType;
@ -94,6 +95,8 @@ type
vk: uint16_t;
modifier_state: uint16_t
): Boolean; overload;
function ToString: string; override;
end;
implementation
@ -134,6 +137,23 @@ begin
end;
end;
function TDebugEvent.ToString: string;
begin
// Debug string
if FEventType = etAction then
begin
Result := Format('A %d %d %d "%s"', [Ord(FAction.ActionType), FAction.dwData, FAction.nExpectedValue, FAction.Text]);
end
else if FEventType = etRuleMatch then
begin
Result := Format('R %d %x %x %d "%s"', [FRule.ItemType, FRule.Key.VirtualKey, FRule.Key.Modifiers, FRule.Line, FRule.Context]);
end
else
begin
Result := '?'+IntToStr(Ord(FEventType));
end;
end;
function TDebugEventList.AddActionItem(key: Word; action: pkm_core_action_item): Boolean;
begin
Result := True;
@ -330,6 +350,15 @@ begin
end;
end;
function TDebugEventList.ToString: string;
var
I: Integer;
begin
Result := '';
for I := 0 to Count - 1 do
Result := Result + '['+IntToStr(I)+': '+Items[I].ToString + '] ';
end;
function TDebugEventList.AddStateItems(
state: pkm_core_state;
vk: uint16_t;