This commit is contained in:
Basile Burg 2014-06-22 02:12:22 +02:00
parent c38d76d1b1
commit ca50a3a51c
18 changed files with 533 additions and 360 deletions

View File

@ -3,34 +3,42 @@ Coedit
Coedit is a simple IDE for the [D2](http://dlang.org) lang. (**Co** mpile & **Edit**).
Initial features (planed)
-------------------------
- targets Win/Macos/Linux
Current features
----------------
- multi platform (Win/Linux/Macos).
- projects.
- multiple project configurations (set of switches and options).
- project configurations templates (release, debug, etc.).
- D syntax highlighter, folding.
- compile, run directly from UI.
- compile, run directly from the UI.
- instant run (without saving, script-like).
- basic auto completion (brackets, key-words, ...)
- synchronized edition in a block.
- D syntax highlighter, folding, identifier markup.
Planed in version 1
-------------------
- project configurations templates (release, debug, etc.).
- basic auto completion (brackets, key-words, ...).
- console input handling.
- static library explorer (using JSON infos).
Project information
-------------------
- draft
- programmed in Object pascal.
- [Lazarus](http://www.lazarus.freepascal.org) is used as IDE.
- based on dmd (gdc or lmd characteristics are not hanlded).
- no other third party dependencies (so far...)
- state: alpha 1.
- programmed in Object pascal with [Lazarus](http://www.lazarus.freepascal.org).
- based on *dmd* (*gdc* or *lmd* characteristics are not handled).
- no other third party dependencies (so far...but using *dscanner* and/or *dcd* is envisaged.)
Setup
-----
- clone this repo.
Setup & test
------------
Coedit must be build from the sources:
- clone this repository (even if not mandatory, preferably from the latest tag, as tagged versions are more tested then the others.)
- both [dmd](http://dlang.org/download.html) and [Lazarus](http://www.lazarus.freepascal.org) must be setup.
- open "coedit.lpr" in Lazarus.
- press the Run button.
- open "coedit.lpr" in *Lazarus*, set the build mode to *Release*
- press the Run button (or build)
- in coedit open *"lazproj\test\coeditproj\test.coedit"* from the project menu.
Preview
-------
![Interface screen-cap, under Windows](lazproj/Gui.tease.png "Coedit GUI preview")
Windows version:
![Win screen-cap](lazproj/Gui.tease.png "Coedit GUI preview")
Linux version:
![Nux screen-cap](lazproj/Gui.tease.kde.png "Coedit GUI preview")

BIN
lazproj/Gui.tease.kde.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

View File

@ -126,7 +126,7 @@
<PackageName Value="LCL"/>
</Item5>
</RequiredPackages>
<Units Count="12">
<Units Count="14">
<Unit0>
<Filename Value="coedit.lpr"/>
<IsPartOfProject Value="True"/>
@ -205,6 +205,16 @@
<IsPartOfProject Value="True"/>
<UnitName Value="ce_jsoninfos"/>
</Unit11>
<Unit12>
<Filename Value="..\src\ce_project.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ce_project"/>
</Unit12>
<Unit13>
<Filename Value="..\src\ce_widgettypes.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ce_widgettypes"/>
</Unit13>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

@ -8,7 +8,8 @@ uses
{$ENDIF}{$ENDIF}
Interfaces, Forms, lazcontrols, runtimetypeinfocontrols, ce_widget,
ce_dmdwrap, ce_common, ce_synmemo, ce_main, ce_messages, ce_editor,
ce_projinspect, ce_projconf, ce_jsoninfos, jsonparser;
ce_projinspect, ce_projconf, ce_jsoninfos, jsonparser, ce_project,
ce_widgettypes;
{$R *.res}

View File

@ -1,4 +1,4 @@
object TCEProject
object _1: TCEProject
OptionsCollection = <
item
name = 'default'
@ -54,7 +54,7 @@ object TCEProject
outputOptions.release = False
outputOptions.unittest = True
outputOptions.versionIdentifier = 'revision_1'
pathsOptions.outputFilename = '..\output\main.exe'
pathsOptions.outputFilename = '..\output\main.exe'
end>
Sources.Strings = (
'..\src\main.d'

View File

@ -5,92 +5,39 @@ unit ce_common;
interface
uses
Classes, SysUtils, ce_dmdwrap, ActnList;
type
TCEProject = class;
Classes, SysUtils, ActnList;
(**
* An implementer is informed when a new document is added, focused or closed.
* Save a component with a readable aspect.
*)
ICEMultiDocMonitor = interface
procedure docChange(const aNewIndex: integer);
procedure docClose(const aNewIndex: integer);
end;
(**
* An implementer adds some menu actions when its context is valid.
*)
ICEContextualActions = interface
function contextName: string;
function contextActionCount: integer;
function contextAction(index: integer): TAction;
end;
(**
* An implementer is informed when a project changes.
*)
ICEProjectMonitor = interface
procedure projNew(const aProject: TCEProject);
procedure projChange(const aProject: TCEProject);
procedure projClose(const aProject: TCEProject);
end;
(*****************************************************************************
* Writable project.
*)
TCEProject = class(TComponent)
private
fOnChange: TNotifyEvent;
fModified: boolean;
fFilename: string;
fBasePath: string;
fOptsColl: TCollection;
fSrcs, fSrcsCop: TStringList;
fConfIx: Integer;
fChangedCount: NativeInt;
procedure doChanged;
procedure subMemberChanged(sender : TObject);
procedure setOptsColl(const aValue: TCollection);
procedure setFname(const aValue: string);
procedure setSrcs(const aValue: TStringList);
procedure setConfIx(aValue: Integer);
function getConfig(const ix: integer): TCompilerConfiguration;
function getSrcs: TStringList;
function getCurrConf: TCompilerConfiguration;
published
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;
public
constructor create(aOwner: TComponent); override;
destructor destroy; override;
procedure beforeChanged;
procedure afterChanged;
procedure reset;
function getAbsoluteSourceName(const aIndex: integer): string;
function getAbsoluteFilename(const aFilename: string): string;
procedure addSource(const aFilename: string);
function addConfiguration: TCompilerConfiguration;
procedure getOpts(const aList: TStrings);
//
property configuration[ix: integer]: TCompilerConfiguration read getConfig;
property currentConfiguration: TCompilerConfiguration read getCurrConf;
property fileName: string read fFilename write setFname;
property onChange: TNotifyEvent read fOnChange write fOnChange;
end;
procedure saveCompToTxtFile(const aComp: TComponent; const aFilename: string);
(**
* Load a component.
*)
procedure loadCompFromTxtFile(const aComp: TComponent; const aFilename: string);
(**
* Converts a relative path to an absolute path.
*)
function expandFilenameEx(const aBasePath, aFilename: string): string;
(**
* Extracts the module name of a D source file.
*)
function getModuleName(const aSource: TStrings): string;
(**
* Patches the directory separators from a string.
* This is used to ensure a that project saved on a plateform can be loaded
* on another one.
*)
function patchPlateformPath(const aPath: string): string;
procedure patchPlateformPaths(const sPaths: TStrings);
implementation
(*****************************************************************************
* Routines
*)
procedure saveCompToTxtFile(const aComp: TComponent; const aFilename: string);
var
str1, str2: TMemoryStream;
@ -144,6 +91,87 @@ begin
end;
end;
function patchPlateformPath(const aPath: string): string;
var
i: Integer;
begin
result := aPath;
{$IFDEF MSWINDOWS}
i := pos('/',result);
if i <> 0 then
begin
repeat
result[i] := directorySeparator;
i := pos('/',result);
until
i = 0;
end;
i := pos(':',result);
if i <> 0 then
begin
repeat
result[i] := directorySeparator;
i := pos(':',result);
until
i = 0;
end;
{$ENDIF}
{$IFDEF LINUX}
i := pos('\',result);
if i <> 0 then
begin
repeat
result[i] := directorySeparator;
i := pos('\',result);
until
i = 0;
end;
i := pos(':',result);
if i <> 0 then
begin
repeat
result[i] := directorySeparator;
i := pos(':',result);
until
i = 0;
end;
{$ENDIF}
{$IFDEF MACOS}
i := pos('\',result);
if i <> 0 then
begin
repeat
result[i] := directorySeparator;
i := pos('\',result);
until
i = 0;
end;
i := pos('/',result);
if i <> 0 then
begin
repeat
result[i] := directorySeparator;
i := pos('/',result);
until
i = 0;
end;
{$ENDIF}
end;
procedure patchPlateformPaths(const sPaths: TStrings);
var
i: Integer;
str: string;
begin
for i:= 0 to sPaths.Count-1 do
begin
str := sPaths.Strings[i];
sPaths.Strings[i] := patchPlateformPath(str);
end;
end;
// TODO: block comments handling
function getModuleName(const aSource: TStrings): string;
var
@ -197,211 +225,4 @@ begin
end;
end;
(*****************************************************************************
* TProject
*)
constructor TCEProject.create(aOwner: TComponent);
begin
inherited create(aOwner);
fSrcs := TStringList.Create;
fSrcs.OnChange := @subMemberChanged;
fSrcsCop := TStringList.Create;
fOptsColl := TCollection.create(TCompilerConfiguration);
reset;
end;
destructor TCEProject.destroy;
begin
fOnChange := nil;
fSrcs.free;
fSrcsCop.Free;
fOptsColl.free;
inherited;
end;
function TCEProject.addConfiguration: TCompilerConfiguration;
begin
result := TCompilerConfiguration(fOptsColl.Add);
result.onChanged := @subMemberChanged;
end;
procedure TCEProject.setOptsColl(const aValue: TCollection);
var
i: nativeInt;
begin
fOptsColl.Assign(aValue);
for i:= 0 to self.fOptsColl.Count-1 do
Configuration[i].onChanged := @subMemberChanged;
end;
procedure TCEProject.addSource(const aFilename: string);
var
relSrc, absSrc: string;
begin
for relSrc in fSrcs do
begin
absSrc := expandFilenameEx(fBasePath,relsrc);
if aFilename = absSrc then exit;
end;
fSrcs.Add(ExtractRelativepath(fBasePath,aFilename));
end;
procedure TCEProject.setFname(const aValue: string);
var
oldAbs, newRel, oldBase: string;
i: NativeInt;
begin
if fFilename = aValue then exit;
//
beforeChanged;
fFilename := aValue;
oldBase := fBasePath;
fBasePath := extractFilePath(fFilename);
//
for i:= 0 to fSrcs.Count-1 do
begin
oldAbs := expandFilenameEx(oldBase,fSrcs[i]);
newRel := ExtractRelativepath(fBasePath, oldAbs);
fSrcs[i] := newRel;
end;
//
afterChanged;
end;
procedure TCEProject.setSrcs(const aValue: TStringList);
begin
beforeChanged;
fSrcs.Assign(aValue);
afterChanged;
end;
procedure TCEProject.setConfIx(aValue: Integer);
begin
if fConfIx = aValue then exit;
beforeChanged;
if aValue < 0 then aValue := 0;
if aValue > fOptsColl.Count-1 then aValue := fOptsColl.Count-1;
fConfIx := aValue;
afterChanged;
end;
procedure TCEProject.subMemberChanged(sender : TObject);
begin
beforeChanged;
fModified := true;
afterChanged;
end;
procedure TCEProject.beforeChanged;
begin
Inc(fChangedCount);
end;
procedure TCEProject.afterChanged;
begin
Dec(fChangedCount);
if fChangedCount > 0 then
begin
{$IFDEF DEBUG}
writeln('project update count > 0');
{$ENDIF}
exit;
end;
fChangedCount := 0;
doChanged;
end;
procedure TCEProject.doChanged;
{$IFDEF DEBUG}
var
lst: TStringList;
{$ENDIF}
begin
fModified := true;
if assigned(fOnChange) then fOnChange(Self);
{$IFDEF DEBUG}
lst := TStringList.Create;
try
lst.Add('---------begin----------');
getOpts(lst);
lst.Add('---------end----------');
writeln(lst.Text);
finally
lst.Free;
end;
{$ENDIF}
end;
function TCEProject.getConfig(const ix: integer): TCompilerConfiguration;
begin
result := TCompilerConfiguration(fOptsColl.Items[ix]);
result.onChanged := @subMemberChanged;
end;
function TCEProject.getCurrConf: TCompilerConfiguration;
begin
result := TCompilerConfiguration(fOptsColl.Items[fConfIx]);
end;
function TCEProject.getSrcs: TStringList;
var
str: TMemoryStream;
begin
if not (csReading in componentState) or (csWriting in componentState) then
begin
str := TMemoryStream.Create;
try
fSrcs.SaveToStream(str);
str.Position:=0;
fSrcsCop.Clear;
fSrcsCop.LoadFromStream(str);
finally
str.Free;
end;
result := fSrcsCop;
end
else result := fSrcs;
end;
procedure TCEProject.reset;
var
defConf: TCompilerConfiguration;
begin
beforeChanged;
fConfIx := 0;
fOptsColl.Clear;
defConf := addConfiguration;
defConf.name := 'default';
fSrcs.Clear;
fFilename := '';
afterChanged;
end;
procedure TCEProject.getOpts(const aList: TStrings);
var
rel, abs: string;
begin
if fConfIx = -1 then exit;
for rel in fSrcs do if rel <> '' then
begin
abs := expandFilenameEx(fBasePath,rel);
aList.Add(abs); // process.inc ln 249. double quotes are added anyway if there's a space...
end;
TCompilerConfiguration(fOptsColl.Items[fConfIx]).getOpts(aList);
end;
function TCEProject.getAbsoluteSourceName(const aIndex: integer): string;
begin
if aIndex < 0 then exit('');
if aIndex > fSrcs.Count-1 then exit('');
result := expandFileNameEx(fBasePath, fSrcs.Strings[aIndex]);
end;
function TCEProject.getAbsoluteFilename(const aFilename: string): string;
begin
result := expandFileNameEx(fBasePath, aFilename);
end;
end.

View File

@ -47,7 +47,7 @@ type
TD2Dictionary = object
private
fLongest: NativeInt;
fEntries: array[0..1024] of TD2DictionaryEntry;
fEntries: array[0..1023] of TD2DictionaryEntry;
function toHash(const aValue: string): word;
procedure addEntry(const aValue: string);
public
@ -80,6 +80,7 @@ type
fRange: TRangeKind;
fFoldKinds: TFoldKinds;
fAttribLut: array[TTokenKind] of TSynHighlighterAttributes;
// readNext is mostly used to advanced the reader head.
function readNext: Char;
function readCurr: Char;
function readPrev: Char;
@ -96,6 +97,7 @@ type
procedure setCurrIdent(const aValue: string);
procedure doChanged;
published
// Defines which kind of ranges can be folded, among curly brackets, block comments and nested comments
property FoldKinds: TFoldKinds read fFoldKinds write setFoldKinds;
property WhiteAttrib: TSynHighlighterAttributes read fWhiteAttrib write setWhiteAttrib;
property NumbrAttrib: TSynHighlighterAttributes read fNumbrAttrib write setNumbrAttrib;
@ -122,7 +124,7 @@ type
function GetRange: Pointer; override;
property CurrentIdentifier: string read fCurrIdent write setCurrIdent;
end;
implementation
function isWhite(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
@ -437,6 +439,7 @@ begin
result := fLineBuf[fTokStop];
end;
// unlike readNext, readPrev doesn't change the reader head position.
function TSynD2Syn.readPrev: Char; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
result := fLineBuf[fTokStop-1];
@ -444,14 +447,15 @@ end;
{
TODO:
- binary literals.
- alternative attributes for ddoc comments.
- asm range.
- stricter number literals.
- string literals: custom token, escape "\" not handled.
- correct nested comments handling.
- range: asm range.
- number literals: stricter.
- number literals: binary.
- string literals: delimited strings.
- string literals: token strings.
- string literals: escape bug: std.path/std.regex: "\\"
- comments: correct nested comments handling.
}
procedure TSynD2Syn.next;
begin
@ -581,7 +585,7 @@ begin
// string 1
if fRange = rkString1 then
begin
if (readCurr <> '"') then while ((readNext <> '"') and (not (readCurr = #10))) do (*!*);
if (readCurr <> '"') then while (((readNext <> '"') or (readPrev = '\')) and (not (readCurr = #10))) do (*!*);
if (readCurr = #10) then
begin
fRange := rkString1;
@ -593,16 +597,35 @@ begin
fTokKind := tkStrng;
fRange := rkNone;
readNext;
// check postfix
if readCurr in ['c','w','d'] then
readNext;
exit;
end;
end;
if fRange <> rkString2 then if (readCurr = '"') then
if fRange <> rkString2 then if (readCurr in ['r','x','"']) then
begin
if fRange = rkNone then
begin
while ((readNext <> '"') and (not (readCurr = #10))) do (*!*);
// check hex/WYSIWYG prefix
if readCurr in ['r','x'] then
begin
if not (readNext = '"') then
begin
fTokKind := tkIdent;
exit; // warning: a goto is avoided but any other r/x is not detectable since it's truncated as tkIdent
end;
end;
// go to end of string/eol
while (((readNext <> '"') or (readPrev = '\')) and (not (readCurr = #10))) do (*!*);
if (readCurr = #10) then fRange := rkString1
else readNext;
else
begin
readNext;
// check postfix
if readCurr in ['c','w','d'] then
readNext;
end;
fTokKind := tkStrng;
exit;
end;
@ -623,6 +646,9 @@ begin
fTokKind := tkStrng;
fRange := rkNone;
readNext;
// check postfix
if readCurr in ['c','w','d'] then
readNext;
exit;
end;
end;
@ -630,9 +656,16 @@ begin
begin
if fRange = rkNone then
begin
// go to end of string/eol
while ((readNext <> '`') and (not (readCurr = #10))) do (*!*);
if (readCurr = #10) then fRange := rkString2
else readNext;
else
begin
readNext;
// check postfix
if readCurr in ['c','w','d'] then
readNext;
end;
fTokKind := tkStrng;
exit;
end;
@ -641,7 +674,7 @@ begin
// char literals
if fRange = rkNone then if (readCurr = #39) then
begin
while ((readNext <> #39) and (not (readCurr = #10))) do (*!*);
while (((readNext <> #39) or (readPrev = '\')) and (not (readCurr = #10))) do (*!*);
if (readCurr = #39) then
begin
fTokKind := tkStrng;

View File

@ -22,7 +22,6 @@ type
protected
property onChange: TNotifyEvent read fOnChange write fOnChange;
public
//function getOpts: string; virtual; abstract;
procedure getOpts(const aList: TStrings); virtual; abstract;
end;
@ -60,7 +59,7 @@ type
*)
TMsgOpts = class(TOptsGroup)
private
fDepHandling : TDepHandling; // could be also related to analysis
fDepHandling : TDepHandling;
fVerb: boolean;
fWarn: boolean;
fWarnEx: boolean;
@ -136,7 +135,7 @@ type
procedure getOpts(const aList: TStrings); override;
end;
(**
(*****************************************************************************
* Encapsulates the options/args related to the debuging
*)
TDebugOpts = class(TOptsGroup)
@ -248,6 +247,9 @@ type
implementation
uses
ce_common;
(*******************************************************************************
* TOptsGroup
*)
@ -276,8 +278,8 @@ begin
src := TDocOpts(aValue);
fGenDoc := src.fGenDoc;
fGenJson := src.fGenJson;
fDocDir := src.fDocDir;
fJsonFname:= src.fJsonFname;
fDocDir := patchPlateformPath(src.fDocDir);
fJsonFname:= patchPlateformPath(src.fJsonFname);
end
else inherited;
end;
@ -299,14 +301,14 @@ end;
procedure TDocOpts.setDocDir(const aValue: string);
begin
if fDocDir = aValue then exit;
fDocDir := aValue;
fDocDir := patchPlateformPath(aValue);
doChanged;
end;
procedure TDocOpts.setJSONFile(const aValue: string);
begin
if fJsonFname = aValue then exit;
fJsonFname := aValue;
fJsonFname := patchPlateformPath(aValue);
doChanged;
end;
@ -573,6 +575,13 @@ end;
(*******************************************************************************
* TPathsOpts
*)
constructor TPathsOpts.create;
begin
fSrcs := TStringList.Create;
fIncl := TStringList.Create;
fImpt := TStringList.Create;
end;
procedure TPathsOpts.getOpts(const aList: TStrings);
var
str: string;
@ -587,13 +596,6 @@ begin
if fObjDir <> '' then aList.Add('-od' + fObjDir);
end;
constructor TPathsOpts.create;
begin
fSrcs := TStringList.Create;
fIncl := TStringList.Create;
fImpt := TStringList.Create;
end;
procedure TPathsOpts.assign(aValue: TPersistent);
var
src: TPathsOpts;
@ -604,8 +606,8 @@ begin
fSrcs.Assign(src.fSrcs);
fIncl.Assign(src.fIncl);
fImpt.Assign(src.fImpt);
fFName := src.fFname;
fObjDir := src.fObjDir;
fFName := patchPlateformPath(src.fFname);
fObjDir := patchPlateformPath(src.fObjDir);
end
else inherited;
end;
@ -621,32 +623,35 @@ end;
procedure TPathsOpts.setFname(const aValue: string);
begin
if fFname = aValue then exit;
fFname := aValue;
fFname := patchPlateformPath(aValue);
doChanged;
end;
procedure TPathsOpts.setObjDir(const aValue: string);
begin
if fObjDir = aValue then exit;
fObjDir := aValue;
fObjDir := patchPlateformPath(aValue);
doChanged;
end;
procedure TPathsOpts.setSrcs(const aValue: TStringList);
begin
fSrcs.Assign(aValue);
patchPlateformPaths(fSrcs);
doChanged;
end;
procedure TPathsOpts.setIncl(const aValue: TStringList);
begin
fIncl.Assign(aValue);
patchPlateformPaths(fIncl);
doChanged;
end;
procedure TPathsOpts.setImpt(const aValue: TStringList);
begin
fImpt.Assign(aValue);
patchPlateformPaths(fImpt);
doChanged;
end;
@ -808,4 +813,7 @@ begin
fOthers.Assign(aValue);
end;
initialization
RegisterClasses([TCompilerConfiguration, TOtherOpts, TPathsOpts,
TDebugOpts, TOutputOpts, TMsgOpts, TDocOpts]);
end.

View File

@ -180,7 +180,7 @@ end;
procedure TCEEditorWidget.autoWidgetUpdate;
const
modstr: array[boolean] of string = ('...','MODIFIED');
modstr: array[boolean] of string = ('...', 'MODIFIED');
var
ed: TCESynMemo;
begin

View File

@ -6,10 +6,10 @@ interface
uses
Classes, SysUtils, FileUtil, SynEditKeyCmds, SynHighlighterLFM, Forms,
AnchorDocking, AnchorDockStorage, AnchorDockOptionsDlg,
Controls, Graphics, Dialogs, Menus, ActnList, ExtCtrls, process, ce_jsoninfos, ce_common,
ce_dmdwrap, ce_synmemo, ce_widget, ce_messages, ce_editor, ce_projinspect,
ce_projconf, ce_staticexplorer;
AnchorDocking, AnchorDockStorage, AnchorDockOptionsDlg, Controls, Graphics,
Dialogs, Menus, ActnList, ExtCtrls, process,
ce_jsoninfos, ce_common, ce_dmdwrap, ce_project, ce_synmemo,
ce_widget, ce_messages, ce_editor, ce_projinspect, ce_projconf, ce_staticexplorer;
type
@ -659,7 +659,7 @@ begin
temppath := GetTempDir(false);
chDir(temppath);
{$IFDEF DEBUG}{$WARNINGS OFF}{$HINTS OFF}{$ENDIF}
fname := temppath + format('temp_%.8x', [NativeInt(@dmdproc)]);
fname := temppath + format('temp_%.8x', [NativeUInt(@dmdproc)]);
{$IFDEF DEBUG}{$WARNINGS ON}{$HINTS ON}{$ENDIF}
fEditWidg.editor[edIndex].Lines.SaveToFile(fname + '.d');
@ -931,6 +931,7 @@ begin
fProject.beforeChanged;
fProject.fileName := aFilename;
loadCompFromTxtFile(fProject, aFilename);
fProject.afterLoad;
fProject.afterChanged;
end;

View File

@ -89,7 +89,7 @@ end;
procedure TCEMessagesWidget.scrollToBack;
begin
if not Visible then exit;
List.ViewOrigin := Point(0,List.Items.Count * 25);
List.ViewOrigin := Point(0, List.Items.Count * 25);
end;
procedure TCEMessagesWidget.addCeInf(const aMsg: string);

View File

@ -233,7 +233,6 @@ inherited CEProjectConfigurationWidget: TCEProjectConfigurationWidget
Indent = 16
NameFont.Color = clWindowText
OnEditorFilter = GridEditorFilter
OnModified = GridModified
PreferredSplitterX = 145
SplitterX = 145
ValueFont.Color = clMaroon

View File

@ -6,8 +6,8 @@ interface
uses
Classes, SysUtils, FileUtil, RTTIGrids, Forms, Controls, Graphics, Dialogs,
ExtCtrls, ComCtrls, StdCtrls, Menus, Buttons, ce_widget, ce_common,
ce_dmdwrap, PropEdits, ObjectInspector;
ExtCtrls, ComCtrls, StdCtrls, Menus, Buttons, PropEdits, ObjectInspector,
ce_dmdwrap, ce_project, ce_widget;
type
@ -26,7 +26,6 @@ type
procedure btnDelConfClick(Sender: TObject);
procedure btnCloneCurrClick(Sender: TObject);
procedure GridEditorFilter(Sender: TObject; aEditor: TPropertyEditor;var aShow: boolean);
procedure GridModified(Sender: TObject);
procedure selConfChange(Sender: TObject);
procedure TreeChange(Sender: TObject; Node: TTreeNode);
private
@ -95,11 +94,6 @@ begin
if aEditor.ClassType = TCollectionPropertyEditor then aShow := false;
end;
procedure TCEProjectConfigurationWidget.GridModified(Sender: TObject);
begin
setFocus;
end;
procedure TCEProjectConfigurationWidget.btnAddConfClick(Sender: TObject);
var
nme: string;

257
src/ce_project.pas Normal file
View File

@ -0,0 +1,257 @@
unit ce_project;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, ce_dmdwrap;
type
(*****************************************************************************
* Represents a D project.
*
* It includes all the options defined in ce_dmdwrap, organized in
* a collection to allow multiples configurations.
*
* Basically it' s designed to provide the options for the dmd process.
*)
TCEProject = class(TComponent)
private
fOnChange: TNotifyEvent;
fModified: boolean;
fFilename: string;
fBasePath: string;
fOptsColl: TCollection;
fSrcs, fSrcsCop: TStringList;
fConfIx: Integer;
fChangedCount: NativeInt;
procedure doChanged;
procedure subMemberChanged(sender : TObject);
procedure setOptsColl(const aValue: TCollection);
procedure setFname(const aValue: string);
procedure setSrcs(const aValue: TStringList);
procedure setConfIx(aValue: Integer);
function getConfig(const ix: integer): TCompilerConfiguration;
function getCurrConf: TCompilerConfiguration;
published
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;
public
constructor create(aOwner: TComponent); override;
destructor destroy; override;
procedure beforeChanged;
procedure afterChanged;
procedure reset;
function getAbsoluteSourceName(const aIndex: integer): string;
function getAbsoluteFilename(const aFilename: string): string;
procedure addSource(const aFilename: string);
function addConfiguration: TCompilerConfiguration;
procedure getOpts(const aList: TStrings);
procedure afterLoad;
//
property configuration[ix: integer]: TCompilerConfiguration read getConfig;
property currentConfiguration: TCompilerConfiguration read getCurrConf;
property fileName: string read fFilename write setFname;
property onChange: TNotifyEvent read fOnChange write fOnChange;
end;
implementation
uses
ce_common;
constructor TCEProject.create(aOwner: TComponent);
begin
inherited create(aOwner);
fSrcs := TStringList.Create;
fSrcs.OnChange := @subMemberChanged;
fSrcsCop := TStringList.Create;
fOptsColl := TCollection.create(TCompilerConfiguration);
reset;
end;
destructor TCEProject.destroy;
begin
fOnChange := nil;
fSrcs.free;
fSrcsCop.Free;
fOptsColl.free;
inherited;
end;
function TCEProject.addConfiguration: TCompilerConfiguration;
begin
result := TCompilerConfiguration(fOptsColl.Add);
result.onChanged := @subMemberChanged;
end;
procedure TCEProject.setOptsColl(const aValue: TCollection);
var
i: nativeInt;
begin
fOptsColl.Assign(aValue);
for i:= 0 to self.fOptsColl.Count-1 do
Configuration[i].onChanged := @subMemberChanged;
end;
procedure TCEProject.addSource(const aFilename: string);
var
relSrc, absSrc: string;
begin
for relSrc in fSrcs do
begin
absSrc := expandFilenameEx(fBasePath,relsrc);
if aFilename = absSrc then exit;
end;
fSrcs.Add(ExtractRelativepath(fBasePath,aFilename));
end;
procedure TCEProject.setFname(const aValue: string);
var
oldAbs, newRel, oldBase: string;
i: NativeInt;
begin
if fFilename = aValue then exit;
//
beforeChanged;
fFilename := aValue;
oldBase := fBasePath;
fBasePath := extractFilePath(fFilename);
//
for i:= 0 to fSrcs.Count-1 do
begin
oldAbs := expandFilenameEx(oldBase,fSrcs[i]);
newRel := ExtractRelativepath(fBasePath, oldAbs);
fSrcs[i] := newRel;
end;
//
afterChanged;
end;
procedure TCEProject.setSrcs(const aValue: TStringList);
begin
beforeChanged;
fSrcs.Assign(aValue);
patchPlateformPaths(fSrcs);
afterChanged;
end;
procedure TCEProject.afterLoad;
begin
patchPlateformPaths(fSrcs);
end;
procedure TCEProject.setConfIx(aValue: Integer);
begin
if fConfIx = aValue then exit;
beforeChanged;
if aValue < 0 then aValue := 0;
if aValue > fOptsColl.Count-1 then aValue := fOptsColl.Count-1;
fConfIx := aValue;
afterChanged;
end;
procedure TCEProject.subMemberChanged(sender : TObject);
begin
beforeChanged;
fModified := true;
afterChanged;
end;
procedure TCEProject.beforeChanged;
begin
Inc(fChangedCount);
end;
procedure TCEProject.afterChanged;
begin
Dec(fChangedCount);
if fChangedCount > 0 then
begin
{$IFDEF DEBUG}
writeln('project update count > 0');
{$ENDIF}
exit;
end;
fChangedCount := 0;
doChanged;
end;
procedure TCEProject.doChanged;
{$IFDEF DEBUG}
var
lst: TStringList;
{$ENDIF}
begin
fModified := true;
if assigned(fOnChange) then fOnChange(Self);
{$IFDEF DEBUG}
lst := TStringList.Create;
try
lst.Add('---------begin----------');
getOpts(lst);
lst.Add('---------end-----------');
writeln(lst.Text);
finally
lst.Free;
end;
{$ENDIF}
end;
function TCEProject.getConfig(const ix: integer): TCompilerConfiguration;
begin
result := TCompilerConfiguration(fOptsColl.Items[ix]);
result.onChanged := @subMemberChanged;
end;
function TCEProject.getCurrConf: TCompilerConfiguration;
begin
result := TCompilerConfiguration(fOptsColl.Items[fConfIx]);
end;
procedure TCEProject.reset;
var
defConf: TCompilerConfiguration;
begin
beforeChanged;
fConfIx := 0;
fOptsColl.Clear;
defConf := addConfiguration;
defConf.name := 'default';
fSrcs.Clear;
fFilename := '';
afterChanged;
end;
procedure TCEProject.getOpts(const aList: TStrings);
var
rel, abs: string;
begin
if fConfIx = -1 then exit;
for rel in fSrcs do if rel <> '' then
begin
abs := expandFilenameEx(fBasePath,rel);
aList.Add(abs); // process.inc ln 249. double quotes are added anyway if there's a space...
end;
TCompilerConfiguration(fOptsColl.Items[fConfIx]).getOpts(aList);
end;
function TCEProject.getAbsoluteSourceName(const aIndex: integer): string;
begin
if aIndex < 0 then exit('');
if aIndex > fSrcs.Count-1 then exit('');
result := expandFileNameEx(fBasePath, fSrcs.Strings[aIndex]);
end;
function TCEProject.getAbsoluteFilename(const aFilename: string): string;
begin
result := expandFileNameEx(fBasePath, aFilename);
end;
initialization
RegisterClasses([TCEProject]);
end.

View File

@ -6,7 +6,7 @@ interface
uses
Classes, SysUtils, FileUtil, TreeFilterEdit, Forms, Controls, Graphics,
Dialogs, ExtCtrls, ComCtrls, Menus, Buttons, ce_common, ce_widget;
Dialogs, ExtCtrls, ComCtrls, Menus, Buttons, ce_project, ce_widget;
type
{ TCEProjectInspectWidget }

View File

@ -5,8 +5,8 @@ unit ce_synmemo;
interface
uses
Classes, SysUtils, SynEdit, SynMemo, ce_common, ce_d2syn,
SynPluginSyncroEdit, SynEditKeyCmds;
Classes, SysUtils, SynEdit, SynMemo, ce_d2syn,
SynPluginSyncroEdit, SynEditKeyCmds, ce_project;
type
@ -43,8 +43,8 @@ begin
//
Gutter.LineNumberPart.ShowOnlyLineNumbersMultiplesOf := 5;
Gutter.LineNumberPart.MarkupInfo.Foreground := clGray;
Gutter.SeparatorPart.LineOffset:=1;
Gutter.SeparatorPart.LineWidth:=1;
Gutter.SeparatorPart.LineOffset := 1;
Gutter.SeparatorPart.LineWidth := 1;
Gutter.SeparatorPart.MarkupInfo.Foreground := clGray;
Gutter.CodeFoldPart.MarkupInfo.Foreground := clGray;
//

View File

@ -6,7 +6,8 @@ interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, ExtCtrls,
AnchorDocking, AnchorDockStorage, ActnList, Menus, ce_common;
AnchorDocking, AnchorDockStorage, ActnList, Menus,
ce_widgettypes, ce_project;
type

40
src/ce_widgettypes.pas Normal file
View File

@ -0,0 +1,40 @@
unit ce_widgettypes;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, actnList, ce_project;
type
(**
* An implementer is informed when a new document is added, focused or closed.
*)
ICEMultiDocMonitor = interface
procedure docChange(const aNewIndex: integer);
procedure docClose(const aNewIndex: integer);
end;
(**
* An implementer adds some menu actions when its context is valid.
*)
ICEContextualActions = interface
function contextName: string;
function contextActionCount: integer;
function contextAction(index: integer): TAction;
end;
(**
* An implementer is informed when a project changes.
*)
ICEProjectMonitor = interface
procedure projNew(const aProject: TCEProject);
procedure projChange(const aProject: TCEProject);
procedure projClose(const aProject: TCEProject);
end;
implementation
end.