diff --git a/lazproj/Gui.tease.png b/lazproj/Gui.tease.png index 34787a41..973549b8 100644 Binary files a/lazproj/Gui.tease.png and b/lazproj/Gui.tease.png differ diff --git a/lazproj/test/src/bar.d b/lazproj/test/src/bar.d index 197dde19..c748073c 100644 --- a/lazproj/test/src/bar.d +++ b/lazproj/test/src/bar.d @@ -1,4 +1,4 @@ -module barclass; +module bar; import std.stdio; diff --git a/lazproj/test/src/foo.d b/lazproj/test/src/foo.d index 59a6a07f..00e51d6a 100644 --- a/lazproj/test/src/foo.d +++ b/lazproj/test/src/foo.d @@ -1,4 +1,4 @@ -module fooclass; +module foo; import std.stdio; diff --git a/lazproj/test/src/main.d b/lazproj/test/src/main.d index 99c79c05..84c5701b 100644 --- a/lazproj/test/src/main.d +++ b/lazproj/test/src/main.d @@ -10,18 +10,18 @@ Test: module main; import std.stdio; -import fooclass; -import barclass; +import foo; +import bar; void main(string args[]) { - auto foo = new Foo; - auto bar = new Bar; + auto ffoo = new Foo; + auto bbar = new Bar; scope(exit) { - delete foo; - delete bar; + delete ffoo; + delete bbar; } readln; } diff --git a/src/ce_common.pas b/src/ce_common.pas index 546ac3f9..94740ac0 100644 --- a/src/ce_common.pas +++ b/src/ce_common.pas @@ -29,7 +29,7 @@ uses (** * Patches the directory separators from a string. - * This is used to ensure that a project saved on a plateform can be loaded + * This is used to ensure that a project saved on a platform can be loaded * on another one. *) function patchPlateformPath(const aPath: string): string; @@ -40,6 +40,11 @@ uses *) function dlgOkCancel(const aMsg: string): TModalResult; + (** + * Returns an unique object identifier, based on its heap address. + *) + function uniqueObjStr(const aObject: Tobject): string; + implementation @@ -237,4 +242,11 @@ begin exit( MessageDlg('Coedit', aMsg, mtConfirmation, Btns, '')); end; +function uniqueObjStr(const aObject: Tobject): string; +begin + {$HINTS OFF}{$WARNINGS OFF} + exit( format('%.8X',[NativeUint(@aObject)])); + {$HINTS ON}{$WARNINGS ON} +end; + end. diff --git a/src/ce_main.pas b/src/ce_main.pas index 8b42a54c..19fa510e 100644 --- a/src/ce_main.pas +++ b/src/ce_main.pas @@ -238,9 +238,9 @@ begin DockMaster.HeaderStyle := adhsPoints; DockMaster.ManualDock(DockMaster.GetAnchorSite(fEditWidg), Self, alBottom); DockMaster.ManualDock(DockMaster.GetAnchorSite(fMesgWidg), Self, alBottom); + DockMaster.ManualDock(DockMaster.GetAnchorSite(fStExpWidg), Self, alLeft); width := width - fProjWidg.Width; DockMaster.ManualDock(DockMaster.GetAnchorSite(fProjWidg), Self, alRight); - DockMaster.GetAnchorSite(fEditWidg).Header.HeaderPosition := adlhpTop; end; @@ -691,7 +691,7 @@ begin temppath := GetTempDir(false); chDir(temppath); {$IFDEF DEBUG}{$WARNINGS OFF}{$HINTS OFF}{$ENDIF} - fname := temppath + format('temp_%.8x', [NativeUInt(@dmdproc)]); + fname := temppath + 'temp_' + uniqueObjStr(dmdProc); {$IFDEF DEBUG}{$WARNINGS ON}{$HINTS ON}{$ENDIF} fEditWidg.editor[edIndex].Lines.SaveToFile(fname + '.d'); diff --git a/src/ce_messages.lfm b/src/ce_messages.lfm index 30d376c8..32f63cdf 100644 --- a/src/ce_messages.lfm +++ b/src/ce_messages.lfm @@ -16,6 +16,7 @@ inherited CEMessagesWidget: TCEMessagesWidget Width = 744 ClientHeight = 172 ClientWidth = 744 + PopupMenu = nil object List: TListView[0] Left = 2 Height = 168 diff --git a/src/ce_messages.pas b/src/ce_messages.pas index 2881ff9e..4f4bbf16 100644 --- a/src/ce_messages.pas +++ b/src/ce_messages.pas @@ -52,12 +52,7 @@ uses ce_main; constructor TCEMessagesWidget.create(aOwner: TComponent); -var - itm: TMenuItem; begin - inherited; - fID := 'ID_MSGS'; - // fActClear := TAction.Create(self); fActClear.OnExecute := @actClearExecute; fActClear.caption := 'Clear messages'; @@ -71,19 +66,10 @@ begin fActSaveMsg.OnExecute := @actSaveMsgExecute; fActSaveMsg.caption := 'Save messages to...'; // + inherited; + fID := 'ID_MSGS'; + // List.PopupMenu := contextMenu; - itm := TMenuItem.Create(self); - itm.Action := fActClear; - contextMenu.Items.Add(itm); - itm := TMenuItem.Create(self); - itm.Action := fActCopyMsg; - contextMenu.Items.Add(itm); - itm := TMenuItem.Create(self); - itm.Action := fActSelAll; - contextMenu.Items.Add(itm); - itm := TMenuItem.Create(self); - itm.Action := fActSaveMsg; - contextMenu.Items.Add(itm); end; procedure TCEMessagesWidget.scrollToBack; diff --git a/src/ce_projinspect.lfm b/src/ce_projinspect.lfm index d36d7936..388df53c 100644 --- a/src/ce_projinspect.lfm +++ b/src/ce_projinspect.lfm @@ -18,6 +18,7 @@ inherited CEProjectInspectWidget: TCEProjectInspectWidget Width = 264 ClientHeight = 383 ClientWidth = 264 + PopupMenu = nil object Tree: TTreeView[0] Left = 2 Height = 353 @@ -29,11 +30,13 @@ inherited CEProjectInspectWidget: TCEProjectInspectWidget DefaultItemHeight = 18 Images = imgList ReadOnly = True + RightClickSelect = True ScrollBars = ssAutoBoth ShowRoot = False TabOrder = 0 OnKeyDown = TreeKeyDown - Options = [tvoAutoExpand, tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoToolTips, tvoThemedDraw] + OnSelectionChanged = TreeSelectionChanged + Options = [tvoAutoExpand, tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoRightClickSelect, tvoShowButtons, tvoShowLines, tvoToolTips, tvoThemedDraw] Items.Data = { F9FFFFFF020002000000000000000000000000000000FFFFFFFF000000000000 0000000C000000536F757263652066696C6573010000000100000001000000FF diff --git a/src/ce_projinspect.pas b/src/ce_projinspect.pas index 08214fe3..31ae9f65 100644 --- a/src/ce_projinspect.pas +++ b/src/ce_projinspect.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, FileUtil, TreeFilterEdit, Forms, Controls, Graphics, - Dialogs, ExtCtrls, ComCtrls, Menus, Buttons, ce_project, ce_widget; + actnlist, Dialogs, ExtCtrls, ComCtrls, Menus, Buttons, ce_project, ce_widget; type { TCEProjectInspectWidget } @@ -24,18 +24,27 @@ type procedure btnRemFileClick(Sender: TObject); procedure FormDropFiles(Sender: TObject; const FileNames: array of String); procedure TreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure TreeSelectionChanged(Sender: TObject); protected procedure UpdateByEvent; override; private + fActOpenFile: TAction; + fActSelConf: TAction; fProject: TCEProject; fFileNode, fConfNode: TTreeNode; + procedure actUpdate(sender: TObject); procedure TreeDblClick(sender: TObject); + procedure actOpenFileExecute(sender: TObject); public constructor create(aOwner: TComponent); override; // procedure projNew(const aProject: TCEProject); override; procedure projChange(const aProject: TCEProject); override; procedure projClose(const aProject: TCEProject); override; + // + function contextName: string; override; + function contextActionCount: integer; override; + function contextAction(index: integer): TAction; override; end; implementation @@ -46,11 +55,40 @@ uses constructor TCEProjectInspectWidget.create(aOwner: TComponent); begin + fActOpenFile := TAction.Create(self); + fActOpenFile.Caption := 'Open file in editor'; + fActOpenFile.OnExecute := @actOpenFileExecute; + fActSelConf := TAction.Create(self); + fActSelConf.Caption := 'Select configuration'; + fActSelConf.OnExecute := @actOpenFileExecute; + fActSelConf.OnUpdate := @actUpdate; + // inherited; fID := 'ID_PROJ'; Tree.OnDblClick := @TreeDblClick; fFileNode := Tree.Items[0]; fConfNode := Tree.Items[1]; + // + Tree.PopupMenu := contextMenu; +end; + +function TCEProjectInspectWidget.contextName: string; +begin + exit('Inspector'); +end; + +function TCEProjectInspectWidget.contextActionCount: integer; +begin + exit(2); +end; + +function TCEProjectInspectWidget.contextAction(index: integer): TAction; +begin + case index of + 0: exit(fActOpenFile); + 1: exit(fActSelConf); + else exit(nil); + end; end; procedure TCEProjectInspectWidget.projNew(const aProject: TCEProject); @@ -76,6 +114,11 @@ begin if Key = 13 then TreeDblClick(nil); end; +procedure TCEProjectInspectWidget.TreeSelectionChanged(Sender: TObject); +begin + actUpdate(sender); +end; + procedure TCEProjectInspectWidget.TreeDblClick(sender: TObject); var fname: string; @@ -103,6 +146,20 @@ begin end; end; +procedure TCEProjectInspectWidget.actOpenFileExecute(sender: TObject); +begin + TreeDblClick(sender); +end; + +procedure TCEProjectInspectWidget.actUpdate(sender: TObject); +begin + fActSelConf.Enabled := false; + fActOpenFile.Enabled := false; + if Tree.Selected = nil then exit; + fActSelConf.Enabled := Tree.Selected.Parent = fConfNode; + fActOpenFile.Enabled := Tree.Selected.Parent = fFileNode; +end; + procedure TCEProjectInspectWidget.btnAddFileClick(Sender: TObject); begin if fProject = nil then exit; diff --git a/src/ce_staticexplorer.lfm b/src/ce_staticexplorer.lfm index 01f4db8b..51492770 100644 --- a/src/ce_staticexplorer.lfm +++ b/src/ce_staticexplorer.lfm @@ -16,6 +16,7 @@ inherited CEStaticExplorerWidget: TCEStaticExplorerWidget Width = 261 ClientHeight = 276 ClientWidth = 261 + PopupMenu = nil object Tree: TTreeView[0] Left = 4 Height = 240 @@ -28,11 +29,12 @@ inherited CEStaticExplorerWidget: TCEStaticExplorerWidget HideSelection = False Images = imgList ReadOnly = True + RowSelect = True ScrollBars = ssAutoBoth SelectionColor = clActiveBorder TabOrder = 0 OnDeletion = TreeDeletion - Options = [tvoAutoItemHeight, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] + Options = [tvoAutoItemHeight, tvoKeepCollapsedNodes, tvoReadOnly, tvoRowSelect, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] Items.Data = { F9FFFFFF020009000000000000000000000000000000FFFFFFFF000000000000 00000005000000416C6961730100000001000000FFFFFFFFFFFFFFFF00000000 @@ -59,6 +61,7 @@ inherited CEStaticExplorerWidget: TCEStaticExplorerWidget BevelOuter = bvNone ClientHeight = 26 ClientWidth = 257 + PopupMenu = contextMenu TabOrder = 1 object TreeFilterEdit1: TTreeFilterEdit Left = 2 diff --git a/src/ce_staticexplorer.pas b/src/ce_staticexplorer.pas index 6e9a98a1..cabb1d30 100644 --- a/src/ce_staticexplorer.pas +++ b/src/ce_staticexplorer.pas @@ -7,7 +7,7 @@ interface uses Classes, SysUtils, FileUtil, TreeFilterEdit, Forms, Controls, Graphics, Dialogs, ExtCtrls, Menus, ComCtrls, ce_widget, jsonparser, fpjson, - ce_synmemo, process; + ce_synmemo, process, actnlist, ce_common, ce_project; type @@ -19,13 +19,22 @@ type TreeFilterEdit1: TTreeFilterEdit; procedure TreeDeletion(Sender: TObject; Node: TTreeNode); private + fActRefresh: TAction; + fActAutoRefresh: TAction; + fActSelectInSource: TAction; fDoc: TCESynMemo; + fProj: TCEProject; + fAutoRefresh: boolean; ndAlias, ndClass, ndEnum, ndFunc: TTreeNode; ndImp, ndMix, ndStruct, ndTmp, ndVar: TTreeNode; procedure Rescan; procedure TreeDblClick(Sender: TObject); + procedure actRefreshExecute(Sender: TObject); + procedure actAutoRefreshExecute(Sender: TObject); protected procedure UpdateByDelay; override; + published + property autoRefresh: boolean read fAutoRefresh write fAutoRefresh; public constructor create(aOwner: TComponent); override; // @@ -33,6 +42,14 @@ type procedure docFocused(const aDoc: TCESynMemo); override; procedure docChanged(const aDoc: TCESynMemo); override; procedure docClose(const aDoc: TCESynMemo); override; + // + function contextName: string; override; + function contextActionCount: integer; override; + function contextAction(index: integer): TAction; override; + // + procedure projNew(const aProject: TCEProject); override; + procedure projChange(const aProject: TCEProject); override; + procedure projClose(const aProject: TCEProject); override; end; implementation @@ -40,6 +57,19 @@ implementation constructor TCEStaticExplorerWidget.create(aOwner: TComponent); begin + fAutoRefresh := true; + 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; + fActSelectInSource := TAction.Create(self); + fActSelectInSource.OnExecute := @TreeDblClick; + fActSelectInSource.Caption := 'Select in source'; + // inherited; fID := 'ID_SEXPL'; // @@ -54,6 +84,53 @@ begin ndVar := Tree.Items[8]; // Tree.OnDblClick := @TreeDblClick; + Tree.PopupMenu := contextMenu; +end; + +function TCEStaticExplorerWidget.contextName: string; +begin + result := 'Static explorer'; +end; + +function TCEStaticExplorerWidget.contextActionCount: integer; +begin + result := 3; +end; + +function TCEStaticExplorerWidget.contextAction(index: integer): TAction; +begin + case index of + 0: result := fActSelectInSource; + 1: result := fActRefresh; + 2: result := fActAutoRefresh; + else result := nil; + end; +end; + +procedure TCEStaticExplorerWidget.actRefreshExecute(Sender: TObject); +begin + if Updating then exit; + Rescan; +end; + +procedure TCEStaticExplorerWidget.actAutoRefreshExecute(Sender: TObject); +begin + AutoRefresh := not AutoRefresh; +end; + +procedure TCEStaticExplorerWidget.projNew(const aProject: TCEProject); +begin + fProj := aProject; +end; + +procedure TCEStaticExplorerWidget.projChange(const aProject: TCEProject); +begin + fProj := aProject; +end; + +procedure TCEStaticExplorerWidget.projClose(const aProject: TCEProject); +begin + fProj := nil; end; procedure TCEStaticExplorerWidget.docNew(const aDoc: TCESynMemo); @@ -81,6 +158,7 @@ end; procedure TCEStaticExplorerWidget.UpdateByDelay; begin + if not fAutoRefresh then exit; Rescan; end; @@ -136,13 +214,16 @@ begin memb := nil; // generate json + // note: only if + // - the imports can be found (either using the project infos or sc.conf) + // - the source is error-less dmdproc := TProcess.Create(nil); lines := TStringList.Create; try jsf := GetTempDir(false); - jsf += format('%.8X.json',[NativeUint(@dmdproc)]); + jsf += uniqueObjStr(dmdProc) + '.json'; scf := GetTempDir(false); - scf += format('%.8X.d',[NativeUint(@dmdproc)]); + scf += uniqueObjStr(dmdProc) + '.d'; // lines.Assign(fDoc.Lines); lines.SaveToFile(scf); @@ -154,7 +235,17 @@ begin dmdproc.Parameters.Add('-c'); dmdproc.Parameters.Add('-o-'); dmdproc.Parameters.Add('-X'); - dmdproc.Parameters.Add('-Xf' + jsf ); + dmdproc.Parameters.Add('-Xf' + jsf); + if fProj <> nil then + begin + dmdProc.CurrentDirectory := extractFilePath(fProj.fileName); + if fProj <> nil then for i := 0 to fProj.Sources.Count-1 do + dmdproc.Parameters.Add('-I' + fProj.getAbsoluteSourceName(i)); + for nme in fProj.Sources do + dmdproc.Parameters.Add('-I' + extractFilePath(nme)); + for nme in fProj.currentConfiguration.pathsOptions.Includes do + dmdproc.Parameters.Add('-I' + nme); + end; dmdproc.Execute; while dmdproc.Running do; finally @@ -184,44 +275,45 @@ begin 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 + try + memb := dat.items[0].FindPath('members'); + if memb <> nil then for i := 0 to memb.Count-1 do begin + + // category ln := new(PInt64); - ln^ := submemb.Items[j].GetPath('line').AsInt64; - nme := submemb.Items[j].GetPath('name').AsString; - Tree.Items.AddChildObject(ndCat, nme, ln); + 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; + finally + if dat <> nil then + begin + dat.Clear; + dat.Free; end; - - end; - - - if dat <> nil then - begin - dat.Clear; - dat.Free; end; end; diff --git a/src/ce_widget.lfm b/src/ce_widget.lfm index eb1d964e..548c271a 100644 --- a/src/ce_widget.lfm +++ b/src/ce_widget.lfm @@ -28,6 +28,7 @@ object CEWidget: TCEWidget Width = 332 Align = alClient BevelOuter = bvNone + PopupMenu = contextMenu TabOrder = 0 end end diff --git a/src/ce_widget.pas b/src/ce_widget.pas index aaadf8e2..9882ecbc 100644 --- a/src/ce_widget.pas +++ b/src/ce_widget.pas @@ -56,7 +56,7 @@ type // decrements the update count and call 'UpdateByEvent' if the // counter value is null. procedure endUpdateByEvent; - // immediate call the 'UpdateByEvent' + // immediate call 'UpdateByEvent' procedure forceUpdateByEvent; // procedure docNew(const aDoc: TCESynMemo); virtual; @@ -103,6 +103,9 @@ implementation * TCEWidget *) constructor TCEWidget.create(aOwner: TComponent); +var + i: NativeInt; + itm: TmenuItem; begin inherited; fID := 'ID_XXXX'; @@ -117,6 +120,15 @@ begin DockMaster.MakeDockable(Self, true, true, true); DockMaster.GetAnchorSite(Self).Header.HeaderPosition := adlhpTop; + + for i := 0 to contextActionCount-1 do + begin + itm := TMenuItem.Create(self); + itm.Action := contextAction(i); + contextMenu.Items.Add(itm); + end; + + PopupMenu := contextMenu; end; destructor TCEWidget.destroy; diff --git a/src/ce_widgettypes.pas b/src/ce_widgettypes.pas index 2f9284ea..610c63ce 100644 --- a/src/ce_widgettypes.pas +++ b/src/ce_widgettypes.pas @@ -20,7 +20,7 @@ type end; (** - * An implementer adds some menu actions when its context is valid. + * An implementer declares some actions on demand. *) ICEContextualActions = interface function contextName: string;