Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Run `:checkhealth coderabbit` to verify everything is wired up.
| `:CodeRabbitStop` | Cancel a running review |
| `:CodeRabbitClear` | Clear diagnostics |
| `:CodeRabbitShow [id]` | View results (float or buffer). Defaults to the latest review |
| `:CodeRabbitRestore [id]` | Reapply diagnostics from a saved review. Defaults to the most recent |
| `:CodeRabbitHistory` | Browse past reviews |

For your statusline:
Expand Down
8 changes: 8 additions & 0 deletions doc/coderabbit.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ COMMANDS *coderabbit-commands*
Pass an `id` from `:CodeRabbitHistory` to view a saved review.
Press `q` to close.

:CodeRabbitRestore [id] *:CodeRabbitRestore*
Reapply diagnostics from a saved review. Pass an `id` from
`:CodeRabbitHistory` to restore a specific review. Without an `id`,
restores the most recent review.

:CodeRabbitHistory *:CodeRabbitHistory*
Browse saved reviews via |vim.ui.select|.

Expand All @@ -128,6 +133,9 @@ require("coderabbit").clear() *coderabbit.clear()*
require("coderabbit").show({id}) *coderabbit.show()*
Open the review buffer. `nil` = current, number = saved.

require("coderabbit").restore({id}) *coderabbit.restore()*
Reapply diagnostics from a saved review. `nil` = most recent.

require("coderabbit").history() *coderabbit.history()*
Open the review history picker.

Expand Down
4 changes: 4 additions & 0 deletions lua/coderabbit/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ function M.clear()
require("coderabbit.review").clear()
end

function M.restore(id)
require("coderabbit.review").restore(id)
end

function M.show(id)
require("coderabbit.show").open(id)
end
Expand Down
30 changes: 30 additions & 0 deletions lua/coderabbit/review.lua
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,36 @@ function M.stop()
end
end

function M.restore(id)
local entries = storage.list()
if #entries == 0 then
vim.notify("CodeRabbit: No saved reviews found", vim.log.levels.WARN)
return
end

if not id then
id = entries[#entries].id
end

local review = storage.load(id)
if not review then
vim.notify("CodeRabbit: Review #" .. id .. " not found", vim.log.levels.WARN)
return
end

diagnostics.clear()
vim.schedule(function()
for _, finding in ipairs(review.findings) do
diagnostics.set(finding.filepath, { finding.diagnostic })
end
Comment thread
coderabbitai[bot] marked this conversation as resolved.

vim.notify(
string.format("CodeRabbit: Restored %d findings from review #%d", #review.findings, id),
vim.log.levels.INFO
)
end)
end

function M.clear()
diagnostics.clear()
state.findings = {}
Expand Down
12 changes: 12 additions & 0 deletions plugin/coderabbit.lua
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ end, {
desc = "Show CodeRabbit review results in a buffer (optional: review ID)",
})

vim.api.nvim_create_user_command("CodeRabbitRestore", function(args)
ensure_setup()
local id = args.fargs[1] and tonumber(args.fargs[1]) or nil
require("coderabbit").restore(id)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
end, {
nargs = "?",
complete = function()
return require("coderabbit.storage").ids()
end,
desc = "Restore diagnostics from a previous CodeRabbit review (default: most recent)",
})

vim.api.nvim_create_user_command("CodeRabbitHistory", function()
ensure_setup()
require("coderabbit").history()
Expand Down
107 changes: 107 additions & 0 deletions tests/coderabbit/restore_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
local diagnostics = require("coderabbit.diagnostics")
local review = require("coderabbit.review")
local storage = require("coderabbit.storage")
local h = require("tests.helpers")
local test, eq = h.test, h.eq

local test_dir = vim.fn.tempname() .. "/coderabbit_restore_test"
storage._set_base_dir(test_dir)

local function flush()
vim.wait(10, function()
return false
end)
end

local function cleanup()
vim.fn.delete(test_dir, "rf")
diagnostics.clear()
end

local function make_findings(n)
local tmpdir = vim.fn.tempname()
vim.fn.mkdir(tmpdir, "p")
local findings = {}
for i = 1, n do
local filepath = tmpdir .. "/file" .. i .. ".ts"
vim.fn.writefile({ "// mock" }, filepath)
table.insert(findings, h.finding(filepath, i * 10, h.W, "finding " .. i))
end
return findings
end

-- ──────────────────────────────────────────────────────────
-- Tests
-- ──────────────────────────────────────────────────────────

test("restore: warns when no saved reviews exist", function()
cleanup()
-- Should not error, just warn
review.restore(nil)
end)

test("restore: warns when review ID not found", function()
cleanup()
storage.save(make_findings(1), h.context())
review.restore(999)
end)

test("restore: restores diagnostics from a specific review", function()
cleanup()
local findings = make_findings(2)
storage.save(findings, h.context())

review.restore(1)
flush()

for _, finding in ipairs(findings) do
local bufnr = vim.fn.bufnr(finding.filepath)
local got = vim.diagnostic.get(bufnr, { namespace = diagnostics.ns })
eq(#got, 1)
eq(got[1].message, finding.diagnostic.message)
end
end)

test("restore: defaults to most recent review when no ID given", function()
cleanup()
local old_findings = make_findings(1)
storage.save(old_findings, h.context("old-branch"))
local new_findings = make_findings(2)
storage.save(new_findings, h.context("new-branch"))

review.restore(nil)
flush()

-- Should have diagnostics from the second review (2 findings)
local total = 0
for _, d in ipairs(vim.diagnostic.get()) do
if d.source == "coderabbit" then
total = total + 1
end
end
eq(total, 2)
end)

test("restore: clears previous diagnostics before applying", function()
cleanup()
local first = make_findings(3)
storage.save(first, h.context())
local second = make_findings(1)
storage.save(second, h.context())

review.restore(1) -- 3 findings
flush()
review.restore(2) -- 1 finding — should replace, not accumulate
flush()

local total = 0
for _, d in ipairs(vim.diagnostic.get()) do
if d.source == "coderabbit" then
total = total + 1
end
end
eq(total, 1)
end)

cleanup()
h.summary()
Loading