From 6d03577184ca3f1c46f7304d5c3206bb6bbb86a5 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Tue, 28 Oct 2025 17:57:01 -1000 Subject: [PATCH] use terminal CWD when sending paths --- lua/claudecode/init.lua | 12 ++++-- lua/claudecode/terminal.lua | 13 ++++++ tests/unit/at_mention_edge_cases_spec.lua | 52 +++++++++++++++++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/lua/claudecode/init.lua b/lua/claudecode/init.lua index c4b7744e..2fce763c 100644 --- a/lua/claudecode/init.lua +++ b/lua/claudecode/init.lua @@ -1094,9 +1094,10 @@ end ---Format file path for at mention (exposed for testing) ---@param file_path string The file path to format +---@param base_cwd string|nil Optional base working directory (defaults to Neovim's CWD) ---@return string formatted_path The formatted path ---@return boolean is_directory Whether the path is a directory -function M._format_path_for_at_mention(file_path) +function M._format_path_for_at_mention(file_path, base_cwd) -- Input validation if not file_path or type(file_path) ~= "string" or file_path == "" then error("format_path_for_at_mention: file_path must be a non-empty string") @@ -1112,9 +1113,9 @@ function M._format_path_for_at_mention(file_path) local is_directory = vim.fn.isdirectory(file_path) == 1 local formatted_path = file_path + local cwd = base_cwd or vim.fn.getcwd() if is_directory then - local cwd = vim.fn.getcwd() if string.find(file_path, cwd, 1, true) == 1 then local relative_path = string.sub(file_path, #cwd + 2) if relative_path ~= "" then @@ -1127,7 +1128,6 @@ function M._format_path_for_at_mention(file_path) formatted_path = formatted_path .. "/" end else - local cwd = vim.fn.getcwd() if string.find(file_path, cwd, 1, true) == 1 then local relative_path = string.sub(file_path, #cwd + 2) if relative_path ~= "" then @@ -1145,9 +1145,13 @@ function M._broadcast_at_mention(file_path, start_line, end_line) return false, "Claude Code integration is not running" end + -- Get terminal CWD for path formatting (falls back to Neovim CWD if nil) + local terminal = require("claudecode.terminal") + local terminal_cwd = terminal.get_terminal_cwd() + -- Safely format the path and handle validation errors local formatted_path, is_directory - local format_success, format_result, is_dir_result = pcall(M._format_path_for_at_mention, file_path) + local format_success, format_result, is_dir_result = pcall(M._format_path_for_at_mention, file_path, terminal_cwd) if not format_success then return false, format_result -- format_result contains the error message end diff --git a/lua/claudecode/terminal.lua b/lua/claudecode/terminal.lua index fae0b30f..0925dafb 100644 --- a/lua/claudecode/terminal.lua +++ b/lua/claudecode/terminal.lua @@ -6,6 +6,9 @@ local M = {} local claudecode_server_module = require("claudecode.server.init") +-- Cache the terminal's working directory (set when terminal is opened) +local last_terminal_cwd = nil + ---@type ClaudeCodeTerminalConfig local defaults = { split_side = "right", @@ -498,6 +501,7 @@ end ---@param cmd_args string? Arguments to append to the claude command. function M.open(opts_override, cmd_args) local effective_config = build_config(opts_override) + last_terminal_cwd = effective_config.cwd local cmd_string, claude_env_table = get_claude_command_and_env(cmd_args) get_provider().open(cmd_string, claude_env_table, effective_config) @@ -513,6 +517,7 @@ end ---@param cmd_args string? Arguments to append to the claude command. function M.simple_toggle(opts_override, cmd_args) local effective_config = build_config(opts_override) + last_terminal_cwd = effective_config.cwd local cmd_string, claude_env_table = get_claude_command_and_env(cmd_args) get_provider().simple_toggle(cmd_string, claude_env_table, effective_config) @@ -523,6 +528,7 @@ end ---@param cmd_args string|nil (optional) Arguments to append to the claude command. function M.focus_toggle(opts_override, cmd_args) local effective_config = build_config(opts_override) + last_terminal_cwd = effective_config.cwd local cmd_string, claude_env_table = get_claude_command_and_env(cmd_args) get_provider().focus_toggle(cmd_string, claude_env_table, effective_config) @@ -569,4 +575,11 @@ function M._get_managed_terminal_for_test() return nil end +---Gets the cached terminal working directory. +---This returns the CWD that was resolved when the terminal was opened. +---@return string|nil The terminal's working directory, or nil if no terminal has been opened. +function M.get_terminal_cwd() + return last_terminal_cwd +end + return M diff --git a/tests/unit/at_mention_edge_cases_spec.lua b/tests/unit/at_mention_edge_cases_spec.lua index 79a98722..5dce98e2 100644 --- a/tests/unit/at_mention_edge_cases_spec.lua +++ b/tests/unit/at_mention_edge_cases_spec.lua @@ -326,4 +326,56 @@ describe("At Mention Edge Cases", function() assert_contains(result, "file.lua") end) end) + + describe("custom base_cwd parameter", function() + it("should use custom base_cwd when provided", function() + mock_vim.fn.filereadable = function(path) + return path == "/git/repo/src/main.lua" and 1 or 0 + end + + -- Default behavior uses vim.fn.getcwd() which returns /Users/test/project + local result_default = init_module._format_path_for_at_mention("/git/repo/src/main.lua") + expect(result_default).to_be("/git/repo/src/main.lua") -- Not relative to /Users/test/project + + -- With custom base_cwd, should be relative to /git/repo + local result_custom = init_module._format_path_for_at_mention("/git/repo/src/main.lua", "/git/repo") + expect(result_custom).to_be("src/main.lua") + end) + + it("should use custom base_cwd for directories", function() + mock_vim.fn.isdirectory = function(path) + return path == "/git/repo/src" and 1 or 0 + end + mock_vim.fn.filereadable = function() + return 0 + end + + -- With custom base_cwd, directory should be relative + local result_custom = init_module._format_path_for_at_mention("/git/repo/src", "/git/repo") + expect(result_custom).to_be("src/") + end) + + it("should fall back to vim.fn.getcwd() when base_cwd is nil", function() + mock_vim.fn.filereadable = function(path) + return path == "/Users/test/project/config.lua" and 1 or 0 + end + + -- When base_cwd is nil, should use vim.fn.getcwd() + local result = init_module._format_path_for_at_mention("/Users/test/project/config.lua", nil) + expect(result).to_be("config.lua") -- Relative to /Users/test/project (getcwd) + end) + + it("should handle root directory with custom base_cwd", function() + mock_vim.fn.isdirectory = function(path) + return path == "/git/repo" and 1 or 0 + end + mock_vim.fn.filereadable = function() + return 0 + end + + -- Path is exactly the base_cwd + local result = init_module._format_path_for_at_mention("/git/repo", "/git/repo") + expect(result).to_be("./") + end) + end) end)