mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-08 23:18:01 +02:00
Debugger: Allow to expand/unfold locals values
This commit is contained in:
parent
26f4160df9
commit
ad9eaf0474
@ -1805,6 +1805,8 @@ type
|
||||
class function GetDebuggerClass(const AIndex: Integer): TDebuggerClass;static;
|
||||
class function GetDebuggerClassByName(const AIndex: String): TDebuggerClass; static;
|
||||
function FindDebuggerClass(const Astring: String): TDebuggerClass;
|
||||
public
|
||||
procedure RequestWatchData(AWatchValue: TWatchValueIntf); virtual; abstract;
|
||||
public
|
||||
class function DebuggerCount: Integer;
|
||||
|
||||
|
@ -24,10 +24,10 @@ type
|
||||
FOwner: TDbgEntityValuesList;
|
||||
FFlags: set of (devImmutable);
|
||||
function GetImmutable: Boolean;
|
||||
function GetStackFrame: Integer;
|
||||
function GetThreadId: Integer;
|
||||
procedure SetImmutable(AValue: Boolean);
|
||||
protected
|
||||
function GetStackFrame: Integer;
|
||||
function GetThreadId: Integer;
|
||||
procedure DoAssign({%H-}AnOther: TDbgEntityValue); virtual;
|
||||
property Owner: TDbgEntityValuesList read FOwner;
|
||||
public
|
||||
@ -63,7 +63,7 @@ type
|
||||
constructor Create(AThreadId, AStackFrame: Integer);
|
||||
destructor Destroy; override;
|
||||
procedure Assign(AnOther: TDbgEntityValuesList); // assert other has same thread/stack
|
||||
procedure Add(AnEntry: TDbgEntityValue);
|
||||
procedure Add(AnEntry: TDbgEntityValue); virtual;
|
||||
procedure Clear;
|
||||
function Count: Integer;
|
||||
property Entries[AnIndex: Integer]: TDbgEntityValue read GetEntry;
|
||||
|
@ -198,6 +198,7 @@ type
|
||||
function ShowBreakPointProperties(const ABreakpoint: TIDEBreakPoint): TModalresult; virtual; abstract;
|
||||
function ShowWatchProperties(const AWatch: TCurrentWatch; AWatchExpression: String = ''): TModalresult; virtual; abstract;
|
||||
|
||||
procedure RequestWatchData(AWatchValue: TWatchValueIntf); override;
|
||||
// Dialog routines
|
||||
procedure CreateDebugDialog(Sender: TObject; aFormName: string;
|
||||
var AForm: TCustomForm; DoDisableAutoSizing: boolean); virtual; abstract;
|
||||
@ -247,6 +248,15 @@ var
|
||||
|
||||
implementation
|
||||
|
||||
{ TBaseDebugManager }
|
||||
|
||||
procedure TBaseDebugManager.RequestWatchData(AWatchValue: TWatchValueIntf);
|
||||
begin
|
||||
if (Watches <> nil) and (Watches.Supplier <> nil)
|
||||
then
|
||||
Watches.Supplier.RequestData(AWatchValue);
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterIDEOptionsGroup(GroupDebugger, TDebuggerOptions);
|
||||
DebugBoss := nil;
|
||||
|
@ -43,7 +43,7 @@ type
|
||||
constructor Create(ATreeView: TDbgTreeView);
|
||||
//destructor Destroy; override;
|
||||
|
||||
procedure AddWatchData(AWatchAble: TObject; AWatchAbleResult: TWatchAbleResultIntf = nil);
|
||||
function AddWatchData(AWatchAble: TObject; AWatchAbleResult: TWatchAbleResultIntf = nil; AVNode: PVirtualNode = nil): PVirtualNode;
|
||||
procedure UpdateWatchData(AWatchAble: TObject; AVNode: PVirtualNode; AWatchAbleResult: TWatchAbleResultIntf = nil);
|
||||
|
||||
property CancelUpdate: Boolean read FCancelUpdate write FCancelUpdate;
|
||||
@ -365,19 +365,26 @@ begin
|
||||
FTreeView.OnInitChildren := @TreeViewInitChildren;
|
||||
end;
|
||||
|
||||
procedure TDbgTreeViewWatchDataMgr.AddWatchData(AWatchAble: TObject;
|
||||
AWatchAbleResult: TWatchAbleResultIntf);
|
||||
var
|
||||
AVNode: PVirtualNode;
|
||||
function TDbgTreeViewWatchDataMgr.AddWatchData(AWatchAble: TObject;
|
||||
AWatchAbleResult: TWatchAbleResultIntf; AVNode: PVirtualNode): PVirtualNode;
|
||||
begin
|
||||
if AWatchAble = nil then
|
||||
exit;
|
||||
AVNode := FTreeView.FindNodeForItem(AWatchAble);
|
||||
if AVNode = nil then begin
|
||||
AVNode := FTreeView.AddChild(nil, AWatchAble);
|
||||
|
||||
if (AVNode <> nil) then begin
|
||||
FTreeView.NodeItem[AVNode] := AWatchAble;
|
||||
FTreeView.SelectNode(AVNode);
|
||||
(AWatchAble as TFreeNotifyingIntf).AddFreeNotification(@DoWatchAbleFreed);
|
||||
end
|
||||
else begin
|
||||
AVNode := FTreeView.FindNodeForItem(AWatchAble);
|
||||
if AVNode = nil then begin
|
||||
AVNode := FTreeView.AddChild(nil, AWatchAble);
|
||||
FTreeView.SelectNode(AVNode);
|
||||
(AWatchAble as TFreeNotifyingIntf).AddFreeNotification(@DoWatchAbleFreed);
|
||||
end;
|
||||
end;
|
||||
Result := AVNode;
|
||||
|
||||
UpdateWatchData(AWatchAble, AVNode, AWatchAbleResult);
|
||||
end;
|
||||
|
@ -590,7 +590,7 @@ type
|
||||
|
||||
{ TIdeWatch }
|
||||
|
||||
TIdeWatch = class(TWatch, TWatchAbleDataIntf)
|
||||
TIdeWatch = class(TWatch, TWatchAbleDataIntf, TFreeNotifyingIntf)
|
||||
private
|
||||
FChildWatches: TIdeWatches;
|
||||
FDisplayName: String;
|
||||
@ -922,6 +922,40 @@ type
|
||||
property OnChange;
|
||||
end;
|
||||
|
||||
TSubLocals = class;
|
||||
|
||||
{ TIdeLocalsValue }
|
||||
|
||||
TIdeLocalsValue = class(TLocalsValue, TWatchAbleResultIntf, TWatchAbleDataIntf, TFreeNotifyingIntf)
|
||||
private
|
||||
FSubLocals: TSubLocals;
|
||||
FDisplayName: String;
|
||||
private
|
||||
// TWatchAble
|
||||
procedure LimitChildWatchCount(AMaxCnt: Integer; AKeepIndexEntriesBelow: Int64 = low(Int64)); virtual;
|
||||
procedure ClearDisplayData; // Clear any cached display-data / keep only what's needed for the snapshot
|
||||
|
||||
function GetDisplayName: String;
|
||||
function GetExpression: String;
|
||||
function GetEnabled: Boolean;
|
||||
function GetValidity: TDebuggerDataState; virtual;
|
||||
function GetDisplayFormat: TWatchDisplayFormat;
|
||||
function GetTypeInfo: TDBGType; deprecated;
|
||||
|
||||
function GetChildrenByNameAsArrayEntry(AName: Int64): TObject;
|
||||
function GetChildrenByNameAsField(AName, AClassName: String): TObject;
|
||||
|
||||
private
|
||||
procedure CreateSubLocals; virtual;
|
||||
function GetSubLocal(ADispName, AnExpr: String): TIdeLocalsValue;
|
||||
protected
|
||||
procedure SetDisplayName(AValue: String); virtual;
|
||||
procedure DoAssign(AnOther: TDbgEntityValue); override;
|
||||
public
|
||||
destructor Destroy; override;
|
||||
property DisplayName: String read GetDisplayName write SetDisplayName;
|
||||
end;
|
||||
|
||||
{ TIDELocals }
|
||||
|
||||
TIDELocals = class(TLocals)
|
||||
@ -930,19 +964,84 @@ type
|
||||
APath: string);
|
||||
procedure SaveDataToXMLConfig(const AConfig: TXMLConfig;
|
||||
APath: string);
|
||||
function CreateEntry: TDbgEntityValue; override;
|
||||
public
|
||||
constructor CreateFromXMLConfig(const AConfig: TXMLConfig; APath: string);
|
||||
procedure SetDataValidity({%H-}AValidity: TDebuggerDataState); override;
|
||||
end;
|
||||
|
||||
{ THistoryLocalValue }
|
||||
|
||||
THistoryLocalValue = class(TIdeLocalsValue)
|
||||
protected
|
||||
FSnapShot: TIdeLocalsValue;
|
||||
procedure SetSnapShot(const AValue: TIdeLocalsValue); virtual;
|
||||
procedure CreateSubLocals; override;
|
||||
procedure SetDisplayName(AValue: String); override;
|
||||
end;
|
||||
|
||||
{ THistoryLocals }
|
||||
|
||||
THistoryLocals = class(TIDELocals)
|
||||
protected
|
||||
FSnapShot: TIDELocals;
|
||||
procedure SetSnapShot(const AValue: TIDELocals); virtual;
|
||||
end;
|
||||
|
||||
{ TSubLocalsValue }
|
||||
|
||||
TSubLocalsValue = class(specialize TDbgDataRequestTemplateBase<THistoryLocalValue, TWatchValueIntf>, TWatchValueIntf)
|
||||
private
|
||||
FValidity: TDebuggerDataState;
|
||||
FCurrentResData: TCurrentResData;
|
||||
private
|
||||
FOnChange: TNotifyEvent;
|
||||
// TWatchValueIntf
|
||||
function GetEvaluateFlags: TWatcheEvaluateFlags;
|
||||
function GetDbgValConverter: TLazDbgValueConvertSelectorIntf;
|
||||
function GetFirstIndexOffs: Int64;
|
||||
function GetRepeatCount: Integer;
|
||||
function GetValidity: TDebuggerDataState; override;
|
||||
procedure SetTypeInfo(AValue: TDBGTypeBase);
|
||||
procedure SetValidity(AValue: TDebuggerDataState);
|
||||
procedure SetValue(AValue: String);
|
||||
|
||||
function ResData: TLzDbgWatchDataIntf; // new ResData for debugger to fill in
|
||||
procedure DoBeginUpdating; override;
|
||||
procedure DoEndUpdating; override;
|
||||
procedure RequestData;
|
||||
|
||||
protected
|
||||
function GetResultData: TWatchResultData; override;
|
||||
function GetValue: String; override;
|
||||
public
|
||||
destructor Destroy; override;
|
||||
property OnChange: TNotifyEvent read FOnChange write FOnChange;
|
||||
end;
|
||||
|
||||
{ TSubLocals }
|
||||
|
||||
TSubLocals = class(THistoryLocals)
|
||||
private
|
||||
FOwnerLocals: TIDELocals;
|
||||
protected
|
||||
function CreateEntry: TDbgEntityValue; override;
|
||||
function Add(const AName: String): TIdeLocalsValue; overload;
|
||||
procedure SetSnapShot(const AValue: TIDELocals); override;
|
||||
function TopOwner: TIDELocals;
|
||||
public
|
||||
constructor Create(AThreadId, AStackFrame: Integer; AOwnerLocals: TIDELocals);
|
||||
end;
|
||||
|
||||
TCurrentLocalValue = class(THistoryLocalValue)
|
||||
end;
|
||||
|
||||
{ TCurrentLocals }
|
||||
|
||||
TCurrentLocals = class(specialize TDbgDataRequestTemplateBase<TIDELocals, TLocalsListIntf>, TLocalsListIntf)
|
||||
TCurrentLocals = class(specialize TDbgDataRequestTemplateBase<THistoryLocals, TLocalsListIntf>, TLocalsListIntf)
|
||||
private
|
||||
FMonitor: TIdeLocalsMonitor;
|
||||
FSnapShot: TIDELocals;
|
||||
FDataValidity: TDebuggerDataState;
|
||||
procedure SetSnapShot(const AValue: TIDELocals);
|
||||
private
|
||||
(* TLocalsListIntf *)
|
||||
FCurrentResName: String;
|
||||
@ -955,14 +1054,19 @@ type
|
||||
procedure DoEndUpdating; override;
|
||||
procedure SetValidity(AValue: TDebuggerDataState);
|
||||
function Add(AName: String): TLzDbgWatchDataIntf; overload;
|
||||
procedure FinishCurrentRes;
|
||||
protected
|
||||
procedure FinishCurrentRes(AnInUpdate: Boolean = False);
|
||||
function CreateEntry: TDbgEntityValue; override;
|
||||
procedure SetSnapShot(const AValue: TIDELocals); override;
|
||||
property SnapShot: TIDELocals read FSnapShot write SetSnapShot;
|
||||
public
|
||||
constructor Create(AMonitor: TIdeLocalsMonitor; AThreadId, AStackFrame: Integer);
|
||||
destructor Destroy; override;
|
||||
function Count: Integer; override;
|
||||
procedure Add(AnEntry: TDbgEntityValue); override;
|
||||
function Add(const AName: String; AValue: TWatchResultData): TLocalsValue; override; overload;
|
||||
procedure SetDataValidity(AValidity: TDebuggerDataState); override;
|
||||
property Validity: TDebuggerDataState read FDataValidity;
|
||||
end;
|
||||
|
||||
{ TLocalsList }
|
||||
@ -7055,6 +7159,115 @@ end;
|
||||
(******************************************************************************)
|
||||
(******************************************************************************)
|
||||
|
||||
{ TIdeLocalsValue }
|
||||
|
||||
procedure TIdeLocalsValue.LimitChildWatchCount(AMaxCnt: Integer;
|
||||
AKeepIndexEntriesBelow: Int64);
|
||||
begin
|
||||
//
|
||||
end;
|
||||
|
||||
procedure TIdeLocalsValue.ClearDisplayData;
|
||||
begin
|
||||
//
|
||||
end;
|
||||
|
||||
function TIdeLocalsValue.GetDisplayName: String;
|
||||
begin
|
||||
Result := FDisplayName;
|
||||
if Result = '' then
|
||||
Result := Name;
|
||||
end;
|
||||
|
||||
function TIdeLocalsValue.GetExpression: String;
|
||||
begin
|
||||
Result := Name;
|
||||
end;
|
||||
|
||||
function TIdeLocalsValue.GetEnabled: Boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TIdeLocalsValue.GetValidity: TDebuggerDataState;
|
||||
begin
|
||||
if ResultData <> nil then
|
||||
Result := ddsValid
|
||||
else
|
||||
Result := ddsRequested;
|
||||
end;
|
||||
|
||||
function TIdeLocalsValue.GetDisplayFormat: TWatchDisplayFormat;
|
||||
begin
|
||||
Result := wdfDefault;
|
||||
end;
|
||||
|
||||
function TIdeLocalsValue.GetTypeInfo: TDBGType;
|
||||
begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
function TIdeLocalsValue.GetChildrenByNameAsArrayEntry(AName: Int64): TObject;
|
||||
begin
|
||||
Result := GetSubLocal(IntToStr(AName),
|
||||
GetExpressionForArrayElement(Name, AName)
|
||||
);
|
||||
end;
|
||||
|
||||
function TIdeLocalsValue.GetChildrenByNameAsField(AName, AClassName: String
|
||||
): TObject;
|
||||
var
|
||||
Expr: String;
|
||||
begin
|
||||
Expr := Name;
|
||||
if AClassName <> '' then
|
||||
Expr := AClassName + '(' + Expr + ')';
|
||||
Expr := Expr + '.' + AName;
|
||||
Result := GetSubLocal(AName, Expr);
|
||||
end;
|
||||
|
||||
procedure TIdeLocalsValue.CreateSubLocals;
|
||||
begin
|
||||
if FSubLocals = nil then
|
||||
FSubLocals := TSubLocals.Create(ThreadId, StackFrame, TIDELocals(Owner));
|
||||
end;
|
||||
|
||||
function TIdeLocalsValue.GetSubLocal(ADispName, AnExpr: String
|
||||
): TIdeLocalsValue;
|
||||
begin
|
||||
if FSubLocals = nil then begin
|
||||
CreateSubLocals;
|
||||
end
|
||||
else begin
|
||||
Result := TIdeLocalsValue(FSubLocals.Find(AnExpr));
|
||||
if Result <> nil then
|
||||
exit;
|
||||
end;
|
||||
|
||||
Result := FSubLocals.Add(AnExpr);
|
||||
Result.DisplayName := ADispName;
|
||||
end;
|
||||
|
||||
procedure TIdeLocalsValue.SetDisplayName(AValue: String);
|
||||
begin
|
||||
FDisplayName := AValue;
|
||||
end;
|
||||
|
||||
procedure TIdeLocalsValue.DoAssign(AnOther: TDbgEntityValue);
|
||||
begin
|
||||
inherited DoAssign(AnOther);
|
||||
if AnOther is TIdeLocalsValue then begin
|
||||
FDisplayName := TIdeLocalsValue(AnOther).FDisplayName;
|
||||
// skip SubLocals
|
||||
end;
|
||||
end;
|
||||
|
||||
destructor TIdeLocalsValue.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
FSubLocals.Free;
|
||||
end;
|
||||
|
||||
{ =========================================================================== }
|
||||
{ TLocals }
|
||||
{ =========================================================================== }
|
||||
@ -7092,6 +7305,11 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TIDELocals.CreateEntry: TDbgEntityValue;
|
||||
begin
|
||||
Result := TIdeLocalsValue.Create;
|
||||
end;
|
||||
|
||||
constructor TIDELocals.CreateFromXMLConfig(const AConfig: TXMLConfig; APath: string);
|
||||
var
|
||||
LoadThreadId, LoadStackFrame: Integer;
|
||||
@ -7102,17 +7320,247 @@ begin
|
||||
LoadDataFromXMLConfig(AConfig, APath);
|
||||
end;
|
||||
|
||||
{ THistoryLocalValue }
|
||||
|
||||
procedure THistoryLocalValue.SetSnapShot(const AValue: TIdeLocalsValue);
|
||||
begin
|
||||
FSnapShot := AValue;
|
||||
FSnapShot.Assign(Self);
|
||||
|
||||
if FSubLocals <> nil then begin
|
||||
FSnapShot.CreateSubLocals;
|
||||
FSubLocals.SetSnapShot(FSnapShot.FSubLocals);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure THistoryLocalValue.CreateSubLocals;
|
||||
begin
|
||||
inherited CreateSubLocals;
|
||||
if FSnapShot <> nil then begin
|
||||
FSnapShot.CreateSubLocals;
|
||||
FSubLocals.SetSnapShot(FSnapShot.FSubLocals);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure THistoryLocalValue.SetDisplayName(AValue: String);
|
||||
begin
|
||||
inherited SetDisplayName(AValue);
|
||||
if FSnapShot <> nil then
|
||||
FSnapShot.DisplayName := AValue;
|
||||
end;
|
||||
|
||||
{ THistoryLocals }
|
||||
|
||||
procedure THistoryLocals.SetSnapShot(const AValue: TIDELocals);
|
||||
begin
|
||||
FSnapShot := AValue;
|
||||
end;
|
||||
|
||||
{ TSubLocalsValue }
|
||||
|
||||
function TSubLocalsValue.ResData: TLzDbgWatchDataIntf;
|
||||
begin
|
||||
if FCurrentResData = nil then
|
||||
FCurrentResData := TCurrentResData.Create;
|
||||
Result := FCurrentResData;
|
||||
end;
|
||||
|
||||
procedure TSubLocalsValue.DoBeginUpdating;
|
||||
begin
|
||||
AddReference;
|
||||
FValidity := ddsEvaluating;
|
||||
end;
|
||||
|
||||
procedure TSubLocalsValue.DoEndUpdating;
|
||||
begin
|
||||
FCurrentResData := FCurrentResData.RootResultData;
|
||||
// TODO: maybe create an error entry, if only FNewResultData is missing
|
||||
if (FCurrentResData <> nil) then begin
|
||||
if (FCurrentResData.FNewResultData = nil) then begin
|
||||
FreeAndNil(FCurrentResData);
|
||||
FValidity := ddsInvalid;
|
||||
ReleaseReference;
|
||||
exit;
|
||||
end;
|
||||
|
||||
FCurrentResData.Done;
|
||||
FValue := FCurrentResData.FNewResultData;
|
||||
FreeAndNil(FCurrentResData);
|
||||
|
||||
if FValidity = ddsEvaluating then
|
||||
FValidity := ddsValid;
|
||||
end
|
||||
else
|
||||
FValidity := ddsInvalid;
|
||||
|
||||
if FSnapShot <> nil then begin
|
||||
TSubLocalsValue(FSnapShot).FValidity := FValidity;
|
||||
TSubLocalsValue(FSnapShot).FValue := FValue.CreateCopy;
|
||||
end;
|
||||
|
||||
if FOnChange <> nil then
|
||||
FOnChange(Self);
|
||||
|
||||
ReleaseReference;
|
||||
end;
|
||||
|
||||
procedure TSubLocalsValue.RequestData;
|
||||
begin
|
||||
if(DebugBossManager <> nil) and
|
||||
(FValidity = ddsUnknown) and
|
||||
(TSubLocals(Owner).TopOwner is TCurrentLocals) and
|
||||
(inherited GetResultData = nil)
|
||||
then begin
|
||||
FValidity := ddsRequested;
|
||||
DebugBossManager.RequestWatchData(Self);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSubLocalsValue.GetResultData: TWatchResultData;
|
||||
begin
|
||||
RequestData;
|
||||
Result := inherited GetResultData;
|
||||
end;
|
||||
|
||||
function TSubLocalsValue.GetValue: String;
|
||||
begin
|
||||
RequestData;
|
||||
case FValidity of
|
||||
ddsRequested, ddsEvaluating: Result := '<evaluating>';
|
||||
ddsValid: Result := inherited GetValue;
|
||||
ddsInvalid: Result := '<invalid>';
|
||||
ddsError: Result := '<Error: '+ (inherited GetValue) +'>';
|
||||
else Result := '<not evaluated>';
|
||||
end;
|
||||
end;
|
||||
|
||||
destructor TSubLocalsValue.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
DoDestroy;
|
||||
end;
|
||||
|
||||
function TSubLocalsValue.GetEvaluateFlags: TWatcheEvaluateFlags;
|
||||
begin
|
||||
Result := [];
|
||||
end;
|
||||
|
||||
function TSubLocalsValue.GetDbgValConverter: TLazDbgValueConvertSelectorIntf;
|
||||
begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
function TSubLocalsValue.GetFirstIndexOffs: Int64;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
function TSubLocalsValue.GetRepeatCount: Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
function TSubLocalsValue.GetValidity: TDebuggerDataState;
|
||||
begin
|
||||
RequestData;
|
||||
Result := FValidity;
|
||||
end;
|
||||
|
||||
procedure TSubLocalsValue.SetTypeInfo(AValue: TDBGTypeBase);
|
||||
begin
|
||||
//assert(False, 'TSubLocalsValue.SetTypeInfo: False');
|
||||
end;
|
||||
|
||||
procedure TSubLocalsValue.SetValidity(AValue: TDebuggerDataState);
|
||||
begin
|
||||
FValidity := AValue;
|
||||
if not IsUpdating then begin
|
||||
AddReference;
|
||||
DoEndUpdating;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSubLocalsValue.SetValue(AValue: String);
|
||||
begin
|
||||
FValue.Free;
|
||||
FValue := TWatchResultDataPrePrinted.Create(AValue);
|
||||
end;
|
||||
|
||||
{ TSubLocals }
|
||||
|
||||
function TSubLocals.CreateEntry: TDbgEntityValue;
|
||||
begin
|
||||
Result := TSubLocalsValue.Create;
|
||||
end;
|
||||
|
||||
function TSubLocals.Add(const AName: String): TIdeLocalsValue;
|
||||
var
|
||||
V: TSubLocalsValue;
|
||||
begin
|
||||
Result := TIdeLocalsValue(CreateEntry);
|
||||
Result.FName := AName;
|
||||
Add(Result);
|
||||
|
||||
if FSnapShot <> nil then begin
|
||||
V := TSubLocalsValue(FSnapShot.Add('', nil));
|
||||
assert(V is TSubLocalsValue, 'TSubLocals.Add: V is TSubLocalsValue');
|
||||
assert(Result is TSubLocalsValue, 'TSubLocals.Add: Result is TSubLocalsValue');
|
||||
TSubLocalsValue(Result).SetSnapShot(V);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSubLocals.SetSnapShot(const AValue: TIDELocals);
|
||||
var
|
||||
V: TSubLocalsValue;
|
||||
i: Integer;
|
||||
begin
|
||||
assert((FSnapShot=nil) or (AValue=nil), 'TSubLocals.SetSnapShot: (FSnapShot=nil) or (AValue=nil)');
|
||||
inherited SetSnapShot(AValue);
|
||||
|
||||
if FSnapShot <> nil then begin
|
||||
assert(FSnapShot is TSubLocals, 'TSubLocals.SetSnapShot: FSnapShot is TSubLocals');
|
||||
FSnapShot.Clear;
|
||||
for i := 0 to Count - 1 do begin
|
||||
V := TSubLocalsValue(FSnapShot.Add('', nil));
|
||||
TSubLocalsValue(Entries[i]).SetSnapShot(V);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSubLocals.TopOwner: TIDELocals;
|
||||
begin
|
||||
Result := FOwnerLocals;
|
||||
while (Result <> nil) and (Result is TSubLocals) do
|
||||
Result := TSubLocals(Result).FOwnerLocals;
|
||||
end;
|
||||
|
||||
constructor TSubLocals.Create(AThreadId, AStackFrame: Integer;
|
||||
AOwnerLocals: TIDELocals);
|
||||
begin
|
||||
inherited Create(AThreadId, AStackFrame);
|
||||
FOwnerLocals := AOwnerLocals;
|
||||
end;
|
||||
|
||||
{ =========================================================================== }
|
||||
{ TCurrentLocals }
|
||||
{ =========================================================================== }
|
||||
|
||||
procedure TCurrentLocals.SetSnapShot(const AValue: TIDELocals);
|
||||
var
|
||||
V: TIdeLocalsValue;
|
||||
i: Integer;
|
||||
begin
|
||||
assert((FSnapShot=nil) or (AValue=nil), 'TCurrentLocals already have snapshot');
|
||||
if FSnapShot = AValue then exit;
|
||||
FSnapShot := AValue;
|
||||
if FSnapShot <> nil
|
||||
then FSnapShot.Assign(Self);
|
||||
inherited SetSnapShot(AValue);
|
||||
|
||||
if FSnapShot <> nil then begin
|
||||
FSnapShot.Clear;
|
||||
for i := 0 to Count - 1 do begin
|
||||
V := TIdeLocalsValue(FSnapShot.Add('', nil));
|
||||
TCurrentLocalValue(Entries[i]).SetSnapShot(V);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCurrentLocals.GetStackFrame: Integer;
|
||||
@ -7140,7 +7588,7 @@ procedure TCurrentLocals.DoEndUpdating;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
FinishCurrentRes;
|
||||
FinishCurrentRes(True);
|
||||
|
||||
for i := 0 to FCurrentResList.Count - 1 do
|
||||
Add(TLocalsValue(FCurrentResList[i]));
|
||||
@ -7173,7 +7621,7 @@ begin
|
||||
Result := FCurrentResData;
|
||||
end;
|
||||
|
||||
procedure TCurrentLocals.FinishCurrentRes;
|
||||
procedure TCurrentLocals.FinishCurrentRes(AnInUpdate: Boolean);
|
||||
var
|
||||
v: TLocalsValue;
|
||||
begin
|
||||
@ -7191,7 +7639,7 @@ begin
|
||||
v := TLocalsValue(CreateEntry);
|
||||
v.Init(FCurrentResName, FCurrentResData.FNewResultData);
|
||||
|
||||
if IsUpdating then
|
||||
if IsUpdating or AnInUpdate then
|
||||
FCurrentResList.Add(v)
|
||||
else
|
||||
Add(v);
|
||||
@ -7199,6 +7647,11 @@ begin
|
||||
FreeAndNil(FCurrentResData);
|
||||
end;
|
||||
|
||||
function TCurrentLocals.CreateEntry: TDbgEntityValue;
|
||||
begin
|
||||
Result := TCurrentLocalValue.Create;
|
||||
end;
|
||||
|
||||
constructor TCurrentLocals.Create(AMonitor: TIdeLocalsMonitor; AThreadId, AStackFrame: Integer);
|
||||
begin
|
||||
FMonitor := AMonitor;
|
||||
@ -7209,6 +7662,7 @@ end;
|
||||
destructor TCurrentLocals.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
DoDestroy;
|
||||
|
||||
FCurrentResData := FCurrentResData.RootResultData;
|
||||
if (FCurrentResData <> nil) {and (FResultData = nil)} then
|
||||
@ -7240,6 +7694,30 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCurrentLocals.Add(AnEntry: TDbgEntityValue);
|
||||
var
|
||||
V: TIdeLocalsValue;
|
||||
begin
|
||||
inherited Add(AnEntry);
|
||||
assert(AnEntry is TCurrentLocalValue, 'TCurrentLocals.Add: AnEntry is TCurrentLocalValue');
|
||||
if FSnapShot <> nil then begin
|
||||
V := TIdeLocalsValue(FSnapShot.Add('', nil));
|
||||
TCurrentLocalValue(AnEntry).SetSnapShot(V);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCurrentLocals.Add(const AName: String; AValue: TWatchResultData
|
||||
): TLocalsValue;
|
||||
var
|
||||
V: TIdeLocalsValue;
|
||||
begin
|
||||
Result := inherited Add(AName, AValue);
|
||||
if FSnapShot <> nil then begin
|
||||
V := TIdeLocalsValue(FSnapShot.Add('', nil));
|
||||
TCurrentLocalValue(Result).SetSnapShot(V);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCurrentLocals.SetDataValidity(AValidity: TDebuggerDataState);
|
||||
begin
|
||||
if FDataValidity = AValidity then exit;
|
||||
|
@ -56,8 +56,10 @@ type
|
||||
|
||||
procedure SelectNode(Node: PVirtualNode; ASetFocus: boolean = True);
|
||||
function FindNodeForItem(AnItem: TObject): PVirtualNode;
|
||||
function FindNodeForText(AText: String; AColumn: integer): PVirtualNode;
|
||||
function FindNodeForText(AText: String; AColumn: integer; ATopLvlOnly: Boolean = False): PVirtualNode;
|
||||
procedure DeleteNodeEx(Node: PVirtualNode; FreeItem: Boolean; Reindex: Boolean = True);
|
||||
// LazMoveTo: Don't mess with children
|
||||
procedure LazMoveTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode);
|
||||
|
||||
property NodeItem[Node: PVirtualNode]: TObject read GetNodeItem write SetNodeItem;
|
||||
property NodeText[Node: PVirtualNode; AColumn: integer]: String read GetNodeText write SetNodeText;
|
||||
@ -351,14 +353,19 @@ begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
function TDbgTreeView.FindNodeForText(AText: String; AColumn: integer
|
||||
): PVirtualNode;
|
||||
function TDbgTreeView.FindNodeForText(AText: String; AColumn: integer;
|
||||
ATopLvlOnly: Boolean): PVirtualNode;
|
||||
var
|
||||
VNode: PVirtualNode;
|
||||
begin
|
||||
for VNode in NoInitNodes do begin
|
||||
VNode := GetFirstNoInit;
|
||||
while VNode <> nil do begin
|
||||
if GetNodeText(VNode, AColumn) = AText then
|
||||
exit(VNode);
|
||||
if ATopLvlOnly then
|
||||
VNode := GetNextSiblingNoInit(VNode)
|
||||
else
|
||||
VNode := GetNextNoInit(VNode);
|
||||
end;
|
||||
Result := nil;
|
||||
end;
|
||||
@ -377,6 +384,46 @@ begin
|
||||
Item.Free;
|
||||
end;
|
||||
|
||||
procedure TDbgTreeView.LazMoveTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode);
|
||||
var
|
||||
NewNode: PVirtualNode;
|
||||
begin
|
||||
if Target = nil then
|
||||
begin
|
||||
Target := RootNode;
|
||||
Mode := amAddChildFirst;
|
||||
end;
|
||||
|
||||
if Target = RootNode then
|
||||
begin
|
||||
case Mode of
|
||||
amInsertBefore:
|
||||
Mode := amAddChildFirst;
|
||||
amInsertAfter:
|
||||
Mode := amAddChildLast;
|
||||
end;
|
||||
end;
|
||||
|
||||
if (Source <> Target) and HasAsParent(Target, Source) then
|
||||
exit;
|
||||
|
||||
// Disconnect from old location.
|
||||
InternalDisconnectNode(Source, True);
|
||||
// Connect to new location.
|
||||
InternalConnectNode(Source, Target, Self, Mode);
|
||||
DoNodeMoved(Source);
|
||||
|
||||
|
||||
InvalidateCache;
|
||||
if (UpdateCount = 0) then
|
||||
begin
|
||||
ValidateCache;
|
||||
UpdateScrollBars(True);
|
||||
Invalidate;
|
||||
end;
|
||||
StructureChange(Source, crNodeMoved);
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterClass(TDbgTreeView);
|
||||
|
||||
|
@ -235,18 +235,20 @@ type
|
||||
|
||||
{ TLocalsValue }
|
||||
|
||||
TLocalsValue = class(TDbgEntityValue)
|
||||
private
|
||||
FName: String;
|
||||
FValue: TWatchResultData;
|
||||
protected
|
||||
procedure DoAssign(AnOther: TDbgEntityValue); override;
|
||||
public
|
||||
destructor Destroy; override;
|
||||
procedure Init(AName: String; AValue: TWatchResultData);
|
||||
property Name: String read FName;
|
||||
property Value: TWatchResultData read FValue;
|
||||
end;
|
||||
TLocalsValue = class(TDbgEntityValue)
|
||||
protected
|
||||
FName: String;
|
||||
FValue: TWatchResultData;
|
||||
function GetValue: String; virtual;
|
||||
function GetResultData: TWatchResultData; virtual;
|
||||
procedure DoAssign(AnOther: TDbgEntityValue); override;
|
||||
public
|
||||
destructor Destroy; override;
|
||||
procedure Init(AName: String; AValue: TWatchResultData);
|
||||
property Name: String read FName;
|
||||
property Value: String read GetValue;
|
||||
property ResultData: TWatchResultData read GetResultData;
|
||||
end;
|
||||
|
||||
{ TLocals }
|
||||
|
||||
@ -254,17 +256,18 @@ type
|
||||
private
|
||||
function GetEntry(AnIndex: Integer): TLocalsValue;
|
||||
function GetName(const AnIndex: Integer): String;
|
||||
function GetValue(const AnIndex: Integer): TWatchResultData;
|
||||
function GetResultData(const AnIndex: Integer): TWatchResultData;
|
||||
protected
|
||||
function CreateEntry: TDbgEntityValue; override;
|
||||
public
|
||||
procedure Add(const AName: String; AValue: TWatchResultData); overload; deprecated;
|
||||
function Add(const AName: String; AValue: TWatchResultData): TLocalsValue; virtual; overload;
|
||||
procedure SetDataValidity({%H-}AValidity: TDebuggerDataState); virtual;
|
||||
public
|
||||
function Count: Integer;reintroduce; virtual;
|
||||
function Find(AName: String): TLocalsValue;
|
||||
property Entries[AnIndex: Integer]: TLocalsValue read GetEntry;
|
||||
property Names[const AnIndex: Integer]: String read GetName;
|
||||
property Values[const AnIndex: Integer]: TWatchResultData read GetValue;
|
||||
property Values[const AnIndex: Integer]: TWatchResultData read GetResultData;
|
||||
end;
|
||||
|
||||
{ TLocalsList }
|
||||
@ -972,6 +975,18 @@ end;
|
||||
|
||||
{ TLocalsValue }
|
||||
|
||||
function TLocalsValue.GetValue: String;
|
||||
begin
|
||||
Result := '';
|
||||
if FValue <> nil then
|
||||
Result := FValue.AsString;
|
||||
end;
|
||||
|
||||
function TLocalsValue.GetResultData: TWatchResultData;
|
||||
begin
|
||||
Result := FValue;
|
||||
end;
|
||||
|
||||
procedure TLocalsValue.DoAssign(AnOther: TDbgEntityValue);
|
||||
begin
|
||||
inherited DoAssign(AnOther);
|
||||
@ -1016,9 +1031,9 @@ begin
|
||||
Result := Entries[AnIndex].Name;
|
||||
end;
|
||||
|
||||
function TLocals.GetValue(const AnIndex: Integer): TWatchResultData;
|
||||
function TLocals.GetResultData(const AnIndex: Integer): TWatchResultData;
|
||||
begin
|
||||
Result := Entries[AnIndex].Value;
|
||||
Result := Entries[AnIndex].ResultData;
|
||||
end;
|
||||
|
||||
function TLocals.CreateEntry: TDbgEntityValue;
|
||||
@ -1026,15 +1041,14 @@ begin
|
||||
Result := TLocalsValue.Create;
|
||||
end;
|
||||
|
||||
procedure TLocals.Add(const AName: String; AValue: TWatchResultData);
|
||||
var
|
||||
v: TLocalsValue;
|
||||
function TLocals.Add(const AName: String; AValue: TWatchResultData
|
||||
): TLocalsValue;
|
||||
begin
|
||||
assert(not Immutable, 'TLocalsBase.Add Immutable');
|
||||
v := TLocalsValue(CreateEntry);
|
||||
v.FName := AName;
|
||||
v.FValue := AValue;
|
||||
inherited Add(v);
|
||||
Result := TLocalsValue(CreateEntry);
|
||||
Result.FName := AName;
|
||||
Result.FValue := AValue;
|
||||
inherited Add(Result);
|
||||
end;
|
||||
|
||||
procedure TLocals.SetDataValidity(AValidity: TDebuggerDataState);
|
||||
@ -1047,6 +1061,20 @@ begin
|
||||
Result := inherited Count;
|
||||
end;
|
||||
|
||||
function TLocals.Find(AName: String): TLocalsValue;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
i := Count - 1;
|
||||
while i >= 0 do begin
|
||||
Result := Entries[i];
|
||||
if Result.Name = AName then
|
||||
exit;
|
||||
dec(i);
|
||||
end;
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
{ TLocalsMonitor }
|
||||
|
||||
procedure TLocalsMonitor.DoStateChange(const AOldState, ANewState: TDBGState);
|
||||
|
@ -26,7 +26,7 @@ function ClearMultiline(const AValue: ansistring): ansistring;
|
||||
The Index "11" returns Foo[11]
|
||||
*)
|
||||
function GetExpressionForArrayElement(AnArrayExpression: AnsiString; AnIndex: String): AnsiString; overload;
|
||||
function GetExpressionForArrayElement(AnArrayExpression: AnsiString; AnIndex: Integer): AnsiString; overload;
|
||||
function GetExpressionForArrayElement(AnArrayExpression: AnsiString; AnIndex: Int64): AnsiString; overload;
|
||||
|
||||
implementation
|
||||
|
||||
@ -349,7 +349,7 @@ begin
|
||||
end;
|
||||
|
||||
function GetExpressionForArrayElement(AnArrayExpression: AnsiString;
|
||||
AnIndex: Integer): AnsiString;
|
||||
AnIndex: Int64): AnsiString;
|
||||
begin
|
||||
Result := GetExpressionForArrayElement(AnArrayExpression, IntToStr(AnIndex));
|
||||
end;
|
||||
|
@ -45,13 +45,17 @@ uses
|
||||
IDEWindowIntf,
|
||||
// DebuggerIntf
|
||||
DbgIntfDebuggerBase, laz.VirtualTrees, LazDebuggerIntf,
|
||||
LazDebuggerIntfBaseTypes,
|
||||
// IDE Debugger
|
||||
IdeDebuggerStringConstants, BaseDebugManager, EnvironmentOpts, Debugger,
|
||||
DebuggerDlg, IdeDebuggerWatchResPrinter, IdeDebuggerUtils, DebuggerTreeView,
|
||||
IdeDebuggerWatchResult, IdeDebuggerBase, Controls, ActiveX;
|
||||
IdeDebuggerWatchResult, IdeDebuggerBase, DbgTreeViewWatchData, Controls,
|
||||
ActiveX;
|
||||
|
||||
type
|
||||
|
||||
TDbgTreeViewLocalsValueMgr = class;
|
||||
|
||||
{ TLocalsDlg }
|
||||
|
||||
TLocalsDlg = class(TDebuggerDlg)
|
||||
@ -95,16 +99,18 @@ type
|
||||
const HitInfo: THitInfo);
|
||||
private
|
||||
FWatchPrinter: TWatchResultPrinter;
|
||||
FLocolsTreeMgr: TDbgTreeViewLocalsValueMgr;
|
||||
|
||||
FUpdateFlags: set of (ufNeedUpdating);
|
||||
function GetSelected: TLocalsValue; // The focused Selected Node
|
||||
procedure CopyRAWValueEvaluateCallback(Sender: TObject; ASuccess: Boolean;
|
||||
ResultText: String; ResultDBGType: TDBGType);
|
||||
procedure CopyValueEvaluateCallback(Sender: TObject; ASuccess: Boolean;
|
||||
ResultText: String; ResultDBGType: TDBGType);
|
||||
procedure DoLocalValueFreed(Sender: TObject);
|
||||
|
||||
procedure ClearTree(OnlyClearNodeData: boolean = False);
|
||||
procedure LocalsChanged(Sender: TObject);
|
||||
procedure SubLocalChanged(Sender: TObject);
|
||||
function GetThreadId: Integer;
|
||||
function GetSelectedThreads(Snap: TSnapshot): TIdeThreads;
|
||||
function GetStackframe: Integer;
|
||||
@ -123,6 +129,23 @@ type
|
||||
property SnapshotManager;
|
||||
end;
|
||||
|
||||
{ TDbgTreeViewLocalsValueMgr }
|
||||
|
||||
TDbgTreeViewLocalsValueMgr = class(TDbgTreeViewWatchDataMgr)
|
||||
private
|
||||
FLocalsDlg: TLocalsDlg;
|
||||
protected
|
||||
function WatchAbleResultFromNode(AVNode: PVirtualNode): TWatchAbleResultIntf; override;
|
||||
function WatchAbleResultFromObject(AWatchAble: TObject): TWatchAbleResultIntf; override;
|
||||
|
||||
procedure UpdateColumnsText(AWatchAble: TObject; AWatchAbleResult: TWatchAbleResultIntf; AVNode: PVirtualNode); override;
|
||||
procedure ConfigureNewSubItem(AWatchAble: TObject); override;
|
||||
//procedure UpdateSubItems(AWatchAble: TObject; AWatchAbleResult: TWatchAbleResultIntf;
|
||||
// AVNode: PVirtualNode; out ChildCount: LongWord); override;
|
||||
//procedure UpdateSubItemsLocked(AWatchAble: TObject; AWatchAbleResult: TWatchAbleResultIntf;
|
||||
// AVNode: PVirtualNode; out ChildCount: LongWord); override;
|
||||
end;
|
||||
|
||||
function ValueToRAW(const AValue: string): string;
|
||||
|
||||
implementation
|
||||
@ -289,6 +312,8 @@ begin
|
||||
CallstackNotification.OnCurrent := @LocalsChanged;
|
||||
SnapshotNotification.OnCurrent := @LocalsChanged;
|
||||
FWatchPrinter := TWatchResultPrinter.Create;
|
||||
FLocolsTreeMgr := TDbgTreeViewLocalsValueMgr.Create(vtLocals);
|
||||
FLocolsTreeMgr.FLocalsDlg := Self;
|
||||
|
||||
Caption:= lisLocals;
|
||||
vtLocals.Header.Columns[0].Text:= lisName;
|
||||
@ -310,6 +335,7 @@ begin
|
||||
ClearTree;
|
||||
inherited Destroy;
|
||||
FWatchPrinter.free;
|
||||
FLocolsTreeMgr.Free;
|
||||
end;
|
||||
|
||||
procedure TLocalsDlg.actInspectUpdate(Sender: TObject);
|
||||
@ -326,7 +352,7 @@ begin
|
||||
if LVal = nil then
|
||||
exit;
|
||||
|
||||
ResVal := LVal.Value;
|
||||
ResVal := LVal.ResultData;
|
||||
if ResVal = nil then
|
||||
exit;
|
||||
|
||||
@ -347,7 +373,7 @@ begin
|
||||
end
|
||||
else begin
|
||||
Clipboard.Open;
|
||||
Clipboard.AsText := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault));
|
||||
Clipboard.AsText := ClearMultiline(FWatchPrinter.PrintWatchValue(ResVal, wdfDefault));
|
||||
Clipboard.Close;
|
||||
end;
|
||||
|
||||
@ -357,7 +383,7 @@ begin
|
||||
if not DebugBoss.Evaluate(LVal.Name, @CopyRAWValueEvaluateCallback, []) then
|
||||
begin
|
||||
Clipboard.Open;
|
||||
Clipboard.AsText := ValueToRAW(ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault)));
|
||||
Clipboard.AsText := ValueToRAW(ClearMultiline(FWatchPrinter.PrintWatchValue(ResVal, wdfDefault)));
|
||||
Clipboard.Close;
|
||||
end;
|
||||
end;
|
||||
@ -459,7 +485,7 @@ begin
|
||||
for VNode in vtLocals.NoInitNodes do begin
|
||||
LVal := TLocalsValue((vtLocals.NodeItem[VNode]));
|
||||
if LVal <> nil then
|
||||
AStringList.Values[LVal.Name] := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault));
|
||||
AStringList.Values[LVal.Name] := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.ResultData, wdfDefault));
|
||||
end;
|
||||
|
||||
Clipboard.Open;
|
||||
@ -482,13 +508,13 @@ begin
|
||||
if LVal = nil then
|
||||
exit;
|
||||
|
||||
ResVal := LVal.Value;
|
||||
ResVal := LVal.ResultData;
|
||||
if ResVal = nil then
|
||||
exit;
|
||||
|
||||
if (ResVal.ValueKind <> rdkPrePrinted) then begin
|
||||
Clipboard.Open;
|
||||
Clipboard.AsText := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault));
|
||||
Clipboard.AsText := ClearMultiline(FWatchPrinter.PrintWatchValue(ResVal, wdfDefault));
|
||||
Clipboard.Close;
|
||||
exit;
|
||||
end;
|
||||
@ -496,7 +522,7 @@ begin
|
||||
if not DebugBoss.Evaluate(LVal.Name, @CopyValueEvaluateCallback, []) then
|
||||
begin
|
||||
Clipboard.Open;
|
||||
Clipboard.AsText := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault));
|
||||
Clipboard.AsText := ClearMultiline(FWatchPrinter.PrintWatchValue(ResVal, wdfDefault));
|
||||
Clipboard.Close;
|
||||
end
|
||||
end;
|
||||
@ -507,10 +533,10 @@ var
|
||||
Locals: TIDELocals;
|
||||
Snap: TSnapshot;
|
||||
s: String;
|
||||
LVal: TLocalsValue;
|
||||
LVal: TIdeLocalsValue;
|
||||
VNode, VN2: PVirtualNode;
|
||||
begin
|
||||
if (ThreadsMonitor = nil) or (CallStackMonitor = nil) or (LocalsMonitor=nil) then begin
|
||||
if (DebugBoss = nil) or (ThreadsMonitor = nil) or (CallStackMonitor = nil) or (LocalsMonitor=nil) then begin
|
||||
ClearTree;
|
||||
exit;
|
||||
end;
|
||||
@ -529,6 +555,19 @@ begin
|
||||
end;
|
||||
|
||||
Snap := GetSelectedSnapshot;
|
||||
|
||||
if (Snap = nil) then begin
|
||||
if (DebugBoss.State in [dsInit, dsIdle, dsStop]) then begin
|
||||
ClearTree;
|
||||
exit;
|
||||
end;
|
||||
|
||||
if not (DebugBoss.State in [dsPause, dsInternalPause]) then begin
|
||||
ClearTree(True);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
if (Snap <> nil)
|
||||
then begin
|
||||
Locals := LocalsMonitor.Snapshots[Snap][GetThreadId, GetStackframe];
|
||||
@ -539,32 +578,29 @@ begin
|
||||
Caption:= lisLocals;
|
||||
end;
|
||||
|
||||
if Locals = nil
|
||||
then begin
|
||||
if (Locals = nil) then begin
|
||||
ClearTree;
|
||||
VNode:= vtLocals.AddChild(nil, nil);
|
||||
vtLocals.NodeText[VNode, 1] := lisLocalsNotEvaluated;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if (Locals is TCurrentLocals) and (TCurrentLocals(Locals).Validity in [ddsUnknown, ddsRequested, ddsEvaluating])
|
||||
then begin
|
||||
Locals.Count; // trigger
|
||||
ClearTree(True);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
BeginUpdate;
|
||||
try
|
||||
ClearTree(True);
|
||||
VN2 := nil;
|
||||
for n := 0 to Locals.Count - 1 do begin
|
||||
LVal := Locals.Entries[n];
|
||||
LVal.AddFreeNotification(@DoLocalValueFreed);
|
||||
|
||||
VNode := vtLocals.FindNodeForText(LVal.Name, 0);
|
||||
if (VNode = nil) then begin
|
||||
VNode := vtLocals.AddChild(nil, LVal);
|
||||
LVal.AddFreeNotification(@DoLocalValueFreed);
|
||||
end
|
||||
else
|
||||
vtLocals.NodeItem[VNode] := LVal;
|
||||
|
||||
s := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault));
|
||||
vtLocals.NodeText[VNode, 0] := LVal.Name;
|
||||
vtLocals.NodeText[VNode, 1] := s;
|
||||
LVal := TIdeLocalsValue(Locals.Entries[n]);
|
||||
VNode := vtLocals.FindNodeForText(LVal.DisplayName, 0, True);
|
||||
if (VNode <> nil) and (VNode^.PrevSibling <> VN2) then
|
||||
vtLocals.LazMoveTo(VNode, VN2, amInsertAfter);
|
||||
VNode := FLocolsTreeMgr.AddWatchData(LVal, LVal, VNode);
|
||||
VN2 := VNode;
|
||||
end;
|
||||
|
||||
|
||||
@ -578,12 +614,21 @@ begin
|
||||
else
|
||||
VNode := vtLocals.GetNextVisibleNoInit(VNode);
|
||||
end;
|
||||
|
||||
finally
|
||||
EndUpdate;
|
||||
vtLocals.Invalidate;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TLocalsDlg.SubLocalChanged(Sender: TObject);
|
||||
var
|
||||
VNode: PVirtualNode;
|
||||
begin
|
||||
VNode := vtLocals.FindNodeForItem(Sender);
|
||||
if VNode <> nil then
|
||||
FLocolsTreeMgr.UpdateWatchData(TSubLocalsValue(Sender), VNode);
|
||||
end;
|
||||
|
||||
function TLocalsDlg.GetThreadId: Integer;
|
||||
var
|
||||
Threads: TIdeThreads;
|
||||
@ -682,9 +727,9 @@ begin
|
||||
else
|
||||
begin
|
||||
LVal := GetSelected;
|
||||
if (LVal <> nil) and (LVal.Value <> nil) then begin
|
||||
if (LVal <> nil) and (LVal.ResultData <> nil) then begin
|
||||
Clipboard.Open;
|
||||
Clipboard.AsText := ValueToRAW(ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault)));
|
||||
Clipboard.AsText := ValueToRAW(ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.ResultData, wdfDefault)));
|
||||
Clipboard.Close;
|
||||
end;
|
||||
end;
|
||||
@ -702,9 +747,9 @@ begin
|
||||
Clipboard.AsText := ExtractValue(ResultText, ResultDBGType.TypeName)
|
||||
else begin
|
||||
LVal := GetSelected;
|
||||
if (LVal <> nil) and (LVal.Value <> nil) then begin
|
||||
if (LVal <> nil) and (LVal.ResultData <> nil) then begin
|
||||
Clipboard.Open;
|
||||
Clipboard.AsText := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.Value, wdfDefault));
|
||||
Clipboard.AsText := ClearMultiline(FWatchPrinter.PrintWatchValue(LVal.ResultData, wdfDefault));
|
||||
Clipboard.Close;
|
||||
end;
|
||||
end;
|
||||
@ -712,35 +757,55 @@ begin
|
||||
FreeAndNil(ResultDBGType);
|
||||
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;
|
||||
if OnlyClearNodeData then
|
||||
vtLocals.NodeText[VNode, 1] := '<not evaluated>';
|
||||
end;
|
||||
|
||||
if not OnlyClearNodeData then
|
||||
vtLocals.Clear;
|
||||
end;
|
||||
|
||||
{ TDbgTreeViewLocalsValueMgr }
|
||||
|
||||
function TDbgTreeViewLocalsValueMgr.WatchAbleResultFromNode(AVNode: PVirtualNode
|
||||
): TWatchAbleResultIntf;
|
||||
begin
|
||||
Result := TIdeLocalsValue(TreeView.NodeItem[AVNode]);
|
||||
end;
|
||||
|
||||
function TDbgTreeViewLocalsValueMgr.WatchAbleResultFromObject(
|
||||
AWatchAble: TObject): TWatchAbleResultIntf;
|
||||
begin
|
||||
Result := TIdeLocalsValue(AWatchAble);
|
||||
end;
|
||||
|
||||
procedure TDbgTreeViewLocalsValueMgr.UpdateColumnsText(AWatchAble: TObject;
|
||||
AWatchAbleResult: TWatchAbleResultIntf; AVNode: PVirtualNode);
|
||||
var
|
||||
s: String;
|
||||
ResData: TWatchResultData;
|
||||
begin
|
||||
ResData := AWatchAbleResult.ResultData;
|
||||
if ResData = nil then
|
||||
s := AWatchAbleResult.Value
|
||||
else
|
||||
s := ClearMultiline(FLocalsDlg.FWatchPrinter.PrintWatchValue(ResData, wdfDefault));
|
||||
TreeView.NodeText[AVNode, 0] := TIdeLocalsValue(AWatchAble).DisplayName;
|
||||
TreeView.NodeText[AVNode, 1] := s;
|
||||
end;
|
||||
|
||||
procedure TDbgTreeViewLocalsValueMgr.ConfigureNewSubItem(AWatchAble: TObject);
|
||||
begin
|
||||
TSubLocalsValue(AWatchAble).OnChange := @FLocalsDlg.SubLocalChanged;
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
LocalsDlgWindowCreator := IDEWindowCreators.Add(DebugDialogNames[ddtLocals]);
|
||||
|
Loading…
Reference in New Issue
Block a user