tab.go RawHistoryFolder
1package entity
2
3import (
4 "fmt"
5 "time"
6)
7
8// TabID uniquely identifies a tab.
9type TabID string
10
11// Tab represents a browser tab containing a workspace.
12// Tabs are the top-level container in the browser's tab bar.
13type Tab struct {
14 ID TabID
15 Name string // Display name (often derived from active pane title)
16 Workspace *Workspace // The workspace this tab contains
17 Position int // Position in the tab bar (0-indexed)
18 IsPinned bool // Pinned tabs stay at the left
19 CreatedAt time.Time
20}
21
22// NewTab creates a new tab with an initial pane.
23func NewTab(tabID TabID, workspaceID WorkspaceID, initialPane *Pane) *Tab {
24 return &Tab{
25 ID: tabID,
26 Workspace: NewWorkspace(workspaceID, initialPane),
27 Position: 0,
28 CreatedAt: time.Now(),
29 }
30}
31
32// Title returns the display title for the tab.
33// Uses the tab's Name if set, otherwise returns "Tab N" based on position.
34func (t *Tab) Title() string {
35 if t.Name != "" {
36 return t.Name
37 }
38 return fmt.Sprintf("Tab %d", t.Position+1)
39}
40
41// PaneCount returns the number of panes in this tab's workspace.
42func (t *Tab) PaneCount() int {
43 if t.Workspace == nil {
44 return 0
45 }
46 return t.Workspace.PaneCount()
47}
48
49// TabList manages an ordered collection of tabs.
50type TabList struct {
51 Tabs []*Tab
52 ActiveTabID TabID
53 PreviousActiveTabID TabID // Tracks last active tab for Alt+Tab style switching
54}
55
56// NewTabList creates an empty tab list.
57func NewTabList() *TabList {
58 return &TabList{
59 Tabs: make([]*Tab, 0),
60 }
61}
62
63// Add appends a tab to the list.
64func (tl *TabList) Add(tab *Tab) {
65 tab.Position = len(tl.Tabs)
66 tl.Tabs = append(tl.Tabs, tab)
67 if tl.ActiveTabID == "" {
68 tl.ActiveTabID = tab.ID
69 }
70}
71
72// Remove removes a tab by ID and reindexes positions.
73func (tl *TabList) Remove(id TabID) bool {
74 for i, tab := range tl.Tabs {
75 if tab.ID == id {
76 tl.Tabs = append(tl.Tabs[:i], tl.Tabs[i+1:]...)
77 // Reindex positions
78 for j := i; j < len(tl.Tabs); j++ {
79 tl.Tabs[j].Position = j
80 }
81 // Update active tab if needed
82 if tl.ActiveTabID == id {
83 if len(tl.Tabs) > 0 {
84 if i < len(tl.Tabs) {
85 tl.ActiveTabID = tl.Tabs[i].ID
86 } else {
87 tl.ActiveTabID = tl.Tabs[len(tl.Tabs)-1].ID
88 }
89 } else {
90 tl.ActiveTabID = ""
91 tl.PreviousActiveTabID = ""
92 }
93 }
94 return true
95 }
96 }
97 return false
98}
99
100// Find returns a tab by ID.
101func (tl *TabList) Find(id TabID) *Tab {
102 for _, tab := range tl.Tabs {
103 if tab.ID == id {
104 return tab
105 }
106 }
107 return nil
108}
109
110// ActiveTab returns the currently active tab.
111func (tl *TabList) ActiveTab() *Tab {
112 return tl.Find(tl.ActiveTabID)
113}
114
115// Count returns the number of tabs.
116func (tl *TabList) Count() int {
117 return len(tl.Tabs)
118}
119
120// SetActive sets the active tab and updates the previous active tab.
121func (tl *TabList) SetActive(id TabID) {
122 if id != tl.ActiveTabID && tl.ActiveTabID != "" {
123 tl.PreviousActiveTabID = tl.ActiveTabID
124 }
125 tl.ActiveTabID = id
126}
127
128// TabAt returns the tab at the given 0-based index.
129func (tl *TabList) TabAt(index int) *Tab {
130 if index < 0 || index >= len(tl.Tabs) {
131 return nil
132 }
133 return tl.Tabs[index]
134}
135
136// Move moves a tab to a new position.
137func (tl *TabList) Move(id TabID, newPos int) bool {
138 if newPos < 0 || newPos >= len(tl.Tabs) {
139 return false
140 }
141 var tab *Tab
142 var oldPos int
143 for i, t := range tl.Tabs {
144 if t.ID == id {
145 tab = t
146 oldPos = i
147 break
148 }
149 }
150 if tab == nil {
151 return false
152 }
153 // Remove from old position
154 tl.Tabs = append(tl.Tabs[:oldPos], tl.Tabs[oldPos+1:]...)
155 // Insert at new position
156 tl.Tabs = append(tl.Tabs[:newPos], append([]*Tab{tab}, tl.Tabs[newPos:]...)...)
157 // Reindex all
158 for i := range tl.Tabs {
159 tl.Tabs[i].Position = i
160 }
161 return true
162}
163
164// ReplaceFrom replaces this TabList's contents with those from another TabList.
165// This modifies in-place so existing references to this TabList remain valid.
166func (tl *TabList) ReplaceFrom(other *TabList) {
167 if other == nil {
168 tl.Tabs = make([]*Tab, 0)
169 tl.ActiveTabID = ""
170 tl.PreviousActiveTabID = ""
171 return
172 }
173 tl.Tabs = other.Tabs
174 tl.ActiveTabID = other.ActiveTabID
175 tl.PreviousActiveTabID = other.PreviousActiveTabID
176}