diff --git a/debugger/debugger.pp b/debugger/debugger.pp index 00e7d674b5..c9fec617ca 100644 --- a/debugger/debugger.pp +++ b/debugger/debugger.pp @@ -201,6 +201,7 @@ type FValid: TValidState; FInitialEnabled: Boolean; protected + procedure AssignLocationTo(Dest: TPersistent); virtual; procedure AssignTo(Dest: TPersistent); override; procedure DoBreakHitCountChange; virtual; procedure DoExpressionChange; virtual; @@ -1924,6 +1925,13 @@ end; TBaseBreakPoint =========================================================================== } +procedure TBaseBreakPoint.AssignLocationTo(Dest: TPersistent); +var + DestBreakPoint: TBaseBreakPoint absolute Dest; +begin + DestBreakPoint.SetLocation(FSource, FLine); +end; + procedure TBaseBreakPoint.AssignTo(Dest: TPersistent); var DestBreakPoint: TBaseBreakPoint absolute Dest; @@ -1931,8 +1939,8 @@ begin // updatelock is set in source.assignto if Dest is TBaseBreakPoint then begin + AssignLocationTo(DestBreakPoint); DestBreakPoint.SetBreakHitCount(FBreakHitCount); - DestBreakPoint.SetLocation(FSource, FLine); DestBreakPoint.SetExpression(FExpression); DestBreakPoint.SetEnabled(FEnabled); DestBreakPoint.InitialEnabled := FInitialEnabled; diff --git a/ide/debugmanager.pas b/ide/debugmanager.pas index f4b01e75c9..b9fb802d4d 100644 --- a/ide/debugmanager.pas +++ b/ide/debugmanager.pas @@ -210,6 +210,7 @@ type private FMaster: TDBGBreakPoint; FSourceMark: TSourceMark; + FCurrentDebugExeLine: Integer; procedure OnSourceMarkBeforeFree(Sender: TObject); procedure OnSourceMarkCreatePopupMenu(SenderMark: TSourceMark; const AddMenuItem: TAddMenuItemProc); @@ -219,6 +220,7 @@ type procedure OnDeleteMenuItemClick(Sender: TObject); procedure OnViewPropertiesMenuItemClick(Sender: TObject); protected + procedure AssignLocationTo(Dest: TPersistent); override; procedure AssignTo(Dest: TPersistent); override; procedure DoChanged; override; function GetHitCount: Integer; override; @@ -230,6 +232,7 @@ type procedure UpdateSourceMark; procedure UpdateSourceMarkImage; procedure UpdateSourceMarkLineColor; + function DebugExeLine: Integer; // If known, the line in the compiled exe public destructor Destroy; override; procedure ResetMaster; @@ -1057,6 +1060,16 @@ begin DebugBoss.ShowBreakPointProperties(Self); end; +procedure TManagedBreakPoint.AssignLocationTo(Dest: TPersistent); +var + DestBreakPoint: TBaseBreakPoint absolute Dest; +begin + if DestBreakPoint is TDBGBreakPoint then + DestBreakPoint.SetLocation(Source, DebugExeLine) + else + inherited; +end; + procedure TManagedBreakPoint.OnSourceMarkBeforeFree(Sender: TObject); begin SourceMark:=nil; @@ -1166,10 +1179,15 @@ end; procedure TManagedBreakPoint.SetLocation(const ASource: String; const ALine: Integer); +var + NewDebugExeLine: Integer; begin - if (Source = ASource) and (Line = ALine) then exit; + NewDebugExeLine := DebugExeLine; + if (Source = ASource) and (Line = ALine) and (FCurrentDebugExeLine = NewDebugExeLine) + then exit; inherited SetLocation(ASource, ALine); - if FMaster<>nil then FMaster.SetLocation(ASource,ALine); + FCurrentDebugExeLine := NewDebugExeLine; + if FMaster<>nil then FMaster.SetLocation(ASource, DebugExeLine); if Project1 <> nil then Project1.Modified := True; end; @@ -1225,6 +1243,14 @@ begin SourceMark.LineColorAttrib := aha; end; +function TManagedBreakPoint.DebugExeLine: Integer; +begin + if (FSourceMark <> nil) and (FSourceMark.SourceEditor <> nil) then + Result := TSourceEditor(FSourceMark.SourceEditor).SourceToDebugLine(Line) + else + Result := Line; +end; + procedure TManagedBreakPoint.UpdateSourceMark; begin UpdateSourceMarkImage; @@ -1464,6 +1490,7 @@ const var Editor: TSourceEditor; MsgResult: TModalResult; + i: Integer; begin if (ADebugger<>FDebugger) or (ADebugger=nil) then RaiseException('TDebugManager.OnDebuggerChangeState'); @@ -1532,8 +1559,13 @@ begin then SourceEditorManager.FillExecutionMarks; - if not (FDebugger.State in [dsRun, dsPause]) and (SourceEditorManager <> nil) then + if not (FDebugger.State in [dsRun, dsPause]) and (SourceEditorManager <> nil) + then begin SourceEditorManager.ClearExecutionMarks; + // Refresh DebugExeLine + for i := 0 to FBreakPoints.Count - 1 do + FBreakPoints[i].SetLocation(FBreakPoints[i].Source, FBreakPoints[i].Line); + end; case FDebugger.State of dsError: begin @@ -1633,21 +1665,23 @@ begin end; // clear old error and execution lines + Editor := nil; if SourceEditorManager <> nil then begin + Editor := SourceEditorManager.GetActiveSE; SourceEditorManager.ClearExecutionLines; SourceEditorManager.ClearErrorLines; end; + // jump editor to execution line FocusEditor := (FCurrentBreakPoint = nil) or (FCurrentBreakPoint.AutoContinueTime = 0); - if MainIDE.DoJumpToCodePos(nil,nil,NewSource,1,SrcLine,-1,true, FocusEditor)<>mrOk + i := SrcLine; + if Editor <> nil then + i := Editor.DebugToSourceLine(i); + if MainIDE.DoJumpToCodePos(nil,nil,NewSource,1,i,-1,true, FocusEditor)<>mrOk then exit; // mark execution line - if SourceEditorManager <> nil - then Editor := SourceEditorManager.GetActiveSE - else Editor := nil; - if Editor <> nil then begin if not Editor.HasExecutionMarks then diff --git a/ide/sourceeditor.pp b/ide/sourceeditor.pp index 87d7cff7e9..dad0f75dc1 100644 --- a/ide/sourceeditor.pp +++ b/ide/sourceeditor.pp @@ -424,6 +424,8 @@ type procedure FillExecutionMarks; procedure ClearExecutionMarks; procedure LineInfoNotificationChange(const ASender: TObject; const ASource: String); + function SourceToDebugLine(aLinePos: Integer): Integer; + function DebugToSourceLine(aLinePos: Integer): Integer; public // properties property CodeBuffer: TCodeBuffer read FCodeBuffer write SetCodeBuffer; @@ -3372,6 +3374,7 @@ end; procedure TSourceEditor.SetExecutionLine(NewLine: integer); begin + NewLine := EditorComponent.IDEGutterMarks.DebugLineToSourceLine(NewLine); if ExecutionLine=NewLine then exit; if (FSharedValues.ExecutionMark = nil) then begin if NewLine = -1 then @@ -4353,6 +4356,16 @@ begin FillExecutionMarks; end; +function TSourceEditor.SourceToDebugLine(aLinePos: Integer): Integer; +begin + Result := FEditor.IDEGutterMarks.SourceLineToDebugLine(aLinePos, True); +end; + +function TSourceEditor.DebugToSourceLine(aLinePos: Integer): Integer; +begin + Result := FEditor.IDEGutterMarks.DebugLineToSourceLine(aLinePos); +end; + function TSourceEditor.SharedEditorCount: Integer; begin Result := FSharedValues.SharedEditorCount; diff --git a/ide/sourcesyneditor.pas b/ide/sourcesyneditor.pas index e51961b5fd..a43e5c6bc4 100644 --- a/ide/sourcesyneditor.pas +++ b/ide/sourcesyneditor.pas @@ -37,7 +37,7 @@ interface {$I ide.inc} uses - Classes, SysUtils, Graphics, SynEdit, SynEditMiscClasses, SynGutter, + Classes, SysUtils, LCLProc, Graphics, SynEdit, SynEditMiscClasses, SynGutter, SynGutterLineNumber, SynGutterCodeFolding, SynGutterMarks, SynGutterChanges, SynEditTextBuffer, SynEditFoldedView, SynTextDrawer, SynEditTextBase; @@ -78,8 +78,8 @@ type constructor Create; procedure IncRefCount; procedure DecRefCount; - // Index is the Current line in editor (including source modification) - // Result is the original Line as known by the debugger + // Index is the Current line-index (0 based) in editor (including source modification) + // Result is the original Line-pos (1 based) as known by the debugger property SrcLineToMarkLine[SrcIndex: Integer]: Integer read GetSrcLineToMarkLine write SetSrcLineToMarkLine; default; property RefCount: Integer read FRefCount; @@ -99,6 +99,8 @@ type procedure SetDebugMarks(AFirstLinePos, ALastLinePos: Integer); procedure ClearDebugMarks; function HasDebugMarks: Boolean; + function DebugLineToSourceLine(aLinePos: Integer): Integer; + function SourceLineToDebugLine(aLinePos: Integer; AdjustOnError: Boolean = False): Integer; end; implementation @@ -183,7 +185,8 @@ begin aGutterOffs := 0; HasAnyMark := PaintMarks(aScreenLine, Canvas, AClip, aGutterOffs); TxtIdx := FFoldView.TextIndex[aScreenLine]; - if (not HasAnyMark) and (HasDebugMarks) and (FDebugMarkInfo.SrcLineToMarkLine[TxtIdx] > 0) + if (not HasAnyMark) and (HasDebugMarks) and (TxtIdx < FDebugMarkInfo.Count) and + (FDebugMarkInfo.SrcLineToMarkLine[TxtIdx] > 0) then DrawDebugMark(aScreenLine); end; @@ -213,7 +216,7 @@ begin end; for i := AFirstLinePos - 1 to ALastLinePos - 1 do - FDebugMarkInfo[i] := i; + FDebugMarkInfo[i] := i + 1; TSynEdit(SynEdit).InvalidateGutter; end; @@ -245,6 +248,55 @@ begin Result := FDebugMarkInfo <> nil; end; +function TIDESynGutterMarks.DebugLineToSourceLine(aLinePos: Integer): Integer; +var + i, c: LongInt; +begin + CheckTextBuffer; + if (aLinePos < 1) or (not HasDebugMarks) then exit(aLinePos); + Result := aLinePos - 1; // 0 based + if (FDebugMarkInfo[Result] = 0) or (FDebugMarkInfo[Result] > aLinePos) then begin + i := Result; + repeat + dec(i); + while (i >= 0) and (FDebugMarkInfo[i] = 0) do dec(i); + if (i < 0) or (FDebugMarkInfo[i] < aLinePos) then break; + Result := i; + until FDebugMarkInfo[Result] = aLinePos; + if (FDebugMarkInfo[Result] > aLinePos) and // line not found + (Result > 0) and (FDebugMarkInfo[Result - 1] = 0) + then + dec(Result); + end; + if (FDebugMarkInfo[Result] = 0) or (FDebugMarkInfo[Result] < aLinePos) then begin + c := FDebugMarkInfo.Count; + i := Result; + repeat + inc(i); + while (i < c) and (FDebugMarkInfo[i] = 0) do inc(i); + if (i >= c) or (FDebugMarkInfo[i] > aLinePos) then break; + Result := i; + until FDebugMarkInfo[Result] = aLinePos; + if (FDebugMarkInfo[Result] < aLinePos) and // line not found + (Result < c-1) and (FDebugMarkInfo[Result + 1] = 0) + then + inc(Result); + end; + inc(Result); // 1 based +end; + +function TIDESynGutterMarks.SourceLineToDebugLine(aLinePos: Integer; + AdjustOnError: Boolean): Integer; +begin + CheckTextBuffer; + if (aLinePos < 1) or (not HasDebugMarks) then exit(aLinePos); + Result := FDebugMarkInfo[aLinePos - 1]; + while (Result = 0) and AdjustOnError and (aLinePos < FDebugMarkInfo.Count-1) do begin + inc(aLinePos); + Result := FDebugMarkInfo[aLinePos - 1]; + end; +end; + { TIDESynDebugMarkInfo } function TIDESynDebugMarkInfo.GetSrcLineToMarkLine(SrcIndex: Integer): Integer;