Skip to content

Commit a5d1f65

Browse files
committed
Add Drag Tab Feature
1 parent 41b912b commit a5d1f65

File tree

2 files changed

+61
-42
lines changed

2 files changed

+61
-42
lines changed

internal/action/command.go

Lines changed: 11 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -160,55 +160,28 @@ func (h *BufPane) TextFilterCmd(args []string) {
160160
}
161161
}
162162

163-
// TabMoveCmd moves the current tab to a given index (starts at 1). The
164-
// displaced tabs are moved up.
163+
// TabMoveCmd moves the current tab to a given index (starting at 1),
164+
// or by a relative offset using +N/-N. Displaced tabs shift accordingly.
165165
func (h *BufPane) TabMoveCmd(args []string) {
166-
if len(args) <= 0 {
167-
InfoBar.Error("Not enough arguments: provide an index, starting at 1")
168-
return
169-
}
170-
171-
if len(args[0]) <= 0 {
172-
InfoBar.Error("Invalid argument: empty string")
166+
if len(args) < 1 {
167+
InfoBar.Error("Not enough arguments")
173168
return
174169
}
175170

176-
num, err := strconv.Atoi(args[0])
171+
i, err := strconv.Atoi(args[0])
177172
if err != nil {
178-
InfoBar.Error("Invalid argument: ", err)
173+
InfoBar.Error("Invalid argument")
179174
return
180175
}
181176

182-
// Preserve sign for relative move, if one exists
183-
var shiftDirection byte
184-
if strings.Contains("-+", string([]byte{args[0][0]})) {
185-
shiftDirection = args[0][0]
186-
}
187-
188-
// Relative positions -> absolute positions
189-
idxFrom := Tabs.Active()
190-
idxTo := 0
191-
offset := util.Abs(num)
192-
if shiftDirection == '-' {
193-
idxTo = idxFrom - offset
194-
} else if shiftDirection == '+' {
195-
idxTo = idxFrom + offset
177+
if strings.ContainsRune("-+", rune(args[0][0])) {
178+
i = Tabs.Active() + i
196179
} else {
197-
idxTo = offset - 1
180+
i = i - 1
198181
}
182+
Tabs.MoveTab(MainTab(), i)
183+
Tabs.SetActive(i)
199184

200-
// Restrain position to within the valid range
201-
idxTo = util.Clamp(idxTo, 0, len(Tabs.List)-1)
202-
203-
activeTab := Tabs.List[idxFrom]
204-
Tabs.RemoveTab(activeTab.Panes[0].ID())
205-
Tabs.List = append(Tabs.List, nil)
206-
copy(Tabs.List[idxTo+1:], Tabs.List[idxTo:])
207-
Tabs.List[idxTo] = activeTab
208-
Tabs.Resize()
209-
Tabs.UpdateNames()
210-
Tabs.SetActive(idxTo)
211-
// InfoBar.Message(fmt.Sprintf("Moved tab from slot %d to %d", idxFrom+1, idxTo+1))
212185
}
213186

214187
// TabSwitchCmd switches to a given tab either by name or by number

internal/action/tab.go

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/zyedidia/micro/v2/internal/display"
1010
ulua "github.com/zyedidia/micro/v2/internal/lua"
1111
"github.com/zyedidia/micro/v2/internal/screen"
12+
"github.com/zyedidia/micro/v2/internal/util"
1213
"github.com/zyedidia/micro/v2/internal/views"
1314
)
1415

@@ -17,6 +18,11 @@ import (
1718
type TabList struct {
1819
*display.TabWindow
1920
List []*Tab
21+
22+
// captures whether the mouse is released
23+
release bool
24+
// captures whether the mouse is released
25+
dragging bool
2026
}
2127

2228
// NewTabList creates a TabList from a list of buffers by creating a Tab
@@ -35,6 +41,7 @@ func NewTabList(bufs []*buffer.Buffer) *TabList {
3541
}
3642
tl.TabWindow = display.NewTabWindow(w, 0)
3743
tl.Names = make([]string, len(bufs))
44+
tl.release = true
3845

3946
return tl
4047
}
@@ -107,20 +114,45 @@ func (t *TabList) HandleEvent(event tcell.Event) {
107114
mx, my := e.Position()
108115
switch e.Buttons() {
109116
case tcell.Button1:
117+
wasReleased := t.release
118+
t.release = false
119+
if !wasReleased && !t.dragging {
120+
//Non-tabbar dragging
121+
break
122+
}
110123
if my == t.Y && len(t.List) > 1 {
111124
if mx == 0 {
112125
t.Scroll(-4)
113126
} else if mx == t.Width-1 {
114127
t.Scroll(4)
115128
} else {
116-
ind := t.LocFromVisual(buffer.Loc{mx, my})
117-
if ind != -1 {
118-
t.SetActive(ind)
129+
i := t.LocFromVisual(buffer.Loc{mx, my})
130+
131+
if i == -1 {
132+
if t.dragging {
133+
i = len(t.List) - 1
134+
} else {
135+
//Non-tab click/drag
136+
return
137+
}
138+
}
139+
if t.dragging {
140+
Tabs.MoveTab(MainTab(), i)
141+
Tabs.SetActive(i)
142+
} else {
143+
t.dragging = true
144+
t.SetActive(i)
119145
}
120146
}
121147
return
122148
}
149+
if wasReleased {
150+
t.dragging = false
151+
}
123152
case tcell.ButtonNone:
153+
t.release = true
154+
t.dragging = false
155+
124156
if t.List[t.Active()].release {
125157
// Mouse release received, while already released
126158
t.ResetMouse()
@@ -138,7 +170,9 @@ func (t *TabList) HandleEvent(event tcell.Event) {
138170
}
139171
}
140172
}
141-
t.List[t.Active()].HandleEvent(event)
173+
if !t.dragging {
174+
t.List[t.Active()].HandleEvent(event)
175+
}
142176
}
143177

144178
// Display updates the names and then displays the tab bar
@@ -150,6 +184,7 @@ func (t *TabList) Display() {
150184
}
151185

152186
func (t *TabList) SetActive(a int) {
187+
a = util.Clamp(a, 0, len(t.List)-1)
153188
t.TabWindow.SetActive(a)
154189

155190
for i, p := range t.List {
@@ -399,3 +434,14 @@ func (t *Tab) CurPane() *BufPane {
399434
}
400435
return p
401436
}
437+
438+
// MoveTab moves the specified tab to the given index
439+
func (tl *TabList) MoveTab(t *Tab, i int) {
440+
i = util.Clamp(i, 0, len(tl.List)-1)
441+
tl.RemoveTab(t.Panes[0].ID())
442+
tl.List = append(tl.List, nil)
443+
copy(tl.List[i+1:], tl.List[i:])
444+
tl.List[i] = t
445+
tl.Resize()
446+
tl.UpdateNames()
447+
}

0 commit comments

Comments
 (0)