This commit is contained in:
Basile Burg 2014-06-26 16:23:02 +02:00
parent a522efb185
commit fdadfc810b
12 changed files with 301 additions and 111 deletions

View File

@ -5,7 +5,7 @@ Coedit is a simple IDE for the [D2](http://dlang.org) lang. (**Co** mpile & **Ed
Current features
----------------
- multi platform (Win/Linux/Macos).
- multi platform (Win/Linux).
- projects.
- multiple project configurations (set of switches and options).
- compile, run directly from the UI.
@ -34,7 +34,7 @@ Coedit must be build from the sources:
- both [dmd](http://dlang.org/download.html) and [Lazarus](http://www.lazarus.freepascal.org) must be setup.
- 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.
- run coedit and project, open *"lazproj\test\coeditproj\test.coedit"* from the project menu to give a brief try.
Preview
-------

View File

@ -54,7 +54,8 @@
<CompilerMessages>
<MsgFileName Value=""/>
</CompilerMessages>
<CustomOptions Value="-dDEBUG"/>
<CustomOptions Value="-dDEBUG
-dUSE_DICT_LINKEDCHARMAP"/>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
@ -74,7 +75,7 @@
<CodeGeneration>
<SmartLinkUnit Value="True"/>
<Optimizations>
<OptimizationLevel Value="2"/>
<OptimizationLevel Value="3"/>
</Optimizations>
</CodeGeneration>
<Linking>
@ -95,7 +96,8 @@
<CompilerMessages>
<MsgFileName Value=""/>
</CompilerMessages>
<CustomOptions Value="-dRELEASE"/>
<CustomOptions Value="-dRELEASE
-dUSE_DICT_LINKEDCHARMAP"/>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
@ -250,6 +252,7 @@
<CompilerMessages>
<MsgFileName Value=""/>
</CompilerMessages>
<CustomOptions Value="-dUSE_DICT_LINKEDCHARMAP"/>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>

View File

@ -7,6 +7,10 @@ interface
uses
Classes, SysUtils, ActnList, dialogs, forms;
const
DdiagFilter = 'D source|*.d|D interface|*.di|All files|*.*';
type
(**
@ -275,9 +279,4 @@ begin
{$HINTS ON}{$WARNINGS ON}
end;
operator =(lhs,rhs: TPoint): boolean;
begin
exit( (lhs.x = rhs.x) and (lhs.y = rhs.y) );
end;
end.

View File

@ -39,22 +39,46 @@ const
type
{$IFDEF USE_DICT_LINKEDCHARMAP}
PCharMap = ^TCharMap;
TCharMap = record
chars: array [Byte] of PCharMap;
end;
// slightly fatest then a hash-based-dictionary but huge memory use.
TD2Dictionary = object
private
fRoot: TCharMap;
fTerm: NativeInt;
fFreeList: array of pointer;
fLongest, fShortest: NativeInt;
procedure addEntry(const aValue: string);
public
constructor create;
destructor destroy;
function find(const aValue: string): boolean;
end;
{$ELSE} {$IFDEF USE_DICT_GPERF}
// TODO: a perfect hash dictionnary based on gperf
{$ELSE}
TD2DictionaryEntry = record
filled: Boolean;
values: array of string;
end;
// TODO: rather gperf ?
TD2Dictionary = object
private
fLongest: NativeInt;
fEntries: array[0..255] of TD2DictionaryEntry;
fLongest, fShortest: NativeInt;
fEntries: array[Byte] of TD2DictionaryEntry;
function toHash(const aValue: string): Byte;
procedure addEntry(const aValue: string);
public
constructor create;
destructor destroy;
function find(const aValue: string): boolean;
end;
{$ENDIF}
{$ENDIF}
TTokenKind = (tkCommt, tkIdent, tkKeywd, tkStrng, tkBlank, tkSymbl, tkNumbr, tkCurrI);
@ -98,7 +122,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
// Defines which kind of range 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;
@ -217,70 +241,120 @@ begin
result := (s = '>>>=') or (s = '!<>=');
end;
{$IFDEF USE_DICT_LINKEDCHARMAP}
constructor TD2Dictionary.create;
var
value: string;
i: NativeInt;
begin
fTerm := 1;
for i := 0 to 255 do fRoot.chars[i] := nil;
for value in D2Kw do
addEntry(value);
end;
destructor TD2Dictionary.destroy;
var
i: NativeInt;
begin
for i := 0 to high(fFreeList) do
FreeMem(fFreeList[i]);
end;
procedure TD2Dictionary.addEntry(const aValue: string);
var
len, i, j: NativeInt;
currMap: PCharMap;
newMap: PCharMap;
begin
len := length(aValue);
if len > fLongest then fLongest := len;
if len < fShortest then fShortest := len;
currMap := @fRoot;
for i := 1 to len do
begin
if (currMap^.chars[Byte(aValue[i])] = nil) then
begin
newMap := new(PCharMap);
for j := 0 to 255 do newMap^.chars[j] := nil;
setLength(fFreeList, length(fFreeList) + 1);
fFreeList[high(fFreeList)] := newMap;
currMap^.chars[Byte(aValue[i])] := newMap;
end;
if i < len then currMap := currMap^.chars[Byte(aValue[i])];
end;
currMap^.chars[0] := @fTerm;
end;
function TD2Dictionary.find(const aValue: string): boolean;
var
len, i: NativeInt;
currMap: PCharMap;
begin
len := length(aValue);
if len > fLongest then exit(false);
if len < fShortest then exit(false);
currMap := @fRoot;
for i := 1 to len do
begin
if currMap^.chars[Byte(aValue[i])] = nil then exit(false);
if i < len then currMap := currMap^.chars[Byte(aValue[i])];
end;
exit( currMap^.chars[0] = @fTerm );
end;
{$ELSE}
constructor TD2Dictionary.create;
var
value: string;
begin
for value in D2Kw do
begin
addEntry(value);
end;
end;
destructor TD2Dictionary.destroy;
begin
end;
{$IFDEF DEBUG}{$R-}{$ENDIF}
function TD2Dictionary.toHash(const aValue: string): Byte;
var
i, len: Integer;
i: Integer;
begin
result := 0;
len := length(aValue);
for i := 1 to len do
result += (Byte(aValue[i]) shl i) xor 63;
for i := 1 to length(aValue) do
result += (Byte(aValue[i]) shl (4 and (1-i))) xor 25;
end;
{$IFDEF DEBUG}{$R+}{$ENDIF}
procedure TD2Dictionary.addEntry(const aValue: string);
var
hash: word;
hash: Byte;
begin
if find(aValue) then
exit;
if find(aValue) then exit;
hash := toHash(aValue);
assert(hash < 1024);
fEntries[hash].filled := true;
setLength(fEntries[hash].values, length(fEntries[hash].values) + 1);
fEntries[hash].values[high(fEntries[hash].values)] := aValue;
if fLongest <= length(aValue) then
fLongest := length(aValue);
if fShortest >= length(aValue) then
fShortest := length(aValue);
end;
function TD2Dictionary.find(const aValue: string): boolean;
var
hash: word;
hash: Byte;
i: NativeInt;
begin
if length(aValue) > fLongest then
result := false
else
begin
hash := toHash(aValue);
if (not fEntries[hash].filled) then
result := false else
begin
for i:= 0 to high(fEntries[hash].values) do
begin
if fEntries[hash].values[i] = aValue then
begin
result := true;
exit;
end;
result := false;
end
end;
end;
result := false;
if length(aValue) > fLongest then exit;
if length(aValue) < fShortest then exit;
hash := toHash(aValue);
if (not fEntries[hash].filled) then exit(false);
for i:= 0 to high(fEntries[hash].values) do
if fEntries[hash].values[i] = aValue then exit(true);
end;
{$ENDIF}
constructor TSynD2Syn.create(aOwner: TComponent);
@ -342,6 +416,7 @@ end;
destructor TSynD2Syn.destroy;
begin
fKeyWords.destroy;
inherited;
end;

View File

@ -620,6 +620,15 @@ object CEMainForm: TCEMainForm
object MenuItem21: TMenuItem
Caption = '-'
end
object MenuItem54: TMenuItem
Action = actEdIndent
end
object MenuItem53: TMenuItem
Action = actEdUnIndent
end
object MenuItem52: TMenuItem
Caption = '-'
end
object MenuItem22: TMenuItem
Action = actEdMacStartStop
Bitmap.Data = {
@ -1663,6 +1672,20 @@ object CEMainForm: TCEMainForm
ImageIndex = 21
OnExecute = actProjRunWithArgsExecute
end
object actEdIndent: TAction
Category = 'Edit'
Caption = 'Indent'
ImageIndex = 16
OnExecute = actEdIndentExecute
ShortCut = 24649
end
object actEdUnIndent: TAction
Category = 'Edit'
Caption = 'Unindent'
ImageIndex = 17
OnExecute = actEdUnIndentExecute
ShortCut = 24661
end
end
object imgList: TImageList
left = 64

View File

@ -44,6 +44,8 @@ type
actEdUndo: TAction;
actEdPaste: TAction;
actEdCopy: TAction;
actEdIndent: TAction;
actEdUnIndent: TAction;
Actions: TActionList;
ApplicationProperties1: TApplicationProperties;
imgList: TImageList;
@ -93,6 +95,9 @@ type
MenuItem49: TMenuItem;
MenuItem50: TMenuItem;
MenuItem51: TMenuItem;
MenuItem52: TMenuItem;
MenuItem53: TMenuItem;
MenuItem54: TMenuItem;
mnuItemWin: TMenuItem;
MenuItem4: TMenuItem;
MenuItem5: TMenuItem;
@ -106,6 +111,7 @@ type
procedure actFileCompAndRunExecute(Sender: TObject);
procedure actFileCompAndRunWithArgsExecute(Sender: TObject);
procedure actFileSaveAllExecute(Sender: TObject);
procedure actEdIndentExecute(Sender: TObject);
procedure actProjCompAndRunWithArgsExecute(Sender: TObject);
procedure actProjCompileAndRunExecute(Sender: TObject);
procedure actProjCompileExecute(Sender: TObject);
@ -131,6 +137,7 @@ type
procedure actProjSaveExecute(Sender: TObject);
procedure actEdUndoExecute(Sender: TObject);
procedure actProjSourceExecute(Sender: TObject);
procedure actEdUnIndentExecute(Sender: TObject);
procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
procedure FormShow(Sender: TObject);
private
@ -285,6 +292,8 @@ begin
{$ENDIF}
actEdMacPlay.Enabled := true;
actEdMacStartStop.Enabled := true;
actEdIndent.Enabled := true;
actEdUnIndent.Enabled := true;
//
actFileCompAndRun.Enabled := true;
actFileCompAndRunWithArgs.Enabled := true;
@ -303,6 +312,8 @@ begin
{$ENDIF}
actEdMacPlay.Enabled := false;
actEdMacStartStop.Enabled := false;
actEdIndent.Enabled := false;
actEdUnIndent.Enabled := false;
//
actFileCompAndRun.Enabled := false;
actFileCompAndRunWithArgs.Enabled := false;
@ -474,7 +485,7 @@ begin
//
with TOpenDialog.Create(nil) do
try
filter := 'D source|*.d|D interface|*.di|all files|*.*';
filter := DdiagFilter;
if execute then
begin
openFile(filename);
@ -512,10 +523,9 @@ begin
//
with TSaveDialog.Create(nil) do
try
Filter := DdiagFilter;
if execute then
begin
saveFileAs(fEditWidg.editorIndex, filename);
end;
finally
free;
end;
@ -640,7 +650,21 @@ begin
end;
end;
procedure TCEMainForm.actEdIndentExecute(Sender: TObject);
var
curr: TCESynMemo;
begin
curr := fEditWidg.currentEditor;
if assigned(curr) then curr.ExecuteCommand(ecBlockIndent, '', nil);
end;
procedure TCEMainForm.actEdUnIndentExecute(Sender: TObject);
var
curr: TCESynMemo;
begin
curr := fEditWidg.currentEditor;
if assigned(curr) then curr.ExecuteCommand(ecBlockUnIndent, '', nil);
end;
{$ENDREGION}
{$REGION run ******************************************************************}

View File

@ -4,6 +4,10 @@ unit ce_project;
interface
// TODO: pre/post compilation shell-script / process
// TODO: run opts, newConsole, catch output, etc
// TODO: configuration templates
uses
Classes, SysUtils, ce_dmdwrap;

View File

@ -6,7 +6,8 @@ interface
uses
Classes, SysUtils, FileUtil, TreeFilterEdit, Forms, Controls, Graphics,
actnlist, Dialogs, ExtCtrls, ComCtrls, Menus, Buttons, ce_project, ce_widget;
actnlist, Dialogs, ExtCtrls, ComCtrls, Menus, Buttons, ce_project,
ce_common, ce_widget;
type
{ TCEProjectInspectWidget }
@ -166,7 +167,7 @@ begin
//
with TOpenDialog.Create(nil) do
try
filter := 'D source|*.d|D interface|*.di|all files|*.*';
filter := DdiagFilter;
if execute then
fProject.addSource(filename);
finally

View File

@ -1,48 +1,37 @@
inherited CESearchWidget: TCESearchWidget
Left = 1338
Height = 276
Top = 697
Width = 405
Left = 1468
Height = 237
Top = 516
Width = 394
Caption = 'Search & replace'
ClientHeight = 276
ClientWidth = 405
ClientHeight = 237
ClientWidth = 394
inherited Back: TPanel
Height = 276
Width = 405
ClientHeight = 276
ClientWidth = 405
Height = 237
Width = 394
ClientHeight = 237
ClientWidth = 394
inherited Content: TPanel
Height = 276
Width = 405
ClientHeight = 276
ClientWidth = 405
Height = 237
Width = 394
ClientHeight = 237
ClientWidth = 394
object cbToFind: TComboBox[0]
Left = 4
Height = 23
Top = 4
Width = 397
Width = 386
Align = alTop
BorderSpacing.Around = 4
ItemHeight = 15
OnChange = cbToFindChange
TabOrder = 0
end
object cbReplaceWth: TComboBox[1]
Left = 4
Height = 23
Top = 31
Width = 397
Align = alTop
BorderSpacing.Around = 4
ItemHeight = 15
OnChange = cbReplaceWthChange
TabOrder = 1
end
object btnFind: TBitBtn[2]
object btnFind: TBitBtn[1]
Left = 4
Height = 24
Top = 192
Width = 397
Top = 153
Width = 386
Align = alBottom
BorderSpacing.Around = 4
Caption = 'btnFind'
@ -82,13 +71,13 @@ inherited CESearchWidget: TCESearchWidget
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00
}
TabOrder = 2
TabOrder = 1
end
object btnReplace: TBitBtn[3]
object btnReplace: TBitBtn[2]
Left = 4
Height = 24
Top = 220
Width = 397
Top = 181
Width = 386
Align = alBottom
BorderSpacing.Around = 4
Caption = 'btnReplace'
@ -128,19 +117,19 @@ inherited CESearchWidget: TCESearchWidget
4766E69547FFE69A4EFFE2904122FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00
}
TabOrder = 3
TabOrder = 2
end
object grpOpts: TGroupBox[4]
object grpOpts: TGroupBox[3]
Left = 4
Height = 130
Top = 58
Width = 397
Height = 88
Top = 61
Width = 386
Align = alClient
BorderSpacing.Around = 4
Caption = 'Options'
ClientHeight = 112
ClientWidth = 393
TabOrder = 4
ClientHeight = 70
ClientWidth = 382
TabOrder = 3
object chkWWord: TCheckBox
Left = 8
Height = 19
@ -184,11 +173,11 @@ inherited CESearchWidget: TCESearchWidget
TabOrder = 4
end
end
object btnReplaceAll: TBitBtn[5]
object btnReplaceAll: TBitBtn[4]
Left = 4
Height = 24
Top = 248
Width = 397
Top = 209
Width = 386
Align = alBottom
BorderSpacing.Around = 4
Caption = 'btnReplaceAll'
@ -228,12 +217,49 @@ inherited CESearchWidget: TCESearchWidget
4766E69547FFE69A4EFFE2904122FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00
}
TabOrder = 4
end
object Panel1: TPanel[5]
Left = 4
Height = 26
Top = 31
Width = 386
Align = alTop
BorderSpacing.Around = 4
BevelOuter = bvNone
ClientHeight = 26
ClientWidth = 386
TabOrder = 5
object cbReplaceWth: TComboBox
Left = 90
Height = 23
Top = 0
Width = 296
Align = alClient
ItemHeight = 15
OnChange = cbReplaceWthChange
TabOrder = 0
end
object chkEnableRep: TCheckBox
Left = 0
Height = 26
Top = 0
Width = 90
Align = alLeft
Caption = 'Replace with '
OnChange = chkEnableRepChange
TabOrder = 1
end
end
end
end
inherited contextMenu: TPopupMenu
left = 216
top = 16
end
object imgList: TImageList[2]
left = 32
left = 248
top = 16
Bitmap = {
4C690200000010000000100000007B7977007B7977007B7977FF73716FFF6D6B
69FF696665FF625F5EFF615E5D007E7C7A007B7977FF73716FFF6D6B69FF6966

View File

@ -19,6 +19,7 @@ type
btnReplaceAll: TBitBtn;
cbToFind: TComboBox;
cbReplaceWth: TComboBox;
chkEnableRep: TCheckBox;
chkPrompt: TCheckBox;
chkWWord: TCheckBox;
chkBack: TCheckBox;
@ -26,8 +27,10 @@ type
chkCaseSens: TCheckBox;
grpOpts: TGroupBox;
imgList: TImageList;
Panel1: TPanel;
procedure cbReplaceWthChange(Sender: TObject);
procedure cbToFindChange(Sender: TObject);
procedure chkEnableRepChange(Sender: TObject);
private
fEditor: TCESynMemo;
fToFind: string;
@ -35,6 +38,7 @@ type
fActFindNext, fActReplaceNext: TAction;
fActReplaceAll: TAction;
fSearchMru, fReplaceMru: TMruList;
fCancelAll: boolean;
function getOptions: TSynSearchOptions;
procedure actFindNextExecute(sender: TObject);
procedure actReplaceAllExecute(sender: TObject);
@ -56,24 +60,24 @@ implementation
constructor TCESearchWidget.Create(aOwner: TComponent);
begin
inherited;
fID := 'ID_FIND';
//
fSearchMru := TMruList.Create;
fReplaceMru:= TMruList.Create;
//
fActFindNext := TAction.Create(self);
fActFindNext.Caption := 'Find';
fActFindNext.OnExecute := @actFindNextExecute;
btnFind.Action := fActFindNext;
fActReplaceNext := TAction.Create(self);
fActReplaceNext.Caption := 'Replace';
fActReplaceNext.OnExecute := @actReplaceNextExecute;
btnReplace.Action := fActReplaceNext;
fActReplaceAll := TAction.Create(self);
fActReplaceAll.Caption := 'Replace all';
fActReplaceAll.OnExecute := @actReplaceAllExecute;
inherited;
fID := 'ID_FIND';
//
btnFind.Action := fActFindNext;
btnReplace.Action := fActReplaceNext;
btnReplaceAll.Action := fActReplaceAll;
//
fSearchMru := TMruList.Create;
fReplaceMru:= TMruList.Create;
end;
destructor TCESearchWidget.Destroy;
@ -101,6 +105,12 @@ begin
fToFind := cbToFind.Text;
end;
procedure TCESearchWidget.chkEnableRepChange(Sender: TObject);
begin
if Updating then exit;
UpdateByEvent;
end;
procedure TCESearchWidget.cbReplaceWthChange(Sender: TObject);
begin
if Updating then exit;
@ -109,7 +119,7 @@ end;
function TCESearchWidget.getOptions: TSynSearchOptions;
begin
result := [];
result := [ssoRegExpr];
if chkWWord.Checked then result += [ssoWholeWord];
if chkBack.Checked then result += [ssoBackwards];
if chkCaseSens.Checked then result += [ssoMatchCase];
@ -160,23 +170,45 @@ begin
begin
if fEditor.SearchReplace(fToFind, fReplaceWth, opts) = 0
then break;
if fCancelAll then
begin
fCancelAll := false;
break;
end;
end;
fEditor.OnReplaceText := nil;
UpdateByEvent;
end;
function dlgReplaceAll: TModalResult;
const
Btns = [mbYes, mbNo, mbYesToAll, mbNoToAll];
begin
exit( MessageDlg('Coedit', 'Replace this match ?', mtConfirmation, Btns, ''));
end;
procedure TCESearchWidget.replaceEvent(Sender: TObject; const ASearch, AReplace:
string; Line, Column: integer; var ReplaceAction: TSynReplaceAction);
begin
ReplaceAction := raSkip;
if dlgOkCancel('Replace this match ?') = mrOK then
ReplaceAction := raReplace;
case dlgReplaceAll of
mrYes: ReplaceAction := raReplace;
mrNo: ReplaceAction := raSkip;
mrYesToAll: ReplaceAction := raReplaceAll;
mrCancel, mrClose, mrNoToAll:
begin
ReplaceAction := raCancel;
fCancelAll := true;
end;
end;
end;
procedure TCESearchWidget.UpdateByEvent;
begin
fActFindNext.Enabled := fEditor <> nil;
fActReplaceNext.Enabled := fEditor <> nil;
fActReplaceNext.Enabled := (fEditor <> nil) and (chkEnableRep.Checked);
fActReplaceAll.Enabled := (fEditor <> nil) and (chkEnableRep.Checked);
cbReplaceWth.Enabled := (fEditor <> nil) and (chkEnableRep.Checked);
cbToFind.Enabled := fEditor <> nil;
//
cbToFind.Items.Assign(fSearchMru);
cbReplaceWth.Items.Assign(fReplaceMru);

View File

@ -38,7 +38,8 @@ begin
TabWidth := 4;
Options :=
[ eoAutoIndent, eoBracketHighlight, eoGroupUndo, eoTabsToSpaces,
eoTrimTrailingSpaces, eoDragDropEditing, eoShowCtrlMouseLinks];
eoTrimTrailingSpaces, eoDragDropEditing, eoShowCtrlMouseLinks,
eoEnhanceHomeKey, eoTabIndent];
Options2 := [eoEnhanceEndKey, eoFoldedCopyPaste, eoOverwriteBlock];
//
Gutter.LineNumberPart.ShowOnlyLineNumbersMultiplesOf := 5;

View File

@ -9,6 +9,8 @@ uses
type
// TODO: interface for document content access/modification
(**
* An implementer is informed when a new document is added, focused or closed.
*)