diff --git a/README.md b/README.md
index 3abb7da6..d1264360 100644
--- a/README.md
+++ b/README.md
@@ -12,23 +12,24 @@ Current features
- instant run (without saving, script-like).
- synchronized edition in a block.
- D syntax highlighter, folding, identifier markup.
-- current module member list.
+- member list of the current module.
+- manager for the static libraries.
- search and replace.
+- [D Completion Daemon](https://github.com/Hackerpilot/DCD) integration for completion proposal and source code hints.
+- mini file browser.
-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).
+Missing features before the first beta
+--------------------------------------
+- Options editor. (the big missing stuff)
+- console input handling. (workarounds exists)
+- project configurations templates (release, debug, etc.). (detail)
Project information
-------------------
- state: alpha 4.
- license: MIT.
-- programmed in Pascal with [Lazarus](http://www.lazarus.freepascal.org).
-- based on *dmd* (*gdc* or *lmd* characteristics are not handled).
-- no other third part dependencies (so far...but using *dscanner* and/or *dcd* is envisaged.)
+- programmed in Pascal with [Lazarus](http://www.lazarus.freepascal.org) as IDE.
+- based on *dmd* (*gdc* or *lmd* switches are not handled).
Setup & test
------------
@@ -37,7 +38,8 @@ The complete procedure is described in the first section of the [wiki](https://g
Preview
-------
-Windows version:
+Windows version (Windows 7, x86):

-Linux version:
+
+Linux version (OpenSuse 13.1, x86_64):

\ No newline at end of file
diff --git a/lazproj/Gui.tease.kde.png b/lazproj/Gui.tease.kde.png
index 5f876a29..578c2f6c 100644
Binary files a/lazproj/Gui.tease.kde.png and b/lazproj/Gui.tease.kde.png differ
diff --git a/lazproj/Gui.tease.png b/lazproj/Gui.tease.png
index 973549b8..4a919eed 100644
Binary files a/lazproj/Gui.tease.png and b/lazproj/Gui.tease.png differ
diff --git a/lazproj/coedit.lpi b/lazproj/coedit.lpi
index 97aab566..9dbad959 100644
--- a/lazproj/coedit.lpi
+++ b/lazproj/coedit.lpi
@@ -135,7 +135,7 @@
-
+
@@ -271,6 +271,11 @@
+
+
+
+
+
diff --git a/lazproj/coedit.lpr b/lazproj/coedit.lpr
index 04e1fe75..e6cb7d5a 100644
--- a/lazproj/coedit.lpr
+++ b/lazproj/coedit.lpr
@@ -7,7 +7,7 @@ uses
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, Forms, lazcontrols, runtimetypeinfocontrols, anchordockpkg,
- AnchorDocking, AnchorDockStorage, AnchorDockOptionsDlg, ce_main;
+ AnchorDocking, AnchorDockStorage, AnchorDockOptionsDlg, ce_main, ce_dcd;
{$R *.res}
diff --git a/src/ce_dcd.pas b/src/ce_dcd.pas
new file mode 100644
index 00000000..f68d6656
--- /dev/null
+++ b/src/ce_dcd.pas
@@ -0,0 +1,146 @@
+unit ce_dcd;
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, process, forms, strutils;
+
+(**
+ * Adds a folder of d sources for DCD.
+ *)
+procedure addDcdImport(const aFilename: string);
+(**
+ * gets a list of propositions for the identifier at aPosition in aFilename.
+ *)
+procedure getCompletion(const aFilename: string; aPosition: Integer; const list: TStrings);
+(**
+ * tries to get the DDoc comment for the identifier at aPosition in aFilename.
+ *)
+procedure getHint(const aFilename: string; aPosition: Integer; const list: TStrings);
+
+var
+ DCD_server: TProcess;
+ DCD_client: TProcess;
+ lines: TStringList;
+ dcdOn: boolean;
+
+implementation
+
+procedure lazyServerStart;
+begin
+ if not DCD_server.Running then
+ DCD_server.Execute;
+end;
+
+procedure addDcdImport(const aFilename: string);
+begin
+ if not dcdOn then exit;
+ //
+ if not DCD_server.Running then
+ DCD_server.Parameters.Add('-I'+ aFilename)
+ else if DCD_client <> nil then begin
+ DCD_client.Parameters.Clear;
+ DCD_client.Parameters.Add('-I'+ aFilename);
+ DCD_client.Execute;
+ end;
+end;
+
+procedure getCompletion(const aFilename: string; aPosition: Integer; const list: TStrings);
+var
+ i: NativeInt;
+ kind: Char;
+ item: string;
+begin
+ if not dcdOn then exit;
+ lazyServerStart;
+ //
+ DCD_client.Parameters.Clear;
+ DCD_client.Parameters.Add('-c');
+ DCD_client.Parameters.Add(intToStr(aPosition));
+ DCD_client.Parameters.Add(aFilename);
+ DCD_client.Execute;
+ //
+ lines.LoadFromStream(DCD_client.Output);
+ list.Clear;
+ for i := 1 to lines.Count-1 do
+ begin
+ item := lines.Strings[i];
+ kind := item[length(item)];
+ setLength(item, length(item)-2);
+ case kind of
+ 'c': item += ' (class) ';
+ 'i': item += ' (interface) ';
+ 's': item += ' (struct) ';
+ 'u': item += ' (union) ';
+ 'v': item += ' (variable) ';
+ 'm': item += ' (member) ';
+ 'k': item += ' (reserved word) ';
+ 'f': item += ' (function) ';
+ 'g': item += ' (enum) ';
+ 'e': item += ' (enum member) ';
+ 'P': item += ' (package) ';
+ 'M': item += ' (module) ';
+ 'a': item += ' (array) ';
+ 'A': item += ' (associative array)';
+ 'l': item += ' (alias) ';
+ 't': item += ' (template) ';
+ 'T': item += ' (mixin) ';
+ end;
+ list.Add(item);
+ end;
+end;
+
+procedure getHint(const aFilename: string; aPosition: Integer; const list: TStrings);
+var
+ i: Integer;
+ str: string;
+begin
+ if not dcdOn then exit;
+ lazyServerStart;
+ //
+ if DCD_client.Running then exit;
+
+ DCD_client.Parameters.Clear;
+ DCD_client.Parameters.Add('-c');
+ DCD_client.Parameters.Add(intToStr(aPosition));
+ DCD_client.Parameters.Add('-d');
+ DCD_client.Parameters.Add(aFilename);
+ DCD_client.Execute;
+ //
+ list.LoadFromStream(DCD_client.Output);
+ for i := 0 to list.Count-1 do
+ begin
+ str := list.Strings[i];
+ list.Strings[i] := ReplaceStr(str, '\n', '');
+ end;
+end;
+
+
+initialization
+ DCD_server := TProcess.Create(nil);
+ DCD_client := TProcess.Create(nil);
+ DCD_server.Executable := extractFilePath(application.ExeName) + directorySeparator
+ + 'dcd-server'{$IFDEF WINDOWS}+ '.exe'{$ENDIF};
+ DCD_client.Executable := extractFilePath(application.ExeName) + directorySeparator
+ + 'dcd-client'{$IFDEF WINDOWS}+ '.exe'{$ENDIF};
+ DCD_client.Options := [poUsePipes{$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
+ DCD_server.Options := [poUsePipes{$IFDEF WINDOWS}, poNewConsole{$ENDIF}];
+ DCD_client.ShowWindow := swoHIDE;
+ DCD_server.ShowWindow := swoHIDE;
+ dcdOn := fileExists(DCD_server.Executable) and fileExists(DCD_client.Executable);
+ lines := TStringList.Create;
+ {$IFDEF WINDOWS}
+ // phobos + runtime
+ {$ENDIF}
+ {$IFDEF POSIX}
+ // phobos + runtime
+ {$ENDIF}
+finalization
+ DCD_server.Active := false;
+ DCD_client.Active := false;
+ DCD_server.Free;
+ DCD_client.Free;
+ lines.Free;
+end.
+
diff --git a/src/ce_editor.lfm b/src/ce_editor.lfm
index f66539e6..9a5095c4 100644
--- a/src/ce_editor.lfm
+++ b/src/ce_editor.lfm
@@ -95,4 +95,17 @@ inherited CEEditorWidget: TCEEditorWidget
0000000000000000000000000000
}
end
+ object completion: TSynCompletion[4]
+ OnExecute = completionExecute
+ Position = 0
+ LinesInWindow = 6
+ SelectedColor = clHighlight
+ CaseSensitive = True
+ Width = 262
+ ShortCut = 16416
+ EndOfTokenChr = '()[].'
+ OnCodeCompletion = completionCodeCompletion
+ ExecCommandID = ecSynCompletionExecute
+ left = 96
+ end
end
diff --git a/src/ce_editor.pas b/src/ce_editor.pas
index a3e7e69b..1ed4d384 100644
--- a/src/ce_editor.pas
+++ b/src/ce_editor.pas
@@ -8,15 +8,23 @@ uses
Classes, SysUtils, FileUtil, ExtendedNotebook, Forms, Controls, lcltype,
Graphics, SynEditKeyCmds, ComCtrls, SynEditHighlighter, ExtCtrls, Menus,
SynEditHighlighterFoldBase, SynMacroRecorder, SynPluginSyncroEdit, SynEdit,
- SynHighlighterLFM, AnchorDocking, ce_widget, ce_d2syn, ce_synmemo, ce_dlang,
- ce_project;
+ SynHighlighterLFM, SynCompletion, AnchorDocking, ce_widget, ce_d2syn,
+ ce_synmemo, ce_dlang, ce_project, ce_common, types, ce_dcd;
type
+
+ { TCEEditorWidget }
+
TCEEditorWidget = class(TCEWidget)
imgList: TImageList;
PageControl: TExtendedNotebook;
macRecorder: TSynMacroRecorder;
editorStatus: TStatusBar;
+ completion: TSynCompletion;
+ procedure completionCodeCompletion(var Value: string; SourceValue: string;
+ var SourceStart, SourceEnd: TPoint; KeyChar: TUTF8Char; Shift: TShiftState
+ );
+ procedure completionExecute(Sender: TObject);
procedure PageControlChange(Sender: TObject);
procedure PageControlCloseTabClicked(Sender: TObject);
protected
@@ -39,12 +47,14 @@ type
function getEditor(index: NativeInt): TCESynMemo;
function getEditorCount: NativeInt;
function getEditorIndex: NativeInt;
+ procedure getCompletionList;
public
constructor create(aOwner: TComponent); override;
destructor destroy; override;
procedure addEditor;
procedure removeEditor(const aIndex: NativeInt);
procedure focusedEditorChanged;
+ function getEditorHint: string;
//
procedure projCompile(const aProject: TCEProject); override;
procedure projRun(const aProject: TCEProject); override;
@@ -55,6 +65,7 @@ type
property editorIndex: NativeInt read getEditorIndex;
end;
+
implementation
{$R *.lfm}
@@ -117,6 +128,7 @@ begin
curr := getCurrentEditor;
macRecorder.Editor := curr;
fSyncEdit.Editor := curr;
+ completion.Editor := curr;
//
if pageControl.ActivePageIndex <> -1 then
CEMainForm.docFocusedNotify(Self, pageControl.ActivePageIndex);
@@ -134,6 +146,19 @@ begin
focusedEditorChanged;
end;
+procedure TCEEditorWidget.completionExecute(Sender: TObject);
+begin
+ getCompletionList
+end;
+
+procedure TCEEditorWidget.completionCodeCompletion(var Value: string;
+ SourceValue: string; var SourceStart, SourceEnd: TPoint; KeyChar: TUTF8Char;
+ Shift: TShiftState);
+begin
+ // warning: '20' depends on ce_dcd, case knd of...
+ Value := Value[1..length(Value)-20];
+end;
+
procedure TCEEditorWidget.PageControlCloseTabClicked(Sender: TObject);
begin
// closeBtn not implemented (Win.)
@@ -219,6 +244,84 @@ begin
stopUpdateByDelay;
end;
+procedure TCEEditorWidget.getCompletionList;
+var
+ curr: TCESynMemo;
+ str: TMemoryStream;
+ srcpos, i: NativeInt;
+ fname: string;
+begin
+ if not dcdOn then exit;
+ //
+ curr := getCurrentEditor;
+ if curr = nil then exit;
+ //
+ str := TMemoryStream.Create;
+ try
+ completion.Position := 0; // previous index could cause an error here.
+ fname := GetTempDir(false) + 'temp_' + uniqueObjStr(curr) + '.d';
+ curr.Lines.SaveToStream(str);
+ str.SaveToFile(fname);
+ try
+ srcpos := 0;
+ for i := 0 to curr.LogicalCaretXY.y-2 do
+ begin
+ srcPos += length(curr.Lines.Strings[i]);
+ if curr.LogicalCaretXY.y <> 0 then
+ srcPos += length(LineEnding);
+ end;
+ srcpos += curr.LogicalCaretXY.x -1;
+ completion.ItemList.Clear;
+ ce_dcd.getCompletion(fname, srcpos, completion.ItemList);
+ finally
+ DeleteFile(fname);
+ end;
+ finally
+ str.Free;
+ end;
+end;
+
+function TCEEditorWidget.getEditorHint: string;
+var
+ curr: TCESynMemo;
+ str: TMemoryStream;
+ lst: TStringList;
+ srcpos, i: NativeInt;
+ fname: string;
+begin
+ result := '';
+ if not dcdOn then exit;
+ //
+ curr := getCurrentEditor;
+ if curr = nil then exit;
+ //
+ str := TMemoryStream.Create;
+ lst := TStringList.Create;
+ try
+ fname := GetTempDir(false) + 'temp_' + uniqueObjStr(curr) + '.d';
+ curr.Lines.SaveToStream(str);
+ try
+ str.SaveToFile(fname);
+ srcpos := 0;
+ for i := 0 to curr.LogicalCaretXY.y-2 do
+ begin
+ srcPos += length(curr.Lines.Strings[i]);
+ if curr.LogicalCaretXY.y <> 0 then
+ srcPos += length(LineEnding);
+ end;
+ srcpos += curr.LogicalCaretXY.x -1;
+ if curr.GetWordAtRowCol(curr.LogicalCaretXY) <> '' then
+ ce_dcd.getHint(fname, srcpos, lst);
+ result := lst.Text;
+ finally
+ DeleteFile(fname);
+ end;
+ finally
+ str.Free;
+ lst.Free;
+ end;
+end;
+
procedure TCEEditorWidget.UpdateByEvent;
const
modstr: array[boolean] of string = ('...', 'MODIFIED');
@@ -276,4 +379,3 @@ begin
end;
end.
-
diff --git a/src/ce_libman.pas b/src/ce_libman.pas
index cceae002..06aaffdf 100644
--- a/src/ce_libman.pas
+++ b/src/ce_libman.pas
@@ -5,7 +5,7 @@ unit ce_libman;
interface
uses
- Classes, SysUtils, ce_common;
+ Classes, SysUtils, ce_common, ce_dcd;
type
@@ -25,7 +25,7 @@ type
end;
(**
- * Represents all the D library present on this system.
+ * Represents all the D libraries present on this system.
*)
TLibraryManager = class(TComponent)
private
@@ -46,6 +46,8 @@ type
//
procedure loadFromFile(const aFilename: string);
procedure saveToFile(const aFilename: string);
+ //
+ procedure updateDCD;
end;
implementation
@@ -67,6 +69,20 @@ begin
fCol.assign(aValue);
end;
+procedure TLibraryManager.updateDCD;
+var
+ itm: TCollectionItem;
+ itmt: TLibraryItem;
+begin
+ if not dcdOn then exit;
+ //
+ for itm in fCol do
+ begin
+ itmt := TLibraryItem(itm);
+ ce_dcd.addDcdImport(itmt.libSourcePath);
+ end;
+end;
+
procedure TLibraryManager.getAdditionalSources(const someAliases, aList: TStrings);
var
itm: TCollectionItem;
@@ -77,7 +93,8 @@ begin
for itm in fCol do
begin
itmt := TLibraryItem(itm);
- if someAliases.IndexOf(itmt.libAlias) = -1 then continue;
+ if someAliases <> nil then
+ if someAliases.IndexOf(itmt.libAlias) = -1 then continue;
//
srcs := TStringList.Create;
try
@@ -103,7 +120,8 @@ begin
for itm in fCol do
begin
itmt := TLibraryItem(itm);
- if someAliases.IndexOf(itmt.libAlias) = -1 then continue;
+ if someAliases <> nil then
+ if someAliases.IndexOf(itmt.libAlias) = -1 then continue;
//
if aList.IndexOf(itmt.libFile) <> -1 then continue;
aList.Add('-I' + itmt.libFile);
@@ -126,6 +144,7 @@ end;
procedure TLibraryManager.loadFromFile(const aFilename: string);
begin
loadCompFromTxtFile(self, aFilename, @readerPropNoFound, @readerError);
+ updateDCD;
end;
procedure TLibraryManager.saveToFile(const aFilename: string);
diff --git a/src/ce_libmaneditor.pas b/src/ce_libmaneditor.pas
index c5648a2d..ba800037 100644
--- a/src/ce_libmaneditor.pas
+++ b/src/ce_libmaneditor.pas
@@ -163,6 +163,7 @@ begin
itm.libFile := row.SubItems.Strings[0];
itm.libSourcePath := row.SubItems.Strings[1];
end;
+ LibraryManager.updateDCD;
end;
end;
diff --git a/src/ce_main.lfm b/src/ce_main.lfm
index 17dde080..eeb50b6b 100644
--- a/src/ce_main.lfm
+++ b/src/ce_main.lfm
@@ -2912,10 +2912,11 @@ object CEMainForm: TCEMainForm
}
end
object ApplicationProperties1: TApplicationProperties
- HintHidePause = 1000
- HintPause = 25
- HintShortPause = 8
+ HintHidePause = 4000
+ HintPause = 100
+ HintShortPause = 50
OnException = ApplicationProperties1Exception
+ OnShowHint = ApplicationProperties1ShowHint
left = 96
end
object LfmSyn: TSynLFMSyn
diff --git a/src/ce_main.pas b/src/ce_main.pas
index aa592354..722b2a87 100644
--- a/src/ce_main.pas
+++ b/src/ce_main.pas
@@ -7,10 +7,10 @@ interface
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_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;
+ Dialogs, Menus, ActnList, ExtCtrls, process, XMLPropStorage, ComCtrls, dynlibs,
+ ce_common, ce_dmdwrap, ce_project, ce_dcd, ce_plugin, ce_synmemo, ce_widget,
+ ce_messages, ce_widgettypes, ce_editor, ce_projinspect, ce_projconf, ce_search,
+ ce_staticexplorer, ce_miniexplorer, ce_libman, ce_libmaneditor;
type
@@ -194,6 +194,8 @@ type
procedure actProjSourceExecute(Sender: TObject);
procedure actEdUnIndentExecute(Sender: TObject);
procedure ApplicationProperties1Exception(Sender: TObject; E: Exception);
+ procedure ApplicationProperties1ShowHint(var HintStr: string;
+ var CanShow: Boolean; var HintInfo: THintInfo);
procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
private
@@ -708,6 +710,15 @@ begin
//
srcLst.Clear;
end;
+
+procedure TCEMainForm.ApplicationProperties1ShowHint(var HintStr: string;
+ var CanShow: Boolean; var HintInfo: THintInfo);
+begin
+ CanShow := true;
+ if EditWidget.currentEditor <> nil then
+ if EditWidget.currentEditor.Focused then
+ HintStr := EditWidget.getEditorHint;
+end;
{$ENDREGION}
{$REGION file ------------------------------------------------------------------}
@@ -1098,6 +1109,8 @@ begin
dmdproc.Parameters.Add('-w');
dmdproc.Parameters.Add('-wi');
dmdproc.Parameters.Add('-of' + fname {$IFDEF WINDOWS}+ '.exe'{$ENDIF});
+ LibraryManager.getAdditionalSources(nil, dmdproc.Parameters);
+ LibraryManager.getAdditionalImport(nil, dmdproc.Parameters);
dmdproc.Execute;
repeat ProcessOutputToMsg(dmdproc, mcEditor) until not dmdproc.Running;
if (dmdProc.ExitStatus = 0) then
diff --git a/src/ce_staticexplorer.pas b/src/ce_staticexplorer.pas
index 2d9e7420..dc26a609 100644
--- a/src/ce_staticexplorer.pas
+++ b/src/ce_staticexplorer.pas
@@ -395,10 +395,11 @@ begin
dmdproc.Parameters.Add('-I' + fProj.getAbsoluteSourceName(i));
for nme in fProj.currentConfiguration.pathsOptions.Includes do
dmdproc.Parameters.Add('-I' + nme);
- with CEMainForm do begin
- Librarymanager.getAdditionalSources( fProj.LibraryAliases, dmdproc.Parameters);
- Librarymanager.getAdditionalImport( fProj.LibraryAliases, dmdproc.Parameters);
- end;
+ end;
+ //adds all the libman entries
+ with CEMainForm do begin
+ Librarymanager.getAdditionalSources(nil, dmdproc.Parameters);
+ Librarymanager.getAdditionalImport(nil, dmdproc.Parameters);
end;
//
dmdproc.Execute;
diff --git a/src/ce_synmemo.pas b/src/ce_synmemo.pas
index dcbf6640..81cd6bce 100644
--- a/src/ce_synmemo.pas
+++ b/src/ce_synmemo.pas
@@ -50,7 +50,7 @@ var
implementation
uses
- graphics, ce_main, forms, ExtendedNotebook, comctrls;
+ graphics, ce_main, forms;
constructor TCESynMemo.Create(aOwner: TComponent);
begin
@@ -74,7 +74,7 @@ begin
//
fFilename := '';
fModified := false;
-
+ ShowHint := true;
TextBuffer.AddNotifyHandler(senrUndoRedoAdded, @changeNotify);
end;