From c5b26d498b9f176c6ca500133b4a8a29666ad00a Mon Sep 17 00:00:00 2001 From: smnatale Date: Mon, 13 Apr 2026 11:55:04 +0100 Subject: [PATCH 1/2] add support for lualine & fidget --- lua/coderabbit/config.lua | 2 +- lua/coderabbit/init.lua | 4 +++ lua/coderabbit/review.lua | 58 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/lua/coderabbit/config.lua b/lua/coderabbit/config.lua index bf00234..097d1ad 100644 --- a/lua/coderabbit/config.lua +++ b/lua/coderabbit/config.lua @@ -3,7 +3,7 @@ local M = {} M.defaults = { cli = { binary = "cr", - timeout = 120000, + timeout = 0, extra_args = {}, }, review = { diff --git a/lua/coderabbit/init.lua b/lua/coderabbit/init.lua index 61249b5..c422b25 100644 --- a/lua/coderabbit/init.lua +++ b/lua/coderabbit/init.lua @@ -20,4 +20,8 @@ function M.clear() require("coderabbit.review").clear() end +function M.status() + return require("coderabbit.review").status() +end + return M diff --git a/lua/coderabbit/review.lua b/lua/coderabbit/review.lua index 9879d5a..972a74e 100644 --- a/lua/coderabbit/review.lua +++ b/lua/coderabbit/review.lua @@ -5,12 +5,48 @@ local cli = require("coderabbit.cli") local parser = require("coderabbit.parser") local diagnostics = require("coderabbit.diagnostics") +local spinner_frames = { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" } +local FRAME_MS = 80 + local state = { job_id = nil, findings = {}, cwd = nil, + start_time = nil, + fidget_handle = nil, } +local function spinner() + local idx = math.floor(vim.uv.hrtime() / (1e6 * FRAME_MS)) % #spinner_frames + 1 + return spinner_frames[idx] +end + +local function fidget_start() + local ok, progress = pcall(require, "fidget.progress") + if not ok then + return nil + end + return progress.handle.create({ + title = "Reviewing", + message = "analyzing...", + lsp_client = { name = "coderabbit" }, + }) +end + +local function fidget_update(msg) + if state.fidget_handle then + state.fidget_handle.message = msg + end +end + +local function fidget_finish(msg) + if state.fidget_handle then + state.fidget_handle.message = msg + state.fidget_handle:finish() + state.fidget_handle = nil + end +end + function M.is_running() return state.job_id ~= nil end @@ -19,6 +55,16 @@ function M.get_results() return state.findings end +--- Return a short status string for statusline integration. +--- Returns nil when no review is running. +function M.status() + if not state.job_id then + return nil + end + local elapsed = os.time() - state.start_time + return string.format("%s CodeRabbit (%ds)", spinner(), elapsed) +end + function M.run(opts) opts = opts or {} @@ -43,6 +89,9 @@ function M.run(opts) vim.notify("CodeRabbit: Reviewing...") + state.start_time = os.time() + state.fidget_handle = fidget_start() + state.job_id = cli.review(opts, { on_line = function(line) local event = parser.parse_line(line) @@ -51,7 +100,8 @@ function M.run(opts) end if event.type == "status" then - vim.notify("CodeRabbit: " .. (event.status or event.phase or "working..."), vim.log.levels.INFO) + local msg = event.status or event.phase or "working..." + fidget_update(msg) elseif event.type == "finding" then finding_count = finding_count + 1 local diag, filepath = parser.finding_to_diagnostic(event, state.cwd, cfg.diagnostics.severity_map) @@ -75,6 +125,7 @@ function M.run(opts) state.job_id = nil if code == -1 then + fidget_finish("timed out") vim.notify("CodeRabbit: Review timed out", vim.log.levels.ERROR) return end @@ -85,6 +136,7 @@ function M.run(opts) if msg:match("[Aa]uth") then msg = msg .. "\nRun: cr auth login" end + fidget_finish("failed") vim.notify("CodeRabbit: " .. msg, vim.log.levels.ERROR) return end @@ -92,7 +144,10 @@ function M.run(opts) if not got_error then local summary = string.format("CodeRabbit: Review complete. %d finding%s.", finding_count, finding_count == 1 and "" or "s") + fidget_finish(summary) vim.notify(summary, vim.log.levels.INFO) + else + fidget_finish("done (with errors)") end if cfg.on_review_complete then @@ -104,6 +159,7 @@ end function M.stop() if state.job_id then + fidget_finish("cancelled") cli.cancel(state.job_id) state.job_id = nil vim.notify("CodeRabbit: Review cancelled", vim.log.levels.INFO) From 6a679dcfa69abc33f5ef887d846c77f0215d08b5 Mon Sep 17 00:00:00 2001 From: smnatale Date: Mon, 13 Apr 2026 12:06:41 +0100 Subject: [PATCH 2/2] shorter fidget.nvim message, state cleanup, add msg when no fidget/lualine --- lua/coderabbit/review.lua | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lua/coderabbit/review.lua b/lua/coderabbit/review.lua index 972a74e..8fb81a4 100644 --- a/lua/coderabbit/review.lua +++ b/lua/coderabbit/review.lua @@ -14,6 +14,7 @@ local state = { cwd = nil, start_time = nil, fidget_handle = nil, + last_notify_time = nil, } local function spinner() @@ -101,7 +102,15 @@ function M.run(opts) if event.type == "status" then local msg = event.status or event.phase or "working..." - fidget_update(msg) + if state.fidget_handle then + fidget_update(msg) + else + local now = os.time() + if not state.last_notify_time or (now - state.last_notify_time) >= 20 then + state.last_notify_time = now + vim.notify("CodeRabbit: " .. msg, vim.log.levels.INFO) + end + end elseif event.type == "finding" then finding_count = finding_count + 1 local diag, filepath = parser.finding_to_diagnostic(event, state.cwd, cfg.diagnostics.severity_map) @@ -123,6 +132,8 @@ function M.run(opts) on_exit = function(code, stderr) state.job_id = nil + state.start_time = nil + state.last_notify_time = nil if code == -1 then fidget_finish("timed out") @@ -144,7 +155,7 @@ function M.run(opts) if not got_error then local summary = string.format("CodeRabbit: Review complete. %d finding%s.", finding_count, finding_count == 1 and "" or "s") - fidget_finish(summary) + fidget_finish(string.format("done — %d finding%s", finding_count, finding_count == 1 and "" or "s")) vim.notify(summary, vim.log.levels.INFO) else fidget_finish("done (with errors)")