{"id":51018083,"url":"https://github.com/adrianmross/review-mode.nvim","last_synced_at":"2026-06-21T13:30:52.394Z","repository":{"id":361734138,"uuid":"1250713390","full_name":"adrianmross/review-mode.nvim","owner":"adrianmross","description":"Fast GitHub pull request review mode for ordinary Neovim buffers","archived":false,"fork":false,"pushed_at":"2026-06-11T00:05:05.000Z","size":217,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-11T00:11:42.133Z","etag":null,"topics":["code-review","github","neovim","nvim-plugin","pull-request"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adrianmross.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-26T22:43:04.000Z","updated_at":"2026-06-11T00:03:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/adrianmross/review-mode.nvim","commit_stats":null,"previous_names":["adrianmross/pr-review.nvim","adrianmross/review-mode.nvim"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/adrianmross/review-mode.nvim","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adrianmross%2Freview-mode.nvim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adrianmross%2Freview-mode.nvim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adrianmross%2Freview-mode.nvim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adrianmross%2Freview-mode.nvim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adrianmross","download_url":"https://codeload.github.com/adrianmross/review-mode.nvim/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adrianmross%2Freview-mode.nvim/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34610832,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-21T02:00:05.568Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-review","github","neovim","nvim-plugin","pull-request"],"created_at":"2026-06-21T13:30:51.586Z","updated_at":"2026-06-21T13:30:52.380Z","avatar_url":"https://github.com/adrianmross.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"# review-mode.nvim\n\nFast GitHub pull request review mode for ordinary Neovim buffers.\n\nThe goal is to keep review inside normal files instead of a dedicated diff UI:\n\n- opens the first changed file when review mode starts\n- uses Gitsigns against the PR base branch for gutter changes\n- jumps between PR hunks, PR comments, and changed files\n- shows changed files/folders in `nvim-tree`\n- loads GitHub review comments asynchronously with a small disk cache\n- tracks viewed/unviewed PR files locally, with optional GitHub-backed viewed sync\n- opens the base version of the current file in a side-by-side diff split\n- creates line or visual-range PR comments and suggestions through `gh`\n- opens quick PR actions for status, checks, browser handoff, URL copy, and thread resolution\n- can use snacks.nvim or Telescope for action and viewed-file pickers, with the native picker as fallback\n\n## Requirements\n\n- Neovim 0.10+\n- `git`\n- GitHub CLI `gh`, authenticated for the target repository\n- optional: `lewis6991/gitsigns.nvim`\n- optional: `nvim-tree/nvim-tree.lua`\n- optional: `folke/snacks.nvim` or `nvim-telescope/telescope.nvim` for picker UI\n\nThe plugin assumes the current checkout is a PR branch and compares\n`origin/\u003cbase\u003e...HEAD`, where `\u003cbase\u003e` comes from `gh pr view`.\n\n## Install\n\nWith `lazy.nvim`:\n\n```lua\n{\n  \"adrianmross/review-mode.nvim\",\n  dependencies = {\n    \"lewis6991/gitsigns.nvim\",\n  },\n  opts = {},\n  keys = {\n    { \"\u003cleader\u003erm\", \"\u003ccmd\u003eReviewMode\u003ccr\u003e\", desc = \"Review mode\" },\n    { \"\u003cleader\u003erN\", \"\u003ccmd\u003eReviewModeStop\u003ccr\u003e\", desc = \"Review mode stop\" },\n    { \"\u003cleader\u003era\", \"\u003ccmd\u003eReviewModeActions\u003ccr\u003e\", desc = \"Review actions\" },\n    { \"\u003cleader\u003erd\", \"\u003ccmd\u003eReviewModeOldToggle\u003ccr\u003e\", desc = \"Review diff\" },\n    { \"\u003cleader\u003erD\", \"\u003ccmd\u003eReviewModeDiffLayoutToggle\u003ccr\u003e\", desc = \"Review diff layout\" },\n    { \"\u003cleader\u003erf\", \"\u003ccmd\u003eReviewModeDiffFullToggle\u003ccr\u003e\", desc = \"Review diff full file\" },\n    { \"\u003cleader\u003erv\", \"\u003ccmd\u003eReviewModeViewedToggle\u003ccr\u003e\", desc = \"Toggle file viewed\" },\n    { \"\u003cleader\u003erl\", \"\u003ccmd\u003eReviewModeViewedList\u003ccr\u003e\", desc = \"Review viewed files list\" },\n    { \"\u003cleader\u003erV\", \"\u003ccmd\u003eReviewModeViewedFeatureToggle\u003ccr\u003e\", desc = \"Review toggle viewed state\" },\n    { \"\u003cleader\u003erC\", \"\u003ccmd\u003eReviewModeCommentsToggle\u003ccr\u003e\", desc = \"Review toggle comments\" },\n    { \"\u003cleader\u003ers\", \"\u003ccmd\u003eReviewModeViewedSync\u003ccr\u003e\", desc = \"Review sync viewed\" },\n    { \"\u003cleader\u003erS\", \"\u003ccmd\u003eReviewModeViewedSyncToggle\u003ccr\u003e\", desc = \"Review toggle viewed sync\" },\n    { \"\u003cleader\u003erc\", \"\u003ccmd\u003eReviewModeThread\u003ccr\u003e\", desc = \"Review line comments\" },\n    { \"\u003cleader\u003err\", \"\u003ccmd\u003eReviewModeReply\u003ccr\u003e\", desc = \"Review reply\" },\n    { \"\u003cleader\u003erR\", \"\u003ccmd\u003eReviewModeResolveThread\u003ccr\u003e\", desc = \"Review resolve thread\" },\n    {\n      \"\u003cleader\u003erp\",\n      function()\n        require(\"review_mode\").comment()\n      end,\n      mode = { \"n\", \"v\" },\n      desc = \"Review comment\",\n    },\n    { \"]h\", \"\u003ccmd\u003eReviewModeNextHunk\u003ccr\u003e\", desc = \"Next PR hunk\" },\n    { \"[h\", \"\u003ccmd\u003eReviewModePrevHunk\u003ccr\u003e\", desc = \"Previous PR hunk\" },\n    { \"]c\", \"\u003ccmd\u003eReviewModeNextComment\u003ccr\u003e\", desc = \"Next PR comment\" },\n    { \"[c\", \"\u003ccmd\u003eReviewModePrevComment\u003ccr\u003e\", desc = \"Previous PR comment\" },\n    { \"]f\", \"\u003ccmd\u003eReviewModeNextFile\u003ccr\u003e\", desc = \"Next changed file\" },\n    { \"[f\", \"\u003ccmd\u003eReviewModePrevFile\u003ccr\u003e\", desc = \"Previous changed file\" },\n  },\n}\n```\n\nSuggested navigation uses hunk keys for changed regions and comment keys for\nreview discussion:\n\n- `]h` / `[h` jump to the next/previous PR hunk\n- `]c` / `[c` jump to the next/previous PR comment\n- `]f` / `[f` jump to the next/previous changed file\n\n## nvim-tree Integration\n\nTo decorate changed files and parent directories in `nvim-tree`, include the\ndecorator in your `nvim-tree` setup:\n\n```lua\nrequire(\"nvim-tree\").setup({\n  renderer = {\n    decorators = {\n      \"Git\",\n      \"Open\",\n      \"Hidden\",\n      \"Modified\",\n      \"Bookmark\",\n      \"Diagnostics\",\n      \"Copied\",\n      require \"review_mode.integrations.nvim_tree\",\n      \"Cut\",\n    },\n  },\n})\n```\n\nUnviewed changed files and closed parent folders are marked with `☐ N`, where\n`N` is the number of unviewed changed files under that node. Viewed files and\nclosed folders are marked with `✓`; files and closed folders with unresolved\ncomments are also marked with ` N`. An open folder hides these folder markers\nbecause its children show the same state inline. A folder switches to viewed\nafter every changed file under it is viewed.\n\n## Commands\n\n- `:ReviewMode` starts normal-buffer Review Mode\n- `:ReviewModeActions` opens an action picker for common PR actions, using the configured picker provider\n- `:ReviewModeBrowser` opens the current PR in your browser\n- `:ReviewModeCopyUrl` copies the current PR URL to registers\n- `:ReviewModeChecks` shows `gh pr checks` output in a floating preview\n- `:ReviewModeStatus` shows current PR status in a floating preview\n- `:ReviewModeStop` stops review mode and clears plugin state\n- `:ReviewModeRefresh` reloads changed files and comments\n- `:ReviewModeNextHunk` jumps to the next PR hunk\n- `:ReviewModePrevHunk` jumps to the previous PR hunk\n- `:ReviewModeNextComment` jumps to the next PR comment\n- `:ReviewModePrevComment` jumps to the previous PR comment\n- `:ReviewModeNextFile` jumps to the next changed file\n- `:ReviewModePrevFile` jumps to the previous changed file\n- `:ReviewModeOldToggle` toggles the base version or unified diff for the current file\n- `:ReviewModeDiffLayoutToggle` toggles the open diff between side-by-side and unified layout\n- `:ReviewModeDiffFullToggle` toggles the open diff between condensed context and full-file context\n- `:ReviewModeThread` shows comments on the current line\n- `:ReviewModeReply` replies to the latest comment on the current line\n- `:ReviewModeResolveThread` resolves the PR review thread on the current line\n- `:ReviewModeUnresolveThread` unresolves the PR review thread on the current line\n- `:ReviewModeComment` creates a PR comment on the current line or visual range\n- `:ReviewModeSuggest` creates a GitHub suggestion comment on the current line or visual range\n- `:ReviewModeViewedToggle` toggles viewed state for the current PR file\n- `:ReviewModeViewedNext` marks the current PR file viewed and jumps to the next unviewed file\n- `:ReviewModeViewedFeatureToggle` toggles viewed-state tracking on or off\n- `:ReviewModeCommentsToggle` toggles PR comments on or off\n- `:ReviewModeViewedList [all|viewed|unviewed]` opens a fuzzy PR file menu with diff stats and preview; press `Space` or `t` in the native picker, or `\u003cTab\u003e`/`\u003cC-t\u003e` in external pickers, to toggle viewed state\n- `:ReviewModeViewedClear` clears local viewed state for the current PR\n- `:ReviewModeViewedSync` pulls viewed state from GitHub\n- `:ReviewModeViewedSyncToggle` toggles GitHub viewed-state sync\n- `:ReviewModeSummary` shows file, comment, thread, and viewed-sync counts.\n\n## gh-dash / Worktree Handoff\n\nFor external launchers, set `GH_REVIEW_REPO` and `GH_REVIEW_PR` before opening\nNeovim, then run `+ReviewMode`:\n\n```sh\nGH_REVIEW_REPO=adrianmross/example GH_REVIEW_PR=123 nvim +ReviewMode\n```\n\nIf those variables are not set, the plugin asks `gh` for the current repo and PR.\n\n## Picker Providers\n\nReviewMode uses its native picker by default, but `picker.provider = \"auto\"`\nwill use snacks.nvim when available, then Telescope, then the native picker.\nSet `picker.provider = \"native\"`, `\"snacks\"`, or `\"telescope\"` to prefer a\nspecific provider. `:ReviewModeActions` uses the provider for the action list,\nand `:ReviewModeViewedList` uses it for changed-file search and diff preview.\n\n## Options\n\n```lua\nrequire(\"review_mode\").setup({\n  auto_open_first_change = true,\n  comments = {\n    enabled = true,\n    cache_ttl_seconds = 300,\n    sign_text = \"\",\n    sign_hl_group = \"DiagnosticInfo\",\n    virtual_text = true,\n  },\n  diff = {\n    fast_diffopt = \"internal,filler,closeoff,indent-heuristic,linematch:0\",\n    full_file = false,\n    layout = \"side_by_side\",\n    partial_line_highlights = true,\n    unified_context = 3,\n    use_fast_diffopt = true,\n  },\n  gitsigns = {\n    enabled = true,\n  },\n  nvim_tree = {\n    enabled = true,\n    show_comments = true,\n    show_viewed = true,\n  },\n  picker = {\n    provider = \"auto\", -- \"auto\" | \"native\" | \"snacks\" | \"telescope\"\n  },\n  viewed = {\n    enabled = true,\n    sync = false,\n    state_path = nil,\n  },\n  performance = {\n    ui_refresh_debounce_ms = 50,\n    hunk_prefetch = {\n      enabled = true,\n      count = 8,\n      concurrency = 2,\n      focused_delay_ms = 0,\n      gitsigns_delay_ms = 5,\n    },\n    background_hunk_scan = {\n      enabled = true,\n      max_files = 5000,\n      delay_ms = 250,\n    },\n  },\n  commands = true,\n})\n```\n\n`ReviewMode` loads PR metadata and changed-file status asynchronously. If\n`GH_REVIEW_BASE` is set by a launcher, changed-file loading starts immediately\nwithout waiting for GitHub metadata. Hunk locations are loaded lazily per file,\nwith immediate focused-file prefetch, opportunistic `gitsigns.nvim` hunk-cache\nreuse, and an optional delayed background scan for PRs under\n`performance.background_hunk_scan.max_files`.\n\nExternal launchers can provide `GH_REVIEW_REPO`, `GH_REVIEW_PR`,\n`GH_REVIEW_BASE`, and `GH_REVIEW_HEAD` to avoid startup discovery calls.\n\nViewed state is persisted in `stdpath(\"state\")/review-mode-state.json` by\ndefault. Set `viewed.sync = true` or run `:ReviewModeViewedSyncToggle` to pull\nGitHub's PR file viewed state at startup and push local viewed/unviewed toggles\nback to GitHub.\n\nThe built-in side-by-side old-version split remains the default diff backend.\nSet `diff.layout = \"unified\"` or run `:ReviewModeDiffLayoutToggle` to use an\ninline unified diff buffer in the current window instead. Closing unified mode\nrestores the original file buffer. Set `diff.full_file = true` or run\n`:ReviewModeDiffFullToggle` to show full-file context; condensed unified diffs use\n`diff.unified_context` common lines around each hunk, and condensed side-by-side\ndiffs fold unchanged regions in both diff windows. When `diff.use_fast_diffopt`\nis enabled, side-by-side diffs temporarily apply `diff.fast_diffopt`, then\nrestore the previous `diffopt` when the split closes. Unified diffs highlight\nchanged spans inside modified lines with `DiffText`; set\n`diff.partial_line_highlights = false` to disable those inline spans.\n\n## Notes\n\nGitHub only accepts review comments on diff lines. If you comment on a line that\nis not part of the PR diff, GitHub may reject the request.\n\n## Release Workflow\n\nPull requests run the same validation as local development with\n`devenv test --no-eval-cache`. Behavior, command, config, validation, and\nrelease-infrastructure changes also need a release-bearing Conventional Commit\nsuch as `fix:`/`feat:`/`perf:`, a `.changeset/*.md` file, or a direct\n`CHANGELOG.md` update so release intent is visible during review.\n\nRelease Please owns the final release PR, changelog update, tag, and GitHub\nRelease. The current released version is tracked in\n`.release-please-manifest.json`; `scripts/release-check.sh` verifies that the\nmanifest, latest changelog section, and release tag agree.\n\nLocal release checks:\n\n```sh\ndevenv test --no-eval-cache\nbash scripts/release-check.sh\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadrianmross%2Freview-mode.nvim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadrianmross%2Freview-mode.nvim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadrianmross%2Freview-mode.nvim/lists"}