6 "github.com/zyedidia/tcell"
12 // This contains all the views in this tab
13 // There is generally only one view per tab, but you can have
14 // multiple views with splits
16 // This is the current view for this tab
22 // NewTabFromView creates a new tab and puts the given view in the tab
23 func NewTabFromView(v *View) *Tab {
25 t.views = append(t.views, v)
28 t.tree = new(SplitTree)
29 t.tree.kind = VerticalSplit
30 t.tree.children = []Node{NewLeafNode(t.views[0], t.tree)}
36 if globalSettings["infobar"].(bool) {
39 if globalSettings["keymenu"].(bool) {
48 // SetNum sets all this tab's views to have the correct tab number
49 func (t *Tab) SetNum(num int) {
51 for _, v := range t.views {
56 func (t *Tab) Cleanup() {
60 func (t *Tab) Resize() {
65 if globalSettings["infobar"].(bool) {
68 if globalSettings["keymenu"].(bool) {
74 for i, v := range t.views {
79 // CurView returns the current view
80 func CurView() *View {
81 curTab := tabs[curTab]
82 return curTab.views[curTab.CurView]
85 // TabbarString returns the string that should be displayed in the tabbar
86 // It also returns a map containing which indicies correspond to which tab number
87 // This is useful when we know that the mouse click has occurred at an x location
88 // but need to know which tab that corresponds to to accurately change the tab
89 func TabbarString() (string, map[int]int) {
91 indicies := make(map[int]int)
92 for i, t := range tabs {
98 buf := t.views[t.CurView].Buf
108 indicies[Count(str)-1] = i + 1
114 // TabbarHandleMouseEvent checks the given mouse event if it is clicking on the tabbar
115 // If it is it changes the current tab accordingly
116 // This function returns true if the tab is changed
117 func TabbarHandleMouseEvent(event tcell.Event) bool {
118 // There is no tabbar displayed if there are less than 2 tabs
123 switch e := event.(type) {
124 case *tcell.EventMouse:
125 button := e.Buttons()
126 // Must be a left click
127 if button == tcell.Button1 {
132 str, indicies := TabbarString()
133 if x+tabBarOffset >= len(str) {
138 for k := range indicies {
139 keys = append(keys, k)
142 for _, k := range keys {
143 if x+tabBarOffset <= k {
144 tabnum = indicies[k] - 1
156 // DisplayTabs displays the tabbar at the top of the editor if there are multiple tabs
162 str, indicies := TabbarString()
164 tabBarStyle := defStyle.Reverse(true)
165 if style, ok := colorscheme["tabbar"]; ok {
169 // Maybe there is a unicode filename?
170 fileRunes := []rune(str)
171 w, _ := screen.Size()
172 tooWide := (w < len(fileRunes))
174 // if the entire tab-bar is longer than the screen is wide,
175 // then it should be truncated appropriately to keep the
176 // active tab visible on the UI.
178 // first we have to work out where the selected tab is
179 // out of the total length of the tab bar. this is done
180 // by extracting the hit-areas from the indicies map
181 // that was constructed by `TabbarString()`
183 for offset := range indicies {
184 keys = append(keys, offset)
186 // sort them to be in ascending order so that values will
187 // correctly reflect the displayed ordering of the tabs
189 // record the offset of each tab and the previous tab so
190 // we can find the position of the tab's hit-box.
191 previousTabOffset := 0
192 currentTabOffset := 0
193 for _, k := range keys {
194 tabIndex := indicies[k] - 1
195 if tabIndex == curTab {
199 // this is +2 because there are two padding spaces that aren't accounted
200 // for in the display. please note that this is for cosmetic purposes only.
201 previousTabOffset = k + 2
203 // get the width of the hitbox of the active tab, from there calculate the offsets
204 // to the left and right of it to approximately center it on the tab bar display.
205 centeringOffset := (w - (currentTabOffset - previousTabOffset))
206 leftBuffer := previousTabOffset - (centeringOffset / 2)
207 rightBuffer := currentTabOffset + (centeringOffset / 2)
209 // check to make sure we haven't overshot the bounds of the string,
210 // if we have, then take that remainder and put it on the left side
211 overshotRight := rightBuffer - len(fileRunes)
212 if overshotRight > 0 {
213 leftBuffer = leftBuffer + overshotRight
216 overshotLeft := leftBuffer - 0
217 if overshotLeft < 0 {
219 rightBuffer = leftBuffer + (w - 1)
221 rightBuffer = leftBuffer + (w - 2)
224 if rightBuffer > len(fileRunes)-1 {
225 rightBuffer = len(fileRunes) - 1
228 // construct a new buffer of text to put the
229 // newly formatted tab bar text into.
230 var displayText []rune
232 // if the left-side of the tab bar isn't at the start
233 // of the constructed tab bar text, then show that are
234 // more tabs to the left by displaying a "+"
236 displayText = append(displayText, '+')
238 // copy the runes in from the original tab bar text string
239 // into the new display buffer
240 for x := leftBuffer; x < rightBuffer; x++ {
241 displayText = append(displayText, fileRunes[x])
243 // if there is more text to the right of the right-most
244 // column in the tab bar text, then indicate there are more
245 // tabs to the right by displaying a "+"
246 if rightBuffer < len(fileRunes)-1 {
247 displayText = append(displayText, '+')
250 // now store the offset from zero of the left-most text
251 // that is being displayed. This is to ensure that when
252 // clicking on the tab bar, the correct tab gets selected.
253 tabBarOffset = leftBuffer
255 // use the constructed buffer as the display buffer to print
257 fileRunes = displayText
262 // iterate over the width of the terminal display and for each column,
263 // write a character into the tab display area with the appropriate style.
264 for x := 0; x < w; x++ {
265 if x < len(fileRunes) {
266 screen.SetContent(x, 0, fileRunes[x], nil, tabBarStyle)
268 screen.SetContent(x, 0, ' ', nil, tabBarStyle)