diff --git a/components/codetools/codetoolmanager.pas b/components/codetools/codetoolmanager.pas index 3562d65d9c..9e60dea11f 100644 --- a/components/codetools/codetoolmanager.pas +++ b/components/codetools/codetoolmanager.pas @@ -323,6 +323,8 @@ type const Filename: string = ''; SearchInCleanSrc: boolean = true): boolean; function AddResourceDirective(Code: TCodeBuffer; const Filename: string; SearchInCleanSrc: boolean = true; const NewSrc: string = ''): boolean; + function RemoveDirective(Code: TCodeBuffer; NewX, NewY: integer; + RemoveEmptyIFs: boolean): boolean; function FixIncludeFilenames(Code: TCodeBuffer; Recursive: boolean; out MissingIncludeFilesCodeXYPos: TFPList): boolean; function FixMissingH2PasDirectives(Code: TCodeBuffer; @@ -2442,6 +2444,41 @@ begin end; end; +function TCodeToolManager.RemoveDirective(Code: TCodeBuffer; NewX, + NewY: integer; RemoveEmptyIFs: boolean): boolean; +var + Tree: TCompilerDirectivesTree; + p: integer; + Node: TCodeTreeNode; + Changed: boolean; + ParentNode: TCodeTreeNode; +begin + Result:=false; + {$IFDEF CTDEBUG} + DebugLn('TCodeToolManager.RemoveDirective A ',Code.Filename); + {$ENDIF} + try + Code.LineColToPosition(NewY,NewX,p); + if (p<1) or (p>Code.SourceLength) then exit; + Tree:=TCompilerDirectivesTree.Create; + try + Tree.Parse(Code,GetNestedCommentsFlagForFile(Code.Filename)); + Node:=Tree.FindNodeAtPos(p); + if Node=nil then exit; + ParentNode:=Node.Parent; + Changed:=false; + Tree.DisableNode(Node,Changed,true); + if RemoveEmptyIFs and (ParentNode<>nil) and Tree.NodeIsEmpty(ParentNode) then + Tree.DisableNode(ParentNode,Changed,true); + Result:=Changed; + finally + Tree.Free; + end; + except + on e: Exception do Result:=HandleException(e); + end; +end; + function TCodeToolManager.FixIncludeFilenames(Code: TCodeBuffer; Recursive: boolean; out MissingIncludeFilesCodeXYPos: TFPList): boolean; diff --git a/components/codetools/directivestree.pas b/components/codetools/directivestree.pas index 04bde87082..a602b898a8 100644 --- a/components/codetools/directivestree.pas +++ b/components/codetools/directivestree.pas @@ -140,21 +140,7 @@ type procedure EndChildNode; procedure EndIFNode(const ErrorMsg: string); - procedure CheckAndImproveExpr_Brackets(Node: TCodeTreeNode; - var Changed: boolean); - procedure CheckAndImproveExpr_IfDefinedMacro(Node: TCodeTreeNode; - var Changed: boolean); - procedure DisableAllUnusedDefines(var Changed: boolean); - procedure MoveIfNotThenDefsUp(var Changed: boolean); - procedure DisableUnreachableBlocks(Undefines, Defines: TStrings; - var Changed: boolean); - procedure DisableDefineNode(Node: TCodeTreeNode; var Changed: boolean); - procedure DisableIfNode(Node: TCodeTreeNode; WithContent: boolean; - var Changed: boolean); - procedure RemoveNode(Node: TCodeTreeNode); - procedure RemoveEmptyNodes(var Changed: boolean); - function InsertDefine(Position: integer; const NewSrc: string; - SubDesc: TCompilerDirectiveNodeDesc): TCodeTreeNode; + procedure InternalRemoveNode(Node: TCodeTreeNode); public Code: TCodeBuffer; Src: string; @@ -180,12 +166,11 @@ type FindDefNodes: boolean); procedure FixMissingH2PasDirectives(var Changed: boolean); - function NodeStartToCodePos(Node: TCodeTreeNode; - out CodePos: TCodeXYPosition): boolean; function FindResourceDirective(const Filename: string = ''; StartPos: integer = 1): TCodeTreeNode; function IsResourceDirective(Node: TCodeTreeNode; const Filename: string = ''): boolean; + function GetDirectiveName(Node: TCodeTreeNode): string; function GetDirective(Node: TCodeTreeNode): string; function GetIfExpression(Node: TCodeTreeNode; @@ -200,7 +185,28 @@ type ): boolean; function DefineUsesName(DefineNode: TCodeTreeNode; Identifier: PChar): boolean; + function NodeIsEmpty(Node: TCodeTreeNode; IgnoreComments: boolean = true): boolean; function FindNodeAtPos(p: integer): TCodeTreeNode; + function NodeStartToCodePos(Node: TCodeTreeNode; + out CodePos: TCodeXYPosition): boolean; + + procedure CheckAndImproveExpr_Brackets(Node: TCodeTreeNode; + var Changed: boolean); + procedure CheckAndImproveExpr_IfDefinedMacro(Node: TCodeTreeNode; + var Changed: boolean); + procedure DisableAllUnusedDefines(var Changed: boolean); + procedure MoveIfNotThenDefsUp(var Changed: boolean); + procedure DisableUnreachableBlocks(Undefines, Defines: TStrings; + var Changed: boolean); + procedure DisableNode(Node: TCodeTreeNode; var Changed: boolean; + WithContent: boolean); + procedure DisableDefineNode(Node: TCodeTreeNode; var Changed: boolean); + procedure DisableIfNode(Node: TCodeTreeNode; WithContent: boolean; + var Changed: boolean); + function InsertDefine(Position: integer; const NewSrc: string; + SubDesc: TCompilerDirectiveNodeDesc): TCodeTreeNode; + procedure RemoveEmptyNodes(var Changed: boolean); + procedure MoveCursorToPos(p: integer); procedure ReadNextAtom; function ReadTilBracketClose(CloseBracket: char): boolean; @@ -208,7 +214,9 @@ type function UpAtomIs(const s: shortstring): boolean; function AtomIsIdentifier: boolean; function GetAtom: string; + procedure Replace(FromPos, ToPos: integer; const NewSrc: string); + procedure IncreaseChangeStep; procedure ResetMacros; procedure ClearMacros; @@ -1317,6 +1325,16 @@ begin {$ENDIF} end; +procedure TCompilerDirectivesTree.DisableNode(Node: TCodeTreeNode; + var Changed: boolean; WithContent: boolean); +begin + if Node=nil then exit; + case Node.Desc of + cdnDefine: DisableDefineNode(Node,Changed); + cdnIf, cdnElseIf, cdnElse: DisableIfNode(Node,WithContent,Changed); + end; +end; + procedure TCompilerDirectivesTree.DisableDefineNode(Node: TCodeTreeNode; var Changed: boolean); var @@ -1341,11 +1359,11 @@ begin end; Replace(FromPos,ToPos,NewSrc); end else begin - // disable directive -> {$off Define MacroName} + // disable directive -> {off $Define MacroName} Replace(Node.StartPos+1,Node.StartPos+1,'off '); end; Changed:=true; - RemoveNode(Node); + InternalRemoveNode(Node); end; procedure TCompilerDirectivesTree.DisableIfNode(Node: TCodeTreeNode; @@ -1430,7 +1448,7 @@ procedure TCompilerDirectivesTree.DisableIfNode(Node: TCodeTreeNode; end else begin // free nodes and delete code while Node.FirstChild<>nil do - RemoveNode(Node.FirstChild); + InternalRemoveNode(Node.FirstChild); FromPos:=FindCommentEnd(Src,Node.StartPos,NestedComments); ToPos:=Node.NextBrother.StartPos; if RemoveDisabledDirectives then begin @@ -1457,6 +1475,7 @@ var Simplified: Boolean; ExprNegated: boolean; Expr2Negated: boolean; + p: LongInt; begin if (Node.NextBrother=nil) then RaiseImpossible; @@ -1520,6 +1539,29 @@ begin ToPos:=Node.NextBrother.StartPos; if WithContent then begin // remove node source with content + if (FromPos>1) and (Src[FromPos-1] in [#10,#13]) + and (ToPos<=SrcLen) and (Src[ToPos] in [#10,#13]) then begin + // the directive has a complete line + // remove the line end too + inc(ToPos); + if (ToPos<=SrcLen) and (Src[ToPos] in [#10,#13]) and (Src[ToPos]<>Src[ToPos-1]) + then inc(ToPos); + if (ToPos<=SrcLen) and (Src[ToPos] in [#10,#13]) then begin + // there is an empty line behind the directive + // check if there is an empty line in front of the directive + p:=FromPos; + if (p>1) and (Src[p-1] in [#10,#13]) then begin + dec(p); + if (p>1) and (Src[p-1] in [#10,#13]) and (Src[p]<>Src[p-1]) then + dec(p); + if (p>1) and (Src[p-1] in [#10,#13]) then begin + // there is an empty line in front of the directive too + // => remove one empty line + FromPos:=p; + end; + end; + end; + end; Replace(FromPos,ToPos,''); end else begin // remove node source keeping content (child node source) @@ -1538,24 +1580,26 @@ begin end; if Node.NextBrother.Desc=cdnEnd then - RemoveNode(Node.NextBrother); - RemoveNode(Node); + InternalRemoveNode(Node.NextBrother); + InternalRemoveNode(Node); end; -procedure TCompilerDirectivesTree.RemoveNode(Node: TCodeTreeNode); +procedure TCompilerDirectivesTree.InternalRemoveNode(Node: TCodeTreeNode); var AVLNode: TAVLTreeNode; MacroNode: TCompilerMacroStats; begin // clear references - AVLNode:=Macros.FindLowest; - while AVLNode<>nil do begin - MacroNode:=TCompilerMacroStats(AVLNode.Data); - if MacroNode.LastDefineNode=Node then - MacroNode.LastDefineNode:=nil; - if MacroNode.LastReadNode=Node then - MacroNode.LastReadNode:=nil; - AVLNode:=Macros.FindSuccessor(AVLNode); + if Macros<>nil then begin + AVLNode:=Macros.FindLowest; + while AVLNode<>nil do begin + MacroNode:=TCompilerMacroStats(AVLNode.Data); + if MacroNode.LastDefineNode=Node then + MacroNode.LastDefineNode:=nil; + if MacroNode.LastReadNode=Node then + MacroNode.LastReadNode:=nil; + AVLNode:=Macros.FindSuccessor(AVLNode); + end; end; // free node @@ -2415,6 +2459,41 @@ begin Result:=CompareIdentifierPtrs(@Src[p],Identifier)=0; end; +function TCompilerDirectivesTree.NodeIsEmpty(Node: TCodeTreeNode; + IgnoreComments: boolean): boolean; +var + DirectiveEndPos: LongInt; +begin + if (Node=nil) then exit(true); + if Node.FirstChild<>nil then exit(false); + case Node.Desc of + cdnNone: exit(true); + cdnRoot: exit(false); // root is never empty, can not be deleted + cdnDefine: exit(true); + cdnIf, + cdnElseIf, + cdnElse: + begin + if Node.NextBrother=nil then exit(false); // maybe continued in another file + MoveCursorToPos(Node.StartPos); + // skip directive + ReadNextAtom; + DirectiveEndPos:=SrcPos; + // read the following atom (token or directive) + ReadNextAtom; + if AtomStart=Node.NextBrother.StartPos then begin + if IgnoreComments then + exit(true) + else if FindNextNonSpace(Src,DirectiveEndPos) - + - + diff --git a/components/codetools/examples/replaceresourcedirectives.lpr b/components/codetools/examples/replaceresourcedirectives.lpr index 2a54fba0db..c60e1aa0cd 100644 --- a/components/codetools/examples/replaceresourcedirectives.lpr +++ b/components/codetools/examples/replaceresourcedirectives.lpr @@ -45,7 +45,7 @@ begin Code:=CodeToolBoss.LoadFile(Filename,false,false); if Code=nil then raise Exception.Create('loading failed '+Filename); - + if not CodeToolBoss.AddResourceDirective(Code,'*.res',false, '{$IFDEF SomePlatform}{$R *.res}{$ENDIF}') then begin @@ -58,16 +58,28 @@ begin if not CodeToolBoss.FindResourceDirective(Code,1,1, NewCode,NewX,NewY,NewTopLine,'',false) then begin - writeln('FAILED: did not find the resource'); + writeln('FAILED: did not find any resource directive'); if CodeToolBoss.ErrorMessage<>'' then writeln('CodeToolBoss.ErrorMessage=',CodeToolBoss.ErrorMessage); halt; end; + // write the new source: + writeln('---------BEFORE REMOVE-------------'); + writeln(Code.Source); + writeln('-----------------------------------'); + writeln(NewCode.Filename,' X=',NewX,' Y=',NewY); + + if not CodeToolBoss.RemoveDirective(NewCode,NewX,NewY,true) then begin + writeln('FAILED to remove resource directive'); + if CodeToolBoss.ErrorMessage<>'' then + writeln('CodeToolBoss.ErrorMessage=',CodeToolBoss.ErrorMessage); + halt; + end; // write the new source: - writeln('-----------------------------------'); + writeln('---------AFTER REMOVE---------------'); writeln(Code.Source); writeln('-----------------------------------'); end. diff --git a/components/daemon/lazdaemon.pas b/components/daemon/lazdaemon.pas index 129579e9c5..022df7267c 100644 --- a/components/daemon/lazdaemon.pas +++ b/components/daemon/lazdaemon.pas @@ -7,13 +7,13 @@ unit lazdaemon; interface uses - reglazdaemon, daemonapp, lazdaemonapp, LazarusPackageIntf; + RegLazDaemon, daemonapp, lazdaemonapp, LazarusPackageIntf; implementation procedure Register; begin - RegisterUnit('reglazdaemon', @reglazdaemon.Register); + RegisterUnit('RegLazDaemon', @RegLazDaemon.Register); end; initialization diff --git a/components/daemon/reglazdaemon.pp b/components/daemon/reglazdaemon.pp index b42c4d69c1..3b56927ff4 100644 --- a/components/daemon/reglazdaemon.pp +++ b/components/daemon/reglazdaemon.pp @@ -10,20 +10,18 @@ * * ***************************************************************************** } -unit reglazdaemon; +unit RegLazDaemon; {$mode objfpc}{$H+} interface uses - Classes, SysUtils, FormEditingIntf, projectintf,newitemintf, lazideintf, - controls, forms; + Classes, SysUtils, FormEditingIntf, ProjectIntf, NewItemIntf, LazIDEIntf, + Controls, Forms; Type - { TDaemonFileDescriptor } - { TDaemonMapperDescriptor } TDaemonMapperDescriptor = Class(TFileDescPascalUnitWithResource) @@ -35,6 +33,8 @@ Type function GetImplementationSource(const Filename, SourceName, ResourceName: string): string; override; end; + { TDaemonFileDescriptor } + TDaemonFileDescriptor = Class(TFileDescPascalUnitWithResource) Public Constructor Create; override; diff --git a/ide/projectopts.pp b/ide/projectopts.pp index a89132b8b7..cc14a8a9fa 100644 --- a/ide/projectopts.pp +++ b/ide/projectopts.pp @@ -461,7 +461,7 @@ begin TargetFilename := TargetFileEdit.Text; UseAppBundle := UseAppBundleCheckBox.Checked; XPManifest.UseManifest := UseXPManifestCheckBox.Checked; - Project.XPManifest.UpdateMainSourceFile(Project.MainFilename); + XPManifest.UpdateMainSourceFile(Project.MainFilename); end; // flags @@ -511,7 +511,7 @@ begin Project.VersionInfo.CopyrightString:=CopyrightEdit.Text; Project.VersionInfo.HexLang:=MSLanguageToHex(LanguageSelectionComboBox.Text); Project.VersionInfo.HexCharSet:=MSCharacterSetToHex(CharacterSetComboBox.Text); - if Project.VersionInfo.UseVersionInfo and Project.VersionInfo.Modified then + if Project.VersionInfo.Modified then Project.VersionInfo.UpdateMainSourceFile(Project.MainFilename); end; diff --git a/ide/projectopts_new.pp b/ide/projectopts_new.pp index c61deaf85f..c690287e80 100644 --- a/ide/projectopts_new.pp +++ b/ide/projectopts_new.pp @@ -515,7 +515,7 @@ begin Project.VersionInfo.CopyrightString:=CopyrightEdit.Text; Project.VersionInfo.HexLang:=MSLanguageToHex(LanguageSelectionComboBox.Text); Project.VersionInfo.HexCharSet:=MSCharacterSetToHex(CharacterSetComboBox.Text); - if Project.VersionInfo.UseVersionInfo and Project.VersionInfo.Modified then + if Project.VersionInfo.Modified then Project.VersionInfo.UpdateMainSourceFile(Project.MainFilename); end; diff --git a/ide/uniteditor.pp b/ide/uniteditor.pp index 556cd2a190..07335a4946 100644 --- a/ide/uniteditor.pp +++ b/ide/uniteditor.pp @@ -1425,7 +1425,7 @@ begin inc(SourceCompletionCaretXY.x,length(AChar)); SourceCompletionTimer.AutoEnabled:=true; end; - //DebugLn(['TSourceEditor.ProcessCommand AddCHar=',AddCHar]); + //DebugLn(['TSourceEditor.ProcessCommand ecChar AddChar=',AddChar]); if not AddChar then Command:=ecNone; end; @@ -1433,6 +1433,7 @@ begin begin AddChar:=true; if AutoCompleteChar(aChar,AddChar,acoLineBreak) then ; + //DebugLn(['TSourceEditor.ProcessCommand ecLineBreak AddChar=',AddChar]); if not AddChar then Command:=ecNone; end; end; @@ -2145,6 +2146,7 @@ begin and (FCodeTemplates.CompletionAttributes[i].IndexOfName(CatName)>=0) then begin Result:=true; + DebugLn(['TSourceEditor.AutoCompleteChar ',AToken,' SrcToken=',SrcToken,' CatName=',CatName,' Index=',FCodeTemplates.CompletionAttributes[i].IndexOfName(CatName)]); FCodeTemplates.ExecuteCompletion(AToken,FEditor); AddChar:=not FCodeTemplates.CompletionAttributes[i].IndexOfName( AutoCompleteOptionNames[acoRemoveChar])>=0; diff --git a/ide/w32manifest.pas b/ide/w32manifest.pas index 15237ef6a1..c526c58cee 100644 --- a/ide/w32manifest.pas +++ b/ide/w32manifest.pas @@ -118,45 +118,39 @@ end; function TProjectXPManifest.UpdateMainSourceFile(const AFilename: string): TModalResult; var NewX, NewY, NewTopLine: integer; - ManifestCodeBuf: TCodeBuffer; - CodePos: TCodeXYPosition; + ManifestCodeBuf, NewCode: TCodeBuffer; + Filename: String; begin Result := mrCancel; ManifestCodeBuf := CodeToolBoss.LoadFile(AFilename,false,false); if ManifestCodeBuf <> nil then begin SetFileNames(AFilename); - if not CodeToolBoss.FindResourceDirective(ManifestCodeBuf, 1, 1, - ManifestCodeBuf, NewX, NewY, - NewTopLine, ExtractFileName(resFileName)) then + Filename:=ExtractFileName(resFileName); + DebugLn(['TProjectXPManifest.UpdateMainSourceFile ',Filename]); + if CodeToolBoss.FindResourceDirective(ManifestCodeBuf, 1, 1, + NewCode, NewX, NewY, + NewTopLine, Filename, false) then begin - if UseManifest then - begin - if not CodeToolBoss.AddResourceDirective(ManifestCodeBuf, ExtractFileName(resFileName)) then + // there is a resource directive in the source + if not UseManifest then begin + if not CodeToolBoss.RemoveDirective(NewCode, NewX,NewY,true) then begin - Messages.Add('Could not add "{$R'+ ExtractFileName(resFileName) +'"} to main source!'); + Messages.Add('Could not remove "{$R'+ Filename +'"} from main source!'); exit; end; end; - end else - if not UseManifest then + end else if UseManifest then begin - with CodeToolBoss.CurCodeTool do + if not CodeToolBoss.AddResourceDirective(ManifestCodeBuf, + Filename,false,'{$IFDEF WINDOWS}{$R '+Filename+'}{$ENDIF}') then begin - CodeToolBoss.SourceChangeCache.MainScanner := Scanner; - CodePos.Code := ManifestCodeBuf; - CodePos.X := NewX; - CodePos.Y := NewY; - CaretToCleanPos(CodePos, NewX); - if CodeToolBoss.SourceChangeCache.Replace(gtNone, gtNone, NewX, NewX + Length(ExtractFileName(resFileName)) + 5, '') then - begin - if not CodeToolBoss.SourceChangeCache.Apply then - exit; - end else - exit; + Messages.Add('Could not add "{$R'+ Filename +'"} to main source!'); + exit; end; end; end; + DebugLn(['TProjectXPManifest.UpdateMainSourceFile END ',ManifestCodeBuf.Source]); Result := mrOk; end; diff --git a/ide/w32versioninfo.pas b/ide/w32versioninfo.pas index 7654c2fd87..3220451f5f 100644 --- a/ide/w32versioninfo.pas +++ b/ide/w32versioninfo.pas @@ -796,28 +796,46 @@ end; TProjectVersionInfo UpdateMainSourceFile -----------------------------------------------------------------------------} function TProjectVersionInfo.UpdateMainSourceFile(const AFilename: string - ): TModalResult; + ): TModalResult; var - NewX, NewY, NewTopLine: integer; - VersionInfoCodeBuf: TCodeBuffer; + NewX, NewY, NewTopLine: integer; + VersionInfoCodeBuf: TCodeBuffer; + Filename: String; + NewCode: TCodeBuffer; begin - Result := mrCancel; - VersionInfoCodeBuf:=CodeToolBoss.LoadFile(AFilename,false,false); - if VersionInfoCodeBuf=nil then exit; - SetFileNames(AFilename); - if not CodeToolBoss.FindResourceDirective(VersionInfoCodeBuf,1,1, - VersionInfoCodeBuf,NewX,NewY, - NewTopLine,ExtractFileName(resFilename)) then - begin - if not CodeToolBoss.AddResourceDirective(VersionInfoCodeBuf, - ExtractFileName(resFilename)) then - begin - VersionInfoMessages.Add('Could not add "{$R ' - + ExtractFileName(resFilename)+'}" to main source!'); - exit; - end - end; - Result:=mrOk; + Result := mrCancel; + VersionInfoCodeBuf:=CodeToolBoss.LoadFile(AFilename,false,false); + if VersionInfoCodeBuf=nil then exit; + SetFileNames(AFilename); + Filename:=ExtractFileName(resFilename); + //DebugLn(['TProjectVersionInfo.UpdateMainSourceFile ',Filename,' UseVersionInfo=',UseVersionInfo]); + if CodeToolBoss.FindResourceDirective(VersionInfoCodeBuf,1,1, + NewCode,NewX,NewY, + NewTopLine,Filename,false) then + begin + if not UseVersionInfo then begin + //DebugLn(['TProjectVersionInfo.UpdateMainSourceFile removing ',NewCode.Filename,' X=',NewX,' Y=',NewY]); + if not CodeToolBoss.RemoveDirective(NewCode,NewX,NewY,true) then + begin + DebugLn(['TProjectVersionInfo.UpdateMainSourceFile FAILED removing']); + VersionInfoMessages.Add('Could not emove "{$R ' + + Filename+'}" from main source!'); + exit; + end + end; + end else if UseVersionInfo then begin + //DebugLn(['TProjectVersionInfo.UpdateMainSourceFile adding ',AFilename]); + if not CodeToolBoss.AddResourceDirective(VersionInfoCodeBuf, + Filename,false,'{$IFDEF WINDOWS}{$R '+Filename+'}{$ENDIF}') then + begin + DebugLn(['TProjectVersionInfo.UpdateMainSourceFile FAILED adding']); + VersionInfoMessages.Add('Could not add "{$R ' + + Filename+'}" to main source!'); + exit; + end + end; + //DebugLn(['TProjectVersionInfo.UpdateMainSourceFile ',VersionInfoCodeBuf.Source]); + Result:=mrOk; end; {-----------------------------------------------------------------------------