IDE: auto indent: using SynEdit.OnPaste event

git-svn-id: trunk@22452 -
This commit is contained in:
mattias 2009-11-05 17:48:41 +00:00
parent c9f863d3a3
commit 166ccb9e94
2 changed files with 92 additions and 81 deletions

View File

@ -296,11 +296,13 @@ type
procedure ParseSource(const Src: string; StartPos, EndPos: integer;
NestedComments: boolean;
Stack: TFABBlockStack; Policies: TFABPolicies;
out LastAtomStart, LastAtomEnd: integer // set if LastAtomStart<EndPos<LastAtomEnd
out LastAtomStart, LastAtomEnd: integer; // set if LastAtomStart<EndPos<LastAtomEnd
LearnFromFirstLine: boolean = true
);
procedure ParseSource(const Src: string; StartPos, EndPos: integer;
NestedComments: boolean;
Stack: TFABBlockStack; Policies: TFABPolicies);
Stack: TFABBlockStack; Policies: TFABPolicies;
LearnFromFirstLine: boolean = true);
function FindPolicyInExamples(StartCode: TCodeBuffer;
ParentTyp, Typ: TFABBlockType): TFABPolicies;
function GetNestedCommentsForCode(Code: TCodeBuffer): boolean;
@ -316,7 +318,8 @@ type
function GetIndent(const Source: string; CleanPos: integer;
NewNestedComments: boolean; UseLineStart: boolean;
out Indent: TFABIndentationPolicy;
ContextLearn: boolean = true // true = learn policies from Source
ContextLearn: boolean = true; // true = learn policies from Source
const InsertText: string = ''
): boolean;
function GetIndents(const Source: string; Positions: TFABPositionIndents;
NewNestedComments: boolean; UseLineStart: boolean;
@ -438,11 +441,13 @@ end;
procedure TFullyAutomaticBeautifier.ParseSource(const Src: string;
StartPos, EndPos: integer; NestedComments: boolean; Stack: TFABBlockStack;
Policies: TFABPolicies; out LastAtomStart, LastAtomEnd: integer);
Policies: TFABPolicies; out LastAtomStart, LastAtomEnd: integer;
LearnFromFirstLine: boolean);
var
p: Integer;
AtomStart: integer;
FirstAtomOnNewLine: Boolean;
InFirstLine: boolean;
{$IFDEF ShowCodeBeautifierLearn}
function PosToStr(p: integer): string;
@ -484,7 +489,8 @@ var
and (Policies<>nil) then begin
if Block^.InnerIdent<0 then UpdateBlockInnerIndent;
if Block^.InnerIdent>=0 then begin
Policies.AddIndent(Block^.Typ,Typ,p,Block^.InnerIdent);
if LearnFromFirstLine or (not InFirstLine) then
Policies.AddIndent(Block^.Typ,Typ,p,Block^.InnerIdent);
{$IFDEF ShowCodeBeautifierLearn}
DebugLn([GetIndentStr(Stack.Top*2),'nested indentation learned ',FABBlockTypeNames[Block^.Typ],'/',FABBlockTypeNames[Typ],': ',GetAtomString(@Src[AtomStart],NestedComments),' at ',PosToStr(p),' Indent=',Block^.InnerIdent]);
{$ENDIF}
@ -642,10 +648,13 @@ begin
p:=StartPos;
if EndPos>length(Src) then EndPos:=length(Src)+1;
AtomStart:=p;
InFirstLine:=true;
repeat
LastAtomStart:=AtomStart;
LastAtomEnd:=p;
ReadRawNextPascalAtom(Src,p,AtomStart,NestedComments);
if InFirstLine and (not PositionsInSameLine(Src,LastAtomEnd,AtomStart)) then
InFirstLine:=false;
//DebugLn(['TFullyAutomaticBeautifier.ParseSource Atom=',copy(Src,AtomStart,p-AtomStart)]);
if p>EndPos then begin
if (AtomStart<EndPos) then begin
@ -1037,7 +1046,8 @@ begin
if FirstAtomOnNewLine then begin
UpdateBlockInnerIndent;
if Block^.InnerIdent>=0 then begin
if (Block^.InnerIdent>=0)
and (LearnFromFirstLine or (not InFirstLine)) then begin
Policies.AddIndent(Block^.Typ,bbtNone,p,Block^.InnerIdent);
{$IFDEF ShowCodeBeautifierLearn}
DebugLn([GetIndentStr(Stack.Top*2),'Indentation learned for statements: ',FABBlockTypeNames[Block^.Typ],' Indent=',Block^.InnerIdent,' at ',PosToStr(p)]);
@ -1049,12 +1059,12 @@ end;
procedure TFullyAutomaticBeautifier.ParseSource(const Src: string; StartPos,
EndPos: integer; NestedComments: boolean; Stack: TFABBlockStack;
Policies: TFABPolicies);
Policies: TFABPolicies; LearnFromFirstLine: boolean);
var
LastAtomStart, LastAtomEnd: integer;
begin
ParseSource(Src,StartPos,EndPos,NestedComments,Stack,Policies,
LastAtomStart,LastAtomEnd);
LastAtomStart,LastAtomEnd,LearnFromFirstLine);
end;
function TFullyAutomaticBeautifier.FindPolicyInExamples(StartCode: TCodeBuffer;
@ -1406,7 +1416,7 @@ end;
function TFullyAutomaticBeautifier.GetIndent(const Source: string;
CleanPos: integer; NewNestedComments: boolean;
UseLineStart: boolean; out Indent: TFABIndentationPolicy;
ContextLearn: boolean): boolean;
ContextLearn: boolean; const InsertText: string): boolean;
var
Block: TBlock;
@ -1444,7 +1454,7 @@ begin
CleanPos:=FindStartOfAtom(Source,CleanPos);
if CleanPos<1 then exit;
if UseLineStart then begin
if UseLineStart and (InsertText='') then begin
while (CleanPos<=length(Source)) and (Source[CleanPos] in [' ',#9]) do
inc(CleanPos);
end;
@ -1480,10 +1490,15 @@ begin
if LastAtomStart>0 then CleanPos:=LastAtomStart;
StackIndex:=Stack.Top;
if UseLineStart then
StackIndex:=FindStackPosForBlockCloseAtPos(Source,CleanPos,
NewNestedComments,Stack);
if UseLineStart then begin
if InsertText='' then begin
StackIndex:=FindStackPosForBlockCloseAtPos(Source,CleanPos,
NewNestedComments,Stack);
end else begin
StackIndex:=FindStackPosForBlockCloseAtPos(InsertText,1,
NewNestedComments,Stack);
end;
end;
if (StackIndex<0) then begin
// no context
{$IFDEF VerboseIndenter}
@ -1504,7 +1519,8 @@ begin
if ContextLearn then begin
// parse source behind
ParseSource(Source,CleanPos,length(Source)+1,NewNestedComments,Stack,Policies);
ParseSource(Source,CleanPos,length(Source)+1,NewNestedComments,Stack,
Policies,false);
{$IFDEF VerboseIndenter}
DebugLn(['TFullyAutomaticBeautifier.GetIndent parsed source behind']);
{$ENDIF}
@ -1660,7 +1676,8 @@ begin
if Policies<>nil then begin
// parse source behind
ParseSource(Source,Item^.CleanPos,length(Source)+1,NewNestedComments,Stack,Policies);
ParseSource(Source,Item^.CleanPos,length(Source)+1,NewNestedComments,
Stack,Policies,false);
{$IFDEF VerboseIndenter}
DebugLn(['TFullyAutomaticBeautifier.GetIndent parsed source behind']);
{$ENDIF}

View File

@ -166,6 +166,9 @@ type
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
procedure EditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure EditorStatusChanged(Sender: TObject; Changes: TSynStatusChanges);
procedure EditorPaste(Sender: TObject; var AText: String;
var AMode: TSynSelectionMode; ALogStartPos: TPoint;
var AnAction: TSynCopyPasteAction);
procedure SetCodeBuffer(NewCodeBuffer: TCodeBuffer);
function GetSource: TStrings;
procedure SetPageName(const AValue: string);
@ -2565,6 +2568,7 @@ Begin
OnClickLink := @EditorClickLink;
OnMouseLink := @EditorMouseLink;
OnKeyDown := @EditorKeyDown;
OnPaste:=@EditorPaste;
// IMPORTANT: when you change above, don't forget updating UnbindEditor
end;
if FCodeTemplates<>nil then
@ -2956,6 +2960,52 @@ begin
Result:=CodeBuffer;
end;
procedure TSourceEditor.EditorPaste(Sender: TObject; var AText: String;
var AMode: TSynSelectionMode; ALogStartPos: TPoint;
var AnAction: TSynCopyPasteAction);
var
p: integer;
NestedComments: Boolean;
NewIndent: TFABIndentationPolicy;
Indent: LongInt;
NewSrc: string;
begin
if AMode<>smNormal then exit;
if SyncroEdit.Active then exit;
if TemplateEdit.Active then exit;
if not CodeToolsOpts.IndentOnPaste then exit;
{$IFDEF VerboseIndenter}
debugln(['TSourceEditor.EditorPaste LogCaret=',dbgs(ALogStartPos)]);
{$ENDIF}
if ALogStartPos.X>1 then exit;
UpdateCodeBuffer;
CodeBuffer.LineColToPosition(ALogStartPos.Y,ALogStartPos.X,p);
if p<1 then exit;
{$IFDEF VerboseIndenter}
if ALogStartPos.Y>0 then
DebugLn(['TSourceEditor.EditorPaste Y-1=',Lines[ALogStartPos.Y-2]]);
DebugLn(['TSourceEditor.EditorPaste Y+0=',Lines[ALogStartPos.Y-1]]);
if ALogStartPos.Y<LineCount then
DebugLn(['TSourceEditor.EditorPaste Y+1=',Lines[ALogStartPos.Y+0]]);
{$ENDIF}
NestedComments:=CodeToolBoss.GetNestedCommentsFlagForFile(CodeBuffer.Filename);
if not CodeToolBoss.Indenter.GetIndent(CodeBuffer.Source,p,NestedComments,
true,NewIndent,CodeToolsOpts.IndentContextSensitive,AText)
then exit;
if not NewIndent.IndentValid then exit;
Indent:=NewIndent.Indent-GetLineIndentWithTabs(AText,1,EditorComponent.TabWidth);
{$IFDEF VerboseIndenter}
debugln(AText);
DebugLn(['TSourceEditor.EditorPaste Indent=',Indent]);
{$ENDIF}
IndentText(AText,Indent,EditorComponent.TabWidth,NewSrc);
AText:=NewSrc;
{$IFDEF VerboseIndenter}
debugln(AText);
DebugLn(['TSourceEditor.EditorPaste END']);
{$ENDIF}
end;
Procedure TSourceEditor.EditorMouseMoved(Sender: TObject;
Shift: TShiftState; X,Y: Integer);
begin
@ -6830,10 +6880,6 @@ var
NewIndent: TFABIndentationPolicy;
Indent: LongInt;
CodeBuf: TCodeBuffer;
Line: string;
OldIndent: LongInt;
CurIndent: LongInt;
i: LongInt;
begin
Result:=false;
SrcEdit:=GetActiveSE;
@ -6846,34 +6892,15 @@ begin
if (SrcEdit.TemplateEdit<>nil) and SrcEdit.TemplateEdit.Active then exit;
if not (SrcEdit.SyntaxHighlighterType in [lshFreePascal, lshDelphi]) then
exit;
case Reason of
ecLineBreak:
if not CodeToolsOpts.IndentOnLineBreak then exit;
ecPaste:
begin
if not CodeToolsOpts.IndentOnPaste then exit;
if SrcEdit.EditorComponent.SelectionMode<>smNormal then exit;
if LogCaret.X>1 then
inc(FirstLinePos);
if LogCaret.Y=LastLinePos then
dec(LastLinePos);
if LastLinePos<FirstLinePos then exit; // not a whole line
end
else
exit;
end;
if Reason<>ecLineBreak then exit;
if not CodeToolsOpts.IndentOnLineBreak then exit;
{$IFDEF VerboseIndenter}
debugln(['TSourceNotebook.EditorGetIndent LogCaret=',dbgs(LogCaret),' FirstLinePos=',FirstLinePos,' LastLinePos=',LastLinePos]);
{$ENDIF}
Result := True;
SrcEdit.UpdateCodeBuffer;
CodeBuf:=SrcEdit.CodeBuffer;
case Reason of
ecLineBreak,ecInsertLine:
CodeBuf.LineColToPosition(LogCaret.Y,LogCaret.X,p);
ecPaste:
CodeBuf.LineColToPosition(FirstLinePos,1,p);
end;
CodeBuf.LineColToPosition(LogCaret.Y,LogCaret.X,p);
if p<1 then exit;
{$IFDEF VerboseIndenter}
if FirstLinePos>0 then
@ -6884,51 +6911,18 @@ begin
{$ENDIF}
NestedComments:=CodeToolBoss.GetNestedCommentsFlagForFile(CodeBuf.Filename);
if not CodeToolBoss.Indenter.GetIndent(CodeBuf.Source,p,NestedComments,
true,NewIndent,CodeToolsOpts.IndentContextSensitive)
True,NewIndent,CodeToolsOpts.IndentContextSensitive)
then exit;
if not NewIndent.IndentValid then exit;
Indent:=NewIndent.Indent;
{$IFDEF VerboseIndenter}
DebugLn(['TSourceNotebook.EditorGetIndent Indent=',Indent]);
{$ENDIF}
case Reason of
ecLineBreak,ecInsertLine:
begin
{$IFDEF VerboseIndenter}
DebugLn(['TSourceNotebook.EditorGetIndent Apply to FirstLinePos+1']);
{$ENDIF}
SetIndentProc(LogCaret.Y, Indent, 0,' ');
SrcEdit.CursorScreenXY:=Point(Indent+1,SrcEdit.CursorScreenXY.Y);
end;
ecPaste:
begin
{$IFDEF VerboseIndenter}
DebugLn(['TSourceNotebook.EditorGetIndent Apply to lines ',FirstLinePos,' .. ',LastLinePos]);
{$ENDIF}
Line:=SrcEdit.EditorComponent.Lines[FirstLinePos-1];
OldIndent:=GetLineIndentWithTabs(Line,1,SrcEdit.EditorComponent.TabWidth);
{$IFDEF VerboseIndenter}
DebugLn(['TSourceNotebook.EditorGetIndent OldIndent=',OldIndent,' Line=',dbgstr(Line)]);
{$ENDIF}
for i:=FirstLinePos to LastLinePos do begin
if i>=SrcEdit.EditorComponent.Lines.Count then break;
Line:=SrcEdit.EditorComponent.Lines[i-1];
CurIndent:=GetLineIndentWithTabs(Line,1,SrcEdit.EditorComponent.TabWidth);
{$IFDEF VerboseIndenter}
DebugLn(['TSourceNotebook.EditorGetIndent CurIndent=',CurIndent,' OldIndent=',OldIndent,' Indent=',Indent,' Line="',Line,'"']);
{$ENDIF}
CurIndent:=CurIndent-OldIndent+Indent;
if CurIndent<0 then begin
dec(Indent,CurIndent);
CurIndent:=0;
end;
{$IFDEF VerboseIndenter}
DebugLn(['TSourceNotebook.EditorGetIndent ']);
{$ENDIF}
SetIndentProc(i, CurIndent, 0,' ');
end;
end;
end;
{$IFDEF VerboseIndenter}
DebugLn(['TSourceNotebook.EditorGetIndent Apply to FirstLinePos+1']);
{$ENDIF}
SetIndentProc(LogCaret.Y, Indent, 0,' ');
SrcEdit.CursorScreenXY:=Point(Indent+1,SrcEdit.CursorScreenXY.Y);
end;
Procedure TSourceNotebook.HintTimer(sender: TObject);