7 "github.com/zyedidia/tcell"
12 // A Tab holds an array of views and a splitTree to determine how the
13 // views should be arranged
15 // This contains all the views in this tab
16 // There is generally only one view per tab, but you can have
17 // multiple views with splits
19 // This is the current view for this tab
25 // NewTabFromView creates a new tab and puts the given view in the tab
26 func NewTabFromView(v *View) *Tab {
28 t.Views = append(t.Views, v)
31 t.tree = new(SplitTree)
32 t.tree.kind = VerticalSplit
33 t.tree.children = []Node{NewLeafNode(t.Views[0], t.tree)}
39 if globalSettings["infobar"].(bool) {
42 if globalSettings["keymenu"].(bool) {
51 // SetNum sets all this tab's views to have the correct tab number
52 func (t *Tab) SetNum(num int) {
54 for _, v := range t.Views {
59 // Cleanup cleans up the tree (for example if views have closed)
60 func (t *Tab) Cleanup() {
64 // Resize handles a resize event from the terminal and resizes
65 // all child views correctly
66 func (t *Tab) Resize() {
71 if globalSettings["infobar"].(bool) {
74 if globalSettings["keymenu"].(bool) {
80 for i, v := range t.Views {
83 v.term.Resize(v.Width, v.Height)
88 // CurView returns the current view
89 func CurView() *View {
90 curTab := tabs[curTab]
91 return curTab.Views[curTab.CurView]
94 // TabbarString returns the string that should be displayed in the tabbar
95 // It also returns a map containing which indicies correspond to which tab number
96 // This is useful when we know that the mouse click has occurred at an x location
97 // but need to know which tab that corresponds to to accurately change the tab
98 func TabbarString() (string, map[int]int) {
100 indicies := make(map[int]int)
101 unique := make(map[string]int)
103 for _, t := range tabs {
104 unique[filepath.Base(t.Views[t.CurView].Buf.GetName())]++
107 for i, t := range tabs {
108 buf := t.Views[t.CurView].Buf
109 name := filepath.Base(buf.GetName())
116 if unique[name] == 1 {
131 indicies[Count(str)-2] = i + 1
136 // TabbarHandleMouseEvent checks the given mouse event if it is clicking on the tabbar
137 // If it is it changes the current tab accordingly
138 // This function returns true if the tab is changed
139 func TabbarHandleMouseEvent(event tcell.Event) bool {
140 // There is no tabbar displayed if there are less than 2 tabs
145 switch e := event.(type) {
146 case *tcell.EventMouse:
147 button := e.Buttons()
148 // Must be a left click
149 if button == tcell.Button1 {
154 str, indicies := TabbarString()
155 if x+tabBarOffset >= len(str) {
160 for k := range indicies {
161 keys = append(keys, k)
164 for _, k := range keys {
165 if x+tabBarOffset <= k {
166 tabnum = indicies[k] - 1
178 // DisplayTabs displays the tabbar at the top of the editor if there are multiple tabs
184 str, indicies := TabbarString()
186 tabBarStyle := defStyle.Reverse(true)
187 if style, ok := colorscheme["tabbar"]; ok {
191 // Maybe there is a unicode filename?
192 fileRunes := []rune(str)
193 w, _ := screen.Size()
194 tooWide := (w < len(fileRunes))
196 // if the entire tab-bar is longer than the screen is wide,
197 // then it should be truncated appropriately to keep the
198 // active tab visible on the UI.
200 // first we have to work out where the selected tab is
201 // out of the total length of the tab bar. this is done
202 // by extracting the hit-areas from the indicies map
203 // that was constructed by `TabbarString()`
205 for offset := range indicies {
206 keys = append(keys, offset)
208 // sort them to be in ascending order so that values will
209 // correctly reflect the displayed ordering of the tabs
211 // record the offset of each tab and the previous tab so
212 // we can find the position of the tab's hit-box.
213 previousTabOffset := 0
214 currentTabOffset := 0
215 for _, k := range keys {
216 tabIndex := indicies[k] - 1
217 if tabIndex == curTab {
221 // this is +2 because there are two padding spaces that aren't accounted
222 // for in the display. please note that this is for cosmetic purposes only.
223 previousTabOffset = k + 2
225 // get the width of the hitbox of the active tab, from there calculate the offsets
226 // to the left and right of it to approximately center it on the tab bar display.
227 centeringOffset := (w - (currentTabOffset - previousTabOffset))
228 leftBuffer := previousTabOffset - (centeringOffset / 2)
229 rightBuffer := currentTabOffset + (centeringOffset / 2)
231 // check to make sure we haven't overshot the bounds of the string,
232 // if we have, then take that remainder and put it on the left side
233 overshotRight := rightBuffer - len(fileRunes)
234 if overshotRight > 0 {
235 leftBuffer = leftBuffer + overshotRight
238 overshotLeft := leftBuffer - 0
239 if overshotLeft < 0 {
241 rightBuffer = leftBuffer + (w - 1)
243 rightBuffer = leftBuffer + (w - 2)
246 if rightBuffer > len(fileRunes)-1 {
247 rightBuffer = len(fileRunes) - 1
250 // construct a new buffer of text to put the
251 // newly formatted tab bar text into.
252 var displayText []rune
254 // if the left-side of the tab bar isn't at the start
255 // of the constructed tab bar text, then show that are
256 // more tabs to the left by displaying a "+"
258 displayText = append(displayText, '+')
260 // copy the runes in from the original tab bar text string
261 // into the new display buffer
262 for x := leftBuffer; x < rightBuffer; x++ {
263 displayText = append(displayText, fileRunes[x])
265 // if there is more text to the right of the right-most
266 // column in the tab bar text, then indicate there are more
267 // tabs to the right by displaying a "+"
268 if rightBuffer < len(fileRunes)-1 {
269 displayText = append(displayText, '+')
272 // now store the offset from zero of the left-most text
273 // that is being displayed. This is to ensure that when
274 // clicking on the tab bar, the correct tab gets selected.
275 tabBarOffset = leftBuffer
277 // use the constructed buffer as the display buffer to print
279 fileRunes = displayText
284 // iterate over the width of the terminal display and for each column,
285 // write a character into the tab display area with the appropriate style.
286 for x := 0; x < w; x++ {
287 if x < len(fileRunes) {
288 screen.SetContent(x, 0, fileRunes[x], nil, tabBarStyle)
290 screen.SetContent(x, 0, ' ', nil, tabBarStyle)