This commit is contained in:
Basile Burg 2015-09-15 14:00:23 +02:00
parent 2a9fb832bc
commit 3ac5fef89b
5 changed files with 178 additions and 71 deletions

View File

@ -135,7 +135,7 @@
<PackageName Value="LCL"/>
</Item6>
</RequiredPackages>
<Units Count="42">
<Units Count="43">
<Unit0>
<Filename Value="coedit.lpr"/>
<IsPartOfProject Value="True"/>
@ -356,6 +356,10 @@
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
</Unit41>
<Unit42>
<Filename Value="..\src\ce_dast.pas"/>
<IsPartOfProject Value="True"/>
</Unit42>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

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

76
src/ce_dast.pas Normal file
View File

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

View File

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

View File

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