dexed/src/u_symlist.pas

934 lines
26 KiB
Plaintext

unit u_symlist;
{$I u_defines.inc}
interface
uses
Classes, SysUtils, TreeFilterEdit, Forms, Controls, Graphics, ExtCtrls, Menus,
ComCtrls, u_widget, jsonparser, process, actnlist, Buttons, Clipbrd, LCLProc,
u_common, u_observer, u_synmemo, u_interfaces, u_writableComponent,
u_processes, u_sharedres, u_dsgncontrols, u_dexed_d;
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: ptrUint;
fName: string;
fType: TSymbolType;
fSubs: TSymbolCollection;
procedure setSubs(value: TSymbolCollection);
published
property line: ptrUint read fline write fLine;
property col: ptrUint 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(value: TSymbolCollection);
published
property symbols: TSymbolCollection read fSymbols write setSymbols;
public
constructor create(aOwner: TCOmponent); override;
destructor destroy; override;
procedure LoadFromString(const s: string);
end;
TSymbolListOptions = 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;
{ TSymbolListWidget }
TSymbolListWidget = class(TDexedWidget, IDocumentObserver, IEditableOptions)
btnRefresh: TDexedToolButton;
Tree: TTreeView;
TreeFilterEdit1: TTreeFilterEdit;
procedure btnRefreshClick(Sender: TObject);
procedure toolbarResize(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
fImages: TImageList;
fHasToolExe: boolean;
fToolExeName: string;
fOptions: TSymbolListOptions;
fSyms: TSymbolList;
fMsgs: IMessagesDisplay;
fActCopyIdent: TAction;
fActRefresh: TAction;
fActRefreshOnChange: TAction;
fActRefreshOnFocus: TAction;
fActAutoRefresh: TAction;
fActSelectInSource: TAction;
fDoc: TDexedMemo;
fAutoRefresh: boolean;
fRefreshOnChange: boolean;
fRefreshOnFocus: boolean;
fDeep: boolean;
fShowChildCategories: boolean;
fSmartFilter: boolean;
fAutoExpandErrors: boolean;
fSortSymbols: boolean;
fSmartExpander: boolean;
fSourcecodeForThread: string;
fTreeDataFromThread: string;
fLockThreadedParsing: boolean;
ndAlias, ndClass, ndEnum, ndFunc, ndUni: TTreeNode;
ndImp, ndIntf, ndMix, ndStruct, ndTmp: TTreeNode;
ndVar, ndWarn, ndErr, ndUt: TTreeNode;
procedure threadedParsing;
procedure threadedParsingFinished(sender: TObject);
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 getSymbols;
procedure docNew(document: TDexedMemo);
procedure docClosing(document: TDexedMemo);
procedure docFocused(document: TDexedMemo);
procedure docChanged(document: TDexedMemo);
function optionedWantCategory(): string;
function optionedWantEditorKind: TOptionEditorKind;
function optionedWantContainer: TPersistent;
procedure optionedEvent(event: 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;
procedure setToolBarFlat(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';
{$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(value: TSymbolCollection);
begin
fSubs.Assign(value);
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(value: TSymbolCollection);
begin
fSymbols.Assign(value);
end;
procedure TSymbolList.LoadFromString(const s: string);
var
txt: TmemoryStream;
bin: TMemoryStream;
begin
txt := TMemoryStream.Create;
bin := TMemoryStream.Create;
try
txt.Write(s[1], s.length);
txt.Position:=0;
try
ObjectTextToBinary(txt, bin);
except
exit;
end;
bin.Position:=0;
bin.ReadComponent(self);
finally
bin.Free;
txt.Free;
end;
end;
{$ENDREGION}
{$REGION TSymbolListOptions --------------------------------------------------}
constructor TSymbolListOptions.Create(AOwner: TComponent);
begin
inherited;
fDeep := true;
fRefreshOnFocus := true;
fShowChildCategories := true;
fAutoExpandErrors := true;
fAutoRefresh := true;
fSmartFilter := true;
fSortSymbols := false;
fAutoRefreshDelay := 750;
end;
procedure TSymbolListOptions.Assign(Source: TPersistent);
var
widg: TSymbolListWidget;
begin
if Source is TSymbolListWidget then
begin
widg := TSymbolListWidget(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 TSymbolListOptions.AssignTo(Dest: TPersistent);
var
widg: TSymbolListWidget;
begin
if Dest is TSymbolListWidget then
begin
widg := TSymbolListWidget(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 TSymbolListWidget.create(aOwner: TComponent);
var
fname: string;
begin
fAutoRefresh := false;
fRefreshOnFocus := true;
fRefreshOnChange := false;
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);
fImages := TImageList.Create(self);
case GetIconScaledSize of
iss16:
begin
Tree.DefaultItemHeight:= 20;
fImages.Width:= 16;
fImages.Height:= 16;
fImages.AddResourceName(HINSTANCE, 'BULLET_BLACK');
fImages.AddResourceName(HINSTANCE, 'BULLET_BLUE');
fImages.AddResourceName(HINSTANCE, 'BULLET_GREEN');
fImages.AddResourceName(HINSTANCE, 'BULLET_ORANGE');
fImages.AddResourceName(HINSTANCE, 'BULLET_PINK');
fImages.AddResourceName(HINSTANCE, 'BULLET_PURPLE');
fImages.AddResourceName(HINSTANCE, 'BULLET_RED');
fImages.AddResourceName(HINSTANCE, 'BULLET_YELLOW');
fImages.AddResourceName(HINSTANCE, 'WARNING');
fImages.AddResourceName(HINSTANCE, 'EXCLAMATION');
AssignPng(TreeFilterEdit1.Glyph, 'FILTER_CLEAR');
end;
iss24:
begin
Tree.DefaultItemHeight:= 28;
fImages.Width:= 24;
fImages.Height:= 24;
fImages.AddResourceName(HINSTANCE, 'BULLET_BLACK24');
fImages.AddResourceName(HINSTANCE, 'BULLET_BLUE24');
fImages.AddResourceName(HINSTANCE, 'BULLET_GREEN24');
fImages.AddResourceName(HINSTANCE, 'BULLET_ORANGE24');
fImages.AddResourceName(HINSTANCE, 'BULLET_PINK24');
fImages.AddResourceName(HINSTANCE, 'BULLET_PURPLE24');
fImages.AddResourceName(HINSTANCE, 'BULLET_RED24');
fImages.AddResourceName(HINSTANCE, 'BULLET_YELLOW24');
fImages.AddResourceName(HINSTANCE, 'WARNING24');
fImages.AddResourceName(HINSTANCE, 'EXCLAMATION24');
AssignPng(TreeFilterEdit1.Glyph, 'FILTER_CLEAR24');
end;
iss32:
begin
Tree.DefaultItemHeight:= 36;
fImages.Width:= 32;
fImages.Height:= 32;
fImages.AddResourceName(HINSTANCE, 'BULLET_BLACK32');
fImages.AddResourceName(HINSTANCE, 'BULLET_BLUE32');
fImages.AddResourceName(HINSTANCE, 'BULLET_GREEN32');
fImages.AddResourceName(HINSTANCE, 'BULLET_ORANGE32');
fImages.AddResourceName(HINSTANCE, 'BULLET_PINK32');
fImages.AddResourceName(HINSTANCE, 'BULLET_PURPLE32');
fImages.AddResourceName(HINSTANCE, 'BULLET_RED32');
fImages.AddResourceName(HINSTANCE, 'BULLET_YELLOW32');
fImages.AddResourceName(HINSTANCE, 'WARNING32');
fImages.AddResourceName(HINSTANCE, 'EXCLAMATION32');
AssignPng(TreeFilterEdit1.Glyph, 'FILTER_CLEAR32');
end;
end;
Tree.Images := fImages;
TreeFilterEdit1.BorderSpacing.Left:= ScaleX(30,96);
fOptions := TSymbolListOptions.Create(self);
fOptions.Name:= 'symbolListOptions';
fname := getDocPath + 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];
Tree.OnDblClick := @TreeDblClick;
Tree.PopupMenu := contextMenu;
timedUpdateKind := tukDelay;
EntitiesConnector.addObserver(self);
end;
destructor TSymbolListWidget.destroy;
begin
EntitiesConnector.removeObserver(self);
fSyms.Free;
fOptions.saveToFile(getDocPath + OptsFname);
fOptions.Free;
inherited;
end;
procedure TSymbolListWidget.SetVisible(value: boolean);
begin
inherited;
getMessageDisplay(fMsgs);
if value then
getSymbols;
end;
procedure TSymbolListWidget.setToolBarFlat(value: boolean);
begin
inherited setToolbarFlat(value);
TreeFilterEdit1.Flat:=value;
end;
{$ENDREGION}
{$REGION IContextualActions---------------------------------------------------}
function TSymbolListWidget.contextName: string;
begin
result := 'Static explorer';
end;
function TSymbolListWidget.contextActionCount: integer;
begin
result := 6;
end;
function TSymbolListWidget.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 TSymbolListWidget.actRefreshExecute(Sender: TObject);
begin
if Updating then
exit;
getSymbols;
end;
procedure TSymbolListWidget.actAutoRefreshExecute(Sender: TObject);
begin
autoRefresh := fActAutoRefresh.Checked;
//fOptions.Assign(self);
end;
procedure TSymbolListWidget.actRefreshOnChangeExecute(Sender: TObject);
begin
refreshOnChange := fActRefreshOnChange.Checked;
fOptions.Assign(self);
end;
procedure TSymbolListWidget.actRefreshOnFocusExecute(Sender: TObject);
begin
refreshOnFocus := fActRefreshOnFocus.Checked;
fOptions.Assign(self);
end;
procedure TSymbolListWidget.actCopyIdentExecute(Sender: TObject);
begin
if Tree.Selected.isNotNil then
Clipboard.AsText:= Tree.Selected.Text;
end;
{$ENDREGION}
{$REGION IEditableOptions ----------------------------------------------------}
function TSymbolListWidget.optionedWantCategory(): string;
begin
exit('Symbol list');
end;
function TSymbolListWidget.optionedWantEditorKind: TOptionEditorKind;
begin
exit(oekGeneric);
end;
function TSymbolListWidget.optionedWantContainer: TPersistent;
begin
fOptions.Assign(self);
exit(fOptions);
end;
procedure TSymbolListWidget.optionedEvent(event: TOptionEditorEvent);
begin
if event <> oeeAccept then
exit;
fOptions.AssignTo(self);
getSymbols;
end;
function TSymbolListWidget.optionedOptionsModified: boolean;
begin
exit(false);
end;
{$ENDREGION}
{$REGION IDocumentObserver ---------------------------------------------------}
procedure TSymbolListWidget.docNew(document: TDexedMemo);
begin
fDoc := document;
beginDelayedUpdate;
end;
procedure TSymbolListWidget.docClosing(document: TDexedMemo);
begin
if fDoc <> document then
exit;
fDoc := nil;
clearTree;
updateVisibleCat;
end;
procedure TSymbolListWidget.docFocused(document: TDexedMemo);
begin
if fDoc = document then
exit;
fDoc := document;
TreeFilterEdit1.Text:='';
if not Visible then
exit;
if fAutoRefresh then
beginDelayedUpdate
else if fRefreshOnFocus then
getSymbols;
end;
procedure TSymbolListWidget.docChanged(document: TDexedMemo);
begin
if (fDoc <> document) or not Visible then
exit;
if fAutoRefresh then
beginDelayedUpdate
else if fRefreshOnChange then
getSymbols;
if fSmartExpander then
smartExpand;
end;
{$ENDREGION}
{$REGION Symbol-tree things ----------------------------------------------------}
procedure TSymbolListWidget.updateDelayed;
begin
if not fAutoRefresh then
exit;
getSymbols;
end;
procedure TSymbolListWidget.btnRefreshClick(Sender: TObject);
begin
fActRefresh.Execute;
end;
procedure TSymbolListWidget.toolbarResize(Sender: TObject);
begin
TreeFilterEdit1.Width := toolbar.Width - TreeFilterEdit1.Left - TreeFilterEdit1.BorderSpacing.Around;
end;
procedure TSymbolListWidget.TreeCompare(Sender: TObject; Node1,
Node2: TTreeNode; var Compare: Integer);
begin
Compare := CompareStr(Node1.Text, Node2.text);
end;
procedure TSymbolListWidget.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 TSymbolListWidget.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 TSymbolListWidget.TreeFilterEdit1AfterFilter(Sender: TObject);
begin
if TreeFilterEdit1.Filter.isEmpty then
updateVisibleCat;
end;
function TSymbolListWidget.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 TSymbolListWidget.TreeFilterEdit1MouseEnter(Sender: TObject);
begin
if not fSmartFilter then
exit;
tree.Selected := nil;
end;
procedure TSymbolListWidget.TreeKeyPress(Sender: TObject; var Key: char);
begin
if Key = #13 then
TreeDblClick(nil);
end;
procedure TSymbolListWidget.TreeDblClick(Sender: TObject);
var
line: PtrUInt;
begin
if fDoc.isNil or Tree.Selected.isNil or Tree.Selected.Data.isNil then
exit;
{$PUSH}{$WARNINGS OFF}{$HINTS OFF}
line := PtrUInt(Tree.Selected.Data);
{$POP}
fDoc.setFocus;
fDoc.CaretY := line;
fDoc.SelectLine;
end;
procedure TSymbolListWidget.getSymbols;
begin
if fLockThreadedParsing then
exit;
if fDoc.isNil then
exit;
if fDoc.Lines.Count.equals(0) or not fDoc.isDSource then
begin
clearTree;
updateVisibleCat;
exit;
end;
fSourcecodeForThread := fDoc.Lines.Text;
fLockThreadedParsing := true;
TTHread.ExecuteInThread(@threadedParsing, @threadedParsingFinished);
end;
procedure TSymbolListWidget.threadedParsing;
begin
fTreeDataFromThread := string(listSymbols(PChar(fSourcecodeForThread), fDeep));
end;
procedure TSymbolListWidget.threadedParsingFinished(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:=0; result.SelectedIndex:=0; end;
_union : begin result.ImageIndex:=1; result.SelectedIndex:=1; end;
_unittest : begin result.ImageIndex:=2; result.SelectedIndex:=2; end;
_variable : begin result.ImageIndex:=3; result.SelectedIndex:=3; end;
_warning : begin result.ImageIndex:=8; result.SelectedIndex:=8; end;
_error : begin result.ImageIndex:=9; result.SelectedIndex:=9; 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;
f: string;
n: TTreeNode;
begin
fLockThreadedParsing := false;
if fDoc.isNil then
exit;
if fTreeDataFromThread.isEmpty or ndAlias.isNil then
exit;
tree.BeginUpdate;
clearTree;
updateVisibleCat;
fSyms.LoadFromString(fTreeDataFromThread);
f := TreeFilterEdit1.Filter;
TreeFilterEdit1.Text := '';
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
begin
n := Tree.Items[i];
if n.Count > 0 then
n.CustomSort(nil);
end;
if fSmartExpander then
smartExpand;
if f.isNotEmpty then
TreeFilterEdit1.Text := f;
tree.EndUpdate;
minimizeGcHeap();
end;
procedure TSymbolListWidget.smartExpand;
var
i: integer;
n: TTreeNode;
target: PtrUInt;
nearest: PtrUInt = 0;
toExpand: TTreeNode = nil;
procedure look(root: TTreeNode);
var
i: integer;
j: PtrUInt;
begin
for i := 0 to root.Count-1 do
begin
n := root.Items[i];
if n.Data.isNil then
continue;
if n.Parent.isNil then
continue;
if (n.Parent = ndAlias)
or (n.Parent = ndEnum)
or (n.Parent = ndImp)
or (n.Parent = ndVar) then
continue;
{$PUSH}{$WARNINGS OFF}{$HINTS OFF}
j := PtrUint(n.Data);
{$POP}
if j > target then
continue;
if j > nearest then
begin
nearest := j;
toExpand := n;
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 --------------------------------------------------------------------}
end.