local M = {} local uv = vim.loop local ok_yaml, lyaml = pcall(require, "lyaml") local prompts = require("chatgpt_nvim.prompts") -- Determines the Git root or fallback directory. local function get_project_root() local current_file = vim.fn.expand("%:p") local root_dir if current_file == "" then root_dir = vim.fn.getcwd() else local file_dir = current_file:match("(.*)/") if not file_dir then root_dir = vim.fn.getcwd() else local cmd = string.format("cd %s && git rev-parse --show-toplevel 2>/dev/null", vim.fn.shellescape(file_dir)) local git_root = vim.fn.systemlist(cmd) if vim.v.shell_error == 0 and git_root and #git_root > 0 then root_dir = git_root[1] else root_dir = file_dir end end end return root_dir end -- Attempt to locate either .chatgpt_config.yaml or chatgpt_config.yaml, returning whichever exists first. local function get_config_path() local root = get_project_root() local dot_config = root .. "/.chatgpt_config.yaml" local non_dot_config = root .. "/chatgpt_config.yaml" local dot_fd = uv.fs_open(dot_config, "r", 438) if dot_fd then uv.fs_close(dot_fd) return dot_config end local non_dot_fd = uv.fs_open(non_dot_config, "r", 438) if non_dot_fd then uv.fs_close(non_dot_fd) return non_dot_config end return nil end function M.load() -- Attempt to find either config file, else fallback local path = get_config_path() local config = { initial_prompt = "", directories = { "." }, default_prompt_blocks = {}, prompt_char_limit = 300000, project_name = "", debug = false, initial_files = {}, include_file_contents = false, -- NEW FLAG: include file contents in prompt if true preview_changes = false, interactive_file_selection = false, partial_acceptance = false, improved_debug = false, enable_chunking = false, enable_step_by_step = true, -- If auto_lint is true, we only do LSP-based checks. auto_lint = false, tool_auto_accept = { read_file = false, edit_file = false, replace_in_file = false, executeCommand = false, } } -- If no config file found, alert user and return default config if not path then config.initial_prompt = "You are a coding assistant who receives a project's context and user instructions..." vim.notify( "No config file found (tried .chatgpt_config.yaml, chatgpt_config.yaml). Using defaults.", vim.log.levels.WARN ) return config end local fd = uv.fs_open(path, "r", 438) if fd then local stat = uv.fs_fstat(fd) local data = uv.fs_read(fd, stat.size, 0) uv.fs_close(fd) if data and ok_yaml then local ok, result = pcall(lyaml.load, data) if ok and type(result) == "table" then if type(result.initial_prompt) == "string" then config.initial_prompt = result.initial_prompt end if type(result.directories) == "table" then config.directories = result.directories end if type(result.default_prompt_blocks) == "table" then config.default_prompt_blocks = result.default_prompt_blocks end if type(result.prompt_char_limit) == "number" then config.prompt_char_limit = result.prompt_char_limit end if type(result.project_name) == "string" then config.project_name = result.project_name end if type(result.debug) == "boolean" then config.debug = result.debug end if type(result.initial_files) == "table" then config.initial_files = result.initial_files end if type(result.include_file_contents) == "boolean" then -- LOAD NEW FLAG config.include_file_contents = result.include_file_contents end if type(result.preview_changes) == "boolean" then config.preview_changes = result.preview_changes end if type(result.interactive_file_selection) == "boolean" then config.interactive_file_selection = result.interactive_file_selection end if type(result.partial_acceptance) == "boolean" then config.partial_acceptance = result.partial_acceptance end if type(result.improved_debug) == "boolean" then config.improved_debug = result.improved_debug end if type(result.enable_chunking) == "boolean" then config.enable_chunking = result.enable_chunking end if type(result.enable_step_by_step) == "boolean" then config.enable_step_by_step = result.enable_step_by_step end if type(result.auto_lint) == "boolean" then config.auto_lint = result.auto_lint end if type(result.tool_auto_accept) == "table" then for k, v in pairs(result.tool_auto_accept) do if config.tool_auto_accept[k] ~= nil and type(v) == "boolean" then config.tool_auto_accept[k] = v end end end end end else config.initial_prompt = "You are a coding assistant who receives a project's context and user instructions..." end -- Merge default prompt blocks if type(config.default_prompt_blocks) == "table" and #config.default_prompt_blocks > 0 then local merged_prompt = {} for _, block_name in ipairs(config.default_prompt_blocks) do if prompts[block_name] then table.insert(merged_prompt, prompts[block_name]) end end if #merged_prompt > 0 then local combined_blocks = table.concat(merged_prompt, "\n\n") if config.initial_prompt ~= "" then config.initial_prompt = config.initial_prompt .. "\n\n" .. combined_blocks else config.initial_prompt = combined_blocks end end end -- Include project name in the final initial prompt, if set if config.project_name ~= "" then config.initial_prompt = "[Project Name: " .. config.project_name .. "]\n\n" .. config.initial_prompt end if config.debug then vim.api.nvim_out_write("[chatgpt_nvim:config] Loaded config from: " .. path .. "\n") vim.api.nvim_out_write("[chatgpt_nvim:config] Debug logging is enabled.\n") end return config end return M