codetools: RemoveWithBlock: unindent

git-svn-id: trunk@30614 -
This commit is contained in:
mattias 2011-05-07 23:10:20 +00:00
parent 56884905ce
commit 934a90187a
5 changed files with 127 additions and 4 deletions

View File

@ -63,9 +63,10 @@ begin
if Code=nil then
raise Exception.Create('loading failed: '+Filename);
// parse the unit
// parse the unit and remove the with variable
if not CodeToolBoss.RemoveWithBlock(Code,X,Y) then
raise Exception.Create('RemoveWithBlock failed');
// write the new source:
writeln('-----------------------------------');
writeln('New source:');

View File

@ -39,6 +39,7 @@ begin
Name:='name of TSon1';
with Son2 do begin
Name:='name of TSon2';
//
end;
end;
end;

View File

@ -37,7 +37,7 @@ unit ExtractProcTool;
{$mode objfpc}{$H+}
{$define CTDEBUG}
{ $define CTDEBUG}
interface
@ -1166,7 +1166,9 @@ var
p:=Pointer(PtrUInt(CleanPos));
if WithIdentifiers=nil then WithIdentifiers:=TAVLTree.Create;
if WithIdentifiers.Find(p)<>nil then exit;
{$IFDEF CTDEBUG}
debugln(['AddIdentifier ',GetIdentifier(@Src[CleanPos])]);
{$ENDIF}
WithIdentifiers.Add(p);
end;
@ -1189,7 +1191,9 @@ var
Cache:=PWithVarCache(WithVarCache[i]);
end else begin
// resolve type of With variable
{$IFDEF CTDEBUG}
debugln(['IdentifierDefinedByWith NEW WithVar']);
{$ENDIF}
New(Cache);
WithVarCache.Add(Cache);
Cache^.WithVarNode:=WithVarNode;
@ -1208,7 +1212,9 @@ var
MoveCursorToCleanPos(Cache^.WithVarNode.StartPos);
RaiseException(ctsExprTypeMustBeClassOrRecord);
end;
{$IFDEF CTDEBUG}
debugln(['IdentifierDefinedByWith WithVarExpr=',ExprTypeToString(Cache^.WithVarExpr)]);
{$ENDIF}
finally
Params.Free;
end;
@ -1223,7 +1229,9 @@ var
Params.Flags:=[fdfSearchInAncestors];
Params.ContextNode:=Cache^.WithVarExpr.Context.Node;
Result:=Cache^.WithVarExpr.Context.Tool.FindIdentifierInContext(Params);
{$IFDEF CTDEBUG}
debugln(['IdentifierDefinedByWith Identifier=',GetIdentifier(@Src[CleanPos]),' FoundInWith=',Result,' WithVar="',dbgstr(Src,WithVarNode.StartPos,10),'"']);
{$ENDIF}
finally
Params.Free;
end;
@ -1287,6 +1295,8 @@ var
DoKeywordEndPos: Integer;
EndKeywordStartPos: LongInt;
EndKeywordEndPos: LongInt;
IndentWith: LongInt;
IndentInnerWith: LongInt;
begin
SourceChangeCache.MainScanner:=Scanner;
@ -1325,15 +1335,28 @@ var
break;
end;
until (CurPos.StartPos>SrcLen) or (CurPos.StartPos>StatementNode.EndPos);
IndentWith:=GetLineIndentWithTabs(Src,WithKeywordStartPos,
SourceChangeCache.BeautifyCodeOptions.TabWidth);
WithKeywordStartPos:=FindLineEndOrCodeInFrontOfPosition(WithKeywordStartPos);
DoKeywordEndPos:=FindLineEndOrCodeAfterPosition(DoKeywordEndPos);
if not SourceChangeCache.Replace(gtSpace,gtNone,WithKeywordStartPos,DoKeywordEndPos,'')
then exit(false);
if EndKeywordStartPos>0 then begin
EndKeywordStartPos:=FindLineEndOrCodeInFrontOfPosition(EndKeywordStartPos);
EndKeywordStartPos:=GetLineStartPosition(Src,EndKeywordStartPos);
while (EndKeywordStartPos>1) and (Src[EndKeywordStartPos-1] in [#10,#13]) do
dec(EndKeywordStartPos);
EndKeywordEndPos:=FindLineEndOrCodeAfterPosition(EndKeywordEndPos);
if not SourceChangeCache.Replace(gtSpace,gtNone,EndKeywordStartPos,EndKeywordEndPos,'')
then exit(false);
// unindent
StartPos:=FindLineEndOrCodeAfterPosition(DoKeywordEndPos,true,true);
IndentInnerWith:=GetLineIndentWithTabs(Src,StartPos,
SourceChangeCache.BeautifyCodeOptions.TabWidth);
if IndentWith<IndentInnerWith then
if not SourceChangeCache.IndentBlock(DoKeywordEndPos,EndKeywordStartPos,
IndentWith-IndentInnerWith)
then exit(false);
end;
end else begin
// remove only variable
@ -1411,7 +1434,9 @@ begin
MoveCursorToAtomPos(LastAtom);
end;
until (CurPos.StartPos>SrcLen) or (CurPos.StartPos>=StatementNode.EndPos);
{$IFDEF CTDEBUG}
debugln(['TExtractProcTool.RemoveWithBlock Statement=',copy(Src,StatementNode.StartPos,StatementNode.EndPos-StatementNode.StartPos)]);
{$ENDIF}
// replace
Result:=Replace;

View File

@ -57,7 +57,7 @@ interface
{ $DEFINE ShowTriedParentContexts}
{ $DEFINE ShowTriedIdentifiers}
{ $DEFINE ShowTriedUnits}
{$DEFINE ShowExprEval}
{ $DEFINE ShowExprEval}
{ $DEFINE ShowFoundIdentifier}
{ $DEFINE ShowInterfaceCache}
{ $DEFINE ShowNodeCache}

View File

@ -230,6 +230,8 @@ type
function ReplaceEx(FrontGap, AfterGap: TGapTyp; FromPos, ToPos: integer;
DirectCode: TCodeBuffer; FromDirectPos, ToDirectPos: integer;
const Text: string): boolean;
function IndentBlock(FromPos, ToPos, IndentDiff: integer): boolean;
function IndentLine(LineStartPos, IndentDiff: integer): boolean;
function Apply: boolean;
function FindEntryInRange(FromPos, ToPos: integer): TSourceChangeCacheEntry;
function FindEntryAtPos(APos: integer): TSourceChangeCacheEntry;
@ -657,6 +659,100 @@ begin
{$ENDIF}
end;
function TSourceChangeCache.IndentBlock(FromPos, ToPos, IndentDiff: integer): boolean;
// (un)indent all lines in FromPos..ToPos
// If FromPos starts in the middle of a line the first line is not changed
// If ToPos is in the indentation the last line is not changed
var
p: LongInt;
begin
if ToPos<1 then ToPos:=1;
if (IndentDiff=0) or (FromPos>=ToPos) then exit;
if MainScanner=nil then begin
debugln(['TSourceChangeCache.IndentBlock need MainScanner']);
exit(false);
end;
Src:=MainScanner.CleanedSrc;
SrcLen:=length(Src);
if FromPos>SrcLen then exit(true);
if ToPos>SrcLen then ToPos:=SrcLen+1;
// skip empty lines at start
while (FromPos<ToPos) and (Src[FromPos] in [#10,#13]) do inc(FromPos);
if (FromPos>1) and (not (Src[FromPos-1] in [#10,#13])) then begin
// FromPos is in the middle of a line => start in next line
while (FromPos<ToPos) and (not (Src[FromPos] in [#10,#13])) do inc(FromPos);
if FromPos>=ToPos then exit(true);
end;
if (ToPos<=SrcLen) and (Src[ToPos] in [' ',#9]) then begin
p:=ToPos;
while (p>=ToPos) and (Src[p] in [' ',#9]) do dec(p);
if (p=1) or (Src[p] in [#10,#13]) then begin
// ToPos in IndentDiff of last line => end in previous line
while (p>ToPos) and (Src[p-1] in [#10,#13]) do dec(p);
ToPos:=p;
if FromPos>=ToPos then exit(true);
end;
end;
//debugln(['TSourceChangeCache.IndentBlock Indent=',IndentDiff,' Src="',dbgstr(Src,FromPos,ToPos-FromPos),'"']);
p:=FromPos;
while p<ToPos do begin
if not IndentLine(p,IndentDiff) then exit(false);
// go to next line
while (p<ToPos) and (not (Src[p] in [#10,#13])) do inc(p);
// skip empty lines
while (p<ToPos) and (Src[p] in [#10,#13]) do inc(p);
end;
Result:=true;
end;
function TSourceChangeCache.IndentLine(LineStartPos, IndentDiff: integer
): boolean;
var
OldIndent: LongInt;
NewIndent: Integer;
p: LongInt;
Indent: Integer;
StartPos: LongInt;
IndentStr: String;
NextIndent: Integer;
begin
if (IndentDiff=0) or (LineStartPos<1) then exit(true);
Src:=MainScanner.CleanedSrc;
SrcLen:=length(Src);
if LineStartPos>SrcLen then exit(true);
OldIndent:=GetLineIndentWithTabs(Src,LineStartPos,BeautifyCodeOptions.TabWidth);
NewIndent:=OldIndent+IndentDiff;
if NewIndent<0 then NewIndent:=0;
if OldIndent=NewIndent then exit(true);
//debugln(['TSourceChangeCache.IndentLine change indent OldIndent=',OldIndent,' NewIndent=',NewIndent]);
p:=LineStartPos;
// use as much of the old space as possible
Indent:=0;
while (p<=SrcLen) and (Indent<NewIndent) do begin
case Src[p] of
' ':
inc(Indent);
#9:
begin
NextIndent:=Indent+BeautifyCodeOptions.TabWidth;
NextIndent:=NextIndent-(NextIndent mod BeautifyCodeOptions.TabWidth);
if NextIndent>NewIndent then break;
Indent:=NextIndent;
end;
end;
inc(p);
end;
StartPos:=p;
while (p<=SrcLen) and (Src[p] in [' ',#9]) do inc(p);
IndentStr:=GetIndentStr(NewIndent-Indent);
Result:=Replace(gtNone,gtNone,StartPos,p,IndentStr);
end;
function TSourceChangeCache.Replace(FrontGap, AfterGap: TGapTyp;
FromPos, ToPos: integer; const Text: string): boolean;
begin