support for DCD

This commit is contained in:
Basile Burg 2014-08-04 03:32:55 +02:00
parent 5ca6cf53f0
commit 54d7f8902d
14 changed files with 337 additions and 34 deletions

View File

@ -12,23 +12,24 @@ Current features
- instant run (without saving, script-like). - instant run (without saving, script-like).
- synchronized edition in a block. - synchronized edition in a block.
- D syntax highlighter, folding, identifier markup. - D syntax highlighter, folding, identifier markup.
- current module member list. - member list of the current module.
- manager for the static libraries.
- search and replace. - 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 Missing features before the first beta
------------------- --------------------------------------
- project configurations templates (release, debug, etc.). - Options editor. (the big missing stuff)
- basic auto completion (brackets, key-words, ...). - console input handling. (workarounds exists)
- console input handling. - project configurations templates (release, debug, etc.). (detail)
- static library explorer (using JSON infos).
Project information Project information
------------------- -------------------
- state: alpha 4. - state: alpha 4.
- license: MIT. - license: MIT.
- programmed in Pascal with [Lazarus](http://www.lazarus.freepascal.org). - programmed in Pascal with [Lazarus](http://www.lazarus.freepascal.org) as IDE.
- based on *dmd* (*gdc* or *lmd* characteristics are not handled). - based on *dmd* (*gdc* or *lmd* switches are not handled).
- no other third part dependencies (so far...but using *dscanner* and/or *dcd* is envisaged.)
Setup & test Setup & test
------------ ------------
@ -37,7 +38,8 @@ The complete procedure is described in the first section of the [wiki](https://g
Preview Preview
------- -------
Windows version: Windows version (Windows 7, x86):
![Win screen-cap](lazproj/Gui.tease.png "Coedit GUI preview") ![Win screen-cap](lazproj/Gui.tease.png "Coedit GUI preview")
Linux version:
Linux version (OpenSuse 13.1, x86_64):
![Nux screen-cap](lazproj/Gui.tease.kde.png "Coedit GUI preview") ![Nux screen-cap](lazproj/Gui.tease.kde.png "Coedit GUI preview")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 124 KiB

View File

@ -135,7 +135,7 @@
<PackageName Value="LCL"/> <PackageName Value="LCL"/>
</Item6> </Item6>
</RequiredPackages> </RequiredPackages>
<Units Count="21"> <Units Count="22">
<Unit0> <Unit0>
<Filename Value="coedit.lpr"/> <Filename Value="coedit.lpr"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
@ -271,6 +271,11 @@
<ResourceBaseClass Value="Form"/> <ResourceBaseClass Value="Form"/>
<UnitName Value="ce_libmaneditor"/> <UnitName Value="ce_libmaneditor"/>
</Unit20> </Unit20>
<Unit21>
<Filename Value="..\src\ce_dcd.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ce_dcd"/>
</Unit21>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

View File

@ -7,7 +7,7 @@ uses
cthreads, cthreads,
{$ENDIF}{$ENDIF} {$ENDIF}{$ENDIF}
Interfaces, Forms, lazcontrols, runtimetypeinfocontrols, anchordockpkg, Interfaces, Forms, lazcontrols, runtimetypeinfocontrols, anchordockpkg,
AnchorDocking, AnchorDockStorage, AnchorDockOptionsDlg, ce_main; AnchorDocking, AnchorDockStorage, AnchorDockOptionsDlg, ce_main, ce_dcd;
{$R *.res} {$R *.res}

146
src/ce_dcd.pas Normal file
View File

@ -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.

View File

@ -95,4 +95,17 @@ inherited CEEditorWidget: TCEEditorWidget
0000000000000000000000000000 0000000000000000000000000000
} }
end 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 end

View File

@ -8,15 +8,23 @@ uses
Classes, SysUtils, FileUtil, ExtendedNotebook, Forms, Controls, lcltype, Classes, SysUtils, FileUtil, ExtendedNotebook, Forms, Controls, lcltype,
Graphics, SynEditKeyCmds, ComCtrls, SynEditHighlighter, ExtCtrls, Menus, Graphics, SynEditKeyCmds, ComCtrls, SynEditHighlighter, ExtCtrls, Menus,
SynEditHighlighterFoldBase, SynMacroRecorder, SynPluginSyncroEdit, SynEdit, SynEditHighlighterFoldBase, SynMacroRecorder, SynPluginSyncroEdit, SynEdit,
SynHighlighterLFM, AnchorDocking, ce_widget, ce_d2syn, ce_synmemo, ce_dlang, SynHighlighterLFM, SynCompletion, AnchorDocking, ce_widget, ce_d2syn,
ce_project; ce_synmemo, ce_dlang, ce_project, ce_common, types, ce_dcd;
type type
{ TCEEditorWidget }
TCEEditorWidget = class(TCEWidget) TCEEditorWidget = class(TCEWidget)
imgList: TImageList; imgList: TImageList;
PageControl: TExtendedNotebook; PageControl: TExtendedNotebook;
macRecorder: TSynMacroRecorder; macRecorder: TSynMacroRecorder;
editorStatus: TStatusBar; 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 PageControlChange(Sender: TObject);
procedure PageControlCloseTabClicked(Sender: TObject); procedure PageControlCloseTabClicked(Sender: TObject);
protected protected
@ -39,12 +47,14 @@ type
function getEditor(index: NativeInt): TCESynMemo; function getEditor(index: NativeInt): TCESynMemo;
function getEditorCount: NativeInt; function getEditorCount: NativeInt;
function getEditorIndex: NativeInt; function getEditorIndex: NativeInt;
procedure getCompletionList;
public public
constructor create(aOwner: TComponent); override; constructor create(aOwner: TComponent); override;
destructor destroy; override; destructor destroy; override;
procedure addEditor; procedure addEditor;
procedure removeEditor(const aIndex: NativeInt); procedure removeEditor(const aIndex: NativeInt);
procedure focusedEditorChanged; procedure focusedEditorChanged;
function getEditorHint: string;
// //
procedure projCompile(const aProject: TCEProject); override; procedure projCompile(const aProject: TCEProject); override;
procedure projRun(const aProject: TCEProject); override; procedure projRun(const aProject: TCEProject); override;
@ -55,6 +65,7 @@ type
property editorIndex: NativeInt read getEditorIndex; property editorIndex: NativeInt read getEditorIndex;
end; end;
implementation implementation
{$R *.lfm} {$R *.lfm}
@ -117,6 +128,7 @@ begin
curr := getCurrentEditor; curr := getCurrentEditor;
macRecorder.Editor := curr; macRecorder.Editor := curr;
fSyncEdit.Editor := curr; fSyncEdit.Editor := curr;
completion.Editor := curr;
// //
if pageControl.ActivePageIndex <> -1 then if pageControl.ActivePageIndex <> -1 then
CEMainForm.docFocusedNotify(Self, pageControl.ActivePageIndex); CEMainForm.docFocusedNotify(Self, pageControl.ActivePageIndex);
@ -134,6 +146,19 @@ begin
focusedEditorChanged; focusedEditorChanged;
end; 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); procedure TCEEditorWidget.PageControlCloseTabClicked(Sender: TObject);
begin begin
// closeBtn not implemented (Win.) // closeBtn not implemented (Win.)
@ -219,6 +244,84 @@ begin
stopUpdateByDelay; stopUpdateByDelay;
end; 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; procedure TCEEditorWidget.UpdateByEvent;
const const
modstr: array[boolean] of string = ('...', 'MODIFIED'); modstr: array[boolean] of string = ('...', 'MODIFIED');
@ -276,4 +379,3 @@ begin
end; end;
end. end.

View File

@ -5,7 +5,7 @@ unit ce_libman;
interface interface
uses uses
Classes, SysUtils, ce_common; Classes, SysUtils, ce_common, ce_dcd;
type type
@ -25,7 +25,7 @@ type
end; end;
(** (**
* Represents all the D library present on this system. * Represents all the D libraries present on this system.
*) *)
TLibraryManager = class(TComponent) TLibraryManager = class(TComponent)
private private
@ -46,6 +46,8 @@ type
// //
procedure loadFromFile(const aFilename: string); procedure loadFromFile(const aFilename: string);
procedure saveToFile(const aFilename: string); procedure saveToFile(const aFilename: string);
//
procedure updateDCD;
end; end;
implementation implementation
@ -67,6 +69,20 @@ begin
fCol.assign(aValue); fCol.assign(aValue);
end; 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); procedure TLibraryManager.getAdditionalSources(const someAliases, aList: TStrings);
var var
itm: TCollectionItem; itm: TCollectionItem;
@ -77,6 +93,7 @@ begin
for itm in fCol do for itm in fCol do
begin begin
itmt := TLibraryItem(itm); itmt := TLibraryItem(itm);
if someAliases <> nil then
if someAliases.IndexOf(itmt.libAlias) = -1 then continue; if someAliases.IndexOf(itmt.libAlias) = -1 then continue;
// //
srcs := TStringList.Create; srcs := TStringList.Create;
@ -103,6 +120,7 @@ begin
for itm in fCol do for itm in fCol do
begin begin
itmt := TLibraryItem(itm); itmt := TLibraryItem(itm);
if someAliases <> nil then
if someAliases.IndexOf(itmt.libAlias) = -1 then continue; if someAliases.IndexOf(itmt.libAlias) = -1 then continue;
// //
if aList.IndexOf(itmt.libFile) <> -1 then continue; if aList.IndexOf(itmt.libFile) <> -1 then continue;
@ -126,6 +144,7 @@ end;
procedure TLibraryManager.loadFromFile(const aFilename: string); procedure TLibraryManager.loadFromFile(const aFilename: string);
begin begin
loadCompFromTxtFile(self, aFilename, @readerPropNoFound, @readerError); loadCompFromTxtFile(self, aFilename, @readerPropNoFound, @readerError);
updateDCD;
end; end;
procedure TLibraryManager.saveToFile(const aFilename: string); procedure TLibraryManager.saveToFile(const aFilename: string);

View File

@ -163,6 +163,7 @@ begin
itm.libFile := row.SubItems.Strings[0]; itm.libFile := row.SubItems.Strings[0];
itm.libSourcePath := row.SubItems.Strings[1]; itm.libSourcePath := row.SubItems.Strings[1];
end; end;
LibraryManager.updateDCD;
end; end;
end; end;

View File

@ -2912,10 +2912,11 @@ object CEMainForm: TCEMainForm
} }
end end
object ApplicationProperties1: TApplicationProperties object ApplicationProperties1: TApplicationProperties
HintHidePause = 1000 HintHidePause = 4000
HintPause = 25 HintPause = 100
HintShortPause = 8 HintShortPause = 50
OnException = ApplicationProperties1Exception OnException = ApplicationProperties1Exception
OnShowHint = ApplicationProperties1ShowHint
left = 96 left = 96
end end
object LfmSyn: TSynLFMSyn object LfmSyn: TSynLFMSyn

View File

@ -7,10 +7,10 @@ interface
uses uses
Classes, SysUtils, FileUtil, SynEditKeyCmds, SynHighlighterLFM, Forms, Classes, SysUtils, FileUtil, SynEditKeyCmds, SynHighlighterLFM, Forms,
AnchorDocking, AnchorDockStorage, AnchorDockOptionsDlg, Controls, Graphics, AnchorDocking, AnchorDockStorage, AnchorDockOptionsDlg, Controls, Graphics,
Dialogs, Menus, ActnList, ExtCtrls, process, XMLPropStorage, ComCtrls, Dialogs, Menus, ActnList, ExtCtrls, process, XMLPropStorage, ComCtrls, dynlibs,
ce_common, ce_dmdwrap, ce_project, ce_plugin, ce_synmemo, ce_widget, ce_messages, ce_common, ce_dmdwrap, ce_project, ce_dcd, ce_plugin, ce_synmemo, ce_widget,
ce_widgettypes, ce_editor, ce_projinspect, ce_projconf, ce_staticexplorer, ce_search, ce_messages, ce_widgettypes, ce_editor, ce_projinspect, ce_projconf, ce_search,
ce_miniexplorer, dynlibs, ce_libman, ce_libmaneditor; ce_staticexplorer, ce_miniexplorer, ce_libman, ce_libmaneditor;
type type
@ -194,6 +194,8 @@ type
procedure actProjSourceExecute(Sender: TObject); procedure actProjSourceExecute(Sender: TObject);
procedure actEdUnIndentExecute(Sender: TObject); procedure actEdUnIndentExecute(Sender: TObject);
procedure ApplicationProperties1Exception(Sender: TObject; E: Exception); 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 FormCloseQuery(Sender: TObject; var CanClose: boolean);
procedure FormDropFiles(Sender: TObject; const FileNames: array of String); procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
private private
@ -708,6 +710,15 @@ begin
// //
srcLst.Clear; srcLst.Clear;
end; 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} {$ENDREGION}
{$REGION file ------------------------------------------------------------------} {$REGION file ------------------------------------------------------------------}
@ -1098,6 +1109,8 @@ begin
dmdproc.Parameters.Add('-w'); dmdproc.Parameters.Add('-w');
dmdproc.Parameters.Add('-wi'); dmdproc.Parameters.Add('-wi');
dmdproc.Parameters.Add('-of' + fname {$IFDEF WINDOWS}+ '.exe'{$ENDIF}); dmdproc.Parameters.Add('-of' + fname {$IFDEF WINDOWS}+ '.exe'{$ENDIF});
LibraryManager.getAdditionalSources(nil, dmdproc.Parameters);
LibraryManager.getAdditionalImport(nil, dmdproc.Parameters);
dmdproc.Execute; dmdproc.Execute;
repeat ProcessOutputToMsg(dmdproc, mcEditor) until not dmdproc.Running; repeat ProcessOutputToMsg(dmdproc, mcEditor) until not dmdproc.Running;
if (dmdProc.ExitStatus = 0) then if (dmdProc.ExitStatus = 0) then

View File

@ -395,10 +395,11 @@ begin
dmdproc.Parameters.Add('-I' + fProj.getAbsoluteSourceName(i)); dmdproc.Parameters.Add('-I' + fProj.getAbsoluteSourceName(i));
for nme in fProj.currentConfiguration.pathsOptions.Includes do for nme in fProj.currentConfiguration.pathsOptions.Includes do
dmdproc.Parameters.Add('-I' + nme); 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; end;
// //
dmdproc.Execute; dmdproc.Execute;

View File

@ -50,7 +50,7 @@ var
implementation implementation
uses uses
graphics, ce_main, forms, ExtendedNotebook, comctrls; graphics, ce_main, forms;
constructor TCESynMemo.Create(aOwner: TComponent); constructor TCESynMemo.Create(aOwner: TComponent);
begin begin
@ -74,7 +74,7 @@ begin
// //
fFilename := '<new document>'; fFilename := '<new document>';
fModified := false; fModified := false;
ShowHint := true;
TextBuffer.AddNotifyHandler(senrUndoRedoAdded, @changeNotify); TextBuffer.AddNotifyHandler(senrUndoRedoAdded, @changeNotify);
end; end;