diff --git a/lua/sidekick/cli/actions.lua b/lua/sidekick/cli/actions.lua index b8404d1..11ddc62 100644 --- a/lua/sidekick/cli/actions.lua +++ b/lua/sidekick/cli/actions.lua @@ -47,6 +47,16 @@ local function nav(dir) return function(terminal) local at_edge = vim.fn.winnr() == vim.fn.winnr(dir) if at_edge or terminal:is_float() then + -- When running under a mux backend (e.g., tmux via psmux on Windows), + -- returning the key as an expr string passes through Neovim's terminal + -- emulation, which can mangle control characters (e.g., C-j becomes CR). + -- Send the key directly to the mux pane instead. + if terminal.parent and terminal.parent.send_key then + vim.schedule(function() + terminal.parent:send_key(("C-%s"):format(dir)) + end) + return + end return (""):format(dir) end vim.schedule(function() diff --git a/lua/sidekick/cli/context/location.lua b/lua/sidekick/cli/context/location.lua index d1a8dbb..1f62248 100644 --- a/lua/sidekick/cli/context/location.lua +++ b/lua/sidekick/cli/context/location.lua @@ -19,14 +19,14 @@ function M.get(ctx, opts) opts.kind = opts.kind or "position" assert(ctx.buf or ctx.name, "Either buf or name must be provided") - local name = ctx.name or vim.api.nvim_buf_get_name(ctx.buf) + local name = vim.fs.normalize(ctx.name or vim.api.nvim_buf_get_name(ctx.buf)) if not name or name == "" then name = "[No Name]" else - local cwd = ctx.cwd or vim.fn.getcwd(0) + local cwd = ctx.cwd or vim.fs.normalize(vim.fn.getcwd(0)) local ok, rel = pcall(vim.fs.relpath, cwd, name) if ok and rel and rel ~= "" and rel ~= "." then - name = rel + name = rel:gsub("\\", "/") end end diff --git a/lua/sidekick/cli/session/tmux.lua b/lua/sidekick/cli/session/tmux.lua index 942ed7d..755de7f 100644 --- a/lua/sidekick/cli/session/tmux.lua +++ b/lua/sidekick/cli/session/tmux.lua @@ -30,11 +30,25 @@ end ---@return sidekick.cli.terminal.Cmd? function M:start() if not self.external then - local cmd = { "tmux", "new", "-A", "-s", self.id } + -- Sanitize session name: replace spaces with hyphens for psmux/Windows compatibility + local session_name = self.id:gsub("%s+", "-") + self.mux_session = session_name + local cmd = { "tmux", "new", "-A", "-s", session_name } vim.list_extend(cmd, { "-c", self.cwd }) self:add_cmd(cmd) - vim.list_extend(cmd, { ";", "set-option", "status", "off" }) - vim.list_extend(cmd, { ";", "set-option", "detach-on-destroy", "on" }) + if vim.fn.has("win32") == 1 then + -- On Windows (psmux), ";" command chaining is not supported. + -- PowerShell interprets ";" as a statement separator, causing + -- "set-option" to be run as a standalone cmdlet (which fails). + -- Instead, run set-option as separate commands after the session starts. + vim.defer_fn(function() + vim.fn.system({ "tmux", "set-option", "-t", session_name, "status", "off" }) + vim.fn.system({ "tmux", "set-option", "-t", session_name, "detach-on-destroy", "on" }) + end, 1000) + else + vim.list_extend(cmd, { ";", "set-option", "status", "off" }) + vim.list_extend(cmd, { ";", "set-option", "detach-on-destroy", "on" }) + end return { cmd = cmd } elseif Config.cli.mux.create == "window" then local cmd = { "tmux", "new-window", "-dP", "-c", self.cwd, "-F", PANE_FORMAT } @@ -186,6 +200,14 @@ function M:submit() Util.exec({ "tmux", "send-keys", "-t", self.tmux_pane_id, "Enter" }) end +---Send a raw key to a tmux pane +---@param key string tmux key name (e.g., "C-j", "Enter", "Escape") +function M:send_key(key) + if self.mux_session then + Util.exec({ "tmux", "send-keys", "-t", self.mux_session, key }) + end +end + function M:dump() local pane_id = self:pane_id() if not pane_id then