codetools: RemoveUnitFromUsesSection: when removing the last unit remove empty lines in front too, bug #18055

git-svn-id: trunk@28498 -
This commit is contained in:
mattias 2010-11-26 12:23:25 +00:00
parent 23252ff1fe
commit 94948dde5e
6 changed files with 172 additions and 34 deletions

View File

@ -109,7 +109,8 @@ function IsFirstNonSpaceCharInLine(const Source: string;
Position: integer): boolean;
function FindLineEndOrCodeInFrontOfPosition(const Source: string;
Position, MinPosition: integer; NestedComments: boolean;
StopAtDirectives: boolean = true; SkipSemicolonComma: boolean = true): integer;
StopAtDirectives: boolean = true; SkipSemicolonComma: boolean = true;
SkipEmptyLines: boolean = false): integer;
function FindLineEndOrCodeAfterPosition(const Source: string;
Position, MaxPosition: integer; NestedComments: boolean;
StopAtDirectives: boolean = true; SkipEmptyLines: boolean = false;
@ -2463,11 +2464,14 @@ begin
end;
function FindLineEndOrCodeInFrontOfPosition(const Source: string;
Position, MinPosition: integer; NestedComments: boolean;
StopAtDirectives: boolean; SkipSemicolonComma: boolean): integer;
Position, MinPosition: integer; NestedComments: boolean;
StopAtDirectives: boolean; SkipSemicolonComma: boolean;
SkipEmptyLines: boolean): integer;
{ search backward for a line end or code
ignore line ends in comments or at the end of comment lines
(comment lines are lines without code and at least one comment)
comment lines directly in front are skipped too
if SkipEmptyLines=true then empty lines are skipped too.
Result is Position of Start of Line End
examples: Position points at char 'a'
@ -2585,6 +2589,28 @@ begin
if IsEmpty then begin
// the line is empty => return start of line end
Result:=LineEndPos;
if SkipEmptyLines then begin
// skip all empty lines
LineStartPos:=Result;
while (LineStartPos>SrcStart) do begin
case Source[LineStartPos-1] of
#10,#13:
begin
// empty line
LineEndPos:=LineStartPos-1;
if (LineEndPos>SrcStart) and (Source[LineEndPos-1] in [#10,#13])
and (Source[LineEndPos]<>Source[LineEndPos-1]) then
dec(LineEndPos);
Result:=LineEndPos;
end;
' ',#9: ;
else
// not empty
break;
end;
dec(LineStartPos);
end;
end;
exit;
end;
TestPos:=LineStartPos;

View File

@ -231,7 +231,7 @@ type
function FindLineEndOrCodeAfterPosition(StartPos: integer;
SkipEmptyLines: boolean = false; IncludeLineEnd: boolean = false): integer;
function FindLineEndOrCodeInFrontOfPosition(StartPos: integer;
StopAtDirectives: boolean = true): integer;
StopAtDirectives: boolean = true; SkipEmptyLines: boolean = false): integer;
function UpdateNeeded(OnlyInterfaceNeeded: boolean): boolean;
procedure BeginParsing(DeleteNodes, OnlyInterfaceNeeded: boolean); virtual;
@ -2601,7 +2601,7 @@ begin
end;
function TCustomCodeTool.FindLineEndOrCodeInFrontOfPosition(StartPos: integer;
StopAtDirectives: boolean): integer;
StopAtDirectives: boolean; SkipEmptyLines: boolean): integer;
{ Searches a nice position in the cleaned source in front of StartPos.
It will skip any space or comments (not directives) till next
line end or compiler directive or code or include file end.
@ -2612,7 +2612,8 @@ begin
LinkIndex:=Scanner.LinkIndexAtCleanPos(StartPos);
LinkStart:=Scanner.Links[LinkIndex].CleanedPos;
Result:=BasicCodeTools.FindLineEndOrCodeInFrontOfPosition(Src,
StartPos,LinkStart,Scanner.NestedComments,StopAtDirectives,false);
StartPos,LinkStart,Scanner.NestedComments,StopAtDirectives,false,
SkipEmptyLines);
end;
procedure TCustomCodeTool.ClearIgnoreErrorAfter;

View File

@ -1,19 +1,18 @@
<?xml version="1.0"?>
<CONFIG>
<ProjectOptions>
<Version Value="7"/>
<Version Value="9"/>
<General>
<Flags>
<LRSInOutputDirectory Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<TargetFileExt Value=""/>
<Title Value="finddeclaration"/>
</General>
<VersionInfo>
<StringTable Comments="" CompanyName="" FileDescription="" FileVersion="0.0.0.0" InternalName="" LegalCopyright="" LegalTrademarks="" OriginalFilename="" ProductName="" ProductVersion="0.0.0.0"/>
</VersionInfo>
<BuildModes Count="1">
<Item1 Name="default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
@ -50,7 +49,7 @@
<CompilerOptions>
<Version Value="9"/>
<SearchPaths>
<OtherUnitFiles Value="scanexamples/"/>
<OtherUnitFiles Value="scanexamples"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>

View File

@ -1086,8 +1086,10 @@ begin
// first unit in uses section
if AtomIsChar(';') then begin
// last unit in uses section -> delete whole uses section
StartPos:=FindLineEndOrCodeInFrontOfPosition(UsesNode.StartPos,true,true);
debugln(['TStandardCodeTool.RemoveUnitFromUsesSection AAA1 "',dbgstr(copy(Src,StartPos,UsesNode.EndPos-StartPos)),'"']);
if not SourceChangeCache.Replace(gtNone,gtNone,
UsesNode.StartPos,UsesNode.EndPos,'') then exit;
StartPos,UsesNode.EndPos,'') then exit;
end else begin
// not last unit -> delete with comma behind
EndPos:=FindLineEndOrCodeAfterPosition(CurPos.EndPos);

View File

@ -27,10 +27,14 @@
<LaunchingApplication PathPlusParams="/usr/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
</local>
</RunParams>
<RequiredPackages Count="1">
<RequiredPackages Count="2">
<Item1>
<PackageName Value="LCL"/>
<PackageName Value="CodeTools"/>
<MinVersion Major="1" Release="1" Valid="True"/>
</Item1>
<Item2>
<PackageName Value="LCL"/>
</Item2>
</RequiredPackages>
<Units Count="2">
<Unit0>

View File

@ -6,7 +6,7 @@ interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, LCLProc,
contnrs;
contnrs, XMLRead;
type
@ -41,16 +41,12 @@ type
procedure FixFPDocFragment(var Fragment: string; Fix: boolean;
out ErrorList: TObjectList);
{ - Fix all tags to lowercase to reduce svn commits
- remove unneeded spaces
< b => <b
b > => b>
a b => a b
- auto close comments
- remove #0 from comments
- auto close unclosed tags
- fix & without ;
- convert special characters to &x;
- fix &name; lower case
- fix unclosed attribute values
- auto close unclosed tags
}
type
TStackItemTyp = (
@ -292,6 +288,125 @@ var
HandleSpecialChar;
end;
procedure LowerCaseName;
var
Start: PChar;
NeedLowercase: PChar;
begin
Start:=p;
NeedLowercase:=nil;
repeat
case p^ of
'a'..'z': inc(p);
'A'..'Z':
begin
inc(p);
if NeedLowercase=nil then
NeedLowercase:=p;
end;
else break;
end;
until false;
if NeedLowercase<>nil then begin
if Fix then begin
Replace(Rel(Start),p-Start,lowercase(copy(Fragment,Rel(Start),p-Start)));
end else begin
// all current tags must be lower case
Error(NeedLowercase,'tags must be lower case');
end;
end;
end;
procedure ParseAttribute;
begin
// attribute name
LowerCaseName;
while p^ in [' ',#9,#10,#13] do inc(p); // skip space
if p^<>'=' then begin
// missing value
if Fix then begin
Replace(Rel(p),0,'=');
end else begin
Error(p,'expected =');
end;
end;
if p^='=' then begin
inc(p);
while p^ in [' ',#9,#10,#13] do inc(p); // skip space
if p^<>'"' then begin
// missing quotes
if Fix then begin
Replace(Rel(p),0,'"');
end else begin
Error(p,'expected "');
end;
end;
end;
if p^='"' then begin
// read value
inc(p);
repeat
case p^ of
'>',#0..#8,#11,#12,#14..#31,#127:
// the > is not allowed in the quotes, probably the ending quot is missing
if Fix then begin
Replace(Rel(p),0,'"');
end else begin
Error(p,'expected ending "');
break;
end;
'&':
ParseAmpersand;
'"':
begin
inc(p);
break;
end
else
inc(p);
end;
until false;
end;
end;
procedure ParseLowerThan;
begin
// comment, tag or 'lower than'
if (p[1]='!') and (p[2]='-') and (p[3]='-') then begin
// comment
ParseComment;
exit;
end;
if p[1] in ['a'..'z','A'..'Z'] then begin
// open tag
Push(sitTag);
TopItem^.StartPos:=Rel(p);
inc(p);
TopItem^.NameStartPos:=Rel(p);
LowerCaseName;
TopItem^.NameEndPos:=Rel(p);
while p^ in [' ',#9,#10,#13] do inc(p); // skip space
case p^ of
'a'..'z','A'..'Z':
ParseAttribute;
'/':
begin
// ToDo: close tag
RaiseGDBException('ToDo');
end;
'>':
begin
// ToDo:
end;
end;
end else if p[1]='/' then begin
// ToDo: close tag
RaiseGDBException('ToDo');
end;
// invalid character => convert or skip
HandleSpecialChar;
end;
begin
ErrorList:=nil;
if Fragment='' then exit;
@ -314,16 +429,7 @@ begin
end;
end;
'<':
begin
// comment, tag or 'lower than'
if (p[1]='!') and (p[2]='-') and (p[3]='-') then
// comment
ParseComment
else begin
// invalid character => convert or skip
HandleSpecialChar;
end;
end;
ParseLowerThan;
'>':
// invalid character => convert or skip
HandleSpecialChar;
@ -346,8 +452,8 @@ end;
procedure TForm1.FormCreate(Sender: TObject);
begin
TestComment;
TestInvalidCharacters;
//TestComment;
//TestInvalidCharacters;
end;
procedure TForm1.TestComment;