dexed/src/ce_symlist.pas

861 lines
24 KiB
Plaintext

unit ce_symlist;
{$I ce_defines.inc}
interface
uses
Classes, SysUtils, TreeFilterEdit, Forms, Controls, Graphics, ExtCtrls, Menus,
ComCtrls, ce_widget, jsonparser, process, actnlist, Buttons, Clipbrd, LCLProc,
ce_common, ce_observer, ce_synmemo, ce_interfaces, ce_writableComponent,
ce_processes, ce_sharedres;
type
// Enumerates the possible symbol kind. To be kept in sync with the tool declaration.
TSymbolType = (
_alias,
_class,
_enum,
_error,
_function,
_interface,
_import,
_mixin,
_struct,
_template,
_union,
_unittest,
_variable,
_warning
);
TSymbolCollection = class;
// Encapsulates a symbol to enable structured serialization
TSymbol = class(TCollectionItem)
private
fline, fCol: nativeUint;
fName: string;
fType: TSymbolType;
fSubs: TSymbolCollection;
procedure setSubs(aValue: TSymbolCollection);
published
property line: nativeUint read fline write fLine;
property col: nativeUint read fCol write fCol;
property name: string read fName write fName;
property symType: TSymbolType read fType write fType;
property subs: TSymbolCollection read fSubs write setSubs;
public
constructor Create(ACollection: TCollection); override;
destructor destroy; override;
end;
// Encapsulates a the sub symbols.
TSymbolCollection = class(TCollection)
private
function getSub(index: Integer): TSymbol;
public
constructor create;
property sub[index: Integer]: TSymbol read getSub; default;
end;
// Serializable symbol list
TSymbolList = class(TComponent)
private
fSymbols: TSymbolCollection;
procedure setSymbols(aValue: TSymbolCollection);
published
property symbols: TSymbolCollection read fSymbols write setSymbols;
public
constructor create(aOwner: TCOmponent); override;
destructor destroy; override;
//
procedure LoadFromTool(str: TStream);
end;
TCESymbolListOptions = class(TWritableLfmTextComponent)
private
fAutoRefresh: boolean;
fRefreshOnChange: boolean;
fRefreshOnFocus: boolean;
fShowChildCategories: boolean;
fAutoRefreshDelay: Integer;
fSmartFilter: boolean;
fAutoExpandErrors: boolean;
fSmartExpander: boolean;
fSortSymbols: boolean;
fDeep: boolean;
published
property autoRefresh: boolean read fAutoRefresh write fAutoRefresh;
property refreshOnChange: boolean read fRefreshOnChange write fRefreshOnChange;
property refreshOnFocus: boolean read fRefreshOnFocus write fRefreshOnFocus;
property showChildCategories: boolean read fShowChildCategories write fShowChildCategories;
property autoRefreshDelay: Integer read fAutoRefreshDelay write fAutoRefreshDelay;
property smartFilter: boolean read fSmartFilter write fSmartFilter;
property autoExpandErrors: boolean read fAutoExpandErrors write fAutoExpandErrors;
property sortSymbols: boolean read fSortSymbols write fSortSymbols;
property smartExpander: boolean read fSmartExpander write fSmartExpander;
property deep: boolean read fDeep write fDeep default true;
public
constructor Create(AOwner: TComponent); override;
procedure Assign(Source: TPersistent); override;
procedure AssignTo(Dest: TPersistent); override;
end;
{ TCESymbolListWidget }
TCESymbolListWidget = class(TCEWidget, ICEMultiDocObserver, ICEEditableOptions)
btnRefresh: TBitBtn;
imgList: TImageList;
Panel1: TPanel;
Tree: TTreeView;
TreeFilterEdit1: TTreeFilterEdit;
procedure btnRefreshClick(Sender: TObject);
procedure TreeCompare(Sender: TObject; Node1, Node2: TTreeNode; var Compare: Integer);
procedure TreeFilterEdit1AfterFilter(Sender: TObject);
function TreeFilterEdit1FilterItem(Item: TObject; out Done: Boolean): Boolean;
procedure TreeFilterEdit1MouseEnter(Sender: TObject);
procedure TreeKeyPress(Sender: TObject; var Key: char);
private
fHasToolExe: boolean;
fToolExeName: string;
fOptions: TCESymbolListOptions;
fSyms: TSymbolList;
fMsgs: ICEMessagesDisplay;
fToolProc: TCEProcess;
fActCopyIdent: TAction;
fActRefresh: TAction;
fActRefreshOnChange: TAction;
fActRefreshOnFocus: TAction;
fActAutoRefresh: TAction;
fActSelectInSource: TAction;
fDoc: TCESynMemo;
fAutoRefresh: boolean;
fRefreshOnChange: boolean;
fRefreshOnFocus: boolean;
fDeep: boolean;
fShowChildCategories: boolean;
fSmartFilter: boolean;
fAutoExpandErrors: boolean;
fSortSymbols: boolean;
fSmartExpander: boolean;
ndAlias, ndClass, ndEnum, ndFunc, ndUni: TTreeNode;
ndImp, ndIntf, ndMix, ndStruct, ndTmp: TTreeNode;
ndVar, ndWarn, ndErr, ndUt: TTreeNode;
procedure TreeDblClick(Sender: TObject);
procedure actRefreshExecute(Sender: TObject);
procedure actAutoRefreshExecute(Sender: TObject);
procedure actRefreshOnChangeExecute(Sender: TObject);
procedure actRefreshOnFocusExecute(Sender: TObject);
procedure actCopyIdentExecute(Sender: TObject);
procedure updateVisibleCat;
procedure clearTree;
procedure smartExpand;
//
procedure checkIfHasToolExe;
procedure callToolProc;
procedure toolTerminated(sender: TObject);
//
procedure docNew(aDoc: TCESynMemo);
procedure docClosing(aDoc: TCESynMemo);
procedure docFocused(aDoc: TCESynMemo);
procedure docChanged(aDoc: TCESynMemo);
//
function optionedWantCategory(): string;
function optionedWantEditorKind: TOptionEditorKind;
function optionedWantContainer: TPersistent;
procedure optionedEvent(anEvent: TOptionEditorEvent);
function optionedOptionsModified: boolean;
protected
procedure updateDelayed; override;
//
function contextName: string; override;
function contextActionCount: integer; override;
function contextAction(index: integer): TAction; override;
//
procedure SetVisible(Value: boolean); override;
published
property autoRefresh: boolean read fAutoRefresh write fAutoRefresh;
property refreshOnChange: boolean read fRefreshOnChange write fRefreshOnChange;
property refreshOnFocus: boolean read fRefreshOnFocus write fRefreshOnFocus;
public
constructor create(aOwner: TComponent); override;
destructor destroy; override;
end;
implementation
{$R *.lfm}
const
OptsFname = 'symbollist.txt';
toolExeName = 'cesyms' + exeExt;
{$REGION Serializable symbols---------------------------------------------------}
constructor TSymbol.create(ACollection: TCollection);
begin
inherited create(ACollection);
fSubs := TSymbolCollection.create;
end;
destructor TSymbol.destroy;
begin
fSubs.Free;
inherited;
end;
procedure TSymbol.setSubs(aValue: TSymbolCollection);
begin
fSubs.Assign(aValue);
end;
constructor TSymbolCollection.create;
begin
inherited create(TSymbol);
end;
function TSymbolCollection.getSub(index: Integer): TSymbol;
begin
exit(TSymbol(self.Items[index]));
end;
constructor TSymbolList.create(aOwner: TCOmponent);
begin
inherited;
fSymbols := TSymbolCollection.create;
end;
destructor TSymbolList.destroy;
begin
fSymbols.free;
inherited;
end;
procedure TSymbolList.setSymbols(aValue: TSymbolCollection);
begin
fSymbols.Assign(aValue);
end;
procedure TSymbolList.LoadFromTool(str: TStream);
var
bin: TMemoryStream;
begin
bin := TMemoryStream.Create;
try
str.Position:=0;
try
ObjectTextToBinary(str, bin);
except
exit;
end;
bin.Position:=0;
bin.ReadComponent(self);
finally
bin.Free;
end;
end;
{$ENDREGION}
{$REGION TCESymbolListOptions --------------------------------------------------}
constructor TCESymbolListOptions.Create(AOwner: TComponent);
begin
inherited;
fDeep := true;
fRefreshOnFocus := true;
fShowChildCategories := true;
fAutoExpandErrors := true;
fAutoRefresh := true;
fSmartFilter := true;
fSortSymbols := false;
fAutoRefreshDelay := 750;
end;
procedure TCESymbolListOptions.Assign(Source: TPersistent);
var
widg: TCESymbolListWidget;
begin
if Source is TCESymbolListWidget then
begin
widg := TCESymbolListWidget(Source);
//
fDeep := widg.fDeep;
fAutoRefreshDelay := widg.updaterByDelayDuration;
fRefreshOnFocus := widg.fRefreshOnFocus;
fRefreshOnChange := widg.fRefreshOnChange;
fAutoRefresh := widg.fAutoRefresh;
fShowChildCategories := widg.fShowChildCategories;
fSmartFilter := widg.fSmartFilter;
fAutoExpandErrors := widg.fAutoExpandErrors;
fSortSymbols := widg.fSortSymbols;
fSmartExpander := widg.fSmartExpander;
end
else inherited;
end;
procedure TCESymbolListOptions.AssignTo(Dest: TPersistent);
var
widg: TCESymbolListWidget;
begin
if Dest is TCESymbolListWidget then
begin
widg := TCESymbolListWidget(Dest);
//
widg.updaterByDelayDuration := fAutoRefreshDelay;
widg.fRefreshOnFocus := fRefreshOnFocus;
widg.fRefreshOnChange := fRefreshOnChange;
widg.fAutoRefresh := fAutoRefresh;
widg.fShowChildCategories := fShowChildCategories;
widg.fSmartFilter := fSmartFilter;
widg.fAutoExpandErrors := fAutoExpandErrors;
widg.fSortSymbols := fSortSymbols;
widg.fSmartExpander := fSmartExpander;
widg.fDeep := fDeep;
//
widg.fActAutoRefresh.Checked := fAutoRefresh;
widg.fActRefreshOnChange.Checked:= fRefreshOnChange;
widg.fActRefreshOnFocus.Checked := fRefreshOnFocus;
end
else inherited;
end;
{$ENDREGION}
{$REGION Standard Comp/Obj------------------------------------------------------}
constructor TCESymbolListWidget.create(aOwner: TComponent);
var
fname: string;
begin
fAutoRefresh := false;
fRefreshOnFocus := true;
fRefreshOnChange := false;
checkIfHasToolExe;
//
fActCopyIdent := TAction.Create(self);
fActCopyIdent.OnExecute:=@actCopyIdentExecute;
fActCopyIdent.Caption := 'Copy identifier';
fActRefresh := TAction.Create(self);
fActRefresh.OnExecute := @actRefreshExecute;
fActRefresh.Caption := 'Refresh';
fActAutoRefresh := TAction.Create(self);
fActAutoRefresh.OnExecute := @actAutoRefreshExecute;
fActAutoRefresh.Caption := 'Auto-refresh';
fActAutoRefresh.AutoCheck := true;
fActAutoRefresh.Checked := fAutoRefresh;
fActRefreshOnChange := TAction.Create(self);
fActRefreshOnChange.OnExecute := @actRefreshOnChangeExecute;
fActRefreshOnChange.Caption := 'Refresh on change';
fActRefreshOnChange.AutoCheck := true;
fActRefreshOnChange.Checked := fRefreshOnChange;
fActRefreshOnFocus := TAction.Create(self);
fActRefreshOnFocus.OnExecute := @actRefreshOnFocusExecute;
fActRefreshOnFocus.Caption := 'Refresh on focused';
fActRefreshOnFocus.AutoCheck := true;
fActRefreshOnFocus.Checked := fRefreshOnFocus;
fActSelectInSource := TAction.Create(self);
fActSelectInSource.OnExecute := @TreeDblClick;
fActSelectInSource.Caption := 'Select in source';
//
inherited;
// allow empty name if owner is nil
fSyms := TSymbolList.create(nil);
//
fOptions := TCESymbolListOptions.Create(self);
fOptions.Name:= 'symbolListOptions';
fname := getCoeditDocPath + OptsFname;
if fname.fileExists then
fOptions.loadFromFile(fname);
fOptions.AssignTo(self);
//
ndAlias := Tree.Items[0];
ndClass := Tree.Items[1];
ndEnum := Tree.Items[2];
ndFunc := Tree.Items[3];
ndImp := Tree.Items[4];
ndIntf := Tree.Items[5];
ndMix := Tree.Items[6];
ndStruct := Tree.Items[7];
ndTmp := Tree.Items[8];
ndUni := Tree.Items[9];
ndUt := Tree.Items[10];
ndVar := Tree.Items[11];
ndWarn := Tree.Items[12];
ndErr := Tree.Items[13];
//
AssignPng(btnRefresh, 'ARROW_UPDATE');
//
Tree.OnDblClick := @TreeDblClick;
Tree.PopupMenu := contextMenu;
//
EntitiesConnector.addObserver(self);
end;
destructor TCESymbolListWidget.destroy;
begin
EntitiesConnector.removeObserver(self);
//
killProcess(fToolProc);
fSyms.Free;
//
fOptions.saveToFile(getCoeditDocPath + OptsFname);
fOptions.Free;
//
inherited;
end;
procedure TCESymbolListWidget.SetVisible(Value: boolean);
begin
inherited;
checkIfHasToolExe;
getMessageDisplay(fMsgs);
if Value then
callToolProc;
end;
{$ENDREGION}
{$REGION ICEContextualActions---------------------------------------------------}
function TCESymbolListWidget.contextName: string;
begin
result := 'Static explorer';
end;
function TCESymbolListWidget.contextActionCount: integer;
begin
result := 6;
end;
function TCESymbolListWidget.contextAction(index: integer): TAction;
begin
case index of
0: exit(fActSelectInSource);
1: exit(fActCopyIdent);
2: exit(fActRefresh);
3: exit(fActAutoRefresh);
4: exit(fActRefreshOnChange);
5: exit(fActRefreshOnFocus);
else result := nil;
end;
end;
procedure TCESymbolListWidget.actRefreshExecute(Sender: TObject);
begin
if Updating then exit;
callToolProc;
end;
procedure TCESymbolListWidget.actAutoRefreshExecute(Sender: TObject);
begin
autoRefresh := fActAutoRefresh.Checked;
//fOptions.Assign(self);
end;
procedure TCESymbolListWidget.actRefreshOnChangeExecute(Sender: TObject);
begin
refreshOnChange := fActRefreshOnChange.Checked;
fOptions.Assign(self);
end;
procedure TCESymbolListWidget.actRefreshOnFocusExecute(Sender: TObject);
begin
refreshOnFocus := fActRefreshOnFocus.Checked;
fOptions.Assign(self);
end;
procedure TCESymbolListWidget.actCopyIdentExecute(Sender: TObject);
begin
if Tree.Selected.isNotNil then
Clipboard.AsText:= Tree.Selected.Text;
end;
{$ENDREGION}
{$REGION ICEEditableOptions ----------------------------------------------------}
function TCESymbolListWidget.optionedWantCategory(): string;
begin
exit('Symbol list');
end;
function TCESymbolListWidget.optionedWantEditorKind: TOptionEditorKind;
begin
exit(oekGeneric);
end;
function TCESymbolListWidget.optionedWantContainer: TPersistent;
begin
fOptions.Assign(self);
exit(fOptions);
end;
procedure TCESymbolListWidget.optionedEvent(anEvent: TOptionEditorEvent);
begin
if anEvent <> oeeAccept then exit;
fOptions.AssignTo(self);
callToolProc;
end;
function TCESymbolListWidget.optionedOptionsModified: boolean;
begin
exit(false);
end;
{$ENDREGION}
{$REGION ICEMultiDocObserver ---------------------------------------------------}
procedure TCESymbolListWidget.docNew(aDoc: TCESynMemo);
begin
fDoc := aDoc;
beginDelayedUpdate;
end;
procedure TCESymbolListWidget.docClosing(aDoc: TCESynMemo);
begin
if fDoc <> aDoc then exit;
fDoc := nil;
clearTree;
updateVisibleCat;
end;
procedure TCESymbolListWidget.docFocused(aDoc: TCESynMemo);
begin
if fDoc = aDoc then exit;
fDoc := aDoc;
if not Visible then exit;
//
if fAutoRefresh then beginDelayedUpdate
else if fRefreshOnFocus then callToolProc;
end;
procedure TCESymbolListWidget.docChanged(aDoc: TCESynMemo);
begin
if fDoc <> aDoc then exit;
if not Visible then exit;
//
if fAutoRefresh then beginDelayedUpdate
else if fRefreshOnChange then callToolProc;
//
if fSmartExpander then
smartExpand;
end;
{$ENDREGION}
{$REGION Symbol-tree things ----------------------------------------------------}
procedure TCESymbolListWidget.updateDelayed;
begin
if not fAutoRefresh then exit;
callToolProc;
end;
procedure TCESymbolListWidget.btnRefreshClick(Sender: TObject);
begin
checkIfHasToolExe;
fActRefresh.Execute;
end;
procedure TCESymbolListWidget.TreeCompare(Sender: TObject; Node1,
Node2: TTreeNode; var Compare: Integer);
begin
Compare := CompareStr(Node1.Text, Node2.text);
end;
procedure TCESymbolListWidget.updateVisibleCat;
begin
if fDoc.isNotNil and fDoc.isDSource then
begin
ndAlias.Visible := ndAlias.Count > 0;
ndClass.Visible := ndClass.Count > 0;
ndEnum.Visible := ndEnum.Count > 0;
ndFunc.Visible := ndFunc.Count > 0;
ndImp.Visible := ndImp.Count > 0;
ndIntf.Visible := ndIntf.Count > 0;
ndMix.Visible := ndMix.Count > 0;
ndStruct.Visible:= ndStruct.Count > 0;
ndTmp.Visible := ndTmp.Count > 0;
ndUni.Visible := ndUni.Count > 0;
ndUt.Visible := ndUt.Count > 0;
ndVar.Visible := ndVar.Count > 0;
ndWarn.Visible := ndWarn.Count > 0;
ndErr.Visible := ndErr.Count > 0;
end else
begin
ndAlias.Visible := true;
ndClass.Visible := true;
ndEnum.Visible := true;
ndFunc.Visible := true;
ndImp.Visible := true;
ndIntf.Visible := true;
ndMix.Visible := true;
ndStruct.Visible:= true;
ndTmp.Visible := true;
ndUni.Visible := true;
ndUt.Visible := true;
ndVar.Visible := true;
ndWarn.Visible := true;
ndErr.Visible := true;
end;
end;
procedure TCESymbolListWidget.clearTree;
begin
ndAlias.DeleteChildren;
ndClass.DeleteChildren;
ndEnum.DeleteChildren;
ndFunc.DeleteChildren;
ndImp.DeleteChildren;
ndIntf.DeleteChildren;
ndMix.DeleteChildren;
ndStruct.DeleteChildren;
ndTmp.DeleteChildren;
ndUni.DeleteChildren;
ndUt.DeleteChildren;
ndVar.DeleteChildren;
ndWarn.DeleteChildren;
ndErr.DeleteChildren;
end;
procedure TCESymbolListWidget.TreeFilterEdit1AfterFilter(Sender: TObject);
begin
if TreeFilterEdit1.Filter.isEmpty then
updateVisibleCat;
end;
function TCESymbolListWidget.TreeFilterEdit1FilterItem(Item: TObject; out
Done: Boolean): Boolean;
begin
if not fSmartFilter then exit(false);
//
if TreeFilterEdit1.Filter.isNotEmpty then
tree.FullExpand
else if tree.Selected.isNil then
tree.FullCollapse
else tree.MakeSelectionVisible;
result := false;
end;
procedure TCESymbolListWidget.TreeFilterEdit1MouseEnter(Sender: TObject);
begin
if not fSmartFilter then exit;
//
tree.Selected := nil;
end;
procedure TCESymbolListWidget.TreeKeyPress(Sender: TObject; var Key: char);
begin
if Key = #13 then TreeDblClick(nil);
end;
procedure TCESymbolListWidget.TreeDblClick(Sender: TObject);
var
line: NativeUint;
begin
if fDoc.isNil then exit;
if Tree.Selected.isNil then exit;
if Tree.Selected.Data.isNil then exit;
//
{$PUSH}{$WARNINGS OFF}{$HINTS OFF}
line := NativeUInt(Tree.Selected.Data);
{$POP}
fDoc.CaretY := line;
fDoc.SelectLine;
end;
procedure TCESymbolListWidget.checkIfHasToolExe;
begin
fToolExeName := exeFullName(toolExeName);
fHasToolExe := fToolExeName.fileExists;
end;
procedure TCESymbolListWidget.callToolProc;
var
str: string;
begin
if not fHasToolExe then exit;
if fDoc.isNil then exit;
if (fDoc.Lines.Count = 0) or not fDoc.isDSource then
begin
clearTree;
updateVisibleCat;
exit;
end;
//
killProcess(fToolProc);
fToolProc := TCEProcess.Create(nil);
fToolProc.ShowWindow := swoHIDE;
fToolProc.Options := [poUsePipes];
fToolProc.Executable := fToolExeName;
fToolProc.OnTerminate := @toolTerminated;
fToolProc.CurrentDirectory := Application.ExeName.extractFileDir;
if fDeep then fToolProc.Parameters.Add('-d');
fToolProc.Execute;
str := fDoc.Text;
fToolProc.Input.Write(str[1], str.length);
fToolProc.CloseInput;
end;
procedure TCESymbolListWidget.toolTerminated(sender: TObject);
//
function getCatNode(node: TTreeNode; stype: TSymbolType ): TTreeNode;
//
function newCat(const aCat: string): TTreeNode;
begin
result := node.FindNode(aCat);
if result.isNil then
result := node.TreeNodes.AddChild(node, aCat);
case stype of
_alias : begin result.ImageIndex:=0; result.SelectedIndex:=0; end;
_class : begin result.ImageIndex:=1; result.SelectedIndex:=1; end;
_enum : begin result.ImageIndex:=2; result.SelectedIndex:=2; end;
_function : begin result.ImageIndex:=3; result.SelectedIndex:=3; end;
_import : begin result.ImageIndex:=4; result.SelectedIndex:=4; end;
_interface: begin result.ImageIndex:=5; result.SelectedIndex:=5; end;
_mixin : begin result.ImageIndex:=6; result.SelectedIndex:=6; end;
_struct : begin result.ImageIndex:=7; result.SelectedIndex:=7; end;
_template : begin result.ImageIndex:=8; result.SelectedIndex:=8; end;
_union : begin result.ImageIndex:=0; result.SelectedIndex:=0; end;
_unittest : begin result.ImageIndex:=1; result.SelectedIndex:=1; end;
_variable : begin result.ImageIndex:=2; result.SelectedIndex:=2; end;
_warning : begin result.ImageIndex:=9; result.SelectedIndex:=9; end;
_error : begin result.ImageIndex:=10; result.SelectedIndex:=10; end;
end;
end;
//
begin
result := nil;
if node.isNil then case stype of
_alias : exit(ndAlias);
_class : exit(ndClass);
_enum : exit(ndEnum);
_function : exit(ndFunc);
_import : exit(ndImp);
_interface: exit(ndIntf);
_mixin : exit(ndMix);
_struct : exit(ndStruct);
_template : exit(ndTmp);
_union : exit(ndUni);
_unittest : exit(ndUt);
_variable : exit(ndVar);
_warning : exit(ndWarn);
_error : exit(ndErr);
end else case stype of
_alias: exit(newCat('Alias'));
_class: exit(newCat('Class'));
_enum: exit(newCat('Enum'));
_function: exit(newCat('Function'));
_import: exit(newCat('Import'));
_interface: exit(newCat('Interface'));
_mixin: exit(newCat('Mixin'));
_struct: exit(newCat('Struct'));
_template: exit(newCat('Template'));
_union: exit(newCat('Union'));
_unittest: exit(newCat('Unittest'));
_variable: exit(newCat('Variable'));
_warning: exit(ndWarn);
_error: exit(ndErr);
end;
end;
//
procedure symbolToTreeNode(origin: TTreenode; sym: TSymbol);
var
cat: TTreeNode;
node: TTreeNode;
i: Integer;
begin
cat := getCatNode(origin, sym.symType);
{$PUSH}{$WARNINGS OFF}{$HINTS OFF}
node := tree.Items.AddChildObject(cat, sym.name, Pointer(sym.fline));
{$POP}
node.SelectedIndex:= cat.SelectedIndex;
node.ImageIndex:= cat.ImageIndex;
if not fShowChildCategories then
node := nil;
cat.Visible:=true;
for i := 0 to sym.subs.Count-1 do
symbolToTreeNode(node, sym.subs[i]);
end;
//
var
i: Integer;
flt: string;
begin
if ndAlias.isNil then exit;
clearTree;
updateVisibleCat;
if fDoc.isNil then exit;
//
fToolProc.OnTerminate := nil;
fToolProc.OnReadData := nil;
fToolProc.OutputStack.Position:=0;
if fToolProc.OutputStack.Size = 0 then exit;
fSyms.LoadFromTool(fToolProc.OutputStack);
//
flt := TreeFilterEdit1.Filter;
TreeFilterEdit1.Text := '';
tree.BeginUpdate;
for i := 0 to fSyms.symbols.Count-1 do
symbolToTreeNode(nil, fSyms.symbols[i]);
if fAutoExpandErrors then
begin
if ndWarn.Visible then
ndWarn.Expand(true);
if ndErr.Visible then
ndErr.Expand(true);
end;
if fSortSymbols then
for i:= 0 to tree.Items.Count-1 do
if Tree.Items[i].Count > 0 then
tree.Items[i].CustomSort(nil);
if fSmartExpander then
smartExpand;
tree.EndUpdate;
if flt.isNotEmpty then
TreeFilterEdit1.Text := flt;
end;
procedure TCESymbolListWidget.smartExpand;
var
i: integer;
target: NativeUint;
nearest: NativeUint = 0;
toExpand: TTreeNode = nil;
procedure look(root: TTreeNode);
var
i: integer;
line: NativeUint;
begin
for i := 0 to root.Count-1 do
begin
if root.Items[i].Data.isNil then
continue;
if root.Items[i].Parent.isNil then
continue;
case root.Items[i].Parent.Text of
'Alias', 'Enum', 'Import', 'Variable':
continue;
end;
{$PUSH}{$WARNINGS OFF}{$HINTS OFF}
line := NativeUInt(root.Items[i].Data);
{$POP}
if line > target then
continue;
if line > nearest then
begin
nearest := line;
toExpand := root.Items[i];
end;
end;
end;
begin
if fDoc.isNil then exit;
//
target := fDoc.CaretY;
for i := 0 to tree.Items.Count-1 do
look(tree.Items[i]);
if toExpand.isNotNil then
begin
tree.Selected := toExpand;
toExpand.MakeVisible;
end;
end;
{$ENDREGION --------------------------------------------------------------------}
initialization
RegisterClasses([TCESymbolListOptions]);
end.