Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Rearrange buffers with mouse drag #113

Merged
merged 5 commits into from
Jun 29, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 138 additions & 13 deletions lua/cokeline/hover.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,26 @@ function M.hovered()
return _G.cokeline.__hovered
end

function M.set_hovered(val)
_G.cokeline.__hovered = val
end

function M.clear_hovered()
_G.cokeline.__hovered = nil
end

function M.dragging()
return _G.cokeline.__dragging
end

function M.set_dragging(val)
_G.cokeline.__dragging = val
end

function M.clear_dragging()
_G.cokeline.__dragging = nil
end

function M.get_current(col)
local bufs = buffers.get_visible()
if not bufs then
Expand All @@ -21,13 +41,13 @@ function M.get_current(col)
for _, component in ipairs(cx.sidebar) do
current_width = current_width + component.width
if current_width >= col then
return component
return component, cx.sidebar
end
end
for _, component in ipairs(cx.buffers) do
current_width = current_width + component.width
if current_width >= col then
return component
return component, cx.buffers
end
end
current_width = current_width + cx.gap
Expand All @@ -37,13 +57,13 @@ function M.get_current(col)
for _, component in ipairs(cx.rhs) do
current_width = current_width + component.width
if current_width >= col then
return component
return component, cx.rhs
end
end
end

local function on_hover(current)
local hovered = _G.cokeline.__hovered
local hovered = M.hovered()
if vim.o.showtabline == 0 then
return
end
Expand Down Expand Up @@ -80,7 +100,7 @@ local function on_hover(current)
hovered.on_mouse_leave(buf)
end
end
_G.cokeline.__hovered = nil
M.clear_hovered()
end
if not component then
vim.cmd.redrawtabline()
Expand All @@ -100,12 +120,12 @@ local function on_hover(current)
component.on_mouse_enter(buf, current.screencol)
end
end
_G.cokeline.__hovered = {
M.set_hovered({
index = component.index,
bufnr = buf and buf.number or nil,
on_mouse_leave = component.on_mouse_leave,
kind = component.kind,
}
})
vim.cmd.redrawtabline()
elseif hovered ~= nil then
local buf = buffers.get_buffer(hovered.bufnr)
Expand All @@ -121,25 +141,130 @@ local function on_hover(current)
hovered.on_mouse_leave(buf)
end
end
_G.cokeline.__hovered = nil
M.clear_hovered()
vim.cmd.redrawtabline()
end
last_position = current
end

local function width(bufs, buf)
return vim
.iter(bufs)
:filter(function(v)
return v.bufnr == buf
end)
:map(function(v)
return v.width
end)
:fold(0, function(acc, v)
return acc + v
end)
end

local function start_pos(bufs, buf)
local pos = 0
for _, v in ipairs(bufs) do
if v.bufnr == buf then
return pos
end
pos = pos + v.width
end
return pos
end

local function on_drag(pos)
if pos.dragging == "l" then
local current, bufs = M.get_current(pos.screencol)
if current == nil or bufs == nil or current.kind ~= "buffer" then
return
end

-- if we're not dragging yet or we're dragging the same buffer, start dragging
if M.dragging() == current.bufnr or not M.dragging() then
M.set_dragging(current.bufnr)
return
end

-- dragged buffer
local dragged_buf = buffers.get_buffer(M.dragging())
if not dragged_buf then
return
end

-- current (hovered) buffer
local cur_buf = buffers.get_buffer(current.bufnr)
if not cur_buf then
return
end

-- start position of dragged buffer
local dragging_start = start_pos(bufs, M.dragging())
-- width of the current (hovered) buffer
local cur_buf_width = width(bufs, current.bufnr)

if
-- buffer is being dragged to the left
(
dragging_start > pos.screencol
and pos.screencol + cur_buf_width > dragging_start
)
-- buffer is being dragged to the right
or dragging_start + cur_buf_width <= pos.screencol
then
buffers.move_buffer(dragged_buf, cur_buf._valid_index)
end
end
end

function M.setup()
if version.minor < 8 then
if version.minor < 8 or not vim.on_key then
return
end

vim.keymap.set({ "", "i" }, "<MouseMove>", function()
local mouse_move = vim.keycode("<MouseMove>")
local drag = {
[vim.keycode("<LeftDrag>")] = "l",
[vim.keycode("<RightDrag>")] = "r",
[vim.keycode("<MiddleDrag>")] = "m",
}
vim.on_key(function(key)
local ok, pos = pcall(vim.fn.getmousepos)
if not ok then
return
end
on_hover(pos)
return "<MouseMove>"
end, { expr = true })

local data = {
dragging = drag[key],
screencol = pos.screencol,
screenrow = pos.screenrow,
line = pos.line,
column = pos.column,
winid = pos.winid,
winrow = pos.winrow,
wincol = pos.wincol,
}
if key == mouse_move then
M.clear_dragging()
on_hover(data)
elseif drag[key] then
local hov = M.hovered()
if hov then
local buf = buffers.get_buffer(hov.bufnr)
if buf then
buf.is_hovered = false
end
if hov.kind == "buffer" then
if buf and hov.on_mouse_leave then
hov.on_mouse_leave(buf)
end
elseif hov.on_mouse_leave then
hov.on_mouse_leave()
end
M.clear_hovered()
end
on_drag(data)
end
end)
end

return M