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**). Coedit is a simple IDE for the [D2](http://dlang.org) lang. (**Co** mpile & **Edit**).
Initial features (planed) Current features
------------------------- ----------------
- targets Win/Macos/Linux - multi platform (Win/Linux/Macos).
- projects. - projects.
- multiple project configurations (set of switches and options). - multiple project configurations (set of switches and options).
- project configurations templates (release, debug, etc.). - compile, run directly from the UI.
- D syntax highlighter, folding.
- compile, run directly from UI.
- instant run (without saving, script-like). - instant run (without saving, script-like).
- basic auto completion (brackets, key-words, ...)
- synchronized edition in a block. - 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 Project information
------------------- -------------------
- draft - state: alpha 1.
- programmed in Object pascal. - programmed in Object pascal with [Lazarus](http://www.lazarus.freepascal.org).
- [Lazarus](http://www.lazarus.freepascal.org) is used as IDE. - based on *dmd* (*gdc* or *lmd* characteristics are not handled).
- based on dmd (gdc or lmd characteristics are not hanlded). - no other third party dependencies (so far...but using *dscanner* and/or *dcd* is envisaged.)
- no other third party dependencies (so far...)
Setup Setup & test
----- ------------
- clone this repo. 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. - both [dmd](http://dlang.org/download.html) and [Lazarus](http://www.lazarus.freepascal.org) must be setup.
- open "coedit.lpr" in Lazarus. - open "coedit.lpr" in *Lazarus*, set the build mode to *Release*
- press the Run button. - press the Run button (or build)
- in coedit open *"lazproj\test\coeditproj\test.coedit"* from the project menu.
Preview Preview
------- -------
Windows version:
![Interface screen-cap, under Windows](lazproj/Gui.tease.png "Coedit GUI preview") ![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"/> <PackageName Value="LCL"/>
</Item5> </Item5>
</RequiredPackages> </RequiredPackages>
<Units Count="12"> <Units Count="14">
<Unit0> <Unit0>
<Filename Value="coedit.lpr"/> <Filename Value="coedit.lpr"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
@ -205,6 +205,16 @@
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
<UnitName Value="ce_jsoninfos"/> <UnitName Value="ce_jsoninfos"/>
</Unit11> </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> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

View File

@ -8,7 +8,8 @@ uses
{$ENDIF}{$ENDIF} {$ENDIF}{$ENDIF}
Interfaces, Forms, lazcontrols, runtimetypeinfocontrols, ce_widget, Interfaces, Forms, lazcontrols, runtimetypeinfocontrols, ce_widget,
ce_dmdwrap, ce_common, ce_synmemo, ce_main, ce_messages, ce_editor, 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} {$R *.res}

View File

@ -1,4 +1,4 @@
object TCEProject object _1: TCEProject
OptionsCollection = < OptionsCollection = <
item item
name = 'default' name = 'default'

View File

@ -5,92 +5,39 @@ unit ce_common;
interface interface
uses uses
Classes, SysUtils, ce_dmdwrap, ActnList; Classes, SysUtils, ActnList;
type
TCEProject = class;
(** (**
* 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); procedure saveCompToTxtFile(const aComp: TComponent; const aFilename: string);
(**
* Load a component.
*)
procedure loadCompFromTxtFile(const aComp: TComponent; const aFilename: string); procedure loadCompFromTxtFile(const aComp: TComponent; const aFilename: string);
(**
* Converts a relative path to an absolute path.
*)
function expandFilenameEx(const aBasePath, aFilename: string): string; function expandFilenameEx(const aBasePath, aFilename: string): string;
(**
* Extracts the module name of a D source file.
*)
function getModuleName(const aSource: TStrings): string; 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 implementation
(*****************************************************************************
* Routines
*)
procedure saveCompToTxtFile(const aComp: TComponent; const aFilename: string); procedure saveCompToTxtFile(const aComp: TComponent; const aFilename: string);
var var
str1, str2: TMemoryStream; str1, str2: TMemoryStream;
@ -144,6 +91,87 @@ begin
end; end;
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 // TODO: block comments handling
function getModuleName(const aSource: TStrings): string; function getModuleName(const aSource: TStrings): string;
var var
@ -197,211 +225,4 @@ begin
end; end;
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. end.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,8 @@ interface
uses uses
Classes, SysUtils, FileUtil, Forms, Controls, ExtCtrls, Classes, SysUtils, FileUtil, Forms, Controls, ExtCtrls,
AnchorDocking, AnchorDockStorage, ActnList, Menus, ce_common; AnchorDocking, AnchorDockStorage, ActnList, Menus,
ce_widgettypes, ce_project;
type 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.