Skip to content

feat: add env configuration option and fix vim.notify scheduling #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lua/claudecode/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ M.defaults = {
port_range = { min = 10000, max = 65535 },
auto_start = true,
terminal_cmd = nil,
env = {}, -- Custom environment variables for Claude terminal
log_level = "info",
track_selection = true,
visual_demotion_delay_ms = 50, -- Milliseconds to wait before demoting a visual selection
Expand Down Expand Up @@ -74,6 +75,13 @@ function M.validate(config)
assert(type(config.diff_opts.vertical_split) == "boolean", "diff_opts.vertical_split must be a boolean")
assert(type(config.diff_opts.open_in_current_tab) == "boolean", "diff_opts.open_in_current_tab must be a boolean")

-- Validate env
assert(type(config.env) == "table", "env must be a table")
for key, value in pairs(config.env) do
assert(type(key) == "string", "env keys must be strings")
assert(type(value) == "string", "env values must be strings")
end

return true
end

Expand Down
6 changes: 4 additions & 2 deletions lua/claudecode/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ M.version = {
--- @field port_range {min: integer, max: integer} Port range for WebSocket server.
--- @field auto_start boolean Auto-start WebSocket server on Neovim startup.
--- @field terminal_cmd string|nil Custom terminal command to use when launching Claude.
--- @field env table<string,string> Custom environment variables for Claude terminal.
--- @field log_level "trace"|"debug"|"info"|"warn"|"error" Log level.
--- @field track_selection boolean Enable sending selection updates to Claude.
--- @field visual_demotion_delay_ms number Milliseconds to wait before demoting a visual selection.
Expand All @@ -49,6 +50,7 @@ local default_config = {
port_range = { min = 10000, max = 65535 },
auto_start = true,
terminal_cmd = nil,
env = {},
log_level = "info",
track_selection = true,
visual_demotion_delay_ms = 50, -- Reduced from 200ms for better responsiveness in tree navigation
Expand Down Expand Up @@ -303,14 +305,14 @@ function M.setup(opts)

logger.setup(M.state.config)

-- Setup terminal module: always try to call setup to pass terminal_cmd,
-- Setup terminal module: always try to call setup to pass terminal_cmd and env,
-- even if terminal_opts (for split_side etc.) are not provided.
local terminal_setup_ok, terminal_module = pcall(require, "claudecode.terminal")
if terminal_setup_ok then
-- Guard in case tests or user replace the module with a minimal stub without `setup`.
if type(terminal_module.setup) == "function" then
-- terminal_opts might be nil, which the setup function should handle gracefully.
terminal_module.setup(terminal_opts, M.state.config.terminal_cmd)
terminal_module.setup(terminal_opts, M.state.config.terminal_cmd, M.state.config.env)
end
else
logger.error("init", "Failed to load claudecode.terminal module for setup.")
Expand Down
22 changes: 11 additions & 11 deletions lua/claudecode/logger.lua
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,18 @@ local function log(level, component, message_parts)
end
end

if level == M.levels.ERROR then
vim.notify(prefix .. " " .. message, vim.log.levels.ERROR, { title = "ClaudeCode Error" })
elseif level == M.levels.WARN then
vim.notify(prefix .. " " .. message, vim.log.levels.WARN, { title = "ClaudeCode Warning" })
else
-- For INFO, DEBUG, TRACE, use nvim_echo to avoid flooding notifications,
-- to make them appear in :messages, and wrap in vim.schedule
-- to avoid "nvim_echo must not be called in a fast event context".
vim.schedule(function()
-- Wrap all vim.notify and nvim_echo calls in vim.schedule to avoid
-- "nvim_echo must not be called in a fast event context" errors
vim.schedule(function()
if level == M.levels.ERROR then
vim.notify(prefix .. " " .. message, vim.log.levels.ERROR, { title = "ClaudeCode Error" })
elseif level == M.levels.WARN then
vim.notify(prefix .. " " .. message, vim.log.levels.WARN, { title = "ClaudeCode Warning" })
else
-- For INFO, DEBUG, TRACE, use nvim_echo to avoid flooding notifications
vim.api.nvim_echo({ { prefix .. " " .. message, "Normal" } }, true, {})
end)
end
end
end)
end

--- @param component string|nil Optional component/module name.
Expand Down
19 changes: 18 additions & 1 deletion lua/claudecode/terminal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ local config = {
show_native_term_exit_tip = true,
terminal_cmd = nil,
auto_close = true,
env = {}, -- Custom environment variables for Claude terminal
}

-- Lazy load providers
Expand Down Expand Up @@ -148,6 +149,11 @@ local function get_claude_command_and_env(cmd_args)
env_table["CLAUDE_CODE_SSE_PORT"] = tostring(sse_port_value)
end

-- Merge custom environment variables from config
for key, value in pairs(config.env) do
env_table[key] = value
end

return cmd_string, env_table
end

Expand Down Expand Up @@ -180,7 +186,8 @@ end
-- @field user_term_config.provider string 'snacks' or 'native' (default: 'snacks').
-- @field user_term_config.show_native_term_exit_tip boolean Show tip for exiting native terminal (default: true).
-- @param p_terminal_cmd string|nil The command to run in the terminal (from main config).
function M.setup(user_term_config, p_terminal_cmd)
-- @param p_env table|nil Custom environment variables to pass to the terminal (from main config).
function M.setup(user_term_config, p_terminal_cmd, p_env)
if user_term_config == nil then -- Allow nil, default to empty table silently
user_term_config = {}
elseif type(user_term_config) ~= "table" then -- Warn if it's not nil AND not a table
Expand All @@ -198,6 +205,16 @@ function M.setup(user_term_config, p_terminal_cmd)
config.terminal_cmd = nil -- Fallback to default behavior
end

if p_env == nil or type(p_env) == "table" then
config.env = p_env or {}
else
vim.notify(
"claudecode.terminal.setup: Invalid env provided: " .. tostring(p_env) .. ". Using empty table.",
vim.log.levels.WARN
)
config.env = {}
end

for k, v in pairs(user_term_config) do
if config[k] ~= nil and k ~= "terminal_cmd" then -- terminal_cmd is handled above
if k == "split_side" and (v == "left" or v == "right") then
Expand Down
Loading