Skip to content
Merged
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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
### lazy.nvim

```lua
---@module "lazy"
---@type LazySpec
{
"afewyards/codereview.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
Expand All @@ -62,6 +64,8 @@
"CodeReviewToggleScroll",
"CodeReviewCommits",
},
---@module "codereview"
---@type codereview.Config
opts = {},
}
```
Expand Down
74 changes: 74 additions & 0 deletions lua/codereview/config.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,65 @@
-- lua/codereview/config.lua

---@class codereview.Config
---@field base_url? string API base URL override (auto-detected)
---@field project? string "owner/repo" override (auto-detected)
---@field platform? "github"|"gitlab" platform override (auto-detected)
---@field github_token? string GitHub personal access token
---@field gitlab_token? string GitLab personal access token
---@field picker? "telescope"|"fzf"|"snacks" picker override (auto-detected)
---@field debug? boolean debug logging to `.codereview.log` (default: `false`)
---@field open_in_tab? boolean open review in a new tab (set `false` to use current window) (default: `true`)
---@field diff? codereview.config.Diff diff viewer
---@field pipeline? codereview.config.Pipeline pipeline viewer
---@field ai? codereview.config.AI AI review
---@field keymaps? codereview.config.Keymap override or disable keybindings

---@class codereview.config.Diff
---@field context? integer lines of context (0-20) (default: 8)
---@field scroll_threshold? integer use scroll mode when file count <= threshold (default: 50)
---@field comment_width? integer comment float width (default: 80)
---@field separator_char? string hunk separator character
---@field separator_lines? integer lines in hunk separator (default: 3)

---@class codereview.config.Pipeline
---@field poll_interval? integer status poll interval (ms) (default: 10000)
---@field log_max_lines? integer max lines in job log viewer (default: 5000)

---@class codereview.config.AI
---@field enabled? boolean enable AI Review (default: `true`)
---@field provider? "claude_cli"|"anthropic"|"openai"|"ollama"|"custom_cmd" AI Provider to use
---@field review_level? "info"|"suggestion"|"warning"|"error" controls the verbosity of AI code reviews (default: `info`)
---@field max_file_size? integer skip files larger than N lines (0 = unlimited) (default: 500)
---@field claude_cli? codereview.config.ai.ClaudeCli Claude CLI options
---@field anthropic? codereview.config.ai.Anthropic Anthropic API options
---@field openai? codereview.config.ai.OpenAI OpenAI API options
---@field ollama? codereview.config.ai.Ollama Ollama options
---@field custom_cmd? codereview.config.ai.CustomCmd Custom command options

---@class codereview.config.ai.ClaudeCli
---@field cmd? string Claude CLI command (default: `claude_cli`)
---@field agent? string Claude Agent (default: `code-review`)

---@class codereview.config.ai.Anthropic
---@field api_key? string Anthropic API key
---@field model? string Anthropic model name

---@class codereview.config.ai.OpenAI
---@field api_key? string OpenAI API key
---@field model? string OpenAI model name
---@field base_url? string OpenAI API base URL

---@class codereview.config.ai.Ollama
---@field model? string Ollama model name
---@field base_url? string Ollama API base URL

---@class codereview.config.ai.CustomCmd
---@field cmd? string shell command
---@field args? string[] command-line arguments

local M = {}

---@type codereview.Config
local defaults = {
base_url = nil, -- API base URL override (auto-detected). Alias: gitlab_url
project = nil,
Expand All @@ -26,8 +85,12 @@ local defaults = {
keymaps = {},
}

---@type codereview.Config?
local current = nil

---@param base table
---@param override table
---@return table
local function deep_merge(base, override)
local result = vim.deepcopy(base)
for k, v in pairs(override) do
Expand All @@ -40,6 +103,8 @@ local function deep_merge(base, override)
return result
end

---@param c codereview.Config
---@return codereview.Config
local function validate(c)
c.diff.context = math.max(0, math.min(20, c.diff.context))
local valid_levels = { info = true, suggestion = true, warning = true, error = true }
Expand All @@ -54,23 +119,31 @@ local function validate(c)
return c
end

---@param opts? codereview.Config
function M.setup(opts)
opts = opts or {}
current = validate(deep_merge(defaults, opts))
-- Backward compat: top-level claude_cmd/agent → claude_cli sub-table
-- Only applies when user passed old keys without the new claude_cli sub-table
local user_ai = opts.ai or {}
local user_claude_cli = user_ai.claude_cli or {}
---@diagnostic disable-next-line: undefined-field
if user_ai.claude_cmd and not user_claude_cli.cmd then
---@diagnostic disable-next-line: undefined-field
current.ai.claude_cli.cmd = user_ai.claude_cmd
end
---@diagnostic disable-next-line: undefined-field
if user_ai.agent and not user_claude_cli.agent then
---@diagnostic disable-next-line: undefined-field
current.ai.claude_cli.agent = user_ai.agent
end
-- Backward compat: gitlab_url → base_url
---@diagnostic disable-next-line: undefined-field
if current.gitlab_url and not current.base_url then
---@diagnostic disable-next-line: undefined-field
current.base_url = current.gitlab_url
end
---@diagnostic disable-next-line: undefined-field
if current.token then
vim.notify(
"[codereview] `token` is deprecated and will NOT be used. Set `github_token` or `gitlab_token` instead.",
Expand All @@ -80,6 +153,7 @@ function M.setup(opts)
require("codereview.keymaps").setup(current.keymaps)
end

---@return codereview.Config
function M.get()
return current or vim.deepcopy(defaults)
end
Expand Down
37 changes: 37 additions & 0 deletions lua/codereview/keymaps.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
local M = {}

---@alias codereview.keymap.Key string|false

---@class codereview.config.Keymap
---@field next_file? codereview.keymap.Key
---@field prev_file? codereview.keymap.Key
---@field next_commit? codereview.keymap.Key
---@field prev_commit? codereview.keymap.Key
---@field move_down? codereview.keymap.Key
---@field move_up? codereview.keymap.Key
---@field select_next_note? codereview.keymap.Key
---@field select_prev_note? codereview.keymap.Key
---@field create_comment? codereview.keymap.Key
---@field create_range_comment? codereview.keymap.Key
---@field accept_suggestion? codereview.keymap.Key
---@field dismiss_suggestion? codereview.keymap.Key
---@field edit_suggestion? codereview.keymap.Key
---@field reply? codereview.keymap.Key
---@field edit_note? codereview.keymap.Key
---@field delete_note? codereview.keymap.Key
---@field react? codereview.keymap.Key
---@field toggle_resolve? codereview.keymap.Key
---@field toggle_full_file? codereview.keymap.Key
---@field dismiss_all_suggestions? codereview.keymap.Key
---@field submit? codereview.keymap.Key
---@field approve? codereview.keymap.Key
---@field refresh? codereview.keymap.Key
---@field quit? codereview.keymap.Key
---@field open_in_browser? codereview.keymap.Key
---@field merge? codereview.keymap.Key
---@field show_pipeline? codereview.keymap.Key
---@field ai_review? codereview.keymap.Key
---@field ai_review_file? codereview.keymap.Key
---@field pick_comments? codereview.keymap.Key
---@field pick_files? codereview.keymap.Key
---@field pick_commits? codereview.keymap.Key

local defaults = {
next_file = { key = "]f", mode = "n", desc = "Next file" },
prev_file = { key = "[f", mode = "n", desc = "Previous file" },
Expand Down Expand Up @@ -49,6 +85,7 @@ end

local resolved = nil

---@param user_opts? codereview.config.Keymap
function M.setup(user_opts)
resolved = deep_copy(defaults)
if not user_opts then
Expand Down
Loading