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;