AI-powered coding partner for Neovim with LLM integration. Features: - Split view for coder files (*.coder.*) and target files - Tag-based prompts with /@ and @/ syntax - Claude API and Ollama (local) LLM support - Smart prompt detection (refactor, add, document, explain) - Automatic code injection into target files - Project tree logging (.coder/tree.log) - Auto .gitignore management Ask Panel (chat interface): - Fixed at 1/4 screen width - File attachment with @ key - Ctrl+n for new chat - Ctrl+Enter to submit - Proper window close behavior - Navigation with Ctrl+h/j/k/l Commands: Coder, CoderOpen, CoderClose, CoderToggle, CoderProcess, CoderAsk, CoderTree, CoderTreeView
126 lines
3.3 KiB
Lua
126 lines
3.3 KiB
Lua
---@mod codetyper.utils Utility functions for Codetyper.nvim
|
|
|
|
local M = {}
|
|
|
|
--- Get the project root directory
|
|
---@return string|nil Root directory path or nil if not found
|
|
function M.get_project_root()
|
|
-- Try to find common root indicators
|
|
local markers = { ".git", ".gitignore", "package.json", "Cargo.toml", "go.mod", "pyproject.toml" }
|
|
|
|
local current = vim.fn.getcwd()
|
|
|
|
for _, marker in ipairs(markers) do
|
|
local found = vim.fn.findfile(marker, current .. ";")
|
|
if found ~= "" then
|
|
return vim.fn.fnamemodify(found, ":p:h")
|
|
end
|
|
found = vim.fn.finddir(marker, current .. ";")
|
|
if found ~= "" then
|
|
return vim.fn.fnamemodify(found, ":p:h")
|
|
end
|
|
end
|
|
|
|
return current
|
|
end
|
|
|
|
--- Check if a file is a coder file
|
|
---@param filepath string File path to check
|
|
---@return boolean
|
|
function M.is_coder_file(filepath)
|
|
return filepath:match("%.coder%.") ~= nil
|
|
end
|
|
|
|
--- Get the target file path from a coder file path
|
|
---@param coder_path string Path to the coder file
|
|
---@return string Target file path
|
|
function M.get_target_path(coder_path)
|
|
-- Convert index.coder.ts -> index.ts
|
|
return coder_path:gsub("%.coder%.", ".")
|
|
end
|
|
|
|
--- Get the coder file path from a target file path
|
|
---@param target_path string Path to the target file
|
|
---@return string Coder file path
|
|
function M.get_coder_path(target_path)
|
|
-- Convert index.ts -> index.coder.ts
|
|
local dir = vim.fn.fnamemodify(target_path, ":h")
|
|
local name = vim.fn.fnamemodify(target_path, ":t:r")
|
|
local ext = vim.fn.fnamemodify(target_path, ":e")
|
|
|
|
if dir == "." then
|
|
return name .. ".coder." .. ext
|
|
end
|
|
return dir .. "/" .. name .. ".coder." .. ext
|
|
end
|
|
|
|
--- Check if a file exists
|
|
---@param filepath string File path to check
|
|
---@return boolean
|
|
function M.file_exists(filepath)
|
|
local stat = vim.loop.fs_stat(filepath)
|
|
return stat ~= nil
|
|
end
|
|
|
|
--- Read file contents
|
|
---@param filepath string File path to read
|
|
---@return string|nil Contents or nil if error
|
|
function M.read_file(filepath)
|
|
local file = io.open(filepath, "r")
|
|
if not file then
|
|
return nil
|
|
end
|
|
local content = file:read("*all")
|
|
file:close()
|
|
return content
|
|
end
|
|
|
|
--- Write content to file
|
|
---@param filepath string File path to write
|
|
---@param content string Content to write
|
|
---@return boolean Success status
|
|
function M.write_file(filepath, content)
|
|
local file = io.open(filepath, "w")
|
|
if not file then
|
|
return false
|
|
end
|
|
file:write(content)
|
|
file:close()
|
|
return true
|
|
end
|
|
|
|
--- Create directory if it doesn't exist
|
|
---@param dirpath string Directory path
|
|
---@return boolean Success status
|
|
function M.ensure_dir(dirpath)
|
|
if vim.fn.isdirectory(dirpath) == 0 then
|
|
return vim.fn.mkdir(dirpath, "p") == 1
|
|
end
|
|
return true
|
|
end
|
|
|
|
--- Notify user with proper formatting
|
|
---@param msg string Message to display
|
|
---@param level? number Vim log level (default: INFO)
|
|
function M.notify(msg, level)
|
|
level = level or vim.log.levels.INFO
|
|
vim.notify("[Codetyper] " .. msg, level)
|
|
end
|
|
|
|
--- Get buffer filetype
|
|
---@param bufnr? number Buffer number (default: current)
|
|
---@return string Filetype
|
|
function M.get_filetype(bufnr)
|
|
bufnr = bufnr or 0
|
|
return vim.bo[bufnr].filetype
|
|
end
|
|
|
|
--- Escape pattern special characters
|
|
---@param str string String to escape
|
|
---@return string Escaped string
|
|
function M.escape_pattern(str)
|
|
return str:gsub("([%(%)%.%%%+%-%*%?%[%]%^%$])", "%%%1")
|
|
end
|
|
|
|
return M
|