Skip to content

Commit aff101b

Browse files
sei40krclaude
andcommitted
fix(cli): apply focus to tmux pane for external sessions
Adds `Session:focus()` backend hook with a tmux implementation via `tmux select-pane`, and unifies the UI layer to dispatch through `state.session:focus()`. `Terminal` is already a `Session` backend so `state.terminal === state.session` for terminal-backed sessions — the same call covers both paths. Also fixes the default-focus asymmetry in `M.attach`: external focus now fires on `opts.show and opts.focus ~= false` to match terminal, so `send()` and `toggle()` (no args) focus external panes the same way they focus terminals. Closes #179. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 17447a0 commit aff101b

4 files changed

Lines changed: 28 additions & 19 deletions

File tree

lua/sidekick/cli/init.lua

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,14 @@ end
100100
function M.toggle(opts)
101101
opts = filter_opts(opts)
102102
State.with(function(state, attached)
103-
if not state.terminal then
104-
return
105-
end
106-
if not attached then
103+
if state.terminal and not attached then
107104
state.terminal:toggle()
108105
end
109-
if state.terminal:is_open() and opts.focus ~= false then
110-
state.terminal:focus()
106+
if opts.focus == false then
107+
return
108+
end
109+
if state.external or (state.terminal and state.terminal:is_open()) then
110+
state.session:focus()
111111
end
112112
end, {
113113
attach = true,
@@ -121,13 +121,10 @@ end
121121
function M.focus(opts)
122122
opts = filter_opts(opts)
123123
State.with(function(state)
124-
if not state.terminal then
125-
return
126-
end
127-
if state.terminal:is_focused() then
124+
if state.terminal and state.terminal:is_focused() then
128125
state.terminal:blur()
129126
else
130-
state.terminal:focus()
127+
state.session:focus()
131128
end
132129
end, {
133130
attach = true,

lua/sidekick/cli/session/init.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ function B:attach() end
5252
--- Detach from an existing session
5353
function B:detach() end
5454

55+
--- Focus an external session (tmux/zellij pane)
56+
function B:focus() end
57+
5558
--- Start a new session
5659
--- If the backend returns a Cmd, a new terminal session will be spawned
5760
---@return sidekick.cli.terminal.Cmd?

lua/sidekick/cli/session/tmux.lua

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,4 +195,13 @@ function M:dump()
195195
return ret
196196
end
197197

198+
---Focus the tmux pane
199+
function M:focus()
200+
local pane_id = self:pane_id()
201+
if not pane_id then
202+
return
203+
end
204+
Util.exec({ "tmux", "select-pane", "-t", pane_id })
205+
end
206+
198207
return M

lua/sidekick/cli/state.lua

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -187,14 +187,14 @@ function M.attach(state, opts)
187187

188188
state = M.get_state(session) -- update state
189189
local terminal = state.terminal
190-
if terminal then
191-
if opts.show then
192-
terminal:show()
193-
if opts.focus ~= false and terminal:is_running() then
194-
terminal:focus()
195-
end
196-
end
197-
elseif attached then
190+
if terminal and opts.show then
191+
terminal:show()
192+
end
193+
local visible = state.external or (terminal and terminal:is_running())
194+
if opts.show and opts.focus ~= false and visible then
195+
session:focus()
196+
end
197+
if not terminal and attached then
198198
Util.info("Attached to `" .. state.tool.name .. "`")
199199
end
200200
return state, attached

0 commit comments

Comments
 (0)