diff --git a/components/codetools/basiccodetools.pas b/components/codetools/basiccodetools.pas index cd98621678..7abd893824 100644 --- a/components/codetools/basiccodetools.pas +++ b/components/codetools/basiccodetools.pas @@ -21,10 +21,9 @@ Author: Mattias Gaertner Abstract: - Basic pascal code functions. Most of the functions have counterparts in the + Basic pascal code functions. Many of the functions have counterparts in the code tools, which are faster, more flexible and aware of compiler settings - and directives. They are only used for code building. - + and directives. } unit BasicCodeTools; @@ -119,15 +118,30 @@ function ReadRawNextPascalAtom(const Source:string; var Position,AtomStart:integer):string; //---------------------------------------------------------------------------- +// comments +function FindCommentEnd(const ASource: string; StartPos: integer; + NestedComments: boolean): integer; +function FindNextCompilerDirective(const ASource: string; StartPos: integer; + NestedComments: boolean): integer; + +// line ranges and indent procedure GetLineStartEndAtPosition(const Source:string; Position:integer; var LineStart,LineEnd:integer); +function GetLineIndent(const Source: string; Position: integer): integer; +function GetIndentStr(Indent: integer): string; +function LineEndCount(const Txt: string; var LengthOfLastLine:integer): integer; + +// identifiers procedure GetIdentStartEndAtPosition(const Source:string; Position:integer; var IdentStart,IdentEnd:integer); function GetIdentLen(Identifier: PChar): integer; -function LineEndCount(const Txt: string; var LengthOfLastLine:integer): integer; +function GetIdentifier(Identifier: PChar): string; +function FindNextIdentifier(const Source: string; StartPos, MaxPos: integer + ): integer; + +// line/code ends function FindFirstNonSpaceCharInLine(const Source: string; Position: integer): integer; -function GetLineIndent(const Source: string; Position: integer): integer; function FindLineEndOrCodeInFrontOfPosition(const Source: string; Position, MinPosition: integer; NestedComments: boolean): integer; function FindLineEndOrCodeAfterPosition(const Source: string; @@ -136,6 +150,8 @@ function FindFirstLineEndInFrontOfInCode(const Source: string; Position, MinPosition: integer; NestedComments: boolean): integer; function FindFirstLineEndAfterInCode(const Source: string; Position, MaxPosition: integer; NestedComments: boolean): integer; + +// replacements function ReplacementNeedsLineEnd(const Source: string; FromPos, ToPos, NewLength, MaxLineLength: integer): boolean; function CountNeededLineEndsToAddForward(const Src: string; @@ -143,23 +159,22 @@ function CountNeededLineEndsToAddForward(const Src: string; function CountNeededLineEndsToAddBackward(const Src: string; StartPos, MinLineEnds: integer): integer; - +// comparison function CompareTextIgnoringSpace(const Txt1, Txt2: string; CaseSensitive: boolean): integer; function CompareSubStrings(const Find, Txt: string; FindStartPos, TxtStartPos, Len: integer; CaseSensitive: boolean): integer; +function CompareIdentifiers(Identifier1, Identifier2: PChar): integer; + +// function CleanCodeFromComments(const DirtyCode: string; NestedComments: boolean): string; -function CompareIdentifiers(Identifier1, Identifier2: PChar): integer; -function GetIdentifier(Identifier: PChar): string; - function TrimCodeSpace(const ACode: string): string; -function GetIndentStr(Indent: integer): string; - //----------------------------------------------------------------------------- + const - MaxLineLength:integer=80; + MaxLineLength: integer = 80; const // ToDo: find the constant in the fpc units. @@ -892,6 +907,123 @@ begin until false; end; +function FindNextCompilerDirective(const ASource: string; StartPos: integer; + NestedComments: boolean): integer; +var + MaxPos: integer; +begin + MaxPos:=length(ASource); + Result:=StartPos; + while (Result<=MaxPos) do begin + case ASource[Result] of + '''': + begin + inc(Result); + while (Result<=MaxPos) do begin + if (ASource[Result]<>'''') then + inc(Result) + else begin + inc(Result); + break; + end; + end; + end; + + '/': + begin + inc(Result); + if (Result<=MaxPos) and (ASource[Result]='/') then begin + // skip Delphi comment + while (Result<=MaxPos) and (not (ASource[Result] in [#10,#13])) do + inc(Result); + end; + end; + + '{': + begin + if (ResultMaxPos+1 then Result:=MaxPos+1; +end; + +function FindCommentEnd(const ASource: string; StartPos: integer; + NestedComments: boolean): integer; +var + MaxPos, CommentLvl: integer; +begin + MaxPos:=length(ASource); + Result:=StartPos; + if Result>MaxPos then exit; + case ASource[Result] of + '/': + begin + if (Result=l do begin + m:=(l+r) shr 1; + if UniqueSortedCodeList[m]ACode then + l:=m+1 + else begin + Result:=m; + exit; + end; + end; + Result:=-1; +end; + +procedure AddCodeToUniqueList(ACode: Pointer; UniqueSortedCodeList: TList); +var l,m,r: integer; +begin + l:=0; + r:=UniqueSortedCodeList.Count-1; + m:=0; + while r>=l do begin + m:=(l+r) shr 1; + if UniqueSortedCodeList[m]ACode then + l:=m+1 + else + exit; + end; + if (m=l do begin - m:=(l+r) shr 1; - if UniqueSortedCodeList[m]ACode then - l:=m+1 - else - exit; - end; - if (m=LinkCount) or (Links[LinkIndex].CleanedPos>CleanEndPos) then exit; if ACode<>Links[LinkIndex].Code then begin ACode:=Links[LinkIndex].Code; - AddCodeToList(ACode); + AddCodeToUniqueList(ACode,UniqueSortedCodeList); end; until false; end; diff --git a/components/codetools/sourcechanger.pas b/components/codetools/sourcechanger.pas index cd0a9f82a1..c36ec9655b 100644 --- a/components/codetools/sourcechanger.pas +++ b/components/codetools/sourcechanger.pas @@ -360,7 +360,7 @@ begin end; // add entry NewEntry:=TSourceChangeCacheEntry.Create(FrontGap,AfterGap,FromPos,ToPos, - Text,FromCode,FromDirectPos); + Text,FromCode,FromDirectPos); ANode:=FEntries.Add(NewEntry); if ToPos=FromPos then FEntries.MoveDataLeftMost(ANode) @@ -368,6 +368,7 @@ begin // the new entry is a delete operation -> put it rightmost, so that it will // be applied first FEntries.MoveDataRightMost(ANode); + FBuffersToModifyNeedsUpdate:=true; Result:=true; {$IFDEF CTDEBUG} diff --git a/components/codetools/stdcodetools.pas b/components/codetools/stdcodetools.pas index cd5c1bab55..ace2f5f1ac 100644 --- a/components/codetools/stdcodetools.pas +++ b/components/codetools/stdcodetools.pas @@ -29,9 +29,6 @@ - Application.CreateForm statements - published variables - ToDo: - -Insert class method body in pipClassOrder - } unit StdCodeTools; @@ -58,6 +55,10 @@ type function ReadForwardTilAnyBracketClose: boolean; function ReadBackwardTilAnyBracketClose: boolean; public + // search & replace + function ReplaceIdentifiers(IdentList: TStrings; + SourceChangeCache: TSourceChangeCache): boolean; + // source name e.g. 'unit UnitName;' function GetSourceNamePos(var NamePos: TAtomPosition): boolean; function GetSourceName: string; @@ -115,6 +116,11 @@ type function SetAllCreateFromStatements(List: TStrings; SourceChangeCache: TSourceChangeCache): boolean; + // forms + function RenameForm(const OldFormName, OldFormClassName: string; + const NewFormName, NewFormClassName: string; + SourceChangeCache: TSourceChangeCache): boolean; + // form components function FindPublishedVariable(const UpperClassName, UpperVarName: string): TCodeTreeNode; @@ -923,6 +929,106 @@ begin Result:=SourceChangeCache.Apply; end; +function TStandardCodeTool.RenameForm(const OldFormName, + OldFormClassName: string; const NewFormName, NewFormClassName: string; + SourceChangeCache: TSourceChangeCache): boolean; +var + IdentList: TStringList; +begin + Result:=false; + if (OldFormName='') or (OldFormClassName='') + or (NewFormName='') or (NewFormClassName='') + or (SourceChangeCache=nil) then exit; + IdentList:=TStringList.Create; + try + IdentList.Add(OldFormName); + IdentList.Add(NewFormName); + IdentList.Add(OldFormClassName); + IdentList.Add(NewFormClassName); + Result:=ReplaceIdentifiers(IdentList,SourceChangeCache); + finally + IdentList.Free; + end; +end; + +{------------------------------------------------------------------------------- + function TStandardCodeTool.ReplaceIdentifiers(IdentList: TStrings; + SourceChangeCache: TSourceChangeCache): boolean; + + Search in all used sources (not the cleaned source) for identifiers. + It will find all identifiers, except identifiers in compiler directives. + This includes identifiers in string constants and comments. +-------------------------------------------------------------------------------} +function TStandardCodeTool.ReplaceIdentifiers(IdentList: TStrings; + SourceChangeCache: TSourceChangeCache): boolean; + + procedure ReplaceIdentifiersInSource(Code: TCodeBuffer); + var + StartPos, EndPos, MaxPos, IdentStart: integer; + CurSource: string; + i: integer; + begin + CurSource:=Code.Source; + MaxPos:=length(CurSource); + StartPos:=1; + // go through all source parts between compiler directives + repeat + EndPos:=FindNextCompilerDirective(CurSource,StartPos, + Scanner.NestedComments); + if EndPos>MaxPos then EndPos:=MaxPos+1; + // search all identifiers + repeat + IdentStart:=FindNextIdentifier(CurSource,StartPos,EndPos-1); + if IdentStart replace + + break; + end; + inc(i,2); + end; + // skip identifier + StartPos:=IdentStart; + while (StartPosMaxPos then break; + end else begin + break; + end; + until false; + end; + +var + SourceList: TList; + i: integer; +begin + Result:=false; + if (IdentList=nil) or (IdentList.Count=0) or (SourceChangeCache=nil) + or (Odd(IdentList.Count)) then exit; + BuildTree(false); + if Scanner=nil then exit; + SourceList:=TList.Create; + try + Scanner.FindCodeInRange(1,SrcLen,SourceList); + for i:=0 to SourceList.Count-1 do begin + ReplaceIdentifiersInSource(TCodeBuffer(SourceList[i])); + end; + finally + SourceList.Free; + end; +end; + function TStandardCodeTool.FindPublishedVariable(const UpperClassName, UpperVarName: string): TCodeTreeNode; var ClassNode, SectionNode: TCodeTreeNode; diff --git a/ide/main.pp b/ide/main.pp index 514be0ebac..ecddb29fe9 100644 --- a/ide/main.pp +++ b/ide/main.pp @@ -5507,7 +5507,7 @@ procedure TMainIDE.OnDesignerModified(Sender: TObject); var i: integer; SrcEdit: TSourceEditor; begin - i:=Project1.IndexOfUnitWithForm(TDesigner(Sender).Form,false); + i:=Project1.IndexOfUnitWithForm(TDesigner(Sender).Form,false,nil); if i>=0 then begin Project1.Units[i].Modified:=true; if Project1.Units[i].Loaded then @@ -6079,11 +6079,15 @@ procedure TMainIDE.OnDesignerRenameComponent(ADesigner: TDesigner; var ActiveSrcEdit: TSourceEditor; ActiveUnitInfo: TUnitInfo; + i: integer; + NewClassName: string; begin BeginCodeTool(ActiveSrcEdit,ActiveUnitInfo,false); + ActiveUnitInfo:=Project1.UnitWithForm(ADesigner.Form); + if CodeToolBoss.IsKeyWord(ActiveUnitInfo.Source,NewName) then + raise Exception.Create('Component name "'+Newname+'" is keyword'); if AComponent.Owner<>nil then begin // rename published variable in form source - ActiveUnitInfo:=Project1.UnitWithForm(ADesigner.Form); if CodeToolBoss.RenamePublishedVariable(ActiveUnitInfo.Source, ADesigner.Form.ClassName, AComponent.Name,NewName,AComponent.ClassName) then @@ -6096,11 +6100,33 @@ begin +'See messages.'); end; end else if AComponent=ADesigner.Form then begin + // rename form // ToDo: // rename form in source - // rename form variable + // rename formclass // replace createform statement - // delete old form resource in resource file + + // check if formname already exists + i:=Project1.IndexOfUnitWithFormName(NewName,true,ActiveUnitInfo); + if i>=0 then + raise Exception.Create( + 'There is already a form with the name "'+Newname+'"'); + NewClassName:='T'+NewName; + + // rename form in source + if CodeToolBoss.RenameForm(ActiveUnitInfo.Source, + AComponent.Name,AComponent.ClassName, + NewName,NewClassName) then + begin + ApplyCodeToolChanges; + end else begin + ApplyCodeToolChanges; + DoJumpToCodeToolBossError; + raise Exception.Create('Unable to rename form in source.'#13 + +'See messages.'); + end; + + MessageDlg('Not implemented yet.', 'Form renaming in source is not implemented yet.', mtInformation,[mbOk],0); @@ -6339,7 +6365,7 @@ procedure TMainIDE.DoSwitchToFormSrc(var ActiveSourceEditor: TSourceEditor; var i: integer; begin if PropertyEditorHook1.LookupRoot<>nil then begin - i:=Project1.IndexOfUnitWithForm(PropertyEditorHook1.LookupRoot,false); + i:=Project1.IndexOfUnitWithForm(PropertyEditorHook1.LookupRoot,false,nil); if (i>=0) then begin i:=Project1.Units[i].EditorIndex; if (i>=0) then begin @@ -6603,6 +6629,9 @@ end. { ============================================================================= $Log$ + Revision 1.346 2002/08/23 07:05:14 lazarus + MG: started form renaming + Revision 1.345 2002/08/21 07:16:57 lazarus MG: reduced mem leak of clipping stuff, still not fixed diff --git a/ide/outputfilter.pas b/ide/outputfilter.pas index 0f2c3e564c..3225749d17 100644 --- a/ide/outputfilter.pas +++ b/ide/outputfilter.pas @@ -60,10 +60,12 @@ type fOptions: TOuputFilterOptions; fProject: TProject; fPrgSourceFilename: string; + FStopExecute: boolean; procedure DoAddFilteredLine(const s: string); procedure DoAddLastLinkerMessages; procedure DoAddLastAssemblerMessages; function SearchIncludeFile(const ShortIncFilename: string): string; + procedure SetStopExecute(const AValue: boolean); public procedure Execute(TheProcess: TProcess); function GetSourcePosition(const Line: string; var Filename:string; @@ -79,6 +81,7 @@ type function ReadMakeLine(const s: string): boolean; property CurrentDirectory: string read fCurrentDirectory; property FilteredLines: TStringList read fFilteredOutput; + property StopExecute: boolean read FStopExecute write SetStopExecute; property Lines: TStringList read fOutput; property LastErrorType: TErrorType read fLastErrorType; property LastMessageType: TOutputMessageType read fLastMessageType; @@ -130,6 +133,7 @@ begin fFilteredOutput.Clear; if fCompilingHistory<>nil then fCompilingHistory.Clear; if fMakeDirHistory<>nil then fMakeDirHistory.Clear; + FStopExecute:=false; end; procedure TOutputFilter.Execute(TheProcess: TProcess); @@ -148,11 +152,13 @@ begin and (fCurrentDirectory[length(fCurrentDirectory)]<>PathDelim) then fCurrentDirectory:=fCurrentDirectory+PathDelim; SetLength(Buf,BufSize); - Application.ProcessMessages; OutputLine:=''; ErrorExists:=false; repeat + Application.ProcessMessages; + if StopExecute then exit; + if TheProcess.Output<>nil then Count:=TheProcess.Output.Read(Buf[1],length(Buf)) else @@ -542,6 +548,11 @@ begin Result:=ShortIncFilename; end; +procedure TOutputFilter.SetStopExecute(const AValue: boolean); +begin + FStopExecute:=AValue; +end; + destructor TOutputFilter.Destroy; begin fFilteredOutput.Free;