diff --git a/lua/sidekick/cli/init.lua b/lua/sidekick/cli/init.lua index 9c0e9b5..5cfa62c 100644 --- a/lua/sidekick/cli/init.lua +++ b/lua/sidekick/cli/init.lua @@ -100,14 +100,14 @@ end function M.toggle(opts) opts = filter_opts(opts) State.with(function(state, attached) - if not state.terminal then - return - end - if not attached then + if state.terminal and not attached then state.terminal:toggle() end - if state.terminal:is_open() and opts.focus ~= false then - state.terminal:focus() + if opts.focus == false then + return + end + if state.external or (state.terminal and state.terminal:is_open()) then + state.session:focus() end end, { attach = true, @@ -121,13 +121,10 @@ end function M.focus(opts) opts = filter_opts(opts) State.with(function(state) - if not state.terminal then - return - end - if state.terminal:is_focused() then - state.terminal:blur() + if state.session:is_focused() then + state.session:blur() else - state.terminal:focus() + state.session:focus() end end, { attach = true, diff --git a/lua/sidekick/cli/session/init.lua b/lua/sidekick/cli/session/init.lua index 1c59892..7870174 100644 --- a/lua/sidekick/cli/session/init.lua +++ b/lua/sidekick/cli/session/init.lua @@ -52,6 +52,18 @@ function B:attach() end --- Detach from an existing session function B:detach() end +--- Focus the session +function B:focus() end + +--- Whether the session currently has user focus +---@return boolean +function B:is_focused() + return false +end + +--- Move focus away from the session +function B:blur() end + --- Start a new session --- If the backend returns a Cmd, a new terminal session will be spawned ---@return sidekick.cli.terminal.Cmd? diff --git a/lua/sidekick/cli/session/tmux.lua b/lua/sidekick/cli/session/tmux.lua index 942ed7d..788f447 100644 --- a/lua/sidekick/cli/session/tmux.lua +++ b/lua/sidekick/cli/session/tmux.lua @@ -195,4 +195,47 @@ function M:dump() return ret end +---Focus the tmux pane +function M:focus() + local pane_id = self:pane_id() + if not pane_id then + return + end + -- select-window first so create="window" switches the client to the pane's window; + -- no-op for create="split" where the pane is already in the current window. + Util.exec({ "tmux", "select-window", "-t", pane_id }) + Util.exec({ "tmux", "select-pane", "-t", pane_id }) +end + +---Whether this tmux pane is the active pane of the calling client +---@return boolean +function M:is_focused() + local pane_id = self:pane_id() + if not pane_id then + return false + end + local lines = Util.exec({ + "tmux", + "display-message", + "-p", + "-t", + pane_id, + "#{==:#{client_active_pane},#{pane_id}}", + }, { notify = false }) + return lines ~= nil and lines[1] == "1" +end + +---Send focus back to the editor pane (identified via $TMUX_PANE) +function M:blur() + if not self:is_focused() then + return + end + local editor_pane = vim.env.TMUX_PANE + if not editor_pane then + return + end + Util.exec({ "tmux", "select-window", "-t", editor_pane }, { notify = false }) + Util.exec({ "tmux", "select-pane", "-t", editor_pane }, { notify = false }) +end + return M diff --git a/lua/sidekick/cli/state.lua b/lua/sidekick/cli/state.lua index 01f1f3e..3c996d0 100644 --- a/lua/sidekick/cli/state.lua +++ b/lua/sidekick/cli/state.lua @@ -187,14 +187,14 @@ function M.attach(state, opts) state = M.get_state(session) -- update state local terminal = state.terminal - if terminal then - if opts.show then - terminal:show() - if opts.focus ~= false and terminal:is_running() then - terminal:focus() - end - end - elseif attached then + if terminal and opts.show then + terminal:show() + end + local visible = state.external or (terminal and terminal:is_running()) + if opts.show and opts.focus ~= false and visible then + session:focus() + end + if not terminal and attached then Util.info("Attached to `" .. state.tool.name .. "`") end return state, attached