mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-12-16 06:00:32 +01:00
SynEdit: Update "change gutter" (yellow/green change indicators) to follow undo/redo. Issue #0032865 and issue #0037209
git-svn-id: trunk@63752 -
This commit is contained in:
parent
a733105c1c
commit
289361a48d
@ -199,7 +199,7 @@ type
|
||||
fOnAdded: TNotifyEvent;
|
||||
FOnNeedCaretUndo: TSynGetCaretUndoProc;
|
||||
FOnNeedCaretUndoList: TSynEditUpdateCaretUndoProcList;
|
||||
fUnModifiedItem: integer;
|
||||
fUnModifiedItem, fSavedItem: integer;
|
||||
FForceGroupEnd: Boolean;
|
||||
procedure EnsureMaxEntries;
|
||||
function GetCanUndo: boolean;
|
||||
@ -213,7 +213,7 @@ type
|
||||
{$ENDIF}
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure AddChange(AChange: TSynEditUndoItem);
|
||||
procedure AddChange(AChange: TSynEditUndoItem; AForceLocked: Boolean = False);
|
||||
// "LastChange: Either in current Group, or in last Group, if no current
|
||||
procedure AppendToLastChange(AChange: TSynEditUndoItem);
|
||||
function GetLastChange: TSynEditUndoItem; // Excludes caret
|
||||
@ -226,11 +226,18 @@ type
|
||||
function PeekItem: TSynEditUndoGroup;
|
||||
procedure Unlock;
|
||||
function IsLocked: Boolean;
|
||||
(* Historically SynEdit has
|
||||
TSynEdit.MarkTextAsSaved; // Affects the "Changes Gutter" only
|
||||
TSynEdit.Modified := False;
|
||||
*)
|
||||
procedure MarkTopAsUnmodified;
|
||||
procedure MarkTopAsSaved;
|
||||
procedure ForceGroupEnd;
|
||||
function RealCount: Integer;
|
||||
function IsTopMarkedAsUnmodified: boolean;
|
||||
function UnModifiedMarkerExists: boolean;
|
||||
function IsTopMarkedAsSaved: boolean;
|
||||
function SavedMarkerExists: boolean;
|
||||
{$IFDEF SynUndoDebugBeginEnd}
|
||||
property InGroupCount: integer read FInGroupCount;
|
||||
{$ENDIF}
|
||||
@ -298,6 +305,7 @@ begin
|
||||
fItems := TList.Create;
|
||||
fMaxUndoActions := 1024;
|
||||
fUnModifiedItem:=-1;
|
||||
fSavedItem := -2; // -1 shall be that there was a SavedMarker, but it went out of scope due to max entries
|
||||
FForceGroupEnd := False;
|
||||
end;
|
||||
|
||||
@ -310,11 +318,12 @@ begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TSynEditUndoList.AddChange(AChange: TSynEditUndoItem);
|
||||
procedure TSynEditUndoList.AddChange(AChange: TSynEditUndoItem;
|
||||
AForceLocked: Boolean);
|
||||
var
|
||||
ugroup: TSynEditUndoGroup;
|
||||
begin
|
||||
if fLockCount > 0 then begin
|
||||
if (not AForceLocked) and (fLockCount > 0) then begin
|
||||
AChange.Free;
|
||||
exit;
|
||||
end;
|
||||
@ -412,6 +421,7 @@ begin
|
||||
fItems.Clear;
|
||||
fFullUndoImposible := FALSE;
|
||||
fUnModifiedItem:=-1;
|
||||
fSavedItem := -2;
|
||||
end;
|
||||
|
||||
procedure TSynEditUndoList.EndBlock;
|
||||
@ -467,6 +477,7 @@ begin
|
||||
Item.Free;
|
||||
fItems.Delete(0);
|
||||
if fUnModifiedItem>=0 then dec(fUnModifiedItem);
|
||||
if fSavedItem >= 0 then dec(fSavedItem);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@ -511,6 +522,8 @@ begin
|
||||
fItems.Delete(iLast);
|
||||
if fUnModifiedItem>fItems.Count then
|
||||
fUnModifiedItem:=-1;
|
||||
if fSavedItem>fItems.Count then
|
||||
fSavedItem:=-2;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -557,6 +570,11 @@ begin
|
||||
fUnModifiedItem := RealCount;
|
||||
end;
|
||||
|
||||
procedure TSynEditUndoList.MarkTopAsSaved;
|
||||
begin
|
||||
fSavedItem := RealCount;
|
||||
end;
|
||||
|
||||
procedure TSynEditUndoList.ForceGroupEnd;
|
||||
begin
|
||||
FForceGroupEnd := True;
|
||||
@ -572,6 +590,16 @@ begin
|
||||
Result := fUnModifiedItem >= 0;
|
||||
end;
|
||||
|
||||
function TSynEditUndoList.IsTopMarkedAsSaved: boolean;
|
||||
begin
|
||||
Result := (RealCount = fSavedItem);
|
||||
end;
|
||||
|
||||
function TSynEditUndoList.SavedMarkerExists: boolean;
|
||||
begin
|
||||
Result := fSavedItem >= -1;
|
||||
end;
|
||||
|
||||
procedure TSynEditUndoList.RegisterUpdateCaretUndo(AnUpdateProc: TSynUpdateCaretUndoProc);
|
||||
begin
|
||||
FOnNeedCaretUndoList.Add(TMethod(AnUpdateProc));
|
||||
|
||||
@ -355,6 +355,28 @@ type
|
||||
function PerformUndo(Caller: TObject): Boolean; override;
|
||||
end;
|
||||
|
||||
TSynEditStringFlagsArray = packed array of TSynEditStringFlags;
|
||||
|
||||
{ TSynEditUndoMarkModified }
|
||||
|
||||
TSynEditUndoMarkModified = class(TSynEditUndoItem)
|
||||
private
|
||||
FPosY: TLineIdx;
|
||||
FWasSaved: TSynEditStringFlagsArray;
|
||||
protected
|
||||
function DebugString: String; override;
|
||||
public
|
||||
constructor Create(ALine: TLineIdx; AWasSaved: TSynEditStringFlagsArray);
|
||||
function PerformUndo(Caller: TObject): Boolean; override;
|
||||
end;
|
||||
|
||||
var
|
||||
(* Re-usable arrays for the most common cases *)
|
||||
SynEditUndoMarkModifiedOneEmpty: TSynEditStringFlagsArray; // = [];
|
||||
SynEditUndoMarkModifiedOneSaved: TSynEditStringFlagsArray; // = [sfSaved];
|
||||
SynEditUndoMarkModifiedOneModified: TSynEditStringFlagsArray; // = [sfModified];
|
||||
|
||||
|
||||
{ TLazSynDisplayBuffer }
|
||||
|
||||
constructor TLazSynDisplayBuffer.Create(ABuffer: TSynEditStringList);
|
||||
@ -565,6 +587,63 @@ begin
|
||||
TSynEditStringList(Caller).EditLinesInsert(FPosY, FCount)
|
||||
end;
|
||||
|
||||
{ TSynEditUndoMarkModified }
|
||||
|
||||
function TSynEditUndoMarkModified.DebugString: String;
|
||||
begin
|
||||
Result := 'Y='+dbgs(FPosY) + ' Cnt='+ dbgs(Length(FWasSaved));
|
||||
end;
|
||||
|
||||
constructor TSynEditUndoMarkModified.Create(ALine: TLineIdx;
|
||||
AWasSaved: TSynEditStringFlagsArray);
|
||||
begin
|
||||
FPosY := ALine;
|
||||
FWasSaved := AWasSaved;
|
||||
{$IFDEF SynUndoDebugItems}debugln(['--- Undo Insert ',DbgSName(self), ' ', dbgs(Self), ' - ', DebugString]);{$ENDIF}
|
||||
end;
|
||||
|
||||
function TSynEditUndoMarkModified.PerformUndo(Caller: TObject): Boolean;
|
||||
var
|
||||
i: Integer;
|
||||
WasSaved: TSynEditStringFlagsArray;
|
||||
Buffer: TSynEditStringList absolute Caller;
|
||||
UnSaved: Boolean;
|
||||
begin
|
||||
Result := Caller is TSynEditStringList;
|
||||
{$IFDEF SynUndoDebugItems}if Result then debugln(['--- Undo Perform ',DbgSName(self), ' ', dbgs(Self), ' - ', DebugString]);{$ENDIF}
|
||||
if Result then begin
|
||||
UnSaved := Buffer.CurUndoList.SavedMarkerExists and (not Buffer.CurUndoList.IsTopMarkedAsSaved);
|
||||
if Length(FWasSaved) = 1 then begin
|
||||
if FPosY < Buffer.Count then begin
|
||||
if sfSaved in Buffer.Flags[FPosY] then
|
||||
WasSaved := SynEditUndoMarkModifiedOneSaved
|
||||
else
|
||||
if sfModified in Buffer.Flags[FPosY] then
|
||||
WasSaved := SynEditUndoMarkModifiedOneModified
|
||||
else
|
||||
WasSaved := SynEditUndoMarkModifiedOneEmpty;
|
||||
|
||||
if (sfSaved in FWasSaved[0]) and UnSaved then
|
||||
Buffer.Flags[FPosY] := [sfModified]
|
||||
else
|
||||
Buffer.Flags[FPosY] := FWasSaved[0];
|
||||
end;
|
||||
end
|
||||
else begin
|
||||
SetLength(WasSaved, Length(FWasSaved));
|
||||
for i := 0 to Min(Length(FWasSaved), Buffer.Count - FPosY) - 1 do begin
|
||||
WasSaved[i] := Buffer.Flags[FPosY + i];
|
||||
|
||||
if (sfSaved in FWasSaved[i]) and UnSaved then
|
||||
Buffer.Flags[FPosY + i] := [sfModified]
|
||||
else
|
||||
Buffer.Flags[FPosY + i] := FWasSaved[i];
|
||||
end;
|
||||
end;
|
||||
if WasSaved <> nil then
|
||||
Buffer.CurUndoList.AddChange(TSynEditUndoMarkModified.Create(FPosY, WasSaved), True);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TSynEditStringList }
|
||||
|
||||
@ -823,6 +902,11 @@ begin
|
||||
if not AValue then
|
||||
SendNotification(senrEndUndoRedo, Self); // before UNDO ends
|
||||
|
||||
if (not AValue) and fUndoList.IsTopMarkedAsSaved then begin
|
||||
fRedoList.MarkTopAsSaved;
|
||||
MarkSaved;
|
||||
end;
|
||||
|
||||
FIsUndoing := AValue;
|
||||
|
||||
if AValue then
|
||||
@ -842,6 +926,11 @@ begin
|
||||
if not AValue then
|
||||
SendNotification(senrEndUndoRedo, Self); // before UNDO ends
|
||||
|
||||
if (not AValue) and fRedoList.IsTopMarkedAsSaved then begin
|
||||
fUndoList.MarkTopAsSaved;
|
||||
MarkSaved;
|
||||
end;
|
||||
|
||||
FIsRedoing := AValue;
|
||||
|
||||
if AValue then
|
||||
@ -1213,11 +1302,35 @@ end;
|
||||
|
||||
procedure TSynEditStringList.MarkModified(AFirst, ALast: Integer);
|
||||
var
|
||||
Index: Integer;
|
||||
Index, i: Integer;
|
||||
WasSaved: TSynEditStringFlagsArray;
|
||||
NeedUndo: Boolean;
|
||||
begin
|
||||
for Index := AFirst - 1 to ALast - 1 do
|
||||
if (Index >= 0) or (Index < Count) then
|
||||
if IsUndoing or IsRedoing then
|
||||
exit;
|
||||
AFirst := ToIdx(AFirst);
|
||||
ALast := ToIdx(ALast);
|
||||
if ALast = AFirst then begin
|
||||
if sfSaved in Flags[AFirst] then
|
||||
CurUndoList.AddChange(TSynEditUndoMarkModified.Create(AFirst, SynEditUndoMarkModifiedOneSaved), True)
|
||||
else
|
||||
if not (sfModified in Flags[AFirst]) then
|
||||
CurUndoList.AddChange(TSynEditUndoMarkModified.Create(AFirst, SynEditUndoMarkModifiedOneEmpty), True);
|
||||
Flags[AFirst] := Flags[AFirst] + [sfModified] - [sfSaved];
|
||||
end
|
||||
else begin
|
||||
SetLength(WasSaved, ALast - AFirst + 1);
|
||||
i := 0;
|
||||
NeedUndo := False;
|
||||
for Index := Max(0, AFirst) to Min(ALast, Count - 1) do begin
|
||||
NeedUndo := NeedUndo or (Flags[Index] <> [sfModified]);
|
||||
WasSaved[i] := Flags[Index];
|
||||
Flags[Index] := Flags[Index] + [sfModified] - [sfSaved];
|
||||
inc(i);
|
||||
end;
|
||||
if NeedUndo then
|
||||
CurUndoList.AddChange(TSynEditUndoMarkModified.Create(AFirst, WasSaved), True);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSynEditStringList.MarkSaved;
|
||||
@ -1227,6 +1340,13 @@ begin
|
||||
for Index := 0 to Count - 1 do
|
||||
if sfModified in Flags[Index] then
|
||||
Flags[Index] := Flags[Index] + [sfSaved];
|
||||
|
||||
if not (IsUndoing or IsRedoing) then begin
|
||||
fUndoList.MarkTopAsSaved;
|
||||
FRedoList.MarkTopAsSaved;
|
||||
end;
|
||||
|
||||
SendNotification(senrHighlightChanged, Self, -1, -1);
|
||||
end;
|
||||
|
||||
procedure TSynEditStringList.AddManagedHandler(AReason: TSynEditNotifyReason;
|
||||
@ -1774,5 +1894,14 @@ begin
|
||||
aLineBrkCnt, aText);
|
||||
end;
|
||||
|
||||
initialization
|
||||
SetLength(SynEditUndoMarkModifiedOneEmpty, 1);
|
||||
SetLength(SynEditUndoMarkModifiedOneSaved, 1);
|
||||
SetLength(SynEditUndoMarkModifiedOneModified, 1);
|
||||
SynEditUndoMarkModifiedOneEmpty[0] := [];
|
||||
SynEditUndoMarkModifiedOneSaved[0] := [sfSaved, sfModified];
|
||||
SynEditUndoMarkModifiedOneModified[0] := [sfModified];
|
||||
|
||||
|
||||
end.
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user