dexed/src/ce_staticexplorer.pas

230 lines
5.4 KiB
Plaintext

unit ce_staticexplorer;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, TreeFilterEdit, Forms, Controls, Graphics,
Dialogs, ExtCtrls, Menus, ComCtrls, ce_widget, jsonparser, fpjson,
ce_synmemo, process;
type
{ TCEStaticExplorerWidget }
TCEStaticExplorerWidget = class(TCEWidget)
imgList: TImageList;
Panel1: TPanel;
Tree: TTreeView;
TreeFilterEdit1: TTreeFilterEdit;
procedure TreeDeletion(Sender: TObject; Node: TTreeNode);
private
fDoc: TCESynMemo;
ndAlias, ndClass, ndEnum, ndFunc: TTreeNode;
ndImp, ndMix, ndStruct, ndTmp, ndVar: TTreeNode;
procedure Rescan;
procedure TreeDblClick(Sender: TObject);
protected
procedure UpdateByDelay; override;
public
constructor create(aOwner: TComponent); override;
//
procedure docNew(const aDoc: TCESynMemo); override;
procedure docFocused(const aDoc: TCESynMemo); override;
procedure docChanged(const aDoc: TCESynMemo); override;
procedure docClose(const aDoc: TCESynMemo); override;
end;
implementation
{$R *.lfm}
constructor TCEStaticExplorerWidget.create(aOwner: TComponent);
begin
inherited;
fID := 'ID_SEXPL';
//
ndAlias := Tree.Items[0];
ndClass := Tree.Items[1];
ndEnum := Tree.Items[2];
ndFunc := Tree.Items[3];
ndImp := Tree.Items[4];
ndMix := Tree.Items[5];
ndStruct := Tree.Items[6];
ndTmp := Tree.Items[7];
ndVar := Tree.Items[8];
//
Tree.OnDblClick := @TreeDblClick;
end;
procedure TCEStaticExplorerWidget.docNew(const aDoc: TCESynMemo);
begin
end;
procedure TCEStaticExplorerWidget.docFocused(const aDoc: TCESynMemo);
begin
fDoc := aDoc;
beginUpdateByDelay;
end;
procedure TCEStaticExplorerWidget.docChanged(const aDoc: TCESynMemo);
begin
if fDoc <> aDoc then exit;
beginUpdateByDelay;
end;
procedure TCEStaticExplorerWidget.docClose(const aDoc: TCESynMemo);
begin
if fDoc <> aDoc then exit;
fDoc := nil;
beginUpdateByDelay;
end;
procedure TCEStaticExplorerWidget.UpdateByDelay;
begin
Rescan;
end;
procedure TCEStaticExplorerWidget.TreeDeletion(Sender: TObject; Node: TTreeNode);
begin
if (node.Data <> nil) then
FreeMem(node.Data)
end;
procedure TCEStaticExplorerWidget.TreeDblClick(Sender: TObject);
var
line: Int64;
begin
if fDoc = nil then exit;
if Tree.Selected = nil then exit;
if Tree.Selected.Data = nil then exit;
//
line := PInt64(Tree.Selected.Data)^;
fDoc.CaretY := line;
fDoc.SelectLine();
end;
procedure TCEStaticExplorerWidget.Rescan;
var
dmdproc: TProcess;
lines: TStringList;
str: TMemoryStream;
prs: TJsonParser;
dat: TJsonData;
memb: TJsonData;
submemb: TJsonData;
jsf, scf: string;
ndCat: TTreeNode;
ln: PInt64;
nme: string;
i, j: NativeInt;
begin
if ndAlias = nil then exit;
ndAlias.DeleteChildren;
ndClass.DeleteChildren;
ndEnum.DeleteChildren;
ndFunc.DeleteChildren;
ndImp.DeleteChildren;
ndMix.DeleteChildren;
ndStruct.DeleteChildren;
ndTmp.DeleteChildren;
ndVar.DeleteChildren;
if fDoc = nil then exit;
if fDoc.Lines.Count = 0 then exit;
subMemb := nil;
memb := nil;
// generate json
dmdproc := TProcess.Create(nil);
lines := TStringList.Create;
try
jsf := GetTempDir(false);
jsf += format('%.8X.json',[NativeUint(@dmdproc)]);
scf := GetTempDir(false);
scf += format('%.8X.d',[NativeUint(@dmdproc)]);
//
lines.Assign(fDoc.Lines);
lines.SaveToFile(scf);
//
dmdProc.ShowWindow := swoHIDE;
dmdproc.Options := [];
dmdproc.Executable := 'dmd';
dmdproc.Parameters.Add(scf);
dmdproc.Parameters.Add('-c');
dmdproc.Parameters.Add('-o-');
dmdproc.Parameters.Add('-X');
dmdproc.Parameters.Add('-Xf' + jsf );
dmdproc.Execute;
while dmdproc.Running do;
finally
i := dmdproc.ExitStatus;
dmdproc.Free;
lines.Free;
DeleteFile(scf);
end;
if i <> 0 then
exit;
// load json
str := TMemoryStream.Create;
try
str.LoadFromFile(jsf);
str.Position := 0;
prs := TJsonParser.Create(str);
try
dat := prs.Parse;
finally
prs.Free;
end;
finally
str.Free;
DeleteFile(jsf);
end;
// update tree
memb := dat.items[0].FindPath('members');
if memb <> nil then for i := 0 to memb.Count-1 do
begin
// category
ln := new(PInt64);
ln^ := memb.Items[i].GetPath('line').AsInt64;
nme := memb.Items[i].GetPath('name').AsString;
case memb.Items[i].GetPath('kind').AsString of
'alias' :ndCat := Tree.Items.AddChildObject(ndAlias, nme, ln);
'class' :ndCat := Tree.Items.AddChildObject(ndClass, nme, ln);
'enum' :ndCat := Tree.Items.AddChildObject(ndEnum, nme, ln);
'function':ndCat := Tree.Items.AddChildObject(ndFunc, nme, ln);
'import' :ndCat := Tree.Items.AddChildObject(ndImp, nme, ln);
'mixin' :ndCat := Tree.Items.AddChildObject(ndMix, nme, ln);
'struct' :ndCat := Tree.Items.AddChildObject(ndStruct, nme, ln);
'template':ndCat := Tree.Items.AddChildObject(ndTmp, nme, ln);
'variable':ndCat := Tree.Items.AddChildObject(ndVar, nme, ln);
end;
// optional item members
submemb := memb.Items[i].FindPath('members');
if subMemb <> nil then for j := 0 to submemb.Count-1 do
begin
ln := new(PInt64);
ln^ := submemb.Items[j].GetPath('line').AsInt64;
nme := submemb.Items[j].GetPath('name').AsString;
Tree.Items.AddChildObject(ndCat, nme, ln);
end;
end;
if dat <> nil then
begin
dat.Clear;
dat.Free;
end;
end;
end.