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 && len(tl.Tabs) > 0 {
83 if i < len(tl.Tabs) {
84 tl.ActiveTabID = tl.Tabs[i].ID
85 } else {
86 tl.ActiveTabID = tl.Tabs[len(tl.Tabs)-1].ID
87 }
88 }
89 return true
90 }
91 }
92 return false
93}
94
95// Find returns a tab by ID.
96func (tl *TabList) Find(id TabID) *Tab {
97 for _, tab := range tl.Tabs {
98 if tab.ID == id {
99 return tab
100 }
101 }
102 return nil
103}
104
105// ActiveTab returns the currently active tab.
106func (tl *TabList) ActiveTab() *Tab {
107 return tl.Find(tl.ActiveTabID)
108}
109
110// Count returns the number of tabs.
111func (tl *TabList) Count() int {
112 return len(tl.Tabs)
113}
114
115// SetActive sets the active tab and updates the previous active tab.
116func (tl *TabList) SetActive(id TabID) {
117 if id != tl.ActiveTabID && tl.ActiveTabID != "" {
118 tl.PreviousActiveTabID = tl.ActiveTabID
119 }
120 tl.ActiveTabID = id
121}
122
123// TabAt returns the tab at the given 0-based index.
124func (tl *TabList) TabAt(index int) *Tab {
125 if index < 0 || index >= len(tl.Tabs) {
126 return nil
127 }
128 return tl.Tabs[index]
129}
130
131// Move moves a tab to a new position.
132func (tl *TabList) Move(id TabID, newPos int) bool {
133 if newPos < 0 || newPos >= len(tl.Tabs) {
134 return false
135 }
136 var tab *Tab
137 var oldPos int
138 for i, t := range tl.Tabs {
139 if t.ID == id {
140 tab = t
141 oldPos = i
142 break
143 }
144 }
145 if tab == nil {
146 return false
147 }
148 // Remove from old position
149 tl.Tabs = append(tl.Tabs[:oldPos], tl.Tabs[oldPos+1:]...)
150 // Insert at new position
151 tl.Tabs = append(tl.Tabs[:newPos], append([]*Tab{tab}, tl.Tabs[newPos:]...)...)
152 // Reindex all
153 for i := range tl.Tabs {
154 tl.Tabs[i].Position = i
155 }
156 return true
157}