1- unit simba.form_tabs_history;
1+ {
2+ Author: Raymond van Venetië and Merlijn Wajer
3+ Project: Simba (https://github.com/MerlijnWajer/Simba)
4+ License: GNU General Public License (https://www.gnu.org/licenses/gpl-3.0)
5+ }
6+ unit simba.form_tabs_history;
27
38{ $i simba.inc}
49
510interface
11+
612uses
7- Classes, SysUtils, Math, LazLogger ,
8- simba.ide_editor , simba.ide_tab, simba.containers;
13+ Classes, SysUtils, Math, SynEdit, SynEditMouseCmds, LazSynEditMouseCmdsTypes ,
14+ simba.base , simba.ide_tab, simba.containers;
915
1016type
11- TSimbaScriptTabHistory = class
17+ TSimbaScriptTabHistory = class (TComponent)
1218 strict private
13- type
14- THistoryPoint = class
15- Tab : TSimbaScriptTab;
16- Caret : TPoint;
17- end ;
18- THistoryList = specialize TSimbaObjectList <THistoryPoint>;
19+ type
20+ THistoryPoint = record
21+ Tab : TSimbaScriptTab;
22+ Caret : TPoint;
23+ end ;
24+ THistoryList = specialize TSimbaList <THistoryPoint>;
1925 strict private
2026 FIndex : Integer; // 1-based “next slot”; 0 means empty
2127 FHistory : THistoryList;
2228 FMaxDepth : Integer;
2329
24- function CreateHistoryPoint (Tab: TSimbaScriptTab; x, y: Integer): THistoryPoint;
2530 procedure PruneIfNeeded ;
2631 procedure DumpState (const msg: String);
32+
33+ procedure DoTabClose (Sender: TObject);
34+ procedure DoTabCaretMoved (Sender: TObject);
2735 public
2836 FSilent : Boolean;
2937 property MaxDepth: Integer read FMaxDepth write FMaxDepth;
3038
31- procedure PushFromEditor (Tab: TSimbaScriptTab; CaretXY: TPoint );
39+ procedure PushFromEditor (Tab: TSimbaScriptTab);
3240 procedure Clear (Tab: TSimbaScriptTab);
3341 procedure GoBack ;
3442 procedure GoForward ;
3543
36- constructor Create;
44+ constructor Create; reintroduce;
3745 destructor Destroy; override;
3846 end ;
3947
48+ TSimbaEditorPlugin_History = class (TLazSynEditPlugin)
49+ protected
50+ procedure DoEditorAdded (Value : TCustomSynEdit); override;
51+ function DoMouseAction (AnAction: TSynEditMouseAction; var AnInfo: TSynEditMouseActionInfo): Boolean;
52+ end ;
53+
4054var
4155 SimbaScriptTabHistory: TSimbaScriptTabHistory;
4256
4357implementation
44- uses simba.base, simba.form_tabs;
4558
46- { ───── helpers ───── }
47- function TSimbaScriptTabHistory.CreateHistoryPoint (Tab: TSimbaScriptTab; x, y: Integer): THistoryPoint;
48- begin
49- DebugLn(' TSimbaScriptTabHistory.MakePoint' );
50- Result := THistoryPoint.Create;
51- Result.Tab := Tab;
52- Result.Caret := Point(x, y);
53- end ;
59+ uses
60+ simba.form_tabs,
61+ simba.ide_events,
62+ simba.ide_initialization,
63+ simba.ide_editor_mousecommands,
64+ simba.threading;
5465
55- procedure TSimbaScriptTabHistory.DumpState (const Msg : String);
66+ procedure TSimbaScriptTabHistory.DumpState (const msg : String);
5667var
57- i : Integer;
58- capStr : String;
68+ i: Integer;
5969begin
6070 DebugLn(' │ State @ ' + Msg +
6171 ' Index=' + IntToStr(FIndex) +
6272 ' Count=' + IntToStr(FHistory.Count));
6373
6474 for i := 0 to FHistory.Count-1 do
6575 begin
66- if Assigned(FHistory[i].Tab) then
67- capStr := FHistory[i].Tab.Caption
68- else
69- capStr := ' <nil-tab>' ;
70-
7176 DebugLn(Format(' │ %2d%s %s (%d,%d)' ,
7277 [i+1 ,
7378 IfThen(i+1 = FIndex, ' ►' , ' ' ),
74- capStr ,
79+ FHistory[i].Tab.Caption ,
7580 FHistory[i].Caret.X,
7681 FHistory[i].Caret.Y]));
7782 end ;
7883end ;
7984
85+ procedure TSimbaScriptTabHistory.DoTabClose (Sender: TObject);
86+ begin
87+ Clear(Sender as TSimbaScriptTab);
88+ end ;
89+
90+ procedure TSimbaScriptTabHistory.DoTabCaretMoved (Sender: TObject);
91+ begin
92+ PushFromEditor(Sender as TSimbaScriptTab);
93+ end ;
8094
8195procedure TSimbaScriptTabHistory.PruneIfNeeded ;
8296begin
8397 if (FMaxDepth > 0 ) and (FHistory.Count > FMaxDepth) then
8498 begin
85- DebugLn([' PruneIfNeeded – trimming to ' , FMaxDepth]);
8699 while FHistory.Count > FMaxDepth do
87100 FHistory.Delete(0 );
88101 FIndex := EnsureRange(FIndex, 0 , FHistory.Count);
89102 DumpState(' Prune' );
90103 end ;
91104end ;
92105
93- procedure TSimbaScriptTabHistory.PushFromEditor (Tab: TSimbaScriptTab; CaretXY: TPoint );
106+ procedure TSimbaScriptTabHistory.PushFromEditor (Tab: TSimbaScriptTab);
94107var
95- Pt: THistoryPoint;
108+ CaretXY: TPoint;
109+ pt: THistoryPoint;
96110begin
111+ if FSilent then
112+ Exit;
113+
97114 DebugLn(' TSimbaScriptTabHistory.PushFromEditor' );
98- Pt := CreateHistoryPoint(Tab, CaretXY.X, CaretXY.Y);
115+ CaretXY := Tab.Editor.CaretXY;
116+ if (CaretXY.X = 1 ) and (CaretXY.Y = 1 ) then
117+ begin
118+ DebugLn(' TSimbaScriptTabHistory.PushFromEditor default caret pos' );
119+ Exit;
120+ end ;
121+
122+ pt := Default(THistoryPoint);
123+ pt.Tab := Tab;
124+ pt.Caret := Tab.Editor.CaretXY;
125+
99126 DebugLn(Format(' TSimbaScriptTabHistory.PushFromEditor pt %d, %d' , [pt.Caret.X, pt.Caret.Y]));
100127
101128 { ignore tiny moves in the same file }
102129 if (FHistory.Count > 0 ) and (FIndex > 0 ) then
103130 with FHistory[FIndex-1 ] do
104131 if (Tab = Pt.Tab) and (Abs(Caret.Y - Pt.Caret.Y) < 15 ) then
105- Exit; // nothing added, nothing deleted
106-
107- DebugLn(' TSimbaScriptTabHistory.PushFromEditor deduped' );
132+ begin
133+ DebugLn(' TSimbaScriptTabHistory.PushFromEditor short distance in same file' );
134+ Exit;
135+ end ;
108136
109137 { if we were in the middle of the list … }
110138 if FIndex < FHistory.Count then
@@ -116,8 +144,7 @@ procedure TSimbaScriptTabHistory.PushFromEditor(Tab: TSimbaScriptTab; CaretXY: T
116144 Inc(FIndex); // just move forward
117145 Exit; // keep the rest of the forward stack
118146 end
119- else
120- begin
147+ else begin
121148 { different location → start a new branch }
122149 while FHistory.Count > FIndex do
123150 FHistory.Delete(FHistory.Count - 1 );
@@ -163,10 +190,9 @@ procedure TSimbaScriptTabHistory.GoBack;
163190
164191 with FHistory[FIndex-1 ] do
165192 begin
166- Tab.Show;
167- Tab.Editor.CaretXY := Caret;
168- Tab.Editor.TopLine := Caret.Y - (Tab.Editor.LinesInWindow div 2 );
169- Tab.Editor.EnsureCursorPosVisible;
193+ SimbaTabsForm.CurrentTab := Tab;
194+ SimbaTabsForm.CurrentTab.Editor.CaretXY := Caret;
195+ SimbaTabsForm.CurrentTab.Editor.TopLine := Caret.Y - (Tab.Editor.LinesInWindow div 2 );
170196 end ;
171197 finally
172198 FSilent := False;
@@ -190,39 +216,68 @@ procedure TSimbaScriptTabHistory.GoForward;
190216
191217 with FHistory[FIndex-1 ] do
192218 begin
193- Tab.Show;
194- Tab.Editor.CaretXY := Caret;
195- Tab.Editor.TopLine := Caret.Y - (Tab.Editor.LinesInWindow div 2 );
196- Tab.Editor.EnsureCursorPosVisible;
219+ SimbaTabsForm.CurrentTab := Tab;
220+ SimbaTabsForm.CurrentTab.Editor.CaretXY := Caret;
221+ SimbaTabsForm.CurrentTab.Editor.TopLine := Caret.Y - (Tab.Editor.LinesInWindow div 2 );
197222 end ;
198223end ;
199224
200225{ ───── lifecycle ───── }
201226constructor TSimbaScriptTabHistory.Create;
202227begin
203- inherited Create;
204- DebugLn( ' TSimbaScriptTabHistory.Create ' );
205- FHistory := THistoryList.Create(True );
228+ inherited Create( nil ) ;
229+
230+ FHistory := THistoryList.Create();
206231 FIndex := 0 ;
207232 FMaxDepth := 128 ;
208233 FSilent := False;
234+
235+ SimbaIDEEvents.Register(Self, SimbaIDEEvent.TAB_CLOSED, @DoTabClose);
236+ SimbaIDEEvents.Register(Self, SimbaIDEEvent.TAB_CARETMOVED, @DoTabCaretMoved);
209237end ;
210238
211239destructor TSimbaScriptTabHistory.Destroy;
212240begin
213- DumpState(' Destroy' );
214- FHistory.Free;
215- inherited Destroy;
241+ if (FHistory <> nil ) then
242+ FreeAndNil(FHistory);
243+
244+ inherited Destroy();
245+ end ;
246+
247+ procedure TSimbaEditorPlugin_History.DoEditorAdded (Value : TCustomSynEdit);
248+ begin
249+ inherited DoEditorAdded(Value );
250+
251+ if (Value <> nil ) then
252+ begin
253+ Value .MouseActions.AddCommand(emcMouseButtonForward, False, LazSynEditMouseCmdsTypes.mbExtra2, ccSingle, cdDown, [], []);
254+ Value .MouseActions.AddCommand(emcMouseButtonBack, False, LazSynEditMouseCmdsTypes.mbExtra1, ccSingle, cdDown, [], []);
255+ Value .RegisterMouseActionExecHandler(@DoMouseAction);
256+ end ;
257+ end ;
258+
259+ function TSimbaEditorPlugin_History.DoMouseAction (AnAction: TSynEditMouseAction; var AnInfo: TSynEditMouseActionInfo): Boolean;
260+ begin
261+ Result := (AnAction.Command = emcMouseButtonForward) or (AnAction.Command = emcMouseButtonBack);
262+
263+ if Result then
264+ if (AnAction.Command = emcMouseButtonForward) then
265+ QueueOnMainThread(@SimbaScriptTabHistory.GoForward)
266+ else if (AnAction.Command = emcMouseButtonBack) then
267+ QueueOnMainThread(@SimbaScriptTabHistory.GoBack);
268+ end ;
269+
270+ procedure CreateTabHistory ;
271+ begin
272+ SimbaScriptTabHistory := TSimbaScriptTabHistory.Create();
216273end ;
217274
218275initialization
219- DebugLn(' simba.form_tabs_history – initialization' );
220- SimbaScriptTabHistory := TSimbaScriptTabHistory.Create;
276+ SimbaIDEInitialization_AddBeforeCreate(@CreateTabHistory, ' Create TabHistory' );
221277
222278finalization
223- DebugLn(' simba.form_tabs_history – finalization' );
224- SimbaScriptTabHistory.Free;
225- SimbaScriptTabHistory := nil ;
279+ if (SimbaScriptTabHistory <> nil ) then
280+ FreeAndNil(SimbaScriptTabHistory);
226281
227282end .
228283
0 commit comments