diff --git a/lazproj/coedit.lpi b/lazproj/coedit.lpi
index 4a164a90..82a73a3e 100644
--- a/lazproj/coedit.lpi
+++ b/lazproj/coedit.lpi
@@ -135,7 +135,7 @@
-
+
@@ -356,6 +356,10 @@
+
+
+
+
diff --git a/lazproj/coedit.lpr b/lazproj/coedit.lpr
index 876402f1..b6d2f23b 100644
--- a/lazproj/coedit.lpr
+++ b/lazproj/coedit.lpr
@@ -10,7 +10,7 @@ uses
ce_observer, ce_libman, ce_tools, ce_dcd, ce_main, ce_writableComponent,
ce_symstring, ce_staticmacro, ce_inspectors, ce_editoroptions, ce_dockoptions,
ce_shortcutseditor, ce_mru, ce_processes, ce_dubproject, ce_dialogs,
-ce_dubprojeditor;
+ce_dubprojeditor, ce_dast;
{$R *.res}
diff --git a/src/ce_dast.pas b/src/ce_dast.pas
new file mode 100644
index 00000000..b0d42138
--- /dev/null
+++ b/src/ce_dast.pas
@@ -0,0 +1,76 @@
+unit ce_dast;
+
+{$I ce_defines.inc}
+
+interface
+
+uses
+ dynlibs, forms;
+
+type
+
+ TAstHandle = type NativeInt;
+
+ TAstNotification = procedure(param: Pointer); cdecl;
+
+ {$Z1}
+ TSerializationFormat = (json, pas);
+
+ // Returns an ID to a D AST. clbsk is the proc called with param when scanning is achieved.
+ TNewAst = function(param: Pointer; clbck: TAstNotification): TAstHandle; cdecl;
+ // Deletes the D AST identified by hdl.
+ TDeleteAst = procedure(hdl: TAstHandle); cdecl;
+
+ // Uses D AST identified by hsdl to parse filename.
+ TScanFile = procedure(hdl: TAstHandle; filename: PChar); cdecl;
+ // Uses D AST identified by hsdl to parse the buffer of length len.
+ TScanBuffer = procedure(hdl: TAstHandle; buffer: PByte; len: NativeUint); cdecl;
+
+ // Returns the name of the module identified by hdl.
+ TModuleName = function(hdl: TAstHandle): PChar; cdecl;
+ // Returns the list of the declarations in the module identified by hdl.
+ TSymbolList = function(hdl: TAstHandle; var len: NativeUint ; fmt: TSerializationFormat): PByte; cdecl;
+
+var
+ newAST: TNewAst;
+ deleteAST: TDeleteAst;
+ scanFile: TScanFile;
+ scanBuffer: TScanBuffer;
+ moduleName: TModuleName;
+ symbolList: TSymbolList;
+ dastAvailable: boolean;
+
+
+implementation
+
+var
+ dastHdl: TLibHandle;
+
+initialization
+
+ if application.GetOptionValue('cedast') = 'off' then
+ exit;
+
+ dastHdl := LoadLibrary('cedast');
+ if dastHdl <> NilHandle then
+ begin
+ newAST := TNewAst(GetProcAddress(dastHdl, 'newAst'));
+ deleteAST := TDeleteAst(GetProcAddress(dastHdl, 'deleteAst'));
+ scanFile := TScanFile(GetProcAddress(dastHdl, 'scanFile'));
+ scanBuffer := TScanBuffer(GetProcAddress(dastHdl, 'scanBuffer'));
+ moduleName := TModuleName(GetProcAddress(dastHdl, 'moduleName'));
+ symbolList := TSymbolList(GetProcAddress(dastHdl, 'symbolList'));
+ symbolList := TSymbolList(GetProcAddress(dastHdl, 'symbolList'));
+ //
+ dastAvailable := assigned(newAST) and assigned(deleteAST) and assigned(scanFile)
+ and assigned(scanBuffer) and assigned(moduleName) and assigned(symbolList);
+ end;
+
+
+finalization
+ {$IFDEF RELEASE}
+ if dastHdl <> NilHandle then
+ UnloadLibrary(dastHdl);
+ {$ENDIF}
+end.
+
diff --git a/src/ce_editor.pas b/src/ce_editor.pas
index 390f4c34..efa6cc27 100644
--- a/src/ce_editor.pas
+++ b/src/ce_editor.pas
@@ -6,7 +6,7 @@ interface
uses
Classes, SysUtils, FileUtil, ExtendedNotebook, Forms, Controls, lcltype,
- Graphics, SynEditKeyCmds, ComCtrls, SynEditHighlighter, ExtCtrls, Menus,
+ Graphics, SynEditKeyCmds, ComCtrls, SynEditHighlighter, ExtCtrls, Menus, ce_dast,
SynMacroRecorder, SynPluginSyncroEdit, SynEdit, SynHighlighterMulti, ce_dialogs,
ce_widget, ce_interfaces, ce_synmemo, ce_dlang, ce_common, ce_dcd, ce_observer;
@@ -43,7 +43,6 @@ type
procedure mnuedJum2DeclClick(Sender: TObject);
procedure PageControlChange(Sender: TObject);
protected
- procedure updateDelayed; override;
procedure updateImperative; override;
private
fKeyChanged: boolean;
@@ -172,8 +171,6 @@ begin
fDoc := aDoc;
pageControl.ActivePage := sheet;
focusedEditorChanged;
- beginDelayedUpdate;
- updateImperative;
end;
procedure TCEEditorWidget.docClosing(aDoc: TCESynMemo);
@@ -195,16 +192,16 @@ begin
if aDoc = fDoc then exit;
fDoc := aDoc;
focusedEditorChanged;
- beginDelayedUpdate;
- updateImperative;
+ beginImperativeUpdate;
+ endImperativeUpdate;
end;
procedure TCEEditorWidget.docChanged(aDoc: TCESynMemo);
begin
if fDoc <> aDoc then exit;
fKeyChanged := true;
- beginDelayedUpdate;
- updateImperative;
+ beginImperativeUpdate;
+ endImperativeUpdate;
end;
{$ENDREGION}
@@ -281,23 +278,28 @@ begin
if (pageControl.ActivePage.Caption = '') then
begin
fKeyChanged := true;
- beginDelayedUpdate;
+ beginImperativeUpdate;
+ endImperativeUpdate;
end;
end;
procedure TCEEditorWidget.PageControlChange(Sender: TObject);
begin
- updateImperative;
+ beginImperativeUpdate;
+ endImperativeUpdate;
end;
procedure TCEEditorWidget.memoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
case Key of
VK_CLEAR,VK_RETURN,VK_BACK : fKeyChanged := true;
- VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT: updateImperative;
+ VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT: fKeyChanged := true;
end;
if fKeyChanged then
- beginDelayedUpdate
+ begin
+ beginImperativeUpdate;
+ endImperativeUpdate;
+ end
else if (Key = VK_UP) and (shift = [ssShift,ssCtrl]) then
getSymbolLoc;
end;
@@ -317,19 +319,21 @@ end;
procedure TCEEditorWidget.memoKeyPress(Sender: TObject; var Key: char);
begin
fKeyChanged := true;
- beginDelayedUpdate;
+ beginImperativeUpdate;
+ endImperativeUpdate;
end;
procedure TCEEditorWidget.memoMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
- beginDelayedUpdate;
- updateImperative;
+ beginImperativeUpdate;
+ endImperativeUpdate;
end;
procedure TCEEditorWidget.memoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
if not (ssLeft in Shift) then exit;
- beginDelayedUpdate;
+ beginImperativeUpdate;
+ endImperativeUpdate;
end;
procedure TCEEditorWidget.memoCtrlClick(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
@@ -372,8 +376,8 @@ end;
procedure TCEEditorWidget.updateImperative;
const
modstr: array[boolean] of string = ('...', 'MODIFIED');
-//var
- //md: string;
+var
+ md: string;
begin
if fDoc = nil then begin
editorStatus.Panels[0].Text := '';
@@ -383,19 +387,16 @@ begin
editorStatus.Panels[0].Text := format('%d : %d | %d', [fDoc.CaretY, fDoc.CaretX, fDoc.SelEnd - fDoc.SelStart]);
editorStatus.Panels[1].Text := modstr[fDoc.modified];
editorStatus.Panels[2].Text := fDoc.fileName;
- // TODO-cEditor: set tab caption directly (e.g one start, if reload last docs)
- //if Visible then if pageControl.ActivePage <> nil then
- //if pageControl.ActivePage.Caption = '' then
- //begin
- // if fDoc.isDSource then
- // begin
- // lex(fDoc.Lines.Text, fTokList, @lexFindToken);
- // md := getModuleName(fTokList);
- // fTokList.Clear;
- // end;
- // if md = '' then md := extractFileName(fDoc.fileName);
- // pageControl.ActivePage.Caption := md;
- //end;
+ if fKeyChanged then
+ begin
+ md := '';
+ if fDoc.isDSource and (fDoc.ast <> 0) then
+ md := moduleName(fDoc.ast);
+ if md = '' then
+ md := extractFileName(fDoc.fileName);
+ pageControl.ActivePage.Caption := md;
+ end;
+ fKeyChanged := false;
end;
end;
@@ -410,37 +411,6 @@ begin
fModStart := false;
end;
end;
-
-procedure TCEEditorWidget.updateDelayed;
-var
- md: string;
-begin
- if fDoc = nil then exit;
- updateImperative;
- if not fKeyChanged then exit;
- //
- fKeyChanged := false;
- if fDoc.Lines.Count = 0 then exit;
- //
- md := '';
- if fDoc.isDSource then
- begin
- fTokList.Clear;
- lex(fDoc.Lines.Text, fTokList, @lexFindToken);
- md := getModuleName(fTokList);
- end;
- if md = '' then md := extractFileName(fDoc.fileName);
- pageControl.ActivePage.Caption := md;
- //
- fTokList.Clear;
- fErrList.Clear;
- // when a widget saves a temp file & syncro mode is on:
- // - editor is saved
- // - gutter is updated (green bar indicating a saved block)
- // - syncroedit icon is hidden
- if fDoc.syncroEdit.Active then
- fDoc.Refresh;
-end;
{$ENDREGION}
{$REGION Editor context menu ---------------------------------------------------}
diff --git a/src/ce_synmemo.pas b/src/ce_synmemo.pas
index 4ae41a13..dd5e30e7 100644
--- a/src/ce_synmemo.pas
+++ b/src/ce_synmemo.pas
@@ -8,7 +8,8 @@ uses
Classes, SysUtils, controls,lcltype, Forms, graphics, ExtCtrls, crc,
SynPluginSyncroEdit, SynCompletion, SynEditKeyCmds, LazSynEditText, SynEdit,
SynHighlighterLFM, SynEditHighlighter, SynEditMouseCmds, SynEditFoldedView,
- ce_common, ce_observer, ce_writableComponent, ce_d2syn, ce_txtsyn, ce_dialogs;
+ ce_common, ce_observer, ce_writableComponent, ce_d2syn, ce_txtsyn, ce_dialogs,
+ ce_dast;
type
@@ -77,6 +78,9 @@ type
TCESynMemo = class(TSynEdit)
private
+ fScanning: boolean;
+ fCanScan: boolean;
+ fAst: TAstHandle;
fFilename: string;
fModified: boolean;
fFileDate: double;
@@ -94,6 +98,7 @@ type
fHintDelay: Integer;
fAutoDotDelay: Integer;
fHintTimer: TIdleTimer;
+ fAstTimer: TIdleTimer;
fAutoDotTimer: TIdleTimer;
fCanShowHint: boolean;
fCanAutoDot: boolean;
@@ -103,6 +108,8 @@ type
fCompletion: TSynCompletion;
fD2Highlighter: TSynD2Syn;
fTxtHighlighter: TSynTxtSyn;
+ function getIfScanning: boolean;
+ function getAstHandle: TAstHandle;
function getMouseFileBytePos: Integer;
procedure changeNotify(Sender: TObject);
procedure identifierToD2Syn;
@@ -111,6 +118,7 @@ type
class procedure cleanCache; static;
procedure setDefaultFontSize(aValue: Integer);
procedure getCallTips;
+ procedure AstTimerEvent(sender: TObject);
procedure HintTimerEvent(sender: TObject);
procedure AutoDotTimerEvent(sender: TObject);
procedure InitHintWins;
@@ -161,6 +169,7 @@ type
property isProjectSource: boolean read fIsConfig;
property isTemporary: boolean read getIfTemp;
property TextView;
+ property ast: TAstHandle read GetAstHandle;
//
property MouseStart: Integer read getMouseFileBytePos;
property D2Highlighter: TSynD2Syn read fD2Highlighter;
@@ -169,6 +178,8 @@ type
procedure SetDefaultCoeditKeystrokes(ed: TSynEdit);
+ procedure astScanned(param: pointer); cdecl;
+
var
D2Syn: TSynD2Syn; // used as model to set the options when no editor exists.
LfmSyn: TSynLfmSyn;
@@ -179,12 +190,6 @@ implementation
uses
ce_interfaces, ce_staticmacro, ce_dcd, SynEditHighlighterFoldBase;
-function TCEEditorHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: String; AData: Pointer): TRect;
-begin
- Font.Size:= FontSize;
- result := inherited CalcHintRect(MaxWidth, AHint, AData);
-end;
-
{$REGION TCESynMemoCache -------------------------------------------------------}
constructor TCESynMemoCache.create(aComponent: TComponent);
begin
@@ -365,6 +370,12 @@ begin
fDefaultFontSize := 10;
SetDefaultCoeditKeystrokes(Self); // not called in inherited if owner = nil !
//
+ fAst := newAST(self, @astScanned);
+ fAstTimer := TIdleTimer.Create(self);
+ fAstTimer.Interval:= 2000;
+ fAstTimer.OnTimer:= @AstTimerEvent;
+ fAstTimer.Enabled:=true;
+ //
ShowHint := false;
InitHintWins;
fHintDelay := 200;
@@ -441,6 +452,8 @@ begin
if fileExists(fTempFileName) then
sysutils.DeleteFile(fTempFileName);
//
+ deleteAst(fAst);
+ //
inherited;
end;
@@ -583,7 +596,50 @@ begin
end;
end;
+{$REGION AST Scanner -----------------------------------------------------------}
+procedure astScanned(param: pointer); cdecl;
+begin
+ with TCESynMemo(param) do
+ begin
+ fScanning := false;
+ end;
+end;
+
+function TCESynMemo.getAstHandle: TAstHandle;
+begin
+ if getIfScanning then result := 0
+ else result := fAst;
+end;
+
+function TCESynMemo.getIfScanning: boolean;
+begin
+ exit(fScanning);
+end;
+
+procedure TCESynMemo.AstTimerEvent(sender: TObject);
+var
+ buff: string;
+ len: NativeUint;
+begin
+ if not fCanScan then exit;
+ fCanScan := false;
+ if fAst = 0 then exit;
+ //
+ buff := Lines.Text;
+ len := length(buff);
+ if len = 0 then exit;
+ fScanning := true;
+ scanBuffer(fast, @buff[1], len);
+end;
+{$ENDREGION --------------------------------------------------------------------}
+
{$REGION DDoc hints ------------------------------------------------------------}
+function TCEEditorHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: String; AData: Pointer): TRect;
+begin
+ Font.Size:= FontSize;
+ result := inherited CalcHintRect(MaxWidth, AHint, AData);
+end;
+
procedure TCESynMemo.InitHintWins;
begin
if fCallTipWin = nil then begin
@@ -723,6 +779,7 @@ procedure TCESynMemo.changeNotify(Sender: TObject);
begin
identifierToD2Syn;
fModified := true;
+ fCanScan := true;
fPositions.store;
subjDocChanged(TCEMultiDocSubject(fMultiDocSubject), self);
end;