diff --git a/lua/opencode/provider/init.lua b/lua/opencode/provider/init.lua index 1a13a759..340ac99a 100644 --- a/lua/opencode/provider/init.lua +++ b/lua/opencode/provider/init.lua @@ -52,6 +52,43 @@ local M = {} +---Get the project root directory using smart detection. +---Priority: 1) git root, 2) LSP workspace, 3) nvim directory argument, 4) current buffer dir, 5) cwd +---@return string +function M.get_project_root() + local cwd = vim.fn.getcwd() + + local git_cmd = "git -C " .. vim.fn.shellescape(cwd) .. " rev-parse --show-toplevel 2>/dev/null" + local git_root = vim.fn.systemlist(git_cmd)[1] + if vim.v.shell_error == 0 and git_root and git_root ~= "" then + return git_root + end + + local clients = vim.lsp.get_clients({ bufnr = 0 }) + for _, client in ipairs(clients) do + if client.config.root_dir then + return client.config.root_dir + end + end + + local arg = vim.fn.argv(0) + ---@cast arg string + if arg and arg ~= "" and vim.fn.isdirectory(arg) == 1 then + local path = vim.fn.fnamemodify(arg, ":p"):gsub("/$", "") + return path + end + + local buf_name = vim.api.nvim_buf_get_name(0) + if buf_name and buf_name ~= "" then + local buf_dir = vim.fn.fnamemodify(buf_name, ":p:h") + if vim.fn.isdirectory(buf_dir) == 1 then + return buf_dir + end + end + + return cwd +end + local function subscribe_to_sse() if not require("opencode.config").opts.events.enabled then return diff --git a/lua/opencode/provider/kitty.lua b/lua/opencode/provider/kitty.lua index 7a818d24..ff9d8e98 100644 --- a/lua/opencode/provider/kitty.lua +++ b/lua/opencode/provider/kitty.lua @@ -103,7 +103,8 @@ function Kitty:start() end local location = self.opts.location - local launch_cmd = { "launch", "--cwd=current", "--hold", "--dont-take-focus" } + local cwd = require("opencode.provider").get_project_root() + local launch_cmd = { "launch", "--cwd=" .. cwd, "--hold", "--dont-take-focus" } -- Input validation for `location` option local VALID_LOCATIONS = { diff --git a/lua/opencode/provider/snacks.lua b/lua/opencode/provider/snacks.lua index ee3fc9fe..0f9c345a 100644 --- a/lua/opencode/provider/snacks.lua +++ b/lua/opencode/provider/snacks.lua @@ -42,13 +42,41 @@ function Snacks:get() return win end +---@param current_cwd string +---@return boolean +---@private +function Snacks:hide_other_visible_terminals(current_cwd) + local terminals = require("snacks.terminal").list() + local did_hide = false + for _, term in ipairs(terminals) do + if term.buf and vim.api.nvim_buf_is_valid(term.buf) then + local term_info = vim.b[term.buf].snacks_terminal + local is_opencode = term_info and term_info.cmd == self.cmd + local is_other_cwd = term_info and term_info.cwd ~= current_cwd + local is_visible = term.win and vim.api.nvim_win_is_valid(term.win) + if is_opencode and is_other_cwd and is_visible then + term:hide() + did_hide = true + end + end + end + return did_hide +end + function Snacks:toggle() - require("snacks.terminal").toggle(self.cmd, self.opts) + local cwd = require("opencode.provider").get_project_root() + if self:hide_other_visible_terminals(cwd) then + return + end + local opts = vim.tbl_deep_extend("force", self.opts, { cwd = cwd }) + require("snacks.terminal").toggle(self.cmd, opts) end function Snacks:start() if not self:get() then - require("snacks.terminal").open(self.cmd, self.opts) + local cwd = require("opencode.provider").get_project_root() + local opts = vim.tbl_deep_extend("force", self.opts, { cwd = cwd }) + require("snacks.terminal").open(self.cmd, opts) end end diff --git a/lua/opencode/provider/terminal.lua b/lua/opencode/provider/terminal.lua index 240a54b1..86d40d84 100644 --- a/lua/opencode/provider/terminal.lua +++ b/lua/opencode/provider/terminal.lua @@ -51,6 +51,7 @@ function Terminal:start() -- FIX: There's a few empty columns on the right side of the terminal until it's redrawn, at least for me. vim.fn.jobstart(self.cmd, { term = true, + cwd = require("opencode.provider").get_project_root(), on_exit = function() self.winid = nil self.bufnr = nil diff --git a/lua/opencode/provider/tmux.lua b/lua/opencode/provider/tmux.lua index 2895c8cf..cb521d04 100644 --- a/lua/opencode/provider/tmux.lua +++ b/lua/opencode/provider/tmux.lua @@ -73,9 +73,10 @@ end function Tmux:start() local pane_id = self:get_pane_id() if not pane_id then - -- Create new pane + local cwd = require("opencode.provider").get_project_root() + local options = self.opts.options or "" self.pane_id = - vim.fn.system(string.format("tmux split-window -d -P -F '#{pane_id}' %s '%s'", self.opts.options, self.cmd)) + vim.fn.system(string.format("tmux split-window -d -P -F '#{pane_id}' -c '%s' %s '%s'", cwd, options, self.cmd)) end end diff --git a/lua/opencode/provider/wezterm.lua b/lua/opencode/provider/wezterm.lua index 9eb3db6d..d58e46d4 100644 --- a/lua/opencode/provider/wezterm.lua +++ b/lua/opencode/provider/wezterm.lua @@ -108,6 +108,9 @@ function Wezterm:start() if not pane_id then local cmd_parts = { "wezterm", "cli", "split-pane" } + table.insert(cmd_parts, "--cwd") + table.insert(cmd_parts, require("opencode.provider").get_project_root()) + if self.opts.direction then table.insert(cmd_parts, "--" .. self.opts.direction) end