1 -- This plugin aims to be something like vim-fugitive but for driving the jj-vcs CLI.
2 -- https://github.com/NicolasGB/jj.nvim
5 cmd = { "J", "Jdiff", "Jvdiff", "Jhdiff", "Jopen", "Jreview", "Jopen", "Jclose" },
7 require("jj").setup({ ["describe_editor"] = "input" })
8 local jj = require("jj.cmd")
11 -- Setup snacks as a picker
13 -- Here you can pass the options as you would for snacks.
14 -- It will be used when using the picker
18 -- Customize syntax highlighting colors for the describe buffer
20 added = { fg = "#3fb950", ctermfg = "Green" }, -- Added files
21 modified = { fg = "#56d4dd", ctermfg = "Cyan" }, -- Modified files
22 deleted = { fg = "#f85149", ctermfg = "Red" }, -- Deleted files
23 renamed = { fg = "#d29922", ctermfg = "Yellow" }, -- Renamed files
26 -- Configure terminal behavior
28 -- Cursor render delay in milliseconds (default: 10)
29 -- If cursor column is being reset to 0 when refreshing commands, try increasing this value
30 -- This delay allows the terminal emulator to complete rendering before restoring cursor position
31 cursor_render_delay = 10,
34 -- Configure cmd module (describe editor, keymaps)
36 -- Configure describe editor
39 -- Choose the editor mode for describe command
40 -- "buffer" - Opens a Git-style commit message buffer with syntax highlighting (default)
41 -- "input" - Uses a simple vim.ui.input prompt
43 -- Customize keymaps for the describe editor buffer
45 close = { "<Esc>", "<C-c>", "q" }, -- Keys to close editor without saving
50 -- Configure log command behavior
52 close_on_edit = false, -- Close log buffer after editing a change
55 -- Configure keymaps for command buffers
57 -- Log buffer keymaps (set to nil to disable)
59 checkout = "<CR>", -- Edit revision under cursor
60 checkout_immutable = "<S-CR>", -- Edit revision (ignore immutability)
61 describe = "d", -- Describe revision under cursor
62 diff = "<S-d>", -- Diff revision under cursor
63 edit = "e", -- Edit revision under cursor
64 new = "n", -- Create new change branching off
65 new_after = "<C-n>", -- Create new change after revision
66 new_after_immutable = "<S-n>", -- Create new change after (ignore immutability)
67 undo = "<S-u>", -- Undo last operation
68 redo = "<S-r>", -- Redo last undone operation
69 abandon = "a", -- Abandon revision under cursor
70 bookmark = "b", -- Create or move bookmark to revision under cursor
71 fetch = "f", -- Fetch from remote
72 push = "p", -- Push bookmark of revision under cursor
73 push_all = "<S-p>", -- Push all changes to remote
74 open_pr = "o", -- Open PR/MR for revision under cursor
75 open_pr_list = "<S-o>", -- Open PR/MR by selecting from all bookmarks
77 -- Status buffer keymaps (set to nil to disable)
79 open_file = "<CR>", -- Open file under cursor
80 restore_file = "<S-x>", -- Restore file under cursor
82 -- Close keymaps (shared across all buffers)
83 close = { "q", "<Esc>" },
88 vim.keymap.set("n", "<leader>jl", jj.log, { desc = "JJ log" })
89 vim.keymap.set("n", "<leader>jl", jj.log, { desc = "JJ log" })
90 vim.keymap.set("n", "<leader>jd", jj.describe, { desc = "JJ describe" })
91 vim.keymap.set("n", "<leader>je", jj.edit, { desc = "JJ edit" })
92 vim.keymap.set("n", "<leader>jn", jj.new, { desc = "JJ new" })
93 vim.keymap.set("n", "<leader>js", jj.status, { desc = "JJ status" })
94 vim.keymap.set("n", "<leader>dj", jj.diff, { desc = "JJ diff" })
95 vim.keymap.set("n", "<leader>sj", jj.squash, { desc = "JJ squash" })
97 vim.api.nvim_create_user_command("Jopen", function(opts)
98 local revset = #opts.fargs > 0 and opts.fargs[1] or "@"
100 if not require("jj.utils").ensure_jj() then
104 -- Get the files changed by given revset
105 local runner = require("jj.core.runner")
106 local output, ok = runner.execute_command(
107 string.format("jj diff --name-only --revisions %s", vim.fn.shellescape(revset)),
108 string.format("Error getting diff of revset: %s", revset)
114 -- Split the output into lines and open each file
115 for file in output:gmatch("[^\r\n]+") do
117 if vim.fn.bufexists(file) ~= 0 then
118 buf = vim.fn.bufnr(file)
120 buf = vim.fn.bufadd(file)
122 -- Explanation: loading many buffers here causes slow down and even Git errors in Neo-tree
123 -- so let any needed loading happen whenever the user browses the buffers.
124 -- if not vim.api.nvim_buf_is_loaded(buf) then
125 -- vim.fn.bufload(buf)
127 vim.api.nvim_set_option_value("buflisted", true, { buf = buf })
129 end, { desc = "Open files changed by given revset", nargs = "?" })
131 vim.api.nvim_create_user_command("Jclose", function(opts)
132 local revset = #opts.fargs > 0 and opts.fargs[1] or "@"
134 if not require("jj.utils").ensure_jj() then
138 -- Get the files changed by given revset
139 local runner = require("jj.core.runner")
140 local output, ok = runner.execute_command(
141 string.format("jj diff --name-only --revisions %s", vim.fn.shellescape(revset)),
142 string.format("Error getting diff of revset: %s", revset)
148 -- Split the output into lines and close each file
149 for file in output:gmatch("[^\r\n]+") do
151 if vim.fn.bufexists(file) ~= 0 then
152 vim.api.nvim_buf_delete(vim.fn.bufnr(file), { force = false, unload = false })
156 -- Refresh Neo-tree of buffers
157 local manager = require("neo-tree.sources.manager")
158 local utils = require("neo-tree.utils")
159 local refresh = utils.wrap(manager.refresh, "buffers")
161 end, { desc = "Close buffers for files changed by given revset", nargs = "?" })
163 vim.api.nvim_create_user_command("Jreview", function(opts)
165 if #opts.fargs > 0 then
166 revset = opts.fargs[1]
170 require("jj.diff").open_vdiff({ rev = revset })
171 end, { desc = "Diff current buffer with the version in given revset", nargs = "?" })
174 local picker = require("jj.picker")
175 vim.keymap.set("n", "<leader>gj", picker.status, { desc = "JJ Picker status" })
176 vim.keymap.set("n", "<leader>gl", picker.file_history, { desc = "JJ Picker file history" })
178 -- Some functions like `describe` or `log` can take parameters
179 vim.keymap.set("n", "<leader>jL", function()
181 revisions = "'all()'",
183 end, { desc = "JJ log all" })
185 -- tug is an alias to move a bookmark
186 vim.keymap.set("n", "<leader>jt", function()
187 local cmd = require("jj.cmd")
190 end, { desc = "JJ tug" })