diff --git a/.gitignore b/.gitignore index 7293f19..9aadf8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ + + +# Codetyper.nvim - AI coding partner files +*.coder.* .coder/ -.*/.coder/.* -**/*.coder.* diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eaf6bd..3214077 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Improved code generation prompts to explicitly request only raw code output (no explanations, markdown, or code fences) + ## [0.2.0] - 2026-01-11 ### Added diff --git a/lua/codetyper/autocmds.lua b/lua/codetyper/autocmds.lua index 93aa9cb..f659a54 100644 --- a/lua/codetyper/autocmds.lua +++ b/lua/codetyper/autocmds.lua @@ -142,10 +142,26 @@ function M.setup() }) end ---- Check if the buffer has a newly closed prompt and auto-process -function M.check_for_closed_prompt() +--- Get config with fallback defaults +local function get_config_safe() local codetyper = require("codetyper") local config = codetyper.get_config() + -- Return defaults if not initialized + if not config or not config.patterns then + return { + patterns = { + open_tag = "/@", + close_tag = "@/", + file_pattern = "*.coder.*", + } + } + end + return config +end + +--- Check if the buffer has a newly closed prompt and auto-process +function M.check_for_closed_prompt() + local config = get_config_safe() local parser = require("codetyper.parser") local bufnr = vim.api.nvim_get_current_buf() diff --git a/lua/codetyper/config.lua b/lua/codetyper/config.lua index dfa1e7e..8606694 100644 --- a/lua/codetyper/config.lua +++ b/lua/codetyper/config.lua @@ -5,14 +5,14 @@ local M = {} ---@type CoderConfig local defaults = { llm = { - provider = "claude", + provider = "ollama", claude = { api_key = nil, -- Will use ANTHROPIC_API_KEY env var if nil model = "claude-sonnet-4-20250514", }, ollama = { host = "http://localhost:11434", - model = "codellama", + model = "deepseek-coder:6.7b", }, }, window = { diff --git a/lua/codetyper/prompts/code.lua b/lua/codetyper/prompts/code.lua index 1341d79..8ecd3e4 100644 --- a/lua/codetyper/prompts/code.lua +++ b/lua/codetyper/prompts/code.lua @@ -14,6 +14,8 @@ Requirements: - Include proper error handling - Use appropriate types (if applicable) - Make it efficient and readable + +OUTPUT ONLY THE RAW CODE. No explanations, no markdown, no code fences. ]] --- Prompt template for creating a new class/module @@ -26,6 +28,8 @@ Requirements: - Include constructor/initialization - Implement proper encapsulation - Add necessary methods as described + +OUTPUT ONLY THE RAW CODE. No explanations, no markdown, no code fences. ]] --- Prompt template for implementing an interface/trait @@ -37,6 +41,8 @@ Requirements: - Implement all required methods - Follow the interface contract exactly - Handle edge cases appropriately + +OUTPUT ONLY THE RAW CODE. No explanations, no markdown, no code fences. ]] --- Prompt template for creating a React component @@ -49,6 +55,8 @@ Requirements: - Include proper TypeScript types (if .tsx) - Follow React best practices - Make it reusable and composable + +OUTPUT ONLY THE RAW CODE. No explanations, no markdown, no code fences. ]] --- Prompt template for creating an API endpoint @@ -61,6 +69,8 @@ Requirements: - Proper error handling and status codes - Follow RESTful conventions - Include appropriate middleware + +OUTPUT ONLY THE RAW CODE. No explanations, no markdown, no code fences. ]] --- Prompt template for creating a utility function @@ -73,6 +83,8 @@ Requirements: - Handle edge cases - Efficient implementation - Well-typed (if applicable) + +OUTPUT ONLY THE RAW CODE. No explanations, no markdown, no code fences. ]] --- Prompt template for generic code generation @@ -88,6 +100,8 @@ Requirements: - Match existing code style - Follow best practices - Handle errors appropriately + +OUTPUT ONLY THE RAW CODE. No explanations, no markdown, no code fences. ]] return M diff --git a/lua/codetyper/tree.lua b/lua/codetyper/tree.lua index 3425280..89c4739 100644 --- a/lua/codetyper/tree.lua +++ b/lua/codetyper/tree.lua @@ -10,6 +10,19 @@ local CODER_FOLDER = ".coder" --- Name of the tree log file local TREE_LOG_FILE = "tree.log" +--- Name of the settings file +local SETTINGS_FILE = "settings.json" + +--- Default settings for the coder folder +local DEFAULT_SETTINGS = { + ["editor.fontSize"] = 14, + ["editor.tabSize"] = 2, + ["files.autoSave"] = "afterDelay", + ["files.autoSaveDelay"] = 1000, + ["terminal.integrated.fontSize"] = 14, + ["workbench.colorTheme"] = "Default Dark+", +} + --- Get the path to the .coder folder ---@return string|nil Path to .coder folder or nil function M.get_coder_folder() @@ -30,6 +43,57 @@ function M.get_tree_log_path() return coder_folder .. "/" .. TREE_LOG_FILE end +--- Get the path to the settings.json file +---@return string|nil Path to settings.json or nil +function M.get_settings_path() + local coder_folder = M.get_coder_folder() + if not coder_folder then + return nil + end + return coder_folder .. "/" .. SETTINGS_FILE +end + +--- Ensure settings.json exists with default settings +---@return boolean Success status +function M.ensure_settings() + local settings_path = M.get_settings_path() + if not settings_path then + return false + end + + -- Check if file already exists + local stat = vim.loop.fs_stat(settings_path) + if stat then + return true -- File already exists, don't overwrite + end + + -- Create settings file with defaults + local json_content = vim.fn.json_encode(DEFAULT_SETTINGS) + -- Pretty print the JSON + local ok, pretty_json = pcall(function() + return vim.fn.system({ "python3", "-m", "json.tool" }, json_content) + end) + + if not ok or vim.v.shell_error ~= 0 then + -- Fallback to simple formatting if python not available + pretty_json = "{\n" + local keys = vim.tbl_keys(DEFAULT_SETTINGS) + table.sort(keys) + for i, key in ipairs(keys) do + local value = DEFAULT_SETTINGS[key] + local value_str = type(value) == "string" and ('"' .. value .. '"') or tostring(value) + pretty_json = pretty_json .. ' "' .. key .. '": ' .. value_str + if i < #keys then + pretty_json = pretty_json .. "," + end + pretty_json = pretty_json .. "\n" + end + pretty_json = pretty_json .. "}\n" + end + + return utils.write_file(settings_path, pretty_json) +end + --- Ensure .coder folder exists ---@return boolean Success status function M.ensure_coder_folder() @@ -198,10 +262,51 @@ function M.update_tree_log() return false end +--- Cache to track initialized projects (by root path) +local initialized_projects = {} + +--- Check if project is already initialized +---@param root string Project root path +---@return boolean +local function is_project_initialized(root) + return initialized_projects[root] == true +end + --- Initialize tree logging (called on setup) -function M.setup() +---@param force? boolean Force re-initialization even if cached +---@return boolean success +function M.setup(force) + local coder_folder = M.get_coder_folder() + if not coder_folder then + return false + end + + local root = utils.get_project_root() + if not root then + return false + end + + -- Skip if already initialized (unless forced) + if not force and is_project_initialized(root) then + return true + end + + -- Ensure .coder folder exists + if not M.ensure_coder_folder() then + utils.notify("Failed to create .coder folder", vim.log.levels.ERROR) + return false + end + + -- Create settings.json with defaults if it doesn't exist + M.ensure_settings() + -- Create initial tree log M.update_tree_log() + + -- Mark project as initialized + initialized_projects[root] = true + + return true end --- Get file statistics from tree diff --git a/lua/codetyper/utils.lua b/lua/codetyper/utils.lua index 243b07f..c4e72be 100644 --- a/lua/codetyper/utils.lua +++ b/lua/codetyper/utils.lua @@ -17,7 +17,8 @@ function M.get_project_root() end found = vim.fn.finddir(marker, current .. ";") if found ~= "" then - return vim.fn.fnamemodify(found, ":p:h") + -- For directories, :p:h gives the dir itself, so we need :p:h:h to get parent + return vim.fn.fnamemodify(found, ":p:h:h") end end diff --git a/plugin/codetyper.lua b/plugin/codetyper.lua index 9e365dc..a91d109 100644 --- a/plugin/codetyper.lua +++ b/plugin/codetyper.lua @@ -18,17 +18,32 @@ if fn.has("nvim-0.8.0") == 0 then return end +--- Initialize codetyper plugin fully +--- Creates .coder folder, settings.json, tree.log, .gitignore +--- Also registers autocmds for /@ @/ prompt detection +---@return boolean success +local function init_coder_files() + local ok, err = pcall(function() + -- Full plugin initialization (includes config, commands, autocmds, tree, gitignore) + local codetyper = require("codetyper") + if not codetyper.is_initialized() then + codetyper.setup() + end + end) + + if not ok then + vim.notify("[Codetyper] Failed to initialize: " .. tostring(err), vim.log.levels.ERROR) + return false + end + return true +end + -- Initialize .coder folder and tree.log on project open api.nvim_create_autocmd("VimEnter", { callback = function() -- Delay slightly to ensure cwd is set vim.defer_fn(function() - local tree = require("codetyper.tree") - tree.setup() - - -- Also ensure gitignore is updated - local gitignore = require("codetyper.gitignore") - gitignore.ensure_ignored() + init_coder_files() end, 100) end, desc = "Initialize Codetyper .coder folder on startup", @@ -38,11 +53,7 @@ api.nvim_create_autocmd("VimEnter", { api.nvim_create_autocmd("DirChanged", { callback = function() vim.defer_fn(function() - local tree = require("codetyper.tree") - tree.setup() - - local gitignore = require("codetyper.gitignore") - gitignore.ensure_ignored() + init_coder_files() end, 100) end, desc = "Initialize Codetyper .coder folder on directory change",