From f48fc903c5da50ff51b165175f71af3b76abaef1 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Sun, 27 Jul 2014 08:59:29 +0200 Subject: [PATCH] r25 --- RevisionLog.txt | 9 +- lazproj/PluginApi/CoeditPlugApi.d | 140 +++++++++ lazproj/PluginApi/DTemplate/CoeditPlug.coedit | 39 +++ lazproj/PluginApi/DTemplate/CoeditPlug.d | 130 ++++++++ lazproj/coedit.lpi | 20 +- lazproj/coedit.lpr | 3 +- src/ce_common.pas | 1 + src/ce_libman.pas | 139 ++++++++ src/ce_libmaneditor.lfm | 296 ++++++++++++++++++ src/ce_libmaneditor.pas | 166 ++++++++++ src/ce_main.lfm | 4 +- src/ce_main.pas | 153 ++++++++- src/ce_miniexplorer.lfm | 4 +- src/ce_plugin.pas | 196 ++++++++++++ src/ce_project.pas | 29 +- src/ce_staticexplorer.pas | 25 +- src/ce_widgettypes.pas | 3 +- 17 files changed, 1329 insertions(+), 28 deletions(-) create mode 100644 lazproj/PluginApi/CoeditPlugApi.d create mode 100644 lazproj/PluginApi/DTemplate/CoeditPlug.coedit create mode 100644 lazproj/PluginApi/DTemplate/CoeditPlug.d create mode 100644 src/ce_libman.pas create mode 100644 src/ce_libmaneditor.lfm create mode 100644 src/ce_libmaneditor.pas create mode 100644 src/ce_plugin.pas diff --git a/RevisionLog.txt b/RevisionLog.txt index d10e1efb..91952211 100644 --- a/RevisionLog.txt +++ b/RevisionLog.txt @@ -1,13 +1,20 @@ Revision log. (single changes can be tracked with the GH commit messages) +r25: +- ce_plugin: added a plug-in API. D example. final goal is to use it to wrap D Completion Daemon and other D libs. +- ce_libman: library manager: additional sources and -I are automatically added to the options. +- ce_project: added a field, General options, for the libman aliases. An entry acts as a selector in the libman. +- ce_libmaneditor: created a widget for the libman. +- ce_staticexplorer: all the libman entries are added when generating the infos, which increases the success chance. + r24: - ce_messages: messages related to a project were not cleared when the project was closed. - ce_messages: obj files could be automatically opened in case of errors in 'compile & run'. - ce_messages: fix position in source code broken. - ce_dmdwrap: removed old project fields 'versionIdentifier' and 'debugIdentifier'. - ce_main: compile & run, compile, run: fixed some inaccuracies related to platform specific process options (poWaitOnExit under win). -- ce_main, option: possible startup crash fixed when invalid height or width. +- ce_main: option, possible startup crash fixed when invalid height or width. r23: - ce_messages: position in source code. diff --git a/lazproj/PluginApi/CoeditPlugApi.d b/lazproj/PluginApi/CoeditPlugApi.d new file mode 100644 index 00000000..894e7dc2 --- /dev/null +++ b/lazproj/PluginApi/CoeditPlugApi.d @@ -0,0 +1,140 @@ +module CoeditPlugApi; + + alias void* Host_t; + alias void* Plugin_t; + + // API version + immutable uint CE_PLG_API_VER = 0; + + /// When passed to the Coedit dispatcher, it shows a 'hello plugin' message. + immutable uint HELLO_PLUGIN = 0xFFFFFFFF; + +// Denotes the emiter and the message kind ------------------------------------- + + /// Coedit sends an event. + immutable uint HOST_EVENT = 0x10000000; + /// Coedit sends some data. + immutable uint HOST_DATA = 0x20000000; + /// The plug-in sends an event. + immutable uint PLUG_EVENT = 0x30000000; + /// The plug-in sends some data. + immutable uint PLUG_DATA = 0x40000000; + +// Denotes the message context ------------------------------------------------- + + /// the dispatcher call is related to the project(s) + immutable uint CTXT_PROJ = 0x01000000; + /// the dispatcher call is related to the document(s) + immutable uint CTXT_DOCS = 0x02000000; + /// the dispatcher call is related to the edition of a document. + immutable uint CTXT_EDIT = 0x03000000; + /// the dispatcher call is related to the Coedit 'Message Widget'. + immutable uint CTXT_MSGS = 0x04000000; + /// the dispatcher call is related to the Coedit dialogs. + immutable uint CTXT_DLGS = 0x05000000; + +// The events kinds ------------------------------------------------------------ + + /// somethings's just changed. + immutable uint EV_CHANGED = 0x00000001; + /// something's just been selected. + immutable uint EV_FOCUSED = 0x00000002; + /// something's just been closed. + immutable uint EV_CLOSED = 0x00000003; + /// something's just been created. + immutable uint EV_NEW = 0x00000004; + /// something gonna be compiled. + immutable uint EV_COMPILE = 0x00000005; + /// something gonna be executed. + immutable uint EV_RUN = 0x00000006; + +// The data kinds -------------------------------------------------------------- + + /// data1 is used to set/get a filename. data1 is a PChar. data0 represents an index. + immutable uint DT_FNAME = 0x00000001; + /// data0 represents a count. + immutable uint DT_COUNT = 0x00000002; + + /// data1 is used to set a message. data1 is a PChar. + immutable uint DT_ERR = 0x00000001; + /// ditto + immutable uint DT_INF = 0x00000002; + /// ditto + immutable uint DT_WARN = 0x00000003; + +// terminal opCodes (emiter + context + event/data kind) ----------------------- + + /// Coedit says that the project's just been modified. + immutable uint HOST_PROJ_CHANGED = HOST_EVENT + CTXT_PROJ + EV_CHANGED; + + /// opCode for asking for a document filename. data0 must be the document index. + immutable uint PLUG_WANT_DOC_NAME = PLUG_EVENT + CTXT_DOCS + DT_FNAME; + + /// opCode for getting a document filenmae. data1 is a PChar to the filename. + immutable uint HOST_GIVE_DOC_NAME = HOST_DATA + CTXT_DOCS + DT_FNAME; + + /// opCodes for displaying a message in a dialog box. + immutable uint PLUG_DLGS_ERR = PLUG_DATA + CTXT_DLGS + DT_ERR; + /// ditto. + immutable uint PLUG_DLGS_WARN = PLUG_DATA + CTXT_DLGS + DT_WARN; + /// ditto. + immutable uint PLUG_DLGS_INF = PLUG_DATA + CTXT_DLGS + DT_INF; + + /// opCodes for displaying a message in the 'Message Widget'. + immutable uint PLUG_MSGS_ERR = PLUG_DATA + CTXT_MSGS + DT_ERR; + /// ditto. + immutable uint PLUG_MSGS_WARN = PLUG_DATA + CTXT_MSGS + DT_WARN; + /// ditto. + immutable uint PLUG_MSGS_INF = PLUG_DATA + CTXT_MSGS + DT_INF; + +// host-side prototypes -------------------------------------------------------- + + /** + * A plugin asks for some information or it passes data here. + * Data1 and data2 are some pointers to a particular variable type. + * In the plugin hostCreatePlugProc, a the location of COedit dispatcher is passed + * to the plugin. + */ + extern(C) alias plugDispatchToHostProc = + void function(Plugin_t aPlugin, uint opCode, uint data0, void* data1, void* data2); + +// plugin-side prototypes------------------------------------------------------- + + /** + * Coedit initializes a plugin, the result is passed during the runtime as "aTarget". + * In the plugin implementation, it must be named 'createPlug'. + * If the result is null then the Plugin is not used at all. + * If the plugin is not warped in a class than the result must be set on something + * that can be pointed to (e.g: a global variable). + */ + extern(C) alias hostCreatePlugProc = + Plugin_t function (plugDispatchToHostProc aHost); + + /** + * Coedit closes and aTarget can be destroyed. + * In the plugin implementation, it must be named 'destroyPlug'. + */ + extern(C) alias hostDestroyPlugProc = + void function (Plugin_t aTarget); + + /** + * Coedit events and data are passed here. data1 and data2 can be casted according to opCode. + * In the plugin implementation, it must be named 'dispatchToPlug'. + */ + extern(C) alias hostDispatchToPlugProc = + void function(Plugin_t aPlugin, uint opCode, uint data0, void* data1, void* data2); + +// helpers --------------------------------------------------------------------- + +uint getEmiter(in uint opCode){ + return opCode & 0xF0000000; +} + +uint getContext(in uint opCode){ + return opCode & 0x0FF00000; +} + +uint getCommand(in uint opCode){ + return opCode & 0x000FFFFF; +} + diff --git a/lazproj/PluginApi/DTemplate/CoeditPlug.coedit b/lazproj/PluginApi/DTemplate/CoeditPlug.coedit new file mode 100644 index 00000000..4a01f61a --- /dev/null +++ b/lazproj/PluginApi/DTemplate/CoeditPlug.coedit @@ -0,0 +1,39 @@ +object CurrentProject: TCEProject + OptionsCollection = < + item + name = 'toPlugDir' + outputOptions.binaryKind = sharedlib + outputOptions.noBoundsCheck = False + outputOptions.boundsCheck = onAlways + outputOptions.optimizations = True + outputOptions.release = True + pathsOptions.outputFilename = '..\..\plugins\CoeditPlug.dll' + preBuildProcess.options = [] + preBuildProcess.showWindow = swoNone + postBuildProcess.options = [] + postBuildProcess.showWindow = swoNone + runOptions.options = [] + runOptions.showWindow = swoNone + end + item + name = 'abovePlugDir' + outputOptions.binaryKind = sharedlib + outputOptions.inlining = True + outputOptions.noBoundsCheck = False + outputOptions.boundsCheck = onAlways + outputOptions.optimizations = True + outputOptions.release = True + pathsOptions.outputFilename = '..\..\plugins\temp\CoeditPlug.dll' + preBuildProcess.options = [] + preBuildProcess.showWindow = swoNone + postBuildProcess.options = [] + postBuildProcess.showWindow = swoNone + runOptions.options = [] + runOptions.showWindow = swoNone + end> + Sources.Strings = ( + '..\CoeditPlugApi.d' + 'CoeditPlug.d' + ) + ConfigurationIndex = 1 +end diff --git a/lazproj/PluginApi/DTemplate/CoeditPlug.d b/lazproj/PluginApi/DTemplate/CoeditPlug.d new file mode 100644 index 00000000..fb60e7c2 --- /dev/null +++ b/lazproj/PluginApi/DTemplate/CoeditPlug.d @@ -0,0 +1,130 @@ +module CoeditPlug; + +/* +Under linux: + +Build: +1:dmd -c CoeditPlug.d ../CoeditPlugApi.d pathtoIZ/types.d -fPIC +(or with a coedit project, select outputKind : object (which is actually -c)) +2:dmd -ofCOeditPlug.so -shared -defaultlib=libphobos2.so + +Note about IZ: + +The GC will make the plugin crash if coeditPlug is not an izObject +because (?). However since izObjects have their own, G.C free, de/allocators +it just instanciates fine. +*/ + + +import std.stdio, std.string, std.conv; +import CoeditPlugApi; + +version(Posix) +{ +} +else +{ + import std.c.windows.windows; + import core.sys.windows.dll; +} + + import iz.types; + pragma( lib, "iz"); + +coeditPlug plugin; + +class coeditPlug :izObject +{ + protected + { + plugDispatchToHostProc fDispatcher; + Plugin_t asPlugin_t(){return cast(Plugin_t)this;} + } + public + { + this(plugDispatchToHostProc aDispatcher) + { + assert(aDispatcher, "the Coedit dispatcher is missing"); + fDispatcher = aDispatcher; + //fDispatcher(asPlugin_t, HELLO_PLUGIN, 0, null, null); + + auto msg = "simple Coedit plugin is created".toStringz; + fDispatcher(asPlugin_t, PLUG_MSGS_INF, 0, cast(void*)msg, null); + } + + void hostEvent(uint eventContext, uint eventKind) + { + auto msg = (to!string(eventContext) ~ " " ~ to!string(eventKind)).toStringz; + fDispatcher(asPlugin_t, PLUG_MSGS_INF, 0, cast(void*)msg, null); + } + + void hostData(uint dataContext, uint dataKind, uint data0, void* data1, void* data2) + { + } + } +} + + +extern(C) export +Plugin_t createPlug(plugDispatchToHostProc aHost) +{ + plugin = new coeditPlug(aHost); + return &plugin; +} + +extern(C) export +void destroyPlug(Plugin_t aPlug) +{ + delete plugin; +} + +extern(C) export +void dispatchToPlug(Plugin_t aPlugin, uint opCode, uint data0, void* data1, void* data2) +{ + assert(&plugin == aPlugin); + coeditPlug* plg = (cast(coeditPlug*) aPlugin); + + auto emit = opCode.getEmiter; + auto ctxt = opCode.getContext; + auto comd = opCode.getCommand; + + if (emit == HOST_EVENT) + plg.hostEvent(ctxt, comd); + else + plg.hostData(ctxt, comd, data0, data1, data2); +} + +version(Posix) +{ +} +else +{ + __gshared HINSTANCE g_hInst; + + extern (Windows) + BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) + { + switch (ulReason) + { + case DLL_PROCESS_ATTACH: + g_hInst = hInstance; + dll_process_attach( hInstance, true ); + break; + + case DLL_PROCESS_DETACH: + dll_process_detach( hInstance, true ); + break; + + case DLL_THREAD_ATTACH: + dll_thread_attach( true, true ); + break; + + case DLL_THREAD_DETACH: + dll_thread_detach( true, true ); + break; + + default: break; + } + return true; + } +} diff --git a/lazproj/coedit.lpi b/lazproj/coedit.lpi index 13b07423..45c93bb5 100644 --- a/lazproj/coedit.lpi +++ b/lazproj/coedit.lpi @@ -134,7 +134,7 @@ - + @@ -252,6 +252,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/lazproj/coedit.lpr b/lazproj/coedit.lpr index 3ed573ef..91797ab3 100644 --- a/lazproj/coedit.lpr +++ b/lazproj/coedit.lpr @@ -10,7 +10,8 @@ uses AnchorDocking, AnchorDockStorage, AnchorDockOptionsDlg, ce_widget, ce_dmdwrap, ce_common, ce_synmemo, ce_main, ce_messages, ce_editor, ce_projinspect, ce_projconf, jsonparser, ce_project, ce_widgettypes, - ce_staticexplorer, ce_search, ce_dlang, ce_dlangutils, ce_miniexplorer; + ce_staticexplorer, ce_search, ce_dlang, ce_dlangutils, ce_miniexplorer, + ce_plugin, ce_libman, ce_libmaneditor; {$R *.res} diff --git a/src/ce_common.pas b/src/ce_common.pas index 564d186a..c0011121 100644 --- a/src/ce_common.pas +++ b/src/ce_common.pas @@ -455,6 +455,7 @@ const {$ENDIF} begin {$IFDEF WINDOWS} + PIDL := nil; SHGetSpecialFolderLocation(0, CSIDL_APPDATA, PIDL); SHGetPathFromIDList(PIDL, Folder); result:=Folder; diff --git a/src/ce_libman.pas b/src/ce_libman.pas new file mode 100644 index 00000000..17a0c33b --- /dev/null +++ b/src/ce_libman.pas @@ -0,0 +1,139 @@ +unit ce_libman; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, ce_common; + +type + + (** + * Represents a D static library. In a project libAlias allows to + * resolve automatically the dependencies of a project. + *) + TLibraryItem = class(TCollectionItem) + private + fAlias: string; + fSourcePath: string; + fLibFile: string; + published + property libAlias: string read fAlias write fAlias; + property libSourcePath: string read fSourcePath write fSourcePath; + property libFile: string read fLibFile write fLibFile; + end; + + (** + * Represents all the D library present on this system. + *) + TLibraryManager = class(TComponent) + private + fCol: TCollection; + procedure setCol(const aValue: TCollection); + procedure readerPropNoFound(Reader: TReader; Instance: TPersistent; + var PropName: string; IsPath: boolean; var Handled, Skip: Boolean); + procedure readerError(Reader: TReader; const Message: string; + var Handled: Boolean); + published + property libraries: TCollection read fCol write setCol; + public + constructor create(aOwner: TComponent); override; + destructor destroy; override; + // + procedure getAdditionalSources(const someAliases, aList: TStrings); + procedure getAdditionalImport(const someAliases, aList: TStrings); + // + procedure loadFromFile(const aFilename: string); + procedure saveToFile(const aFilename: string); + end; + +implementation + +constructor TLibraryManager.create(aOwner: TComponent); +begin + inherited; + fCol := TCollection.Create(TLibraryItem); +end; + +destructor TLibraryManager.destroy; +begin + fCol.Free; + inherited; +end; + +procedure TLibraryManager.setCol(const aValue: TCollection); +begin + fCol.assign(aValue); +end; + +procedure TLibraryManager.getAdditionalSources(const someAliases, aList: TStrings); +var + itm: TCollectionItem; + itmt: TLibraryItem; + ext, src: string; + srcs: TStringList; +begin + for itm in fCol do + begin + itmt := TLibraryItem(itm); + if someAliases.IndexOf(itmt.libAlias) = -1 then continue; + // + srcs := TStringList.Create; + try + listFiles(srcs, itmt.libSourcePath, true); + for src in srcs do + begin + ext := extractFileExt(src); + if DExtList.IndexOf(ext) = -1 then continue; + if aList.IndexOf(src) <> -1 then continue; + aList.Add(src); + end; + finally + srcs.Free; + end; + end; +end; + +procedure TLibraryManager.getAdditionalImport(const someAliases, aList: TStrings); +var + itm: TCollectionItem; + itmt: TLibraryItem; +begin + for itm in fCol do + begin + itmt := TLibraryItem(itm); + if someAliases.IndexOf(itmt.libAlias) = -1 then continue; + // + if aList.IndexOf(itmt.libFile) <> -1 then continue; + aList.Add('-I'+ itmt.libFile); + end; +end; + +procedure TLibraryManager.readerPropNoFound(Reader: TReader; Instance: TPersistent; + var PropName: string; IsPath: boolean; var Handled, Skip: Boolean); +begin + Skip := true; + Handled := false; +end; + +procedure TLibraryManager.readerError(Reader: TReader; const Message: string; + var Handled: Boolean); +begin + Handled := true; +end; + +procedure TLibraryManager.loadFromFile(const aFilename: string); +begin + loadCompFromTxtFile(self, aFilename, @readerPropNoFound, @readerError); +end; + +procedure TLibraryManager.saveToFile(const aFilename: string); +begin + saveCompToTxtFile(self, aFilename); +end; + +initialization + registerClasses([TLibraryManager, TLibraryItem]); +end. + diff --git a/src/ce_libmaneditor.lfm b/src/ce_libmaneditor.lfm new file mode 100644 index 00000000..614d0c50 --- /dev/null +++ b/src/ce_libmaneditor.lfm @@ -0,0 +1,296 @@ +inherited CELibManEditorWidget: TCELibManEditorWidget + Left = 1355 + Height = 349 + Top = 210 + Width = 466 + Caption = 'Library manager' + ClientHeight = 349 + ClientWidth = 466 + inherited Back: TPanel + Height = 349 + Width = 466 + ClientHeight = 349 + ClientWidth = 466 + inherited Content: TPanel + Height = 349 + Width = 466 + ClientHeight = 349 + ClientWidth = 466 + object Panel1: TPanel[0] + Left = 4 + Height = 28 + Top = 4 + Width = 458 + Align = alTop + BorderSpacing.Around = 4 + BevelOuter = bvNone + ClientHeight = 28 + ClientWidth = 458 + TabOrder = 0 + object btnAddLib: TBitBtn + Left = 0 + Height = 28 + Hint = 'add library alias' + Top = 0 + Width = 28 + Align = alLeft + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000001E0000003300000033000000330000001E00000000000000240000 + 0033000000330000003300000033000000330000003300000033000000330000 + 0033008D56A9009E5FFF009D5DFF009E5EFF008C55AC0000001EAA783CC1B985 + 46FFB88546FFB88445FFB78445FFB78445FFB78445FFB98345FFC68244FF5293 + 54FF00A66BFF00BA86FF77DFC4FF00BA86FF00A66AFF008C55ACB88446FFEDB2 + 5AFFC79049FFEAB05DFFE8AB55FFE7AB55FFE7AB56FFEBAB55FFFCAB53FF009E + 60FF00C08DFF00BB82FFFFFFFFFF00BB82FF00C08CFF009E5EFFB78445FFEBB2 + 60FFC48D48FFE9B364FFE4A853FFE4A854FFE4A854FFE7A854FFFAA852FF009C + 5EFF73E5CCFFFFFFFFFFFFFFFFFFFFFFFFFF77E5CCFF009C5CFFB78345FFECB6 + 66FFC48C46FFEAB76EFFE3A752FFE3A854FFE3A854FFE6A854FFF8A852FF009C + 5FFF00CC98FF00C88FFFFFFFFFFF00C88FFF00CC98FF009D5DFFB78344FFEDB8 + 6AFFC38C45FFEBBC77FFE3A751FFE3A853FFE3A854FFE5A854FFF1A852FF5BA1 + 59FF00AE73FF00D39EFF74EDD4FF00D49EFF00AE72FF009F6097B78344FFEEBD + 72FFC38C45FFECC183FFE3A853FFE3A854FFE3A854FFE3A854FFE8A854FFF7A9 + 52FF5CA159FF009B5DFF009C5BFF009D5EFF009F609600A06200B78243FFF0C3 + 7EFFC38C45FFEFC98FFFE3AB56FFE2A952FFE2A850FFE2A74FFFE3A850FFE8A9 + 52FFF1AB55FFFFCB8FFFD47E3DFF00A3650000A2640000A16300B68242FFF2C8 + 89FFC38C47FFF1D09CFFE3AB57FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFE6AC57FFF7D29EFFBF7F3FFFD283420000A5680000A46600B68141FFF3CE + 93FFC38E48FFF2D7A8FFE3AF5BFFE1AA52FFE0A74CFFE0A74BFFE0A74CFFE1AA + 52FFE3B05CFFF4D9AAFFB7803FFFC1854400CA854500CE844400B68140FFF4D4 + 9DFFC48E48FFF4DCB3FFE4B05EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFE4B15EFFF6DEB5FFB67F3EFFBB854500BD874700BE874700B6813FFFF5D9 + A7FFC38E49FFF7E1BEFFE5B564FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFE5B564FFF9E4C1FFB57F3DFFBA854500BB874700BB874700B6813FFFF7DF + B1FFC48F4BFFF8E9CBFFE5BA6EFFE4B86AFFE4B767FFE4B667FFE4B767FFE4B8 + 6AFFE6BA6EFFFAECCDFFB57F3CFFBA854500BB874700BB874700B88241FFFCE8 + C0FFC69552FFFDF0D6FFFBEED3FFFBEDD2FFFBEDD2FFFBEDD2FFFBEDD2FFFBED + D2FFFCEED3FFFFF2D8FFB7813EFFBB864500BB874700BB874700B88241B2B882 + 41FFB78240FFB67F3DFFB57E3CFFB57E3BFFB57E3BFFB57E3BFFB57E3BFFB57E + 3BFFB57E3CFFB7803EFFB88241B2BB874700BB874700BB874700 + } + OnClick = btnAddLibClick + TabOrder = 0 + end + object btnRemLib: TBitBtn + Left = 28 + Height = 28 + Hint = 'remove library alias' + Top = 0 + Width = 28 + Align = alLeft + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000001E0000003300000033000000330000001E00000000000000240000 + 0033000000330000003300000033000000330000003300000033000000330000 + 00332B42BAA9374DCDFF384DCBFF384DCCFF3145B4AC0000001EAA783CC1B985 + 46FFB88546FFB88445FFB78445FFB78445FFB78445FFB88444FFC2893BFF7066 + 91FF324FDDFF375DFAFF375DFAFF385DF9FF3852D7FF3044B4ACB88446FFEDB2 + 5AFFC79049FFEAB05DFFE8AB55FFE7AB55FFE7AB56FFE9AD54FFF6B349FF2141 + DCFF3E63FFFF3B60FAFF3A5DF8FF3C60FAFF4165FBFF344BCCFFB78445FFEBB2 + 60FFC48D48FFE9B364FFE4A853FFE4A854FFE4A854FFE6AA52FFF4B147FF1F3F + D8FFA6B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFA9BAFFFF3148CAFFB78345FFECB6 + 66FFC48C46FFEAB76EFFE3A752FFE3A854FFE3A854FFE5A952FFF2B048FF1C3E + DCFF5776FFFF5675FFFF5473FDFF5776FEFF5D79FFFF334ACBFFB78344FFEDB8 + 6AFFC38C45FFEBBC77FFE3A751FFE3A853FFE3A854FFE5A852FFEDAD4CFF7B70 + 9BFF3757E7FF6A86FFFF718BFFFF6F89FFFF465EDDFF354CCD97B78344FFEEBD + 72FFC38C45FFECC183FFE3A853FFE3A854FFE3A854FFE3A954FFE6AA51FFF1B0 + 49FF7B719BFF1F3ED8FF2743D4FF2F48D0FF354CCE96374ECF00B78243FFF0C3 + 7EFFC38C45FFEFC98FFFE3AB56FFE2A952FFE2A850FFE2A74FFFE2A84FFFE6AB + 4FFFEDB04FFFFFD385FFCB8A2CFF2647DF00314CD500354ED200B68242FFF2C8 + 89FFC38C47FFF1D09CFFE3AB57FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFE5AC56FFF6D39CFFBC8339FFCB8D34002346E4002949DE00B68141FFF3CE + 93FFC38E48FFF2D7A8FFE3AF5BFFE1AA52FFE0A74CFFE0A74BFFE0A74CFFE1AA + 52FFE3B05CFFF4D9AAFFB7803EFFBF884100C68C3C00C88D3900B68140FFF4D4 + 9DFFC48E48FFF4DCB3FFE4B05EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFE4B15EFFF6DEB5FFB67F3EFFBB864500BD884500BD884500B6813FFFF5D9 + A7FFC38E49FFF7E1BEFFE5B564FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFE5B564FFF9E4C1FFB57F3DFFBA854500BB874700BB874700B6813FFFF7DF + B1FFC48F4BFFF8E9CBFFE5BA6EFFE4B86AFFE4B767FFE4B667FFE4B767FFE4B8 + 6AFFE6BA6EFFFAECCDFFB57F3CFFBA854500BB874700BB874700B88241FFFCE8 + C0FFC69552FFFDF0D6FFFBEED3FFFBEDD2FFFBEDD2FFFBEDD2FFFBEDD2FFFBED + D2FFFCEED3FFFFF2D8FFB7813EFFBB864500BB874700BB874700B88241B2B882 + 41FFB78240FFB67F3DFFB57E3CFFB57E3BFFB57E3BFFB57E3BFFB57E3BFFB57E + 3BFFB57E3CFFB7803EFFB88241B2BB874700BB874700BB874700 + } + OnClick = btnRemLibClick + TabOrder = 1 + end + object btnSelFile: TBitBtn + Left = 402 + Height = 28 + Hint = 'select the library file' + Top = 0 + Width = 28 + Align = alRight + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000000000000A0000 + 002A000000330000002A0000000A000000000000000000000000469AD300469A + D300469AD300449AD500399BE100CF9044000000001200000031674D2B59B586 + 4AD9C18F4FFFB6864AD9684D2B590000003100000012C2915200469AD3000000 + 000B0000000A0000000A00000008000000338C683879BC8B4CF8D5A263FFF7C0 + 82FFFFDDB3FFE6B77FFFC59356FFBC8B4BF88B683A7A000000330000002F2959 + 7A5F2655755C2553745A1C4C6F55CD8E42FFD8A262FFF4BE81FFF8C182FFF3BA + 79FFFBE1C1FFFBCF9BFFFFD6A5FFF3C690FFD8AA6FFFBD8C4CFF4598D0F14398 + D2FF4094D0FF3D92D1FF3395DDFFCA8B3FFFF4BD7DFFECB676FFE6B06FFFECBD + 84FFFDF0DEFFFFC890FFF6C892FFF7CC99FFFFD4A2FFD9A76FFF4499D2FF3F94 + D0FFABFBFFFF9AF4FFFF89F6FFFFC6863BFFE3AC6AFFE1B882FFEFE0C3FFDDD1 + B8FFE0D3B6FFE4E7D7FFEED2AAFFF4C693FFF1C591FFD7A56BFF4397D1FF56AC + DDFF8EDAF5FFA1EFFFFF7BECFFFFC98D47FFEDDDBDFFDFD0B3FFE0B380FFF0CC + A5FFFFDDB8FFFFD3A4FFEDD1ABFFE8EDDCFFF0E8CEFFD9A469FF4296D1FF71C4 + EAFF6CBCE6FFBBF3FFFF6FE3FFFFC0863EFFE4AF73FFFFECCFFFFFDBB0FFFFCA + 92FFD5A76EFFFFE9CEFFFFD9AFFFFFCB92FFEDBB80FFE5A663FF4095D0FF90DD + F8FF44A0D8FFDCFDFFFFD8FCFFFFD4FFFFFFCED1BFFFC7A169FFE8B178FFFFEB + CEFFFFDBB1FFFFCB92FFE0A768FFCD9E61FF8FABADFF2470A6683E93CFFFB2F6 + FFFF51ACDEFF358ACBFF348BCBFF338CCEFF328DD2FF52C2F6FF79C6D4FFCAA4 + 70FFE7AF70FFC79E65FF7BCBE0FF79E2FFFFA5E2FDFF378AC4C63D92CFFFB8F3 + FFFF77DFFEFF7BE0FEFF7CE1FFFF7CE1FFFF7DE2FFFF50ACE0FF51BBEFFFD1FB + FFFFCCF2FDFFCDF9FFFFD0F8FFFFD3F8FFFFDAFDFFFF3E94D1FF3C92CFFFC0F3 + FFFF70D9FBFF73DAFBFF74DAFBFF74DAFBFF74DBFBFF76DEFDFF4FAADDFF358C + CCFF338CCDFF328CCDFF328CCDFF3790CEFF3D94D0FF4398D2AE3B92CFFFCAF6 + FFFF69D5F9FF6CD5F9FF6AD4F9FF69D4F9FF69D5F9FF6AD6FAFF6BD8FBFF6BD9 + FCFF6BDAFDFF69DAFDFFDAFDFFFF3C93D0FF367BAA2F469AD3003B92CFFFD5F7 + FFFF60D1F9FF61D0F8FFB4EBFDFFD9F6FFFFDAF8FFFFDAF8FFFFDAF9FFFFDBF9 + FFFFDAF9FFFFDAFAFFFFDFFEFFFF3D94D0FF4599D335469AD3003D94D0FFDCFC + FFFFD8F7FFFFD8F7FFFFDBFAFFFF358ECDFF3991CEFF3A92CFFF3A92CFFF3A92 + CFFF3A92CFFF3A92CFFF3D94D0FF4298D2EA469AD300469AD3004398D2EF3D94 + D0FF3A92CFFF3A92CFFF3D94D0FF4197D1E44398D22B4498D2324498D2334498 + D2334498D2334499D2334499D337459AD300469AD300469AD300 + } + OnClick = btnSelFileClick + TabOrder = 2 + end + object btnSelRoot: TBitBtn + Left = 430 + Height = 28 + Hint = 'select the sources root' + Top = 0 + Width = 28 + Align = alRight + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000001E0000003300000033000000330000001E00000000469AD300469A + D300469AD300469AD300469AD300469AD300469AD300479AD5004D99DF000000 + 001E008C53AC009E5EFF009D5DFF009E5EFF008C55AC0000001E469AD3000000 + 000B0000000A0000000A0000000A0000000A0000000A0000000A00000008008D + 4BAA00A668FF00BA86FF77DFC4FF00BA86FF00A66AFF008C55AC0000002F2959 + 7A5F2655755C2655745C2655745C2655745C2655745C2653745A24486851009E + 52FF00C08AFF00BB82FFFFFFFFFF00BB82FF00C08CFF009E5EFF4598D0F14398 + D2FF4094D0FF3E92CFFF3E92CEFF3F92CEFF3F92CEFF4092D1FF4792DAFF009B + 4EFF75E5CAFFFFFFFFFFFFFFFFFFFFFFFFFF77E5CCFF009C5CFF4499D2FF3F94 + D0FFABFBFFFF9BF3FFFF92F1FFFF93F1FFFF93F1FFFF95F1FFFF9EF4FFFF0096 + 4AFF00CA93FF00C78EFFFFFFFFFF00C88FFF00CC97FF009D5CFF4397D1FF56AC + DDFF8EDAF5FFA2EDFFFF82E5FEFF84E5FEFF84E5FEFF86E6FFFF8DE9FFFF35BA + 9EFF00A965FF00D299FF74ECD1FF00D29AFF00AE6CFF009F56924296D1FF71C4 + EAFF6CBCE6FFBBF2FFFF75DEFDFF77DEFCFF78DEFCFF7CDFFDFF80E1FFFF89E4 + FFFF32B89EFF009549FF00954AFF00974BFF1F9E91FF000000124095D0FF90DD + F8FF44A0D8FFDDFCFFFFDAFAFFFFDBF9FFFFDEFAFFFF74DCFCFF76DBFBFF78DB + FEFF7CDDFFFF7FDFFFFF7FDFFFFFADECFFFF82C1EEFF3575A7703E93CFFFB2F6 + FFFF51ACDEFF358ACAFF358ACAFF358ACAFF368ACAFF5BBDE9FF6ED9FBFF6AD6 + FAFF69D5FBFF69D5FBFF68D5FCFF84DEFEFFABE1F8FF3A8AC1C83D92CFFFB8F3 + FFFF77DFFEFF7BE0FEFF7CE1FEFF7CE1FFFF7DE2FFFF52ABDDFF56B9E8FFDAF8 + FFFFD6F6FFFFD6F6FFFFD5F6FFFFD5F7FFFFDBFCFFFF3E94D0FF3C92CFFFC0F3 + FFFF70D9FBFF73DAFBFF74DAFBFF74DAFBFF74DBFBFF76DEFDFF4FA9DCFF368B + CAFF358BCBFF338BCBFF338CCCFF3790CEFF3D94D0FF4398D2AE3B92CFFFCAF6 + FFFF69D5F9FF6CD5F9FF6AD4F9FF69D4F9FF69D5F9FF6AD6FAFF6BD8FBFF6BD9 + FCFF6BDAFDFF69DAFDFFDAFDFFFF3C93D0FF367BAA2F469AD3003B92CFFFD5F7 + FFFF60D1F9FF61D0F8FFB4EBFDFFD9F6FFFFDAF8FFFFDAF8FFFFDAF9FFFFDBF9 + FFFFDAF9FFFFDAFAFFFFDFFEFFFF3D94D0FF4599D335469AD3003D94D0FFDCFC + FFFFD8F7FFFFD8F7FFFFDBFAFFFF358ECDFF3991CEFF3A92CFFF3A92CFFF3A92 + CFFF3A92CFFF3A92CFFF3D94D0FF4298D2EA469AD300469AD3004398D2EF3D94 + D0FF3A92CFFF3A92CFFF3D94D0FF4197D1E44398D22B4498D2324498D2334498 + D2334498D2334499D2334499D337459AD300469AD300469AD300 + } + OnClick = btnSelRootClick + TabOrder = 3 + end + object btnEditAlias: TBitBtn + Left = 374 + Height = 28 + Hint = 'edit the library alias' + Top = 0 + Width = 28 + Align = alRight + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF009461 + 3E9C94603DFF93603CFF153E54FF2A5F86FF4A87BBFF55819CFF836048FF8F5B + 37FF8F5A36FF8E5A35FF8E5935B1FFFFFF00FFFFFF00FFFFFF00FFFFFF009562 + 3FE1CCAB85FFD1AF89FF2E6683FF94C7F9FF91C9F9FF4185C9FF2467A8FFB09A + 86FFCB9F77FFC79971FF93613EFF4E3421A1FFFFFF00FFFFFF00FFFFFF009663 + 40E1CAA985FFA37854FF4389AAFFE0F2FFFF549AD8FF1A7ABEFF4998C5FF4283 + B6FFA8886BFFC99D75FF93623FFF553C28E1FFFFFF00FFFFFF00FFFFFF009664 + 41E1CBAC88FFA67E57FF868A80FF7AB6D5FF90B7D1FF55C9E4FF5BDFF5FF78D0 + EDFF4C93CFFFB79E85FF946240FF573E2AFFFFFFFF00FFFFFF00FFFFFF009765 + 43E1CEB08EFFAA855BFFCBA475FF909887FF75B7D3FFC2F6FDFF63DFF7FF5DE2 + F8FF79D3F0FF4896D8FF886854FF573E2AFFFFFFFF00FFFFFF00FFFFFF009866 + 44E1D0B492FFAF8B60FFCEA97CFFCCA677FF8F998BFF77CBE7FFC7F7FDFF5EDC + F5FF5AE1F7FF7BD4F1FF4693D4FF504E4EFFFFFFFF00FFFFFF00FFFFFF009967 + 45E1D2B796FFB49265FFD1AE83FFCFAB7FFFCDA87AFF9AA893FF79D3EEFFC7F7 + FDFF5FDCF5FF5BE2F7FF7AD6F2FF4291CFFF448DCD30FFFFFF00FFFFFF009968 + 46E1D5BB9BFFB89A69FFD4B38AFFD2AF87FFD0AD82FFCFAA7DFF9DAB96FF7DD4 + EDFFC4F6FDFF6CDDF6FF6DCAEDFF63A3D7FF5D9BD2EC5192CA26FFFFFF009A69 + 47E1D7BF9FFFBD9F6FFFD4B590FFCBAD88FFC7A881FFC6A57DFFC4A17AFF8FA8 + 9AFF80D4EBFFB2E3F9FF8BC0E7FFAED3F6FFC4E0FCFF669FD3F7FFFFFF009B6A + 48E1D9C2A4FFC1A472FFD2B894FFF5EDE4FFF4ECE2FFF4ECE1FFF4EBE0FFF3EA + DFFF8FAEA2FF77BEE7FFB4D2F0FFE5F3FFFFACD2EFFF488CC7E8FFFFFF009B6A + 49E1DBC5A6FFC6A776FFD9BF9BFFD1B793FFCBB08EFFCAAE8AFFC8AB87FFCBAB + 83FFD1B087FFA2B7B1FF58A5D8FF85B1DBFF469DD0FF2B95D15EFFFFFF009C6B + 4AE1DDC8A9FFD4BD95FFE6D4B9FFE6D1B6FFE4D0B5FFE3CEB3FFE2CBB0FFE0C9 + ADFFDFC7A9FFDABFA0FF9A6B4AFF573E2AFFFFFFFF00FFFFFF00FFFFFF009C6C + 4BE0D9C2A5FFB59170FFAB805FFFA97E5EFFA97E5EFFA87D5CFFA87C5BFFA77B + 5AFFA67959FF9C6B49FF966441FF573E2AFFFFFFFF00FFFFFF00FFFFFF009D6D + 4BCFBA9778FFD8C5B9FFE8DED7FFE7DDD6FFE6DCD6FFE4DBD4FFE3DAD3FFE2D8 + D1FFE1D7D0FFEBE7E5FFEFEFEFFF573E2AFFFFFFFF00FFFFFF00FFFFFF009D6D + 4C919D6D4BFEBB9778FFAC8262FFAC8161FFAB8060FFAB7F5FFFAA7F5EFFA87E + 5DFFA87C5CFF9D6D4CFF976643FF885C3CFFFFFFFF00FFFFFF00FFFFFF009E6E + 4D2B9D6D4CD69D6D4BC59D6C4BFF9C6C4AFF9C6B49FF9B6A49FF9B6A48FF9A69 + 47FF996846FF986745FF936443FF845D3EDEFFFFFF00FFFFFF00 + } + OnClick = btnEditAliasClick + TabOrder = 4 + end + end + object List: TListView[1] + Left = 4 + Height = 309 + Top = 36 + Width = 458 + Align = alClient + AutoWidthLastColumn = True + BorderSpacing.Around = 4 + Columns = < + item + Caption = 'Alias' + Width = 100 + end + item + Caption = 'Library file' + Width = 200 + end + item + Caption = 'Sources root' + Width = 154 + end> + GridLines = True + HideSelection = False + ReadOnly = True + RowSelect = True + TabOrder = 1 + ViewStyle = vsReport + OnEdited = ListEdited + end + end + end + inherited contextMenu: TPopupMenu + left = 184 + top = 8 + end +end diff --git a/src/ce_libmaneditor.pas b/src/ce_libmaneditor.pas new file mode 100644 index 00000000..ef6a2f82 --- /dev/null +++ b/src/ce_libmaneditor.pas @@ -0,0 +1,166 @@ +unit ce_libmaneditor; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, + Menus, ComCtrls, Buttons, ce_widget; + +type + + { TCELibManEditorWidget } + + TCELibManEditorWidget = class(TCEWidget) + btnSelFile: TBitBtn; + btnAddLib: TBitBtn; + btnRemLib: TBitBtn; + btnEditAlias: TBitBtn; + btnSelRoot: TBitBtn; + List: TListView; + Panel1: TPanel; + procedure btnAddLibClick(Sender: TObject); + procedure btnEditAliasClick(Sender: TObject); + procedure btnRemLibClick(Sender: TObject); + procedure btnSelFileClick(Sender: TObject); + procedure btnSelRootClick(Sender: TObject); + procedure ListEdited(Sender: TObject; Item: TListItem; var AValue: string); + private + procedure dataToGrid; + procedure gridToData; + protected + procedure DoShow; override; + end; + +implementation +{$R *.lfm} + +uses + ce_main, ce_libman; + +procedure TCELibManEditorWidget.ListEdited(Sender: TObject; Item: TListItem; + var AValue: string); +begin + GridToData; +end; + +procedure TCELibManEditorWidget.btnAddLibClick(Sender: TObject); +var + itm: TListItem; +const + notav: string = '< n/a >'; +begin + itm := List.Items.Add; + itm.Caption := notav; + itm.SubItems.Add(notav); + itm.SubItems.Add(notav); +end; + +procedure TCELibManEditorWidget.btnEditAliasClick(Sender: TObject); +var + al: string; +begin + if List.Selected = nil then exit; + al := List.Selected.Caption; + if inputQuery('library alias', '', al) then + List.Selected.Caption := al; + GridToData; +end; + +procedure TCELibManEditorWidget.btnRemLibClick(Sender: TObject); +begin + if List.Selected = nil then exit; + List.Items.Delete( List.Selected.Index ); + gridToData; +end; + +procedure TCELibManEditorWidget.btnSelFileClick(Sender: TObject); +var + ini: string; +begin + if List.Selected = nil then exit; + if List.Selected.SubItems.Count > 0 then + ini := List.Selected.SubItems[0] + else + begin + ini := ''; + List.Selected.SubItems.Add(ini); + end; + with TOpenDialog.Create(nil) do + try + filename := ini; + if execute then + List.Selected.SubItems[0] := filename; + finally + Free; + end; + GridToData; +end; + +procedure TCELibManEditorWidget.btnSelRootClick(Sender: TObject); +var + dir, outdir: string; +begin + if List.Selected = nil then exit; + if List.Selected.SubItems.Count > 1 then + dir := List.Selected.SubItems[1] + else + begin + dir := ''; + while List.Selected.SubItems.Count < 2 do + List.Selected.SubItems.Add(dir); + end; + if selectDirectory('sources root', dir, outdir, true, 0) then + List.Selected.SubItems[1] := outdir; + GridToData; +end; + +procedure TCELibManEditorWidget.DoShow; +begin + inherited; + dataToGrid; +end; + +procedure TCELibManEditorWidget.dataToGrid; +var + itm: TLibraryItem; + row: TListItem; + i: NativeInt; +begin + List.Clear; + with CEMainForm do + begin + if LibraryManager = nil then exit; + for i:= 0 to LibraryManager.libraries.Count-1 do + begin + itm := TLibraryItem( LibraryManager.libraries.Items[i]); + row := List.Items.Add; + row.Caption := itm.libAlias; + row.SubItems.Add(itm.libFile); + row.SubItems.Add(itm.libSourcePath); + end; + end; +end; + +procedure TCELibManEditorWidget.gridToData; +var + itmt: TLibraryItem; + row: TListItem; +begin + with CEMainForm do + begin + if LibraryManager = nil then exit; + LibraryManager.libraries.Clear; + for row in List.Items do + begin + itmt := TLibraryItem(LibraryManager.libraries.Add); + itmt.libAlias := row.Caption; + itmt.libFile := row.SubItems.Strings[0]; + itmt.libSourcePath := row.SubItems.Strings[1]; + end; + end; +end; + +end. + diff --git a/src/ce_main.lfm b/src/ce_main.lfm index 0fd3802d..17dde080 100644 --- a/src/ce_main.lfm +++ b/src/ce_main.lfm @@ -1,7 +1,7 @@ object CEMainForm: TCEMainForm - Left = 1071 + Left = 1064 Height = 49 - Top = 187 + Top = 186 Width = 745 AllowDropFiles = True Caption = 'Coedit' diff --git a/src/ce_main.pas b/src/ce_main.pas index fa69ad91..81840f57 100644 --- a/src/ce_main.pas +++ b/src/ce_main.pas @@ -8,13 +8,15 @@ uses Classes, SysUtils, FileUtil, SynEditKeyCmds, SynHighlighterLFM, Forms, AnchorDocking, AnchorDockStorage, AnchorDockOptionsDlg, Controls, Graphics, Dialogs, Menus, ActnList, ExtCtrls, process, XMLPropStorage, ComCtrls, - ce_common, ce_dmdwrap, ce_project, ce_synmemo, ce_widget, ce_messages, - ce_editor, ce_projinspect, ce_projconf, ce_staticexplorer, ce_search, ce_miniexplorer; + ce_common, ce_dmdwrap, ce_project, ce_plugin, ce_synmemo, ce_widget, ce_messages, + ce_widgettypes, ce_editor, ce_projinspect, ce_projconf, ce_staticexplorer, ce_search, + ce_miniexplorer, dynlibs, ce_libman, ce_libmaneditor; type TCEMainForm = class; + //TODO-cfeature: switches -f, -p, -noplug //TODO-cfeature: options //TODO-cwidget: options editor (** @@ -197,6 +199,7 @@ type private fUpdateCount: NativeInt; fProject: TCEProject; + fPlugList: TCEPlugDescriptorList; fWidgList: TCEWidgetList; fMesgWidg: TCEMessagesWidget; fEditWidg: TCEEditorWidget; @@ -205,16 +208,21 @@ type fStExpWidg: TCEStaticExplorerWidget; fFindWidg: TCESearchWidget; fExplWidg: TCEMiniExplorerWidget; + fLibMWidg: TCELibManEditorWidget; fProjMru: TMruFileList; fFileMru: TMruFileList; + fLibMan: TLibraryManager; //Init - Fina + procedure InitLibMan; procedure InitMRUs; procedure InitWidgets; + procedure InitPlugins; procedure InitDocking; procedure InitSettings; procedure SaveSettings; procedure SaveDocking; + procedure KillPlugs; // widget interfaces subroutines procedure checkWidgetActions(const aWidget: TCEWidget); @@ -263,8 +271,11 @@ type property EditWidget: TCEEditorWidget read fEditWidg; property ProjectWidget: TCEProjectInspectWidget read fProjWidg; property ProjectConfWidget: TCEProjectConfigurationWidget read fPrjCfWidg; + property LibraryManager: TLibraryManager read fLibMan; end; + procedure PlugDispatchToHost(aPlugin: TCEPlugin; opCode: LongWord; data0: Integer; data1, data2: Pointer); cdecl; + var CEMainForm: TCEMainForm; @@ -279,11 +290,23 @@ constructor TCEMainForm.create(aOwner: TComponent); begin inherited create(aOwner); InitMRUs; + InitLibMan; InitWidgets; InitDocking; InitSettings; // newProj; + InitPlugins; +end; + +procedure TCEMainForm.InitLibMan; +var + fname: string; +begin + fLibMan := TLibraryManager.create(self); + fname := getDocPath + 'libraryManager.txt'; + if fileExists(fname) then + fLibMan.loadFromFile(fname); end; procedure TCEMainForm.InitMRUs; @@ -296,6 +319,49 @@ begin fFileMru.OnChange := @mruChange; end; +procedure TCEMainForm.InitPlugins; +var + pth: string; + fname: string; + lst: TStringList; + hdl: TLibHandle; + plg: PPlugDescriptor; +begin + fPlugList := TCEPlugDescriptorList.Create; + pth := extractFilePath(application.ExeName) + 'plugins'; + lst := TStringList.Create; + try + listFiles(lst, pth, false); + for fname in lst do + begin + if extractFileExt(fname) <> '.' + SharedSuffix then + continue; + hdl := LoadLibrary(fname); + if hdl = NilHandle then + continue; + + plg := new(PPlugDescriptor); + plg^.Handle := hdl; + plg^.HostCreatePlug := THostCreatePlug(GetProcAddress(hdl, 'createPlug')); + plg^.HostDestroyPlug := THostDestroyPlug(GetProcAddress(hdl, 'destroyPlug')); + plg^.HostDispatchToPlug := THostDispatchToPlug(GetProcAddress(hdl, 'dispatchToPlug')); + if plg^.HostCreatePlug <> nil then + plg^.Plugin := plg^.HostCreatePlug(@PlugDispatchToHost); + + if (plg^.HostCreatePlug = nil) or (plg^.HostDestroyPlug = nil) or + (plg^.HostDispatchToPlug = nil) then + begin + Dispose(plg); + //FreeLibrary(hdl); + continue; + end; + fPlugList.addPlugin(plg); + end; + finally + lst.Free; + end; +end; + procedure TCEMainForm.InitWidgets; var widg: TCEWidget; @@ -310,6 +376,7 @@ begin fStExpWidg:= TCEStaticExplorerWidget.create(self); fFindWidg := TCESearchWidget.create(self); fExplWidg := TCEMiniExplorerWidget.create(self); + fLibMWidg := TCELibManEditorWidget.create(self); fWidgList.addWidget(@fMesgWidg); fWidgList.addWidget(@fEditWidg); @@ -318,6 +385,7 @@ begin fWidgList.addWidget(@fStExpWidg); fWidgList.addWidget(@fFindWidg); fWidgList.addWidget(@fExplWidg); + fWidgList.addWidget(@fLibMWidg); for widg in fWidgList do begin @@ -350,7 +418,7 @@ begin end; Height := 0; - for i := 0 to fWidgList.Count-1 do + for i := 0 to fWidgList.Count-1 do begin DockMaster.MakeDockable(fWidgList.widget[i],true); DockMaster.GetAnchorSite(fWidgList.widget[i]).Header.HeaderPosition := adlhpTop; @@ -368,6 +436,7 @@ begin DockMaster.GetAnchorSite(fEditWidg).Header.HeaderPosition := adlhpTop; DockMaster.GetAnchorSite(fExplWidg).Close; + DockMaster.GetAnchorSite(fLibMWidg).Close; end; procedure TCEMainForm.InitSettings; @@ -386,9 +455,9 @@ begin if opts.hasLoaded then begin if fileExists(fname2) then - deleteFile(fname2); + sysutils.deleteFile(fname2); if not fileExists(fname2) then - copyFile(fname1, fname2, false); + fileutil.copyFile(fname1, fname2, false); end; end; finally @@ -403,6 +472,7 @@ begin opts := TCEOptions.create(nil); try forceDirectory(getDocPath); + fLibMan.saveToFile(getDocPath + 'libraryManager.txt'); opts.saveToFile(getDocPath + 'options.txt'); finally opts.Free; @@ -416,18 +486,40 @@ begin xcfg := TXMLConfigStorage.Create(getDocPath + 'docking.xml',false); try // is always missing - DockMaster.SaveLayoutToConfig(xcfg); - xcfg.WriteToDisk; + //DockMaster.SaveLayoutToConfig(xcfg); + //xcfg.WriteToDisk; finally xcfg.Free; end; end; +procedure TCEMainForm.KillPlugs; +var + descr: TPlugDescriptor; +begin + if fPlugList = nil then exit; + for descr in fPlugList do + begin + descr.HostDestroyPlug(descr.Plugin); + {$IFDEF WINDOWS} + //FreeLibrary(descr.Handle); + {$ENDIF} + end; + while fPlugList.Count <> 0 do + begin + Dispose(PPlugDescriptor(fPlugList.Items[fPlugList.Count-1])); + fPlugList.Delete(fPlugList.Count-1); + end; + fPlugList.Free; +end; + destructor TCEMainForm.destroy; begin SaveSettings; SaveDocking; // + KillPlugs; + // fWidgList.Free; fProjMru.Free; fFileMru.Free; @@ -1015,11 +1107,11 @@ begin runproc.Execute; repeat ProcessOutputToMsg(runproc, mcEditor) until not runproc.Running; {$IFDEF MSWINDOWS} - DeleteFile(fname + '.exe'); - DeleteFile(fname + '.obj'); + sysutils.DeleteFile(fname + '.exe'); + sysutils.DeleteFile(fname + '.obj'); {$ELSE} - DeleteFile(fname); - DeleteFile(fname + '.o'); + sysutils.DeleteFile(fname); + sysutils.DeleteFile(fname + '.o'); {$ENDIF} end else begin @@ -1031,7 +1123,7 @@ begin dmdproc.Free; runproc.Free; if extractFilePath(editor.fileName) = GetTempDir(false) then - DeleteFile(editor.fileName); + sysutils.DeleteFile(editor.fileName); chDir(olddir); end; end; @@ -1051,7 +1143,7 @@ begin if aProject.Sources.Count = 0 then begin - fMesgWidg.addCeErr( aProject.fileName + ' has no source files', mcProject); + fMesgWidg.addCeWarn('the project has no source files', mcProject); exit; end; @@ -1295,6 +1387,7 @@ begin fProject.Name := 'CurrentProject'; for widg in WidgetList do widg.projNew(fProject); fProject.onChange := @projChange; + fProject.libraryManager := fLibMan; end; procedure TCEMainForm.saveProj; @@ -1549,6 +1642,40 @@ begin end; {$ENDREGION} +procedure PlugDispatchToHost(aPlugin: TCEPlugin; opCode: LongWord; data0: Integer; data1, data2: Pointer); cdecl; +var + ctxt: NativeUint; + oper: NativeUint; +begin + + if opCode = HELLO_PLUGIN then begin + dlgOkInfo('Hello plugin'); + exit; + end; + + ctxt := opCode and $0F000000; + oper := opCode and $000FFFFF; + + case ctxt of + CTXT_MSGS: + case oper of + DT_ERR: CEMainForm.MessageWidget.addCeErr(PChar(data1)); + DT_INF: CEMainForm.MessageWidget.addCeInf(PChar(data1)); + DT_WARN: CEMainForm.MessageWidget.addCeWarn(PChar(data1)); + else CEMainForm.MessageWidget.addCeWarn('unsupported dispatcher opCode'); + end; + CTXT_DLGS: + case oper of + DT_ERR: dlgOkError(PChar(data1)); + DT_INF: dlgOkInfo(PChar(data1)); + DT_WARN: dlgOkInfo(PChar(data1)); + else CEMainForm.MessageWidget.addCeWarn('unsupported dispatcher opCode'); + end; + else CEMainForm.MessageWidget.addCeWarn('unsupported dispatcher opCode'); + end; + +end; + initialization RegisterClasses([TCEOptions]); end. diff --git a/src/ce_miniexplorer.lfm b/src/ce_miniexplorer.lfm index b64da99f..89797ea5 100644 --- a/src/ce_miniexplorer.lfm +++ b/src/ce_miniexplorer.lfm @@ -1,7 +1,7 @@ inherited CEMiniExplorerWidget: TCEMiniExplorerWidget - Left = 1539 + Left = 1493 Height = 651 - Top = 6 + Top = 45 Caption = 'Mini explorer' ClientHeight = 651 inherited Back: TPanel diff --git a/src/ce_plugin.pas b/src/ce_plugin.pas new file mode 100644 index 00000000..864cec0a --- /dev/null +++ b/src/ce_plugin.pas @@ -0,0 +1,196 @@ +unit ce_plugin; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, dynlibs; + +type + + TCEHost = type Pointer; + TCEPlugin = type Pointer; +const + + // API version + CE_PLG_API_VER = 0; + +// opcodes constants -------------------------------------------------------------] + + HELLO_PLUGIN = $FFFFFFFF; // hello world + +// Denotes the emiter and the message kind ------------------------------------- + + /// Coedit sends an event. + HOST_EVENT = $10000000; + /// Coedit sends some data. + HOST_DATA = $20000000; + /// The plug-in sends an event. + PLUG_EVENT = $30000000; + /// The plug-in sends some data. + PLUG_DATA = $40000000; + +// Denotes the message context ------------------------------------------------- + + /// the dispatcher call is related to the project(s) + CTXT_PROJ = $01000000; + /// the dispatcher call is related to the document(s) + CTXT_DOCS = $02000000; + /// the dispatcher call is related to the edition of a document. + CTXT_EDIT = $03000000; + /// the dispatcher call is related to the Coedit 'Message Widget'. + CTXT_MSGS = $04000000; + /// the dispatcher call is related to the Coedit dialogs. + CTXT_DLGS = $05000000; + +// The events kinds ------------------------------------------------------------ + + /// somethings's just changed. + EV_CHANGED = $00000001; + /// something's just been selected. + EV_FOCUSED = $00000002; + /// something's just been closed. + EV_CLOSED = $00000003; + /// something's just been created. + EV_NEW = $00000004; + /// something gonna be compiled. + EV_COMPILE = $00000005; + /// something gonna be executed. + EV_RUN = $00000006; + +// The data kinds -------------------------------------------------------------- + + /// data1 is used to set/get a filename. data1 is a PChar. data0 represents an index. + DT_FNAME = $00000001; + /// data0 represents a count. + DT_COUNT = $00000002; + + /// data1 is used to set a message. data1 is a PChar. + DT_ERR = $00000001; + DT_INF = $00000002; + DT_WARN = $00000003; + + DATA_FNAME = $00000001; + +// terminal opCodes (emiter + context + event/data kind) ----------------------- + + /// Coedit says that the project's just been modified. + HOST_PROJ_CHANGED = HOST_EVENT + CTXT_PROJ + EV_CHANGED; + + /// opCode for asking for a document filename. data0 must be the document index. + PLUG_WANT_DOC_NAME = PLUG_EVENT + CTXT_DOCS + DT_FNAME; + + /// opCode for getting a document filenmae. data1 is a PChar to the filename. + HOST_GIVE_DOC_NAME = HOST_DATA + CTXT_DOCS + DT_FNAME; + + /// opCodes for displaying a message in a dialog box. + PLUG_DLGS_ERR = PLUG_DATA + CTXT_DLGS + DT_ERR; + /// ditto. + PLUG_DLGS_WARN = PLUG_DATA + CTXT_DLGS + DT_WARN; + /// ditto. + PLUG_DLGS_INF = PLUG_DATA + CTXT_DLGS + DT_INF; + + /// opCodes for displaying a message in the 'Message Widget'. + PLUG_MSGS_ERR = PLUG_DATA + CTXT_MSGS + DT_ERR; + /// ditto. + PLUG_MSGS_WARN = PLUG_DATA + CTXT_MSGS + DT_WARN; + /// ditto. + PLUG_MSGS_INF = PLUG_DATA + CTXT_MSGS + DT_INF; + +// host-side prototypes -------------------------------------------------------- +type + + (** + * A plugin asks for some information or it passes data here. + * Data1 and data2 are some pointers to a particular variable type. + * In the plugin hostCreatePlugProc, a the location of COedit dispatcher is passed + * to the plugin. + *) + TPlugDispatchToHost = procedure(aPlugin: TCEPlugin; opCode: LongWord; data0: Integer; data1, data2: Pointer); cdecl; + +// plugin-side prototypes ------------------------------------------------------ + + (** + * Coedit initializes a plugin, the result is passed during the runtime as "aTarget". + * In the plugin implementation, it must be named 'createPlug'. + * If the result is null then the Plugin is not used at all. + * If the plugin is not warped in a class than the result must be set on something + * that can be pointed to (e.g: a global variable). + *) + THostCreatePlug = function(aHost: TPlugDispatchToHost): TCEPlugin; cdecl; + + (** + * Coedit closes and aTarget can be destroyed. + * In the plugin implementation, it must be named 'destroyPlug'. + *) + THostDestroyPlug = procedure(aTarget: TCEPlugin); cdecl; + + (** + * Coedit events and data are passed here. data1 and data2 can be casted according to opCode. + * In the plugin implementation, it must be named 'dispatchToPlug'. + *) + THostDispatchToPlug = procedure(aTarget: TCEPlugin; data0: Integer; opCode: LongWord; data1, data2: Pointer); cdecl; + + + +// internal -------------------------------------------------------------------- + + PPlugDescriptor = ^TPlugDescriptor; + TPlugDescriptor = record + Handle: TLibHandle; + Plugin: TCEPlugin; + HostCreatePlug: THostCreatePlug; + HostDestroyPlug: THostDestroyPlug; + HostDispatchToPlug: THostDispatchToPlug; + end; + + TCEPlugDescriptorList = class(TList) + private + function getPlugin(index: integer): TPlugDescriptor; + public + procedure addPlugin(aValue: PPlugDescriptor); + property plugin[index: integer]: TPlugDescriptor read getPlugin; + end; + TPlugDescriptorEnumerator = class + fList: TCEPlugDescriptorList; + fIndex: Integer; + function getCurrent: TPlugDescriptor; + Function moveNext: boolean; + property current: TPlugDescriptor read getCurrent; + end; + + operator enumerator(aPlugDescrList: TCEPlugDescriptorList): TPlugDescriptorEnumerator; + +implementation + +function TCEPlugDescriptorList.getPlugin(index: integer): TPlugDescriptor; +begin + result := TPlugDescriptor(Items[index]^); +end; + +procedure TCEPlugDescriptorList.addPlugin(aValue: PPlugDescriptor); +begin + add(Pointer(aValue)); +end; + +function TPlugDescriptorEnumerator.getCurrent: TPlugDescriptor; +begin + result := fList.plugin[fIndex]; +end; + +function TPlugDescriptorEnumerator.moveNext: boolean; +begin + Inc(fIndex); + result := fIndex < fList.Count; +end; + +operator enumerator(aPlugDescrList: TCEPlugDescriptorList): TPlugDescriptorEnumerator; +begin + result := TPlugDescriptorEnumerator.Create; + result.fList := aPlugDescrList; + result.fIndex := -1; +end; + +end. + diff --git a/src/ce_project.pas b/src/ce_project.pas index b224a0f8..0f8f7e67 100644 --- a/src/ce_project.pas +++ b/src/ce_project.pas @@ -7,7 +7,7 @@ interface // TODO: configuration templates uses - Classes, SysUtils, ce_dmdwrap; + Classes, SysUtils, ce_dmdwrap, ce_libman; type @@ -25,11 +25,14 @@ type fModified: boolean; fFilename: string; fBasePath: string; + fLibAliases: TStringList; fOptsColl: TCollection; fSrcs, fSrcsCop: TStringList; fConfIx: Integer; + fLibMan: TLibraryManager; fChangedCount: NativeInt; procedure doChanged; + procedure setLibAliases(const aValue: TStringList); procedure subMemberChanged(sender : TObject); procedure setOptsColl(const aValue: TCollection); procedure setFname(const aValue: string); @@ -45,6 +48,7 @@ type property OptionsCollection: TCollection read fOptsColl write setOptsColl; property Sources: TStringList read fSrcs write setSrcs; // 'read' should return a copy to avoid abs/rel errors property ConfigurationIndex: Integer read fConfIx write setConfIx; + property LibraryAliases: TStringList read fLibAliases write setLibAliases; public constructor create(aOwner: TComponent); override; destructor destroy; override; @@ -59,6 +63,7 @@ type procedure saveToFile(const aFilename: string); procedure loadFromFile(const aFilename: string); // + property libraryManager: TLibraryManager read fLibMan write fLibMan; property configuration[ix: integer]: TCompilerConfiguration read getConfig; property currentConfiguration: TCompilerConfiguration read getCurrConf; property fileName: string read fFilename write setFname; @@ -74,6 +79,7 @@ uses constructor TCEProject.create(aOwner: TComponent); begin inherited create(aOwner); + fLibAliases := TStringList.Create; fSrcs := TStringList.Create; fSrcs.OnChange := @subMemberChanged; fSrcsCop := TStringList.Create; @@ -85,6 +91,7 @@ end; destructor TCEProject.destroy; begin fOnChange := nil; + fLibAliases.Free; fSrcs.free; fSrcsCop.Free; fOptsColl.free; @@ -141,6 +148,13 @@ begin afterChanged; end; +procedure TCEProject.setLibAliases(const aValue: TStringList); +begin + beforeChanged; + fLibAliases.Assign(aValue); + afterChanged; +end; + procedure TCEProject.setSrcs(const aValue: TStringList); begin beforeChanged; @@ -242,6 +256,13 @@ begin abs := expandFilenameEx(fBasePath,rel); aList.Add(abs); // process.inc ln 249. double quotes are added if there's a space. end; + // + if fLibMan <> nil then + begin + fLibMan.getAdditionalSources(fLibAliases, aList); + fLibMan.getAdditionalImport(fLibAliases, aList); + end; + // TCompilerConfiguration(fOptsColl.Items[fConfIx]).getOpts(aList); end; @@ -274,9 +295,9 @@ end; procedure TCEProject.readerPropNoFound(Reader: TReader; Instance: TPersistent; var PropName: string; IsPath: boolean; var Handled, Skip: Boolean); -var - idt: string; - curr: TCompilerConfiguration; +//var + //idt: string; + //curr: TCompilerConfiguration; begin // continue loading: this method ensures the project compat. in case of drastic changes. diff --git a/src/ce_staticexplorer.pas b/src/ce_staticexplorer.pas index 2a03eaa1..c4055522 100644 --- a/src/ce_staticexplorer.pas +++ b/src/ce_staticexplorer.pas @@ -74,7 +74,7 @@ type implementation {$R *.lfm} -uses ce_main; +uses ce_main, ce_libman; {$REGION Standard Comp/Obj------------------------------------------------------} constructor TCEStaticExplorerWidget.create(aOwner: TComponent); @@ -323,6 +323,9 @@ var ln: PInt64; nme, knd: string; i: NativeInt; + itm: TCollectionItem; + itmt: TLibraryItem; + allALiases: TStringList; // recursively display members, without master categories. procedure digMembers(const srcDt: TJsonData; const srcNd: TTreeNode); @@ -378,7 +381,7 @@ begin // lines.Assign(fDoc.Lines); lines.SaveToFile(scf); - // + // option to gen. the Json file. dmdProc.ShowWindow := swoHIDE; dmdproc.Options := []; dmdproc.Executable := 'dmd'; @@ -387,6 +390,7 @@ begin dmdproc.Parameters.Add('-o-'); dmdproc.Parameters.Add('-X'); dmdproc.Parameters.Add('-Xf' + jsf); + // projects add.sources and I. if fProj <> nil then begin dmdProc.CurrentDirectory := extractFilePath(fProj.fileName); @@ -395,6 +399,23 @@ begin for nme in fProj.currentConfiguration.pathsOptions.Includes do dmdproc.Parameters.Add('-I' + nme); end; + // add. sources and I from libman. + with CEMainForm do + begin + allALiases := TstringList.Create; + try + for itm in Librarymanager.libraries do + begin + itmt := TLibraryItem(itm); + allALiases.Add(itmt.libAlias); + end; + Librarymanager.getAdditionalSources(allALiases,dmdproc.Parameters); + Librarymanager.getAdditionalImport(allALiases,dmdproc.Parameters); + finally + allALiases.Free; + end; + end; + // dmdproc.Execute; while dmdproc.Running do; finally diff --git a/src/ce_widgettypes.pas b/src/ce_widgettypes.pas index 6da99f5a..61c4a5a8 100644 --- a/src/ce_widgettypes.pas +++ b/src/ce_widgettypes.pas @@ -9,8 +9,6 @@ uses type - // TODO-cfeature: document content access/modification - (** * An implementer can save and load some stuffs on application start/quit *) @@ -69,5 +67,6 @@ type end; implementation + end.