Skip to content

Commit

Permalink
Merge pull request #90 from mrjones2014/mrj/88/mux-split
Browse files Browse the repository at this point in the history
feat(mux): Add API to create mux splits via smart-splits.nvim
  • Loading branch information
mrjones2014 committed Apr 19, 2023
2 parents 3f7980a + 38fb60c commit 25d7c1e
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 32 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ require('smart-splits').setup({
-- current_pane_at_edge(direction:'left'|'right'|'up'|'down'):boolean
-- next_pane(direction:'left'|'right'|'up'|'down'):boolean
-- resize_pane(direction:'left'|'right'|'up'|'down'):boolean
-- split_pane(direction:'left'|'right'|'up'|'down',size:number|nil):boolean
-- },
-- direction = 'left'|'right'|'up'|'down',
-- split(), -- utility function to split current Neovim pane in the current direction
Expand Down Expand Up @@ -468,3 +469,29 @@ listen_on unix:/tmp/mykitty
Thanks @knubie for inspiration for the Kitty implementation from [vim-kitty-navigator](https://github.com/knubie/vim-kitty-navigator).

Thanks to @chancez for the relative resize [Python kitten](https://github.com/chancez/dotfiles/blob/badc69d3895a6a942285126b8c372a55d77533e1/kitty/.config/kitty/relative_resize.py).

### Multiplexer Lua API

You can directly access the multiplexer API for scripting purposes as well.
To get a handle to the current multiplexer backend, you can do:

```lua
local mux = require('smart-splits.mux').get()
```

This returns the currently enabled multiplexer backend, or `nil` if none is currently in use.
The API offers the following methods:

```lua
local mux = require('smart-splits.mux').get()
-- mux matches the following type annotations
---@class SmartSplitsMultiplexer
---@field current_pane_id fun():number|nil
---@field current_pane_at_edge fun(direction:'left'|'right'|'up'|'down'):boolean
---@field is_in_session fun():boolean
---@field current_pane_is_zoomed fun():boolean
---@field next_pane fun(direction:'left'|'right'|'up'|'down'):boolean
---@field resize_pane fun(direction:'left'|'right'|'up'|'down', amount:number):boolean
---@field split_pane fun(direction:'left'|'right'|'up'|'down',size:number|nil):boolean
---@field type 'tmux'|'wezterm'|'kitty'
```
23 changes: 19 additions & 4 deletions lua/smart-splits/mux/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ end
---@param direction SmartSplitsDirection direction to move
---@param will_wrap boolean whether to wrap around edge
---@param at_edge SmartSplitsAtEdgeBehavior behavior at edge
---@return boolean whether we moved with multiplexer or not
---@return boolean success
function M.move_pane(direction, will_wrap, at_edge)
at_edge = at_edge or config.at_edge
local multiplexer = M.get()
Expand All @@ -90,7 +90,7 @@ end
---Try resizing with multiplexer
---@param direction SmartSplitsDirection direction to resize
---@param amount number amount to resize
---@return boolean whether we resized with multiplexer or not
---@return boolean success
function M.resize_pane(direction, amount)
local multiplexer = M.get()
if not multiplexer or not multiplexer.is_in_session() then
Expand All @@ -103,10 +103,25 @@ function M.resize_pane(direction, amount)
local ok = multiplexer.resize_pane(direction, amount)
if not ok then
vim.notify('[smart-splits.nvim] Failed to resize multiplexer pane', vim.log.levels.ERROR)
return false
end

return true
return ok
end

---Try creating a new mux split pane. Not supported in Kitty multiplexer.
---@param direction SmartSplitsDirection
---@param size number|nil
---@return boolean success
function M.split_pane(direction, size)
local mux = M.get()
if not mux or not mux.is_in_session() then
return false
end
local ok = mux.split_pane(direction, size)
if not ok then
vim.notify('[smart-splits.nvim] Failed to create a new mux pane', vim.log.levels.ERROR)
end
return ok
end

return M
17 changes: 10 additions & 7 deletions lua/smart-splits/mux/kitty.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,7 @@ function M.next_pane(direction)
end

direction = dir_keys_kitty[direction] ---@diagnostic disable-line
local ok, _ = pcall(function()
kitty_exec({ 'kitten', 'neighboring_window.py', direction })
end)

local ok, _ = pcall(kitty_exec, { 'kitten', 'neighboring_window.py', direction })
return ok
end

Expand All @@ -93,11 +90,17 @@ function M.resize_pane(direction, amount)
return false
end

local ok, _ = pcall(function()
kitty_exec({ 'kitten', 'relative_resize.py', direction, amount })
end)
local ok, _ = pcall(kitty_exec, { 'kitten', 'relative_resize.py', direction, amount })

return ok
end

function M.split_pane(_, _)
vim.notify(
'[smart-splits.nvim] Sorry, Kitty does not support creation of arbitrary split panes.',
vim.log.levels.WARN
)
return false
end

return M
39 changes: 25 additions & 14 deletions lua/smart-splits/mux/tmux.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,20 @@ local function get_socket_path()
return vim.split(tmux, ',', { trimempty = true })[1]
end

local function tmux_exec(cmd, as_list)
---@param args (string|number)[]
---@param as_list boolean|nil
---@return nil
local function tmux_exec(args, as_list)
local socket = get_socket_path()
if not socket then
return nil
end

local cmd_str = string.format('tmux -S %s %s', socket, cmd)
local cmd = vim.list_extend({ 'tmux', '-S', socket }, args, 1, #args)
if as_list then
return vim.fn.systemlist(cmd_str) --[[ @as string[] ]]
return vim.fn.systemlist(cmd) --[[ @as string[] ]]
end
return vim.fn.system(cmd_str)
return vim.fn.system(cmd)
end

---@type SmartSplitsMultiplexer
Expand Down Expand Up @@ -62,7 +65,7 @@ function M.current_pane_at_edge(direction)
end

local tmux_expr = string.format('#{pane_id}:#{pane_%s}:#{?pane_active,_active_,_no_}', edge)
local panes = tmux_exec(string.format('list-panes -F "%s"', tmux_expr), true)
local panes = tmux_exec({ 'list-panes', '-F', tmux_expr }, true)
local active_pane_output_line = vim.tbl_filter(function(line)
return not not string.find(line, '_active_')
end, panes --[[ @as string[] ]])[1]
Expand Down Expand Up @@ -115,7 +118,7 @@ function M.current_pane_id()
end

local ok, id = pcall(function()
local output = tmux_exec('display-message -p "#{pane_id}"') --[[@as string]]
local output = tmux_exec({ 'display-message', '-p', '#{pane_id}' }) --[[@as string]]
if not output or #output == 0 then
return nil
end
Expand All @@ -137,7 +140,7 @@ function M.current_pane_is_zoomed()
-- if it it includes 'Z' then it's zoomed. A '*' indicates
-- current pane, and since we're only listing current pane flags,
-- we're expecting to see '*Z' if the current pane is zoomed
local output = tmux_exec("display-message -p '#F'")
local output = tmux_exec({ 'display-message', '-p', '#F' })
if output then
output = vim.trim(output --[[@as string]])
end
Expand All @@ -158,10 +161,7 @@ function M.next_pane(direction)
end

direction = dir_keys_tmux[direction] ---@diagnostic disable-line
local ok, _ = pcall(function()
tmux_exec(string.format('select-pane -%s', direction))
end)

local ok, _ = pcall(tmux_exec, { 'select-pane', string.format('-%s', direction) })
return ok
end

Expand All @@ -171,10 +171,21 @@ function M.resize_pane(direction, amount)
end

direction = dir_keys_tmux[direction] ---@diagnostic disable-line
local ok, _ = pcall(function()
tmux_exec(string.format('resize-pane -%s %s', direction, amount))
end)
local ok, _ = pcall(tmux_exec, { 'resize-pane', string.format('-%s', direction), amount })
return ok
end

function M.split_pane(direction, size)
local vert_or_horiz = (direction == Direction.left or direction == Direction.right) and '-h' or '-v'
local args = { 'split-pane', vert_or_horiz }
if direction == Direction.up or direction == Direction.left then
table.insert(args, '-b')
end
if size then
table.insert(args, '-l')
table.insert(args, size)
end
local ok, _ = pcall(tmux_exec, args)
return ok
end

Expand Down
25 changes: 18 additions & 7 deletions lua/smart-splits/mux/wezterm.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ local dir_keys_wezterm = {
[Direction.up] = 'Up',
}

local dir_keys_wezterm_splits = {
[Direction.left] = '--left',
[Direction.right] = '--right',
[Direction.up] = '--top',
[Direction.down] = '--bottom',
}

local function wezterm_exec(cmd)
local command = vim.deepcopy(cmd)
table.insert(command, 1, 'wezterm')
Expand Down Expand Up @@ -119,10 +126,7 @@ function M.next_pane(direction)
end

direction = dir_keys_wezterm[direction] ---@diagnostic disable-line
local ok, _ = pcall(function()
wezterm_exec({ 'activate-pane-direction', direction })
end)

local ok, _ = pcall(wezterm_exec, { 'activate-pane-direction', direction })
return ok
end

Expand All @@ -132,10 +136,17 @@ function M.resize_pane(direction, amount)
end

direction = dir_keys_wezterm[direction] ---@diagnostic disable-line
local ok, _ = pcall(function()
wezterm_exec({ 'adjust-pane-size', '--amount', amount, direction })
end)
local ok, _ = pcall(wezterm_exec, { 'adjust-pane-size', '--amount', amount, direction })
return ok
end

function M.split_pane(direction, size)
local args = { 'split-pane', dir_keys_wezterm_splits[direction] }
if size then
table.insert(args, '--cells')
table.insert(args, size)
end
local ok, _ = pcall(wezterm_exec, args)
return ok
end

Expand Down
1 change: 1 addition & 0 deletions lua/smart-splits/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
---@field current_pane_is_zoomed fun():boolean
---@field next_pane fun(direction:SmartSplitsDirection):boolean
---@field resize_pane fun(direction:SmartSplitsDirection, amount:number):boolean
---@field split_pane fun(direction:SmartSplitsDirection,size:number|nil):boolean
---@field type SmartSplitsMultiplexerType

---@alias SmartSplitsDirection 'left'|'right'|'up'|'down'
Expand Down

0 comments on commit 25d7c1e

Please sign in to comment.