mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-11 15:48:34 +02:00
Jedi Code Format: Improve formatting of preprocessor blocks and preprocessor directives. Issue #39662, patch by Domingo Galmés.
This commit is contained in:
parent
4c6414f837
commit
f4d0eeb099
@ -90,8 +90,8 @@ implementation
|
||||
|
||||
uses
|
||||
{ local }
|
||||
PreProcessorExpressionTokenise, PreProcessorExpressionParser,
|
||||
ParseError, JcfSettings, JcfUiTools;
|
||||
PreProcessorExpressionTokenise, PreProcessorExpressionParser, StrUtils,
|
||||
ParseError, JcfSettings, JcfUiTools, JcfStringUtils, TokenUtils, SettingsTypes;
|
||||
|
||||
procedure RemoveConditionalCompilation(const pcTokens: TSourceTokenList);
|
||||
var
|
||||
@ -420,13 +420,16 @@ begin
|
||||
NextToken;
|
||||
end;
|
||||
|
||||
|
||||
// parse preprocessor block until finds ENDIF IFEND, ELSE ELSEIF.
|
||||
// if the block is inactive then include all nested preprocessor blocks.
|
||||
procedure TPreProcessorParseTree.ParseNonPreProc(
|
||||
const peEndTokens: TPreProcessorSymbolTypeSet);
|
||||
var
|
||||
lcToken: TSourceToken;
|
||||
liNestLevel: integer;
|
||||
begin
|
||||
{ go forward until another preprocessor tag is found. or end of file }
|
||||
liNestLevel := 1;
|
||||
while (fiCurrentTokenIndex < fcTokens.Count) do
|
||||
begin
|
||||
lcToken := CurrentToken;
|
||||
@ -437,14 +440,21 @@ begin
|
||||
|
||||
if (lcToken.CommentStyle = eCompilerDirective) then
|
||||
begin
|
||||
if lcToken.PreprocessorSymbol in peEndTokens then
|
||||
//inactive nested {$IFxxxx}
|
||||
if (not fbPreprocessorIncluded) and (lcToken.PreprocessorSymbol in [ppIfDef, ppIfNotDef, ppIfOpt, ppIfExpr]) then
|
||||
Inc(liNestLevel)
|
||||
else if (liNestLevel > 1) and (lcToken.PreprocessorSymbol in [ppIfEnd, ppEndIf]) then
|
||||
Dec(liNestLevel)
|
||||
else if (liNestLevel = 1) and (lcToken.PreprocessorSymbol in peEndTokens) then
|
||||
begin
|
||||
lcToken.PreProcessedOut := False;
|
||||
break;
|
||||
end;
|
||||
|
||||
// if we are preproc'd in then parse these
|
||||
ParseProcessorBlock;
|
||||
if fbPreprocessorIncluded then
|
||||
// if we are preproc'd in then parse these
|
||||
ParseProcessorBlock
|
||||
else
|
||||
NextToken;
|
||||
end
|
||||
else
|
||||
NextToken;
|
||||
@ -569,6 +579,7 @@ var
|
||||
liLoop: integer;
|
||||
lsOutText: string;
|
||||
lcCurrentToken, lcExcludedText: TSourceToken;
|
||||
lbLFAfter,lbLFBefore:TTriOptionStyle;
|
||||
begin
|
||||
// right, what's out?
|
||||
liLoop := 0;
|
||||
@ -579,7 +590,8 @@ begin
|
||||
if lcCurrentToken.PreprocessedOut then
|
||||
begin
|
||||
lsOutText := '';
|
||||
|
||||
lbLFBefore:= CompilerDirectiveLineBreak(lcCurrentToken, True);
|
||||
lbLFAfter:= CompilerDirectiveLineBreak(lcCurrentToken, False);
|
||||
while (lcCurrentToken <> nil) and lcCurrentToken.PreprocessedOut do
|
||||
begin
|
||||
lsOutText := lsOutText + lcCurrentToken.SourceCode;
|
||||
@ -589,12 +601,19 @@ begin
|
||||
{ next one will have shifted up }
|
||||
lcCurrentToken := fcTokens.SourceTokens[liLoop];
|
||||
end;
|
||||
|
||||
lcExcludedText := TSourceToken.Create;
|
||||
lcExcludedText.FileName := lcCurrentToken.FileName;
|
||||
lcExcludedText.TokenType := ttConditionalCompilationRemoved;
|
||||
lcExcludedText.SourceCode := lsOutText;
|
||||
|
||||
case lbLFBefore of
|
||||
eAlways:lcExcludedText.SourceCode := TrimRightSet(lsOutText,NativeTabSpace); //only spaces not returns
|
||||
eLeave: lcExcludedText.SourceCode := lsOutText;
|
||||
eNever: lcExcludedText.SourceCode := TrimRight(lsOutText); // spaces and returns
|
||||
end;
|
||||
case lbLFAfter of
|
||||
eAlways: lcExcludedText.SourceCode := TrimLeft(lcExcludedText.SourceCode);
|
||||
eLeave: ;
|
||||
eNever: lcExcludedText.SourceCode := TrimLeft(lcExcludedText.SourceCode);
|
||||
end;
|
||||
fcTokens.Insert(liLoop, lcExcludedText);
|
||||
end
|
||||
else
|
||||
|
@ -852,20 +852,20 @@ end;
|
||||
|
||||
function CompilerDirectiveLineBreak(const pt: TSourceToken; const pbBefore: Boolean): TTriOptionStyle;
|
||||
begin
|
||||
if InStatements(pt) then
|
||||
begin
|
||||
if pbBefore then
|
||||
Result := FormattingSettings.Returns.BeforeCompilerDirectStatements
|
||||
else
|
||||
Result := FormattingSettings.Returns.AfterCompilerDirectStatements;
|
||||
end
|
||||
else if pt.HasParentNode(nUses) then
|
||||
if pt.HasParentNode(nUses) then
|
||||
begin
|
||||
if pbBefore then
|
||||
Result := FormattingSettings.Returns.BeforeCompilerDirectUses
|
||||
else
|
||||
Result := FormattingSettings.Returns.AfterCompilerDirectUses;
|
||||
end
|
||||
else if InStatements(pt) then
|
||||
begin
|
||||
if pbBefore then
|
||||
Result := FormattingSettings.Returns.BeforeCompilerDirectStatements
|
||||
else
|
||||
Result := FormattingSettings.Returns.AfterCompilerDirectStatements;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if pbBefore then
|
||||
|
@ -56,7 +56,7 @@ uses
|
||||
{ local }
|
||||
JcfStringUtils,
|
||||
SourceToken, Nesting, FormatFlags, JcfSettings, TokenUtils,
|
||||
Tokens, ParseTreeNode, ParseTreeNodeType;
|
||||
Tokens, ParseTreeNode, ParseTreeNodeType, SettingsTypes;
|
||||
|
||||
{ true if the specified token type occurs before pt on the line }
|
||||
function HasPreceedingTokenTypeOnLine(const pt: TSourceToken; const ptt: TTokenTypeSet): Boolean;
|
||||
@ -159,6 +159,11 @@ begin
|
||||
else
|
||||
Result := FormattingSettings.Indent.KeepCommentsWithCodeElsewhere;
|
||||
end;
|
||||
end
|
||||
else if (pt.TokenType = ttComment) and (pt.CommentStyle = eCompilerDirective)
|
||||
and (CompilerDirectiveLineBreak(pt,True)=eAlways) then
|
||||
begin
|
||||
Result:=true;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
@ -176,21 +176,22 @@ begin
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
if (pt.CommentStyle = eCompilerDirective) and (CompilerDirectiveLineBreak(pt, False) = eNever) then
|
||||
begin
|
||||
Result := True;
|
||||
exit;
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
{ remove returns based on options }
|
||||
|
||||
{ the options don't apply after comments }
|
||||
if (pt.TokenType = ttComment) then
|
||||
if (pt.TokenType = ttComment) and (pt.CommentStyle = eCompilerDirective) then
|
||||
begin
|
||||
Result := False;
|
||||
Result:=CompilerDirectiveLineBreak(pt, False) = eNever;
|
||||
if Result then // remove spaces
|
||||
begin
|
||||
lcNext:=pt.NextToken;
|
||||
while (lcNext<>nil) and (lcNext.TokenType in [ttReturn,ttWhiteSpace]) do
|
||||
begin
|
||||
BlankToken(lcNext);
|
||||
lcNext:=lcNext.NextToken;
|
||||
end;
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
|
||||
|
@ -61,6 +61,7 @@ const
|
||||
ProcNoReturnWords: TTokenTypeSet = [ttThen, ttDo];
|
||||
var
|
||||
lcPrev: TParseTreeNode;
|
||||
lcP:TSourceToken;
|
||||
begin
|
||||
Result := False;
|
||||
|
||||
@ -132,18 +133,31 @@ begin
|
||||
if pt.HasParentNode(nAttribute) then
|
||||
exit(True);
|
||||
end;
|
||||
if (pt.CommentStyle = eCompilerDirective) then
|
||||
begin
|
||||
if (CompilerDirectiveLineBreak(pt, True) = eNever) then
|
||||
begin
|
||||
// remove spaces
|
||||
lcP:=pt.PriorToken;
|
||||
while (lcP<>nil) and (lcP.TokenType in [ttReturn,ttWhiteSpace]) do
|
||||
begin
|
||||
BlankToken(lcP);
|
||||
lcP:=lcP.PriorToken;
|
||||
end;
|
||||
exit(True);
|
||||
end
|
||||
else
|
||||
exit(False);
|
||||
end;
|
||||
|
||||
// "foo in Foo.pas, " has return only after the comma
|
||||
if InFilesUses(pt) then
|
||||
begin
|
||||
if (pt.TokenType in [ttComma, ttWord, ttQuotedLiteralString]) or
|
||||
((pt.TokenType = ttComment) and (pt.CommentStyle in CURLY_COMMENTS)) then
|
||||
((pt.TokenType = ttComment) and (pt.CommentStyle = eCurlyBrace)) then
|
||||
exit(True);
|
||||
end;
|
||||
|
||||
if (pt.CommentStyle = eCompilerDirective) and (CompilerDirectiveLineBreak(pt, True) = eNever) then
|
||||
exit(True);
|
||||
|
||||
end;
|
||||
|
||||
constructor TNoReturnBefore.Create;
|
||||
@ -162,9 +176,18 @@ begin
|
||||
lcSourceToken := TSourceToken(pcNode);
|
||||
|
||||
// not safe to remove return at a comment like this
|
||||
if (lcSourceToken.TokenType = ttComment) and
|
||||
(lcSourceToken.CommentStyle = eDoubleSlash) then
|
||||
fbSafeToRemoveReturn := False
|
||||
if (lcSourceToken.TokenType = ttComment)then
|
||||
begin
|
||||
if (lcSourceToken.CommentStyle = eDoubleSlash) then
|
||||
fbSafeToRemoveReturn := False
|
||||
else if lcSourceToken.CommentStyle = eCompilerDirective then
|
||||
begin
|
||||
if CompilerDirectiveLineBreak(lcSourceToken, True) = eNever then
|
||||
fbSafeToRemoveReturn := true
|
||||
else
|
||||
fbSafeToRemoveReturn := false;
|
||||
end;
|
||||
end
|
||||
else if (lcSourceToken.TokenType <> ttReturn) then
|
||||
fbSafeToRemoveReturn := True;
|
||||
// safe again after the next return
|
||||
|
@ -54,7 +54,7 @@ implementation
|
||||
|
||||
uses
|
||||
{ local }
|
||||
TokenUtils, SourceToken, Tokens,
|
||||
TokenUtils, SourceToken, Tokens, JcfStringUtils,
|
||||
ParseTreeNodeType, ParseTreeNode, JcfSettings, FormatFlags, SettingsTypes;
|
||||
|
||||
const
|
||||
@ -75,8 +75,14 @@ const
|
||||
5) as 4, in a procedure type in a type def
|
||||
}
|
||||
function SemicolonHasReturn(const pt, ptNext: TSourceToken): boolean;
|
||||
var
|
||||
lcN:TSourceToken;
|
||||
begin
|
||||
Result := True;
|
||||
{before compiler directive }
|
||||
lcN:=pt.NextTokenWithExclusions([ttWhiteSpace]); // include comments.
|
||||
if (lcN<>nil) and (lcN.TokenType=ttComment) and (lcN.CommentStyle=eCompilerDirective)then
|
||||
exit(false);
|
||||
{ point 1 }
|
||||
if ptNext.HasParentNode(nProcedureDirectives) then
|
||||
exit(False);
|
||||
@ -368,16 +374,6 @@ begin
|
||||
exit(True);
|
||||
end;
|
||||
|
||||
{ return after compiler directives
|
||||
NB use lcNext as ptNext is the next *solid* token
|
||||
cond comp removed is not solid }
|
||||
if (pt.CommentStyle = eCompilerDirective) and (CompilerDirectiveLineBreak(pt, False) = eAlways) then
|
||||
begin
|
||||
lcNext := pt.NextTokenWithExclusions([ttWhiteSpace]);
|
||||
if (lcNext <> nil) and (lcNext.TokenType <> ttConditionalCompilationRemoved)
|
||||
then
|
||||
exit(True);
|
||||
end;
|
||||
end;
|
||||
|
||||
function NeedsReturn(const pt, ptNext: TSourceToken): boolean;
|
||||
@ -389,6 +385,25 @@ begin
|
||||
{ these can include returns }
|
||||
if pt.TokenType = ttConditionalCompilationRemoved then
|
||||
exit;
|
||||
if (pt.CommentStyle = eCompilerDirective) and (CompilerDirectiveLineBreak(pt, False) = eAlways) then
|
||||
begin
|
||||
Result:=false;
|
||||
lcNext:=pt.NextTokenWithExclusions([ttWhiteSpace]);
|
||||
if (lcNext<>nil) and (lcNext.TokenType<>ttReturn) then
|
||||
begin
|
||||
if (lcNext <> nil) then
|
||||
begin
|
||||
if (lcNext.TokenType <> ttConditionalCompilationRemoved) then
|
||||
result:=true
|
||||
else
|
||||
begin
|
||||
if StrStartsWithLineEnd(lcNext.SourceCode)=false then
|
||||
result:=true;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
|
||||
{ option to Break After Uses }
|
||||
if pt.HasParentNode(nUses) and (pt.TokenType = ttUses) and
|
||||
@ -511,10 +526,6 @@ begin
|
||||
if lcCommentTest = nil then
|
||||
exit;
|
||||
|
||||
if (lcCommentTest.TokenType = ttComment) and
|
||||
(lcCommentTest.CommentStyle = eDoubleSlash) then
|
||||
exit;
|
||||
|
||||
{ white space that was on the end of the line shouldn't be carried over
|
||||
to indent the next line }
|
||||
lcNextSpace := lcSourceToken.NextToken;
|
||||
|
@ -59,7 +59,7 @@ implementation
|
||||
uses
|
||||
TokenUtils,
|
||||
SourceToken, Tokens, ParseTreeNode,
|
||||
ParseTreeNodeType, JcfSettings,
|
||||
ParseTreeNodeType, JcfSettings, JcfStringUtils,
|
||||
FormatFlags, SettingsTypes;
|
||||
|
||||
const
|
||||
@ -250,14 +250,6 @@ begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
{ return before compiler directives }
|
||||
if (pt.CommentStyle = eCompilerDirective) and (CompilerDirectiveLineBreak(pt, True) = eAlways) then
|
||||
begin
|
||||
lcPrev := pt.PriorTokenWithExclusions([ttWhiteSpace]);
|
||||
if (lcPrev <> nil) and (lcPrev.TokenType <> ttConditionalCompilationRemoved) then
|
||||
exit(True);
|
||||
end;
|
||||
|
||||
{ there is not always a return before 'type'
|
||||
e.g.
|
||||
type TMyInteger = type Integer;
|
||||
@ -405,6 +397,27 @@ begin
|
||||
|
||||
{ number to insert = needed - actual }
|
||||
liReturnsNeeded := liReturnsNeeded - fiReturnsBefore;
|
||||
|
||||
//preprocessor directives
|
||||
if (lcSourceToken.TokenType = ttComment) and (lcSourceToken.CommentStyle=eCompilerDirective) then
|
||||
begin
|
||||
liReturnsNeeded := 0;
|
||||
if CompilerDirectiveLineBreak(lcSourceToken, True) = eAlways then
|
||||
begin
|
||||
lcPrev:=lcSourceToken.PriorTokenWithExclusions([ttWhiteSpace]);
|
||||
if (lcPrev<>nil) and (lcPrev.TokenType<>ttReturn) then
|
||||
begin
|
||||
if (lcPrev.TokenType <> ttConditionalCompilationRemoved) then
|
||||
liReturnsNeeded:=1
|
||||
else
|
||||
begin
|
||||
if StrEndsWithLineEnd(lcPrev.SourceCode)=false then
|
||||
liReturnsNeeded:=1;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
//var
|
||||
// Test : function: Integer; // No New Line
|
||||
//type
|
||||
@ -421,7 +434,7 @@ begin
|
||||
Result := True;
|
||||
|
||||
lcPrev := lcSourceToken.PriorToken;
|
||||
if lcPrev.TokenType = ttWhiteSpace then
|
||||
if (lcPrev<>nil) and (lcPrev.TokenType = ttWhiteSpace) then
|
||||
BlankToken(lcPrev);
|
||||
|
||||
for liLoop := 0 to liReturnsNeeded - 1 do
|
||||
@ -452,7 +465,6 @@ begin
|
||||
Inc(fiNextReturnsBefore)
|
||||
else if not (lcSourceToken.TokenType in [ttReturn, ttWhiteSpace, ttComment]) then
|
||||
fiNextReturnsBefore := 0;
|
||||
|
||||
end;
|
||||
|
||||
function TReturnBefore.IsIncludedInSettings: boolean;
|
||||
|
@ -200,8 +200,8 @@ begin
|
||||
{ program uses clauses has a form link comment }
|
||||
if InFilesUses(pt) then
|
||||
begin
|
||||
if ((pt.TokenType = ttComment) and (pt.CommentStyle in CURLY_COMMENTS)) and
|
||||
pt.IsOnRightOf(nUses, ttUses) then
|
||||
if ((pt.TokenType = ttComment) and (pt.CommentStyle=eCurlyBrace)) and
|
||||
pt.IsOnRightOf(nUses, ttUses) then
|
||||
exit(True);
|
||||
end;
|
||||
|
||||
|
@ -89,6 +89,7 @@ const
|
||||
NativeWhiteSpace = [NativeTab, NativeLineFeed, NativeVerticalTab,
|
||||
NativeFormFeed, NativeCarriageReturn, NativeSpace];
|
||||
|
||||
NativeTabSpace =[NativeSpace,NativeTab];
|
||||
NativeDoubleQuote = Char('"');
|
||||
NativeSingleQuote = Char('''');
|
||||
|
||||
@ -125,7 +126,7 @@ function StrCharCount(const S: string; C: Char): Integer;
|
||||
function StrStrCount(const S, SubS: string): Integer;
|
||||
function StrRepeat(const S: string; Count: Integer): string;
|
||||
procedure StrReplace(var S: string; const Search, Replace: string; Flags: TReplaceFlags = []);
|
||||
function StrSearch(const Substr, S: string; const Index: Integer = 1): Integer;
|
||||
function StrSearch(const Substr, S: string; const Index: Integer = 1): Integer; inline;
|
||||
function StrFind(const Substr, S: string; const Index: Integer = 1): Integer;
|
||||
|
||||
function BooleanToStr(B: Boolean): string;
|
||||
@ -155,6 +156,10 @@ function SkipLeftSpaces(const aStr: string; aPos: integer): integer;
|
||||
function SkipToNextLine(const aStr: string; aPos: integer): integer;
|
||||
function HasStringAtLineStart(const aSourceCode: string; const aStr: string): boolean;
|
||||
function StrTrimLastEndOfLine(const aStr:string):string;
|
||||
// string starts with LF, CR, ignores prior spaces
|
||||
function StrStartsWithLineEnd(const aStr:string):boolean;
|
||||
// string ends with LF, CR, ignores trailing spaces
|
||||
function StrEndsWithLineEnd(const aStr:string):boolean;
|
||||
|
||||
type
|
||||
EJcfConversionError = class(Exception)
|
||||
@ -406,14 +411,14 @@ end;
|
||||
|
||||
function StrSearch(const Substr, S: string; const Index: Integer = 1): Integer;
|
||||
begin
|
||||
Result := Pos(SubStr, Copy(S, Index, Length(S)));
|
||||
if Result > 0 then
|
||||
Result := Result + Index - 1;
|
||||
Result := Pos(SubStr, S ,Index);
|
||||
end;
|
||||
|
||||
function StrFind(const Substr, S: string; const Index: Integer = 1): Integer;
|
||||
// Case-insensitive version of StrSearch.
|
||||
begin
|
||||
if Index=1 then
|
||||
exit(PosI(Substr,S));
|
||||
Result := PosI(SubStr, Copy(S, Index, Length(S)));
|
||||
if Result > 0 then
|
||||
Result := Result + Index - 1;
|
||||
@ -730,4 +735,25 @@ begin
|
||||
result:=aStr;
|
||||
end;
|
||||
|
||||
function StrStartsWithLineEnd(const aStr:string):boolean;
|
||||
var
|
||||
i,len:integer;
|
||||
begin
|
||||
len := length(aStr);
|
||||
i:=1;
|
||||
while (i<=len) and (aStr[i] in NativeTabSpace) do //skip spaces
|
||||
inc(i);
|
||||
Result := (i<=len) and CharIsReturn(aStr[i]);
|
||||
end;
|
||||
|
||||
function StrEndsWithLineEnd(const aStr:string):boolean;
|
||||
var
|
||||
i:integer;
|
||||
begin
|
||||
i := length(aStr);
|
||||
while (i>0) and (aStr[i] in NativeTabSpace) do //skip spaces
|
||||
dec(i);
|
||||
Result := (i>0) and CharIsReturn(aStr[i]);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user