mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-27 03:02:13 +02:00
Debugger: Update locals to use VirtualTree / FpDebug: return locals as new WatchResultData
This commit is contained in:
parent
40a5975659
commit
26f4160df9
@ -115,9 +115,6 @@ type
|
|||||||
{ TFpThreadWorkerLocalsUpdate }
|
{ TFpThreadWorkerLocalsUpdate }
|
||||||
|
|
||||||
TFpThreadWorkerLocalsUpdate = class(TFpThreadWorkerLocals)
|
TFpThreadWorkerLocalsUpdate = class(TFpThreadWorkerLocals)
|
||||||
private
|
|
||||||
FLocals: TLocalsListIntf;
|
|
||||||
procedure DoLocalsFreed_DecRef(Sender: TObject);
|
|
||||||
protected
|
protected
|
||||||
procedure UpdateLocals_DecRef(Data: PtrInt = 0); override;
|
procedure UpdateLocals_DecRef(Data: PtrInt = 0); override;
|
||||||
procedure DoRemovedFromLinkedList; override; // _DecRef
|
procedure DoRemovedFromLinkedList; override; // _DecRef
|
||||||
@ -985,41 +982,15 @@ end;
|
|||||||
|
|
||||||
{ TFpThreadWorkerLocalsUpdate }
|
{ TFpThreadWorkerLocalsUpdate }
|
||||||
|
|
||||||
procedure TFpThreadWorkerLocalsUpdate.DoLocalsFreed_DecRef(Sender: TObject);
|
|
||||||
begin
|
|
||||||
assert(system.ThreadID = classes.MainThreadID, 'TFpThreadWorkerLocals.DoLocalsFreed_DecRef: system.ThreadID = classes.MainThreadID');
|
|
||||||
FLocals := nil;
|
|
||||||
RequestStop;
|
|
||||||
UnQueue_DecRef;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TFpThreadWorkerLocalsUpdate.UpdateLocals_DecRef(Data: PtrInt);
|
procedure TFpThreadWorkerLocalsUpdate.UpdateLocals_DecRef(Data: PtrInt);
|
||||||
var
|
var
|
||||||
i: Integer;
|
|
||||||
r: TResultEntry;
|
|
||||||
dbg: TFpDebugDebugger;
|
dbg: TFpDebugDebugger;
|
||||||
rv: TLzDbgWatchDataIntf;
|
|
||||||
begin
|
begin
|
||||||
assert(system.ThreadID = classes.MainThreadID, 'TFpThreadWorkerLocals.UpdateLocals_DecRef: system.ThreadID = classes.MainThreadID');
|
assert(system.ThreadID = classes.MainThreadID, 'TFpThreadWorkerLocals.UpdateLocals_DecRef: system.ThreadID = classes.MainThreadID');
|
||||||
|
|
||||||
if FLocals <> nil then begin
|
if FLocals <> nil then begin
|
||||||
FLocals.RemoveFreeNotification(@DoLocalsFreed_DecRef);
|
|
||||||
if FResults = nil then begin
|
|
||||||
FLocals.Validity := ddsInvalid;
|
|
||||||
FLocals := nil;
|
|
||||||
UnQueue_DecRef;
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
FLocals.BeginUpdate;
|
|
||||||
for i := 0 to FResults.Count - 1 do begin
|
|
||||||
r := FResults[i];
|
|
||||||
rv := FLocals.Add(r.Name);
|
|
||||||
rv.CreatePrePrinted(r.Value);
|
|
||||||
end;
|
|
||||||
FLocals.Validity := ddsValid;
|
FLocals.Validity := ddsValid;
|
||||||
FLocals.EndUpdate;
|
FLocals.EndUpdate;
|
||||||
|
|
||||||
FLocals := nil;
|
FLocals := nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1036,8 +1007,8 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
FLocals.RemoveFreeNotification(@DoLocalsFreed_DecRef);
|
|
||||||
FLocals.Validity := ddsInvalid;
|
FLocals.Validity := ddsInvalid;
|
||||||
|
FLocals.EndUpdate;
|
||||||
end;
|
end;
|
||||||
FLocals := nil;
|
FLocals := nil;
|
||||||
end;
|
end;
|
||||||
@ -1050,7 +1021,7 @@ begin
|
|||||||
// Runs in IDE thread (TThread.Queue)
|
// Runs in IDE thread (TThread.Queue)
|
||||||
assert(system.ThreadID = classes.MainThreadID, 'TFpThreadWorkerLocals.Create: system.ThreadID = classes.MainThreadID');
|
assert(system.ThreadID = classes.MainThreadID, 'TFpThreadWorkerLocals.Create: system.ThreadID = classes.MainThreadID');
|
||||||
FLocals := ALocals;
|
FLocals := ALocals;
|
||||||
FLocals.AddFreeNotification(@DoLocalsFreed_DecRef);
|
FLocals.BeginUpdate;
|
||||||
FThreadId := ALocals.ThreadId;
|
FThreadId := ALocals.ThreadId;
|
||||||
FStackFrame := ALocals.StackFrame;
|
FStackFrame := ALocals.StackFrame;
|
||||||
inherited Create(ADebugger, twpLocal);
|
inherited Create(ADebugger, twpLocal);
|
||||||
|
@ -191,18 +191,11 @@ type
|
|||||||
|
|
||||||
TFpThreadWorkerLocals = class(TFpDbgDebggerThreadWorkerLinkedItem)
|
TFpThreadWorkerLocals = class(TFpDbgDebggerThreadWorkerLinkedItem)
|
||||||
protected type
|
protected type
|
||||||
TResultEntry = record
|
|
||||||
Name, Value: String;
|
|
||||||
class operator = (a, b: TResultEntry): Boolean;
|
|
||||||
end;
|
|
||||||
TResultList = specialize TFPGList<TResultEntry>;
|
|
||||||
protected
|
protected
|
||||||
|
FLocals: TLocalsListIntf;
|
||||||
FThreadId, FStackFrame: Integer;
|
FThreadId, FStackFrame: Integer;
|
||||||
FResults: TResultList;
|
|
||||||
procedure UpdateLocals_DecRef(Data: PtrInt = 0); virtual; abstract;
|
procedure UpdateLocals_DecRef(Data: PtrInt = 0); virtual; abstract;
|
||||||
procedure DoExecute; override;
|
procedure DoExecute; override;
|
||||||
public
|
|
||||||
destructor Destroy; override;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TFpThreadWorkerModify }
|
{ TFpThreadWorkerModify }
|
||||||
@ -657,24 +650,15 @@ begin
|
|||||||
inherited Create(ADebugger, 1, twpThread);
|
inherited Create(ADebugger, 1, twpThread);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TFpThreadWorkerLocals.TResultEntry }
|
|
||||||
|
|
||||||
class operator TFpThreadWorkerLocals.TResultEntry. = (a, b: TResultEntry
|
|
||||||
): Boolean;
|
|
||||||
begin
|
|
||||||
Result := False;
|
|
||||||
assert(False, 'TFpThreadWorkerLocals.TResultEntry.=: False');
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TFpThreadWorkerLocals }
|
{ TFpThreadWorkerLocals }
|
||||||
|
|
||||||
procedure TFpThreadWorkerLocals.DoExecute;
|
procedure TFpThreadWorkerLocals.DoExecute;
|
||||||
var
|
var
|
||||||
LocalScope: TFpDbgSymbolScope;
|
LocalScope: TFpDbgSymbolScope;
|
||||||
ProcVal, m: TFpValue;
|
ProcVal, m: TFpValue;
|
||||||
PrettyPrinter: TFpPascalPrettyPrinter;
|
|
||||||
i: Integer;
|
i: Integer;
|
||||||
r: TResultEntry;
|
WatchResConv: TFpLazDbgWatchResultConvertor;
|
||||||
|
ResData: TLzDbgWatchDataIntf;
|
||||||
begin
|
begin
|
||||||
LocalScope := FDebugger.DbgController.CurrentProcess.FindSymbolScope(FThreadId, FStackFrame);
|
LocalScope := FDebugger.DbgController.CurrentProcess.FindSymbolScope(FThreadId, FStackFrame);
|
||||||
if (LocalScope = nil) or (LocalScope.SymbolAtAddress = nil) then begin
|
if (LocalScope = nil) or (LocalScope.SymbolAtAddress = nil) then begin
|
||||||
@ -688,39 +672,33 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
PrettyPrinter := TFpPascalPrettyPrinter.Create(LocalScope.SizeOfAddress);
|
WatchResConv := TFpLazDbgWatchResultConvertor.Create(LocalScope.LocationContext);
|
||||||
PrettyPrinter.Context := LocalScope.LocationContext;
|
WatchResConv.MaxArrayConv := TFpDebugDebuggerProperties(FDebugger.GetProperties).MemLimits.MaxArrayConversionCnt;
|
||||||
// PrettyPrinter.MemManager.DefaultContext := LocalScope.LocationContext;
|
WatchResConv.MaxTotalConv := TFpDebugDebuggerProperties(FDebugger.GetProperties).MemLimits.MaxTotalConversionCnt;
|
||||||
|
WatchResConv.Debugger := FDebugger;
|
||||||
|
WatchResConv.ExpressionScope := LocalScope;
|
||||||
|
|
||||||
FResults := TResultList.Create;
|
|
||||||
for i := 0 to ProcVal.MemberCount - 1 do begin
|
for i := 0 to ProcVal.MemberCount - 1 do begin
|
||||||
m := ProcVal.Member[i];
|
m := ProcVal.Member[i];
|
||||||
if m <> nil then begin
|
if m <> nil then begin
|
||||||
if m.DbgSymbol <> nil then
|
ResData := FLocals.Add(m.DbgSymbol.Name);
|
||||||
r.Name := m.DbgSymbol.Name
|
if not WatchResConv.WriteWatchResultData(m, ResData)
|
||||||
else
|
then begin
|
||||||
r.Name := '';
|
ResData.CreateError('Unknown Error');
|
||||||
//if not StopRequested then // finish getting all names?
|
end;
|
||||||
PrettyPrinter.PrintValue(r.Value, m);
|
|
||||||
m.ReleaseReference;
|
m.ReleaseReference;
|
||||||
FResults.Add(r);
|
|
||||||
end;
|
end;
|
||||||
if StopRequested then
|
if StopRequested then
|
||||||
Break;
|
Break;
|
||||||
end;
|
end;
|
||||||
PrettyPrinter.Free;
|
|
||||||
|
WatchResConv.Free;
|
||||||
ProcVal.ReleaseReference;
|
ProcVal.ReleaseReference;
|
||||||
LocalScope.ReleaseReference;
|
LocalScope.ReleaseReference;
|
||||||
|
|
||||||
Queue(@UpdateLocals_DecRef);
|
Queue(@UpdateLocals_DecRef);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TFpThreadWorkerLocals.Destroy;
|
|
||||||
begin
|
|
||||||
FResults.Free;
|
|
||||||
inherited Destroy;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TFpThreadWorkerModify }
|
{ TFpThreadWorkerModify }
|
||||||
|
|
||||||
procedure TFpThreadWorkerModify.DoExecute;
|
procedure TFpThreadWorkerModify.DoExecute;
|
||||||
|
@ -7072,7 +7072,9 @@ begin
|
|||||||
APath := APath + 'Entry';
|
APath := APath + 'Entry';
|
||||||
for i := 0 to c - 1 do begin
|
for i := 0 to c - 1 do begin
|
||||||
Add(AConfig.GetValue(APath + IntToStr(i) + '/Expression', ''),
|
Add(AConfig.GetValue(APath + IntToStr(i) + '/Expression', ''),
|
||||||
AConfig.GetValue(APath + IntToStr(i) + '/Value', ''));
|
TWatchResultData.CreateFromXMLConfig(AConfig, APath + IntToStr(i) + '/')
|
||||||
|
);
|
||||||
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -7086,7 +7088,7 @@ begin
|
|||||||
APath := APath + 'Entry';
|
APath := APath + 'Entry';
|
||||||
for i := 0 to Count - 1 do begin
|
for i := 0 to Count - 1 do begin
|
||||||
AConfig.SetValue(APath + IntToStr(i) + '/Expression', Names[i]);
|
AConfig.SetValue(APath + IntToStr(i) + '/Expression', Names[i]);
|
||||||
AConfig.SetValue(APath + IntToStr(i) + '/Value', Values[i]);
|
Values[i].SaveDataToXMLConfig(AConfig, APath + IntToStr(i) + '/');
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -7177,14 +7179,17 @@ var
|
|||||||
begin
|
begin
|
||||||
FCurrentResData := FCurrentResData.RootResultData;
|
FCurrentResData := FCurrentResData.RootResultData;
|
||||||
// TODO: maybe create an error entry, if only FNewResultData is missing
|
// TODO: maybe create an error entry, if only FNewResultData is missing
|
||||||
if (FCurrentResData = nil) or (FCurrentResData.FNewResultData = nil) then
|
if (FCurrentResData = nil) then
|
||||||
exit;
|
exit;
|
||||||
|
if (FCurrentResData.FNewResultData = nil) then begin
|
||||||
|
FreeAndNil(FCurrentResData);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
FCurrentResData.Done;
|
FCurrentResData.Done;
|
||||||
|
|
||||||
v := TLocalsValue(CreateEntry);
|
v := TLocalsValue(CreateEntry);
|
||||||
v.Init(FCurrentResName, FCurrentResData.FNewResultData);
|
v.Init(FCurrentResName, FCurrentResData.FNewResultData);
|
||||||
FCurrentResData.FNewResultData := nil;
|
|
||||||
|
|
||||||
if IsUpdating then
|
if IsUpdating then
|
||||||
FCurrentResList.Add(v)
|
FCurrentResList.Add(v)
|
||||||
|
@ -56,6 +56,7 @@ type
|
|||||||
|
|
||||||
procedure SelectNode(Node: PVirtualNode; ASetFocus: boolean = True);
|
procedure SelectNode(Node: PVirtualNode; ASetFocus: boolean = True);
|
||||||
function FindNodeForItem(AnItem: TObject): PVirtualNode;
|
function FindNodeForItem(AnItem: TObject): PVirtualNode;
|
||||||
|
function FindNodeForText(AText: String; AColumn: integer): PVirtualNode;
|
||||||
procedure DeleteNodeEx(Node: PVirtualNode; FreeItem: Boolean; Reindex: Boolean = True);
|
procedure DeleteNodeEx(Node: PVirtualNode; FreeItem: Boolean; Reindex: Boolean = True);
|
||||||
|
|
||||||
property NodeItem[Node: PVirtualNode]: TObject read GetNodeItem write SetNodeItem;
|
property NodeItem[Node: PVirtualNode]: TObject read GetNodeItem write SetNodeItem;
|
||||||
@ -350,6 +351,18 @@ begin
|
|||||||
Result := nil;
|
Result := nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgTreeView.FindNodeForText(AText: String; AColumn: integer
|
||||||
|
): PVirtualNode;
|
||||||
|
var
|
||||||
|
VNode: PVirtualNode;
|
||||||
|
begin
|
||||||
|
for VNode in NoInitNodes do begin
|
||||||
|
if GetNodeText(VNode, AColumn) = AText then
|
||||||
|
exit(VNode);
|
||||||
|
end;
|
||||||
|
Result := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TDbgTreeView.DeleteNodeEx(Node: PVirtualNode; FreeItem: Boolean;
|
procedure TDbgTreeView.DeleteNodeEx(Node: PVirtualNode; FreeItem: Boolean;
|
||||||
Reindex: Boolean);
|
Reindex: Boolean);
|
||||||
var
|
var
|
||||||
|
@ -238,13 +238,14 @@ type
|
|||||||
TLocalsValue = class(TDbgEntityValue)
|
TLocalsValue = class(TDbgEntityValue)
|
||||||
private
|
private
|
||||||
FName: String;
|
FName: String;
|
||||||
FValue: String;
|
FValue: TWatchResultData;
|
||||||
protected
|
protected
|
||||||
procedure DoAssign(AnOther: TDbgEntityValue); override;
|
procedure DoAssign(AnOther: TDbgEntityValue); override;
|
||||||
public
|
public
|
||||||
|
destructor Destroy; override;
|
||||||
procedure Init(AName: String; AValue: TWatchResultData);
|
procedure Init(AName: String; AValue: TWatchResultData);
|
||||||
property Name: String read FName;
|
property Name: String read FName;
|
||||||
property Value: String read FValue;
|
property Value: TWatchResultData read FValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TLocals }
|
{ TLocals }
|
||||||
@ -253,17 +254,17 @@ type
|
|||||||
private
|
private
|
||||||
function GetEntry(AnIndex: Integer): TLocalsValue;
|
function GetEntry(AnIndex: Integer): TLocalsValue;
|
||||||
function GetName(const AnIndex: Integer): String;
|
function GetName(const AnIndex: Integer): String;
|
||||||
function GetValue(const AnIndex: Integer): String;
|
function GetValue(const AnIndex: Integer): TWatchResultData;
|
||||||
protected
|
protected
|
||||||
function CreateEntry: TDbgEntityValue; override;
|
function CreateEntry: TDbgEntityValue; override;
|
||||||
public
|
public
|
||||||
procedure Add(const AName, AValue: String); overload; deprecated;
|
procedure Add(const AName: String; AValue: TWatchResultData); overload; deprecated;
|
||||||
procedure SetDataValidity({%H-}AValidity: TDebuggerDataState); virtual;
|
procedure SetDataValidity({%H-}AValidity: TDebuggerDataState); virtual;
|
||||||
public
|
public
|
||||||
function Count: Integer;reintroduce; virtual;
|
function Count: Integer;reintroduce; virtual;
|
||||||
property Entries[AnIndex: Integer]: TLocalsValue read GetEntry;
|
property Entries[AnIndex: Integer]: TLocalsValue read GetEntry;
|
||||||
property Names[const AnIndex: Integer]: String read GetName;
|
property Names[const AnIndex: Integer]: String read GetName;
|
||||||
property Values[const AnIndex: Integer]: String read GetValue;
|
property Values[const AnIndex: Integer]: TWatchResultData read GetValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TLocalsList }
|
{ TLocalsList }
|
||||||
@ -975,14 +976,20 @@ procedure TLocalsValue.DoAssign(AnOther: TDbgEntityValue);
|
|||||||
begin
|
begin
|
||||||
inherited DoAssign(AnOther);
|
inherited DoAssign(AnOther);
|
||||||
FName := TLocalsValue(AnOther).FName;
|
FName := TLocalsValue(AnOther).FName;
|
||||||
FValue := TLocalsValue(AnOther).FValue;
|
FValue.Free;
|
||||||
|
FValue := TLocalsValue(AnOther).FValue.CreateCopy();
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TLocalsValue.Destroy;
|
||||||
|
begin
|
||||||
|
inherited Destroy;
|
||||||
|
FreeAndNil(FValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocalsValue.Init(AName: String; AValue: TWatchResultData);
|
procedure TLocalsValue.Init(AName: String; AValue: TWatchResultData);
|
||||||
begin
|
begin
|
||||||
FName := AName;
|
FName := AName;
|
||||||
FValue := AValue.AsString;
|
FValue := AValue;
|
||||||
AValue.Free;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TLocalsList }
|
{ TLocalsList }
|
||||||
@ -1009,7 +1016,7 @@ begin
|
|||||||
Result := Entries[AnIndex].Name;
|
Result := Entries[AnIndex].Name;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TLocals.GetValue(const AnIndex: Integer): String;
|
function TLocals.GetValue(const AnIndex: Integer): TWatchResultData;
|
||||||
begin
|
begin
|
||||||
Result := Entries[AnIndex].Value;
|
Result := Entries[AnIndex].Value;
|
||||||
end;
|
end;
|
||||||
@ -1019,7 +1026,7 @@ begin
|
|||||||
Result := TLocalsValue.Create;
|
Result := TLocalsValue.Create;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocals.Add(const AName, AValue: String);
|
procedure TLocals.Add(const AName: String; AValue: TWatchResultData);
|
||||||
var
|
var
|
||||||
v: TLocalsValue;
|
v: TLocalsValue;
|
||||||
begin
|
begin
|
||||||
|
@ -5,33 +5,42 @@ object LocalsDlg: TLocalsDlg
|
|||||||
Width = 500
|
Width = 500
|
||||||
HorzScrollBar.Page = 499
|
HorzScrollBar.Page = 499
|
||||||
VertScrollBar.Page = 199
|
VertScrollBar.Page = 199
|
||||||
ActiveControl = lvLocals
|
|
||||||
BorderStyle = bsSizeToolWin
|
BorderStyle = bsSizeToolWin
|
||||||
Caption = 'Locals'
|
Caption = 'Locals'
|
||||||
ClientHeight = 200
|
ClientHeight = 200
|
||||||
ClientWidth = 500
|
ClientWidth = 500
|
||||||
LCLVersion = '2.1.0.0'
|
LCLVersion = '2.3.0.0'
|
||||||
object lvLocals: TListView
|
object vtLocals: TDbgTreeView
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 200
|
Height = 200
|
||||||
Top = 0
|
Top = 0
|
||||||
Width = 500
|
Width = 500
|
||||||
Align = alClient
|
Align = alClient
|
||||||
Columns = <
|
Header.AutoSizeIndex = 0
|
||||||
|
Header.Columns = <
|
||||||
item
|
item
|
||||||
Caption = 'Name'
|
Position = 0
|
||||||
Width = 150
|
|
||||||
end
|
end
|
||||||
item
|
item
|
||||||
Caption = 'Value'
|
Position = 2
|
||||||
|
end
|
||||||
|
item
|
||||||
|
MaxWidth = 300
|
||||||
|
Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coAllowFocus, coEditable]
|
||||||
|
Position = 1
|
||||||
end>
|
end>
|
||||||
MultiSelect = True
|
Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
|
||||||
PopupMenu = PopupMenu1
|
PopupMenu = PopupMenu1
|
||||||
ReadOnly = True
|
|
||||||
RowSelect = True
|
|
||||||
SortType = stText
|
|
||||||
TabOrder = 0
|
TabOrder = 0
|
||||||
ViewStyle = vsReport
|
TreeOptions.AutoOptions = [toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale]
|
||||||
|
TreeOptions.MiscOptions = [toFullRepaintOnResize, toInitOnSave, toWheelPanning]
|
||||||
|
TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme]
|
||||||
|
TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect]
|
||||||
|
OnChange = vtLocalsChange
|
||||||
|
OnDragOver = vtLocalsDragOver
|
||||||
|
OnDragDrop = vtLocalsDragDrop
|
||||||
|
OnFocusChanged = vtLocalsFocusChanged
|
||||||
|
OnNodeDblClick = vtLocalsNodeDblClick
|
||||||
end
|
end
|
||||||
object ActionList1: TActionList
|
object ActionList1: TActionList
|
||||||
Left = 152
|
Left = 152
|
||||||
@ -83,13 +92,6 @@ object LocalsDlg: TLocalsDlg
|
|||||||
OnUpdate = actInspectUpdate
|
OnUpdate = actInspectUpdate
|
||||||
ShortCut = 16451
|
ShortCut = 16451
|
||||||
end
|
end
|
||||||
object actEvaluateAll: TAction
|
|
||||||
Category = 'main'
|
|
||||||
Caption = 'actEvaluateAll'
|
|
||||||
OnExecute = actEvaluateAllExecute
|
|
||||||
OnUpdate = actCopyAllUpdate
|
|
||||||
ShortCut = 16466
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
object PopupMenu1: TPopupMenu
|
object PopupMenu1: TPopupMenu
|
||||||
Left = 38
|
Left = 38
|
||||||
@ -103,9 +105,6 @@ object LocalsDlg: TLocalsDlg
|
|||||||
object MenuItem3: TMenuItem
|
object MenuItem3: TMenuItem
|
||||||
Action = actEvaluate
|
Action = actEvaluate
|
||||||
end
|
end
|
||||||
object MenuItem9: TMenuItem
|
|
||||||
Action = actEvaluateAll
|
|
||||||
end
|
|
||||||
object MenuItem4: TMenuItem
|
object MenuItem4: TMenuItem
|
||||||
Caption = '-'
|
Caption = '-'
|
||||||
end
|
end
|
||||||
|
@ -44,9 +44,11 @@ uses
|
|||||||
// IdeIntf
|
// IdeIntf
|
||||||
IDEWindowIntf,
|
IDEWindowIntf,
|
||||||
// DebuggerIntf
|
// DebuggerIntf
|
||||||
DbgIntfDebuggerBase, LazDebuggerIntf,
|
DbgIntfDebuggerBase, laz.VirtualTrees, LazDebuggerIntf,
|
||||||
// IDE
|
// IDE Debugger
|
||||||
IdeDebuggerStringConstants, BaseDebugManager, EnvironmentOpts, Debugger, DebuggerDlg;
|
IdeDebuggerStringConstants, BaseDebugManager, EnvironmentOpts, Debugger,
|
||||||
|
DebuggerDlg, IdeDebuggerWatchResPrinter, IdeDebuggerUtils, DebuggerTreeView,
|
||||||
|
IdeDebuggerWatchResult, IdeDebuggerBase, Controls, ActiveX;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
@ -59,10 +61,9 @@ type
|
|||||||
actCopyValue: TAction;
|
actCopyValue: TAction;
|
||||||
actCopyAll: TAction;
|
actCopyAll: TAction;
|
||||||
actCopyRAWValue: TAction;
|
actCopyRAWValue: TAction;
|
||||||
actEvaluateAll: TAction;
|
|
||||||
actWath: TAction;
|
actWath: TAction;
|
||||||
ActionList1: TActionList;
|
ActionList1: TActionList;
|
||||||
lvLocals: TListView;
|
vtLocals: TDbgTreeView;
|
||||||
MenuItem1: TMenuItem;
|
MenuItem1: TMenuItem;
|
||||||
MenuItem2: TMenuItem;
|
MenuItem2: TMenuItem;
|
||||||
MenuItem3: TMenuItem;
|
MenuItem3: TMenuItem;
|
||||||
@ -71,28 +72,38 @@ type
|
|||||||
MenuItem6: TMenuItem;
|
MenuItem6: TMenuItem;
|
||||||
MenuItem7: TMenuItem;
|
MenuItem7: TMenuItem;
|
||||||
MenuItem8: TMenuItem;
|
MenuItem8: TMenuItem;
|
||||||
MenuItem9: TMenuItem;
|
|
||||||
PopupMenu1: TPopupMenu;
|
PopupMenu1: TPopupMenu;
|
||||||
procedure actCopyAllExecute(Sender: TObject);
|
procedure actCopyAllExecute(Sender: TObject);
|
||||||
procedure actCopyAllUpdate(Sender: TObject);
|
procedure actCopyAllUpdate(Sender: TObject);
|
||||||
procedure actCopyNameExecute(Sender: TObject);
|
procedure actCopyNameExecute(Sender: TObject);
|
||||||
procedure actCopyValueExecute(Sender: TObject);
|
procedure actCopyValueExecute(Sender: TObject);
|
||||||
procedure actEvaluateAllExecute(Sender: TObject);
|
|
||||||
procedure actEvaluateExecute(Sender: TObject);
|
procedure actEvaluateExecute(Sender: TObject);
|
||||||
procedure actInspectExecute(Sender: TObject);
|
procedure actInspectExecute(Sender: TObject);
|
||||||
procedure actInspectUpdate(Sender: TObject);
|
procedure actInspectUpdate(Sender: TObject);
|
||||||
procedure actCopyRAWValueExecute(Sender: TObject);
|
procedure actCopyRAWValueExecute(Sender: TObject);
|
||||||
procedure actWathExecute(Sender: TObject);
|
procedure actWathExecute(Sender: TObject);
|
||||||
|
procedure vtLocalsChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
||||||
|
procedure vtLocalsDragDrop(Sender: TBaseVirtualTree; Source: TObject;
|
||||||
|
DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState;
|
||||||
|
const Pt: TPoint; var Effect: LongWord; Mode: TDropMode);
|
||||||
|
procedure vtLocalsDragOver(Sender: TBaseVirtualTree; Source: TObject;
|
||||||
|
Shift: TShiftState; State: TDragState; const Pt: TPoint; Mode: TDropMode;
|
||||||
|
var Effect: LongWord; var Accept: Boolean);
|
||||||
|
procedure vtLocalsFocusChanged(Sender: TBaseVirtualTree;
|
||||||
|
Node: PVirtualNode; Column: TColumnIndex);
|
||||||
|
procedure vtLocalsNodeDblClick(Sender: TBaseVirtualTree;
|
||||||
|
const HitInfo: THitInfo);
|
||||||
private
|
private
|
||||||
|
FWatchPrinter: TWatchResultPrinter;
|
||||||
FUpdateFlags: set of (ufNeedUpdating);
|
FUpdateFlags: set of (ufNeedUpdating);
|
||||||
EvaluateAllCallbackItem: TListItem;
|
function GetSelected: TLocalsValue; // The focused Selected Node
|
||||||
procedure CopyRAWValueEvaluateCallback(Sender: TObject; ASuccess: Boolean;
|
procedure CopyRAWValueEvaluateCallback(Sender: TObject; ASuccess: Boolean;
|
||||||
ResultText: String; ResultDBGType: TDBGType);
|
ResultText: String; ResultDBGType: TDBGType);
|
||||||
procedure CopyValueEvaluateCallback(Sender: TObject; ASuccess: Boolean;
|
procedure CopyValueEvaluateCallback(Sender: TObject; ASuccess: Boolean;
|
||||||
ResultText: String; ResultDBGType: TDBGType);
|
ResultText: String; ResultDBGType: TDBGType);
|
||||||
procedure EvaluateAllCallback(Sender: TObject; ASuccess: Boolean;
|
procedure DoLocalValueFreed(Sender: TObject);
|
||||||
ResultText: String; ResultDBGType: TDBGType);
|
|
||||||
|
|
||||||
|
procedure ClearTree(OnlyClearNodeData: boolean = False);
|
||||||
procedure LocalsChanged(Sender: TObject);
|
procedure LocalsChanged(Sender: TObject);
|
||||||
function GetThreadId: Integer;
|
function GetThreadId: Integer;
|
||||||
function GetSelectedThreads(Snap: TSnapshot): TIdeThreads;
|
function GetSelectedThreads(Snap: TSnapshot): TIdeThreads;
|
||||||
@ -105,6 +116,7 @@ type
|
|||||||
procedure ColSizeSetter(AColId: Integer; ASize: Integer);
|
procedure ColSizeSetter(AColId: Integer; ASize: Integer);
|
||||||
public
|
public
|
||||||
constructor Create(AOwner: TComponent); override;
|
constructor Create(AOwner: TComponent); override;
|
||||||
|
destructor Destroy; override;
|
||||||
property LocalsMonitor;
|
property LocalsMonitor;
|
||||||
property ThreadsMonitor;
|
property ThreadsMonitor;
|
||||||
property CallStackMonitor;
|
property CallStackMonitor;
|
||||||
@ -112,7 +124,6 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function ValueToRAW(const AValue: string): string;
|
function ValueToRAW(const AValue: string): string;
|
||||||
function ExtractValue(const AValue: string; AType: string = ''): string;
|
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
@ -277,34 +288,76 @@ begin
|
|||||||
ThreadsNotification.OnCurrent := @LocalsChanged;
|
ThreadsNotification.OnCurrent := @LocalsChanged;
|
||||||
CallstackNotification.OnCurrent := @LocalsChanged;
|
CallstackNotification.OnCurrent := @LocalsChanged;
|
||||||
SnapshotNotification.OnCurrent := @LocalsChanged;
|
SnapshotNotification.OnCurrent := @LocalsChanged;
|
||||||
|
FWatchPrinter := TWatchResultPrinter.Create;
|
||||||
|
|
||||||
Caption:= lisLocals;
|
Caption:= lisLocals;
|
||||||
lvLocals.Columns[0].Caption:= lisName;
|
vtLocals.Header.Columns[0].Text:= lisName;
|
||||||
lvLocals.Columns[1].Caption:= lisValue;
|
vtLocals.Header.Columns[1].Text:= lisValue;
|
||||||
actInspect.Caption := lisInspect;
|
actInspect.Caption := lisInspect;
|
||||||
actWath.Caption := lisWatch;
|
actWath.Caption := lisWatch;
|
||||||
actEvaluate.Caption := lisEvaluateModify;
|
actEvaluate.Caption := lisEvaluateModify;
|
||||||
actEvaluateAll.Caption := lisEvaluateAll;
|
|
||||||
actCopyName.Caption := lisLocalsDlgCopyName;
|
actCopyName.Caption := lisLocalsDlgCopyName;
|
||||||
actCopyValue.Caption := lisLocalsDlgCopyValue;
|
actCopyValue.Caption := lisLocalsDlgCopyValue;
|
||||||
actCopyRAWValue.Caption := lisLocalsDlgCopyRAWValue;
|
actCopyRAWValue.Caption := lisLocalsDlgCopyRAWValue;
|
||||||
actCopyAll.Caption := lisCopyAll;
|
actCopyAll.Caption := lisCopyAll;
|
||||||
|
|
||||||
for i := low(COL_WIDTHS) to high(COL_WIDTHS) do
|
for i := low(COL_WIDTHS) to high(COL_WIDTHS) do
|
||||||
lvLocals.Column[i].Width := COL_WIDTHS[i];
|
vtLocals.Header.Columns[i].Width := COL_WIDTHS[i];
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TLocalsDlg.Destroy;
|
||||||
|
begin
|
||||||
|
ClearTree;
|
||||||
|
inherited Destroy;
|
||||||
|
FWatchPrinter.free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocalsDlg.actInspectUpdate(Sender: TObject);
|
procedure TLocalsDlg.actInspectUpdate(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
(Sender as TAction).Enabled := Assigned(lvLocals.Selected);
|
(Sender as TAction).Enabled := Assigned(GetSelected);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocalsDlg.actCopyRAWValueExecute(Sender: TObject);
|
procedure TLocalsDlg.actCopyRAWValueExecute(Sender: TObject);
|
||||||
|
var
|
||||||
|
LVal: TLocalsValue;
|
||||||
|
ResVal: TWatchResultData;
|
||||||
begin
|
begin
|
||||||
if not DebugBoss.Evaluate(lvLocals.Selected.Caption, @CopyRAWValueEvaluateCallback, []) then
|
LVal := GetSelected;
|
||||||
|
if LVal = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
ResVal := LVal.Value;
|
||||||
|
if ResVal = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
if (ResVal.ValueKind <> rdkPrePrinted) then begin
|
||||||
|
while ResVal <> nil do begin
|
||||||
|
case ResVal.ValueKind of
|
||||||
|
rdkVariant: ResVal := ResVal.DerefData;
|
||||||
|
rdkConvertRes: ResVal := ResVal.ConvertedRes;
|
||||||
|
//rdkPCharOrString:
|
||||||
|
else break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if ResVal.ValueKind in [rdkString, rdkWideString, rdkChar] then begin
|
||||||
|
Clipboard.Open;
|
||||||
|
Clipboard.AsText := ResVal.AsString;
|
||||||
|
Clipboard.Close;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
Clipboard.Open;
|
||||||
|
Clipboard.AsText := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault));
|
||||||
|
Clipboard.Close;
|
||||||
|
end;
|
||||||
|
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not DebugBoss.Evaluate(LVal.Name, @CopyRAWValueEvaluateCallback, []) then
|
||||||
begin
|
begin
|
||||||
Clipboard.Open;
|
Clipboard.Open;
|
||||||
Clipboard.AsText := ValueToRAW(lvLocals.Selected.SubItems[0]);
|
Clipboard.AsText := ValueToRAW(ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault)));
|
||||||
Clipboard.Close;
|
Clipboard.Close;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -313,8 +366,13 @@ procedure TLocalsDlg.actWathExecute(Sender: TObject);
|
|||||||
var
|
var
|
||||||
S: String;
|
S: String;
|
||||||
Watch: TCurrentWatch;
|
Watch: TCurrentWatch;
|
||||||
|
LVal: TLocalsValue;
|
||||||
begin
|
begin
|
||||||
S := lvLocals.Selected.Caption;
|
LVal := GetSelected;
|
||||||
|
if LVal = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
S := LVal.Name;
|
||||||
if s = '' then
|
if s = '' then
|
||||||
exit;
|
exit;
|
||||||
if DebugBoss.Watches.CurrentWatches.Find(S) = nil then
|
if DebugBoss.Watches.CurrentWatches.Find(S) = nil then
|
||||||
@ -332,76 +390,128 @@ begin
|
|||||||
DebugBoss.ViewDebugDialog(ddtWatches);
|
DebugBoss.ViewDebugDialog(ddtWatches);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TLocalsDlg.vtLocalsChange(Sender: TBaseVirtualTree; Node: PVirtualNode
|
||||||
|
);
|
||||||
|
begin
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TLocalsDlg.vtLocalsDragDrop(Sender: TBaseVirtualTree;
|
||||||
|
Source: TObject; DataObject: IDataObject; Formats: TFormatArray;
|
||||||
|
Shift: TShiftState; const Pt: TPoint; var Effect: LongWord; Mode: TDropMode);
|
||||||
|
begin
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TLocalsDlg.vtLocalsDragOver(Sender: TBaseVirtualTree;
|
||||||
|
Source: TObject; Shift: TShiftState; State: TDragState; const Pt: TPoint;
|
||||||
|
Mode: TDropMode; var Effect: LongWord; var Accept: Boolean);
|
||||||
|
begin
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TLocalsDlg.vtLocalsFocusChanged(Sender: TBaseVirtualTree;
|
||||||
|
Node: PVirtualNode; Column: TColumnIndex);
|
||||||
|
begin
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TLocalsDlg.vtLocalsNodeDblClick(Sender: TBaseVirtualTree;
|
||||||
|
const HitInfo: THitInfo);
|
||||||
|
begin
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TLocalsDlg.GetSelected: TLocalsValue;
|
||||||
|
begin
|
||||||
|
Result := TLocalsValue(vtLocals.FocusedItem(True));
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TLocalsDlg.actInspectExecute(Sender: TObject);
|
procedure TLocalsDlg.actInspectExecute(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
DebugBoss.Inspect(lvLocals.Selected.Caption);
|
if GetSelected <> nil then
|
||||||
|
DebugBoss.Inspect(GetSelected.Name);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocalsDlg.actEvaluateExecute(Sender: TObject);
|
procedure TLocalsDlg.actEvaluateExecute(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
DebugBoss.EvaluateModify(lvLocals.Selected.Caption);
|
if GetSelected <> nil then
|
||||||
|
DebugBoss.EvaluateModify(GetSelected.Name);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocalsDlg.actCopyNameExecute(Sender: TObject);
|
procedure TLocalsDlg.actCopyNameExecute(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
Clipboard.Open;
|
Clipboard.Open;
|
||||||
Clipboard.AsText := lvLocals.Selected.Caption;
|
if GetSelected <> nil then
|
||||||
|
Clipboard.AsText := GetSelected.Name
|
||||||
|
else
|
||||||
|
Clipboard.AsText := '';
|
||||||
Clipboard.Close;
|
Clipboard.Close;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocalsDlg.actCopyAllExecute(Sender: TObject);
|
procedure TLocalsDlg.actCopyAllExecute(Sender: TObject);
|
||||||
Var
|
Var
|
||||||
AStringList : TStringList;
|
AStringList : TStringList;
|
||||||
I : Integer;
|
LVal: TLocalsValue;
|
||||||
|
VNode: PVirtualNode;
|
||||||
begin
|
begin
|
||||||
if lvLocals.Items.Count > 0 then begin
|
AStringList := TStringList.Create;
|
||||||
AStringList := TStringList.Create;
|
for VNode in vtLocals.NoInitNodes do begin
|
||||||
for I := 0 to lvLocals.Items.Count - 1 do
|
LVal := TLocalsValue((vtLocals.NodeItem[VNode]));
|
||||||
AStringList.Values[lvLocals.Items[I].Caption] := lvLocals.Items[I].SubItems[0];
|
if LVal <> nil then
|
||||||
Clipboard.Open;
|
AStringList.Values[LVal.Name] := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault));
|
||||||
Clipboard.AsText := AStringList.Text;
|
|
||||||
Clipboard.Close;
|
|
||||||
FreeAndNil(AStringList);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Clipboard.Open;
|
||||||
|
Clipboard.AsText := AStringList.Text;
|
||||||
|
Clipboard.Close;
|
||||||
|
FreeAndNil(AStringList);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocalsDlg.actCopyAllUpdate(Sender: TObject);
|
procedure TLocalsDlg.actCopyAllUpdate(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
(Sender as TAction).Enabled := lvLocals.Items.Count > 0;
|
(Sender as TAction).Enabled := vtLocals.ChildCount[nil] > 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocalsDlg.actCopyValueExecute(Sender: TObject);
|
procedure TLocalsDlg.actCopyValueExecute(Sender: TObject);
|
||||||
|
var
|
||||||
|
LVal: TLocalsValue;
|
||||||
|
ResVal: TWatchResultData;
|
||||||
begin
|
begin
|
||||||
if not DebugBoss.Evaluate(lvLocals.Selected.Caption, @CopyValueEvaluateCallback, []) then
|
LVal := GetSelected;
|
||||||
|
if LVal = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
ResVal := LVal.Value;
|
||||||
|
if ResVal = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
if (ResVal.ValueKind <> rdkPrePrinted) then begin
|
||||||
|
Clipboard.Open;
|
||||||
|
Clipboard.AsText := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault));
|
||||||
|
Clipboard.Close;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not DebugBoss.Evaluate(LVal.Name, @CopyValueEvaluateCallback, []) then
|
||||||
begin
|
begin
|
||||||
Clipboard.Open;
|
Clipboard.Open;
|
||||||
Clipboard.AsText := lvLocals.Selected.SubItems[0];
|
Clipboard.AsText := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault));
|
||||||
Clipboard.Close;
|
Clipboard.Close;
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocalsDlg.actEvaluateAllExecute(Sender: TObject);
|
|
||||||
var
|
|
||||||
I: Integer;
|
|
||||||
begin
|
|
||||||
for I := 0 to lvLocals.Items.Count-1 do
|
|
||||||
begin
|
|
||||||
EvaluateAllCallbackItem := lvLocals.Items[I];
|
|
||||||
DebugBoss.Evaluate(EvaluateAllCallbackItem.Caption, @EvaluateAllCallback, []);
|
|
||||||
end;
|
|
||||||
EvaluateAllCallbackItem := nil;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TLocalsDlg.LocalsChanged(Sender: TObject);
|
procedure TLocalsDlg.LocalsChanged(Sender: TObject);
|
||||||
var
|
var
|
||||||
n, idx: Integer;
|
n: Integer;
|
||||||
List: TStringListUTF8Fast;
|
|
||||||
Item: TListItem;
|
|
||||||
Locals: TIDELocals;
|
Locals: TIDELocals;
|
||||||
Snap: TSnapshot;
|
Snap: TSnapshot;
|
||||||
|
s: String;
|
||||||
|
LVal: TLocalsValue;
|
||||||
|
VNode, VN2: PVirtualNode;
|
||||||
begin
|
begin
|
||||||
if (ThreadsMonitor = nil) or (CallStackMonitor = nil) or (LocalsMonitor=nil) then begin
|
if (ThreadsMonitor = nil) or (CallStackMonitor = nil) or (LocalsMonitor=nil) then begin
|
||||||
lvLocals.Items.Clear;
|
ClearTree;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -414,7 +524,7 @@ begin
|
|||||||
DebugLn(DBG_DATA_MONITORS, ['DebugDataMonitor: TLocalsDlg.LocalsChanged']);
|
DebugLn(DBG_DATA_MONITORS, ['DebugDataMonitor: TLocalsDlg.LocalsChanged']);
|
||||||
|
|
||||||
if GetStackframe < 0 then begin // TODO need dedicated validity property
|
if GetStackframe < 0 then begin // TODO need dedicated validity property
|
||||||
lvLocals.Items.Clear;
|
ClearTree;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -429,54 +539,48 @@ begin
|
|||||||
Caption:= lisLocals;
|
Caption:= lisLocals;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
List := TStringListUTF8Fast.Create;
|
if Locals = nil
|
||||||
|
then begin
|
||||||
|
ClearTree;
|
||||||
|
VNode:= vtLocals.AddChild(nil, nil);
|
||||||
|
vtLocals.NodeText[VNode, 1] := lisLocalsNotEvaluated;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
BeginUpdate;
|
||||||
try
|
try
|
||||||
BeginUpdate;
|
ClearTree(True);
|
||||||
try
|
for n := 0 to Locals.Count - 1 do begin
|
||||||
if Locals = nil
|
LVal := Locals.Entries[n];
|
||||||
then begin
|
LVal.AddFreeNotification(@DoLocalValueFreed);
|
||||||
lvLocals.Items.Clear;
|
|
||||||
Item := lvLocals.Items.Add;
|
|
||||||
Item.Caption := '';
|
|
||||||
Item.SubItems.add(lisLocalsNotEvaluated);
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
//Get existing items
|
VNode := vtLocals.FindNodeForText(LVal.Name, 0);
|
||||||
for n := 0 to lvLocals.Items.Count - 1 do
|
if (VNode = nil) then begin
|
||||||
begin
|
VNode := vtLocals.AddChild(nil, LVal);
|
||||||
Item := lvLocals.Items[n];
|
LVal.AddFreeNotification(@DoLocalValueFreed);
|
||||||
List.AddObject(Item.Caption, Item);
|
end
|
||||||
end;
|
else
|
||||||
|
vtLocals.NodeItem[VNode] := LVal;
|
||||||
|
|
||||||
// add/update entries
|
s := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault));
|
||||||
for n := 0 to Locals.Count - 1 do
|
vtLocals.NodeText[VNode, 0] := LVal.Name;
|
||||||
begin
|
vtLocals.NodeText[VNode, 1] := s;
|
||||||
idx := List.IndexOf(Locals.Names[n]);
|
|
||||||
if idx = -1
|
|
||||||
then begin
|
|
||||||
// New entry
|
|
||||||
Item := lvLocals.Items.Add;
|
|
||||||
Item.Caption := Locals.Names[n];
|
|
||||||
Item.SubItems.Add(ExtractValue(Locals.Values[n]));
|
|
||||||
end
|
|
||||||
else begin
|
|
||||||
// Existing entry
|
|
||||||
Item := TListItem(List.Objects[idx]);
|
|
||||||
Item.SubItems[0] := ExtractValue(Locals.Values[n]);
|
|
||||||
List.Delete(idx);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// remove obsolete entries
|
|
||||||
for n := 0 to List.Count - 1 do
|
|
||||||
lvLocals.Items.Delete(TListItem(List.Objects[n]).Index);
|
|
||||||
|
|
||||||
finally
|
|
||||||
EndUpdate;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
VNode := vtLocals.GetFirstNoInit;
|
||||||
|
while VNode <> nil do begin
|
||||||
|
if (vtLocals.NodeItem[VNode] = nil) and (vtLocals.NodeControl[VNode] = nil) then begin
|
||||||
|
VN2 := VNode;
|
||||||
|
VNode := vtLocals.GetNextVisibleSiblingNoInit(VNode);
|
||||||
|
vtLocals.DeleteNode(VN2);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
VNode := vtLocals.GetNextVisibleNoInit(VNode);
|
||||||
|
end;
|
||||||
|
|
||||||
finally
|
finally
|
||||||
List.Free;
|
EndUpdate;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -537,31 +641,23 @@ end;
|
|||||||
|
|
||||||
procedure TLocalsDlg.DoBeginUpdate;
|
procedure TLocalsDlg.DoBeginUpdate;
|
||||||
begin
|
begin
|
||||||
lvLocals.BeginUpdate;
|
inherited DoBeginUpdate;
|
||||||
|
vtLocals.BeginUpdate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocalsDlg.DoEndUpdate;
|
procedure TLocalsDlg.DoEndUpdate;
|
||||||
begin
|
begin
|
||||||
|
inherited DoEndUpdate;
|
||||||
if ufNeedUpdating in FUpdateFlags then LocalsChanged(nil);
|
if ufNeedUpdating in FUpdateFlags then LocalsChanged(nil);
|
||||||
lvLocals.EndUpdate;
|
vtLocals.EndUpdate;
|
||||||
end;
|
vtLocalsChange(nil, nil);
|
||||||
|
|
||||||
procedure TLocalsDlg.EvaluateAllCallback(Sender: TObject; ASuccess: Boolean;
|
|
||||||
ResultText: String; ResultDBGType: TDBGType);
|
|
||||||
begin
|
|
||||||
if ASuccess then
|
|
||||||
begin
|
|
||||||
if Assigned(EvaluateAllCallbackItem) then
|
|
||||||
EvaluateAllCallbackItem.SubItems[0] := ExtractValue(ResultText, ResultDBGType.TypeName);
|
|
||||||
end;
|
|
||||||
FreeAndNil(ResultDBGType);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TLocalsDlg.ColSizeGetter(AColId: Integer; var ASize: Integer): Boolean;
|
function TLocalsDlg.ColSizeGetter(AColId: Integer; var ASize: Integer): Boolean;
|
||||||
begin
|
begin
|
||||||
if (AColId - 1 >= 0) and (AColId - 1 < lvLocals.ColumnCount) then begin
|
if (AColId - 1 >= 0) and (AColId - 1 < vtLocals.Header.Columns.Count) then begin
|
||||||
ASize := lvLocals.Column[AColId - 1].Width;
|
ASize := vtLocals.Header.Columns[AColId - 1].Width;
|
||||||
Result := (ASize <> COL_WIDTHS[AColId - 1]) and (not lvLocals.Column[AColId - 1].AutoSize);
|
Result := (ASize <> COL_WIDTHS[AColId - 1]);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
Result := False;
|
Result := False;
|
||||||
@ -570,35 +666,81 @@ end;
|
|||||||
procedure TLocalsDlg.ColSizeSetter(AColId: Integer; ASize: Integer);
|
procedure TLocalsDlg.ColSizeSetter(AColId: Integer; ASize: Integer);
|
||||||
begin
|
begin
|
||||||
case AColId of
|
case AColId of
|
||||||
COL_LOCALS_NAME: lvLocals.Column[0].Width := ASize;
|
COL_LOCALS_NAME: vtLocals.Header.Columns[0].Width := ASize;
|
||||||
COL_LOCALS_VALUE: lvLocals.Column[1].Width := ASize;
|
COL_LOCALS_VALUE: vtLocals.Header.Columns[1].Width := ASize;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocalsDlg.CopyRAWValueEvaluateCallback(Sender: TObject;
|
procedure TLocalsDlg.CopyRAWValueEvaluateCallback(Sender: TObject;
|
||||||
ASuccess: Boolean; ResultText: String; ResultDBGType: TDBGType);
|
ASuccess: Boolean; ResultText: String; ResultDBGType: TDBGType);
|
||||||
|
var
|
||||||
|
LVal: TLocalsValue;
|
||||||
begin
|
begin
|
||||||
Clipboard.Open;
|
Clipboard.Open;
|
||||||
if ASuccess then
|
if ASuccess then
|
||||||
Clipboard.AsText := ValueToRAW(ExtractValue(ResultText, ResultDBGType.TypeName))
|
Clipboard.AsText := ValueToRAW(ExtractValue(ResultText, ResultDBGType.TypeName))
|
||||||
else
|
else
|
||||||
Clipboard.AsText := ValueToRAW(lvLocals.Selected.SubItems[0]);
|
begin
|
||||||
|
LVal := GetSelected;
|
||||||
|
if (LVal <> nil) and (LVal.Value <> nil) then begin
|
||||||
|
Clipboard.Open;
|
||||||
|
Clipboard.AsText := ValueToRAW(ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault)));
|
||||||
|
Clipboard.Close;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
Clipboard.Close;
|
Clipboard.Close;
|
||||||
FreeAndNil(ResultDBGType);
|
FreeAndNil(ResultDBGType);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TLocalsDlg.CopyValueEvaluateCallback(Sender: TObject;
|
procedure TLocalsDlg.CopyValueEvaluateCallback(Sender: TObject;
|
||||||
ASuccess: Boolean; ResultText: String; ResultDBGType: TDBGType);
|
ASuccess: Boolean; ResultText: String; ResultDBGType: TDBGType);
|
||||||
|
var
|
||||||
|
LVal: TLocalsValue;
|
||||||
begin
|
begin
|
||||||
Clipboard.Open;
|
Clipboard.Open;
|
||||||
if ASuccess then
|
if ASuccess then
|
||||||
Clipboard.AsText := ExtractValue(ResultText, ResultDBGType.TypeName)
|
Clipboard.AsText := ExtractValue(ResultText, ResultDBGType.TypeName)
|
||||||
else
|
else begin
|
||||||
Clipboard.AsText := lvLocals.Selected.SubItems[0];
|
LVal := GetSelected;
|
||||||
|
if (LVal <> nil) and (LVal.Value <> nil) then begin
|
||||||
|
Clipboard.Open;
|
||||||
|
Clipboard.AsText := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault));
|
||||||
|
Clipboard.Close;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
Clipboard.Close;
|
Clipboard.Close;
|
||||||
FreeAndNil(ResultDBGType);
|
FreeAndNil(ResultDBGType);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TLocalsDlg.DoLocalValueFreed(Sender: TObject);
|
||||||
|
var
|
||||||
|
nd: PVirtualNode;
|
||||||
|
begin
|
||||||
|
nd := vtLocals.FindNodeForItem(Sender);
|
||||||
|
if nd = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
//vtLocals.OnItemRemoved := nil;
|
||||||
|
vtLocals.NodeItem[nd] := nil;
|
||||||
|
//vtLocals.OnItemRemoved := @DoItemRemovedFromView;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TLocalsDlg.ClearTree(OnlyClearNodeData: boolean);
|
||||||
|
var
|
||||||
|
LVal: TLocalsValue;
|
||||||
|
VNode: PVirtualNode;
|
||||||
|
begin
|
||||||
|
for VNode in vtLocals.NoInitNodes do begin
|
||||||
|
LVal := TLocalsValue(vtLocals.NodeItem[VNode]);
|
||||||
|
if LVal <> nil then
|
||||||
|
LVal.RemoveFreeNotification(@DoLocalValueFreed);
|
||||||
|
vtLocals.NodeItem[VNode] := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not OnlyClearNodeData then
|
||||||
|
vtLocals.Clear;
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
|
|
||||||
LocalsDlgWindowCreator := IDEWindowCreators.Add(DebugDialogNames[ddtLocals]);
|
LocalsDlgWindowCreator := IDEWindowCreators.Add(DebugDialogNames[ddtLocals]);
|
||||||
|
Loading…
Reference in New Issue
Block a user