mirror of https://gitlab.com/basile.b/dexed.git
934 lines
26 KiB
Plaintext
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.
|