feat(git): Add bcommits_range picker (#2398)
* Filter bcommits by selection in visual mode * Split bcommits_range into new picker * Add option to run bcommits_range as operator Starts operator-pending mode and shows commits in the range of lines covered by the next text object or motion * Rename range arguments to "first" and "last" Can't use start/end, since end is an annoying keyword to use in lua and start/stop doesn't fit as well * Move operators functionality to new module * Run bcommits if no range given to bcommits_range * Make bcommits_range default to current line Instead of calling bcommits * Improve documentation of telescope.operators * Add default value for last_operator Default to a no-op callback * Update bcommits_range for detached worktrees See #2597 * Rename range arguments to "from" and "to" * Move shared bcommits picker into single function
This commit is contained in:
@@ -361,6 +361,7 @@ Built-in functions. Ready to be bound to any key you like.
|
|||||||
|-------------------------------------|------------------------------------------------------------------------------------------------------------|
|
|-------------------------------------|------------------------------------------------------------------------------------------------------------|
|
||||||
| `builtin.git_commits` | Lists git commits with diff preview, checkout action `<cr>`, reset mixed `<C-r>m`, reset soft `<C-r>s` and reset hard `<C-r>h` |
|
| `builtin.git_commits` | Lists git commits with diff preview, checkout action `<cr>`, reset mixed `<C-r>m`, reset soft `<C-r>s` and reset hard `<C-r>h` |
|
||||||
| `builtin.git_bcommits` | Lists buffer's git commits with diff preview and checks them out on `<cr>` |
|
| `builtin.git_bcommits` | Lists buffer's git commits with diff preview and checks them out on `<cr>` |
|
||||||
|
| `builtin.git_bcommits_range` | Lists buffer's git commits in a range of lines. Use options `from` and `to` to specify the range. In visual mode, lists commits for the selected lines |
|
||||||
| `builtin.git_branches` | Lists all branches with log preview, checkout action `<cr>`, track action `<C-t>`, rebase action`<C-r>`, create action `<C-a>`, switch action `<C-s>`, delete action `<C-d>` and merge action `<C-y>` |
|
| `builtin.git_branches` | Lists all branches with log preview, checkout action `<cr>`, track action `<C-t>`, rebase action`<C-r>`, create action `<C-a>`, switch action `<C-s>`, delete action `<C-d>` and merge action `<C-y>` |
|
||||||
| `builtin.git_status` | Lists current changes per file with diff preview and add action. (Multi-selection still WIP) |
|
| `builtin.git_status` | Lists current changes per file with diff preview and add action. (Multi-selection still WIP) |
|
||||||
| `builtin.git_stash` | Lists stash items in current repository with ability to apply them on `<cr>` |
|
| `builtin.git_stash` | Lists stash items in current repository with ability to apply them on `<cr>` |
|
||||||
|
|||||||
@@ -1052,6 +1052,36 @@ builtin.git_bcommits({opts}) *telescope.builtin.git_bcommits()*
|
|||||||
{"git","log","--pretty=oneline","--abbrev-commit"}
|
{"git","log","--pretty=oneline","--abbrev-commit"}
|
||||||
|
|
||||||
|
|
||||||
|
builtin.git_bcommits_range({opts}) *telescope.builtin.git_bcommits_range()*
|
||||||
|
Lists commits for a range of lines in the current buffer with diff preview
|
||||||
|
In visual mode, lists commits for the selected lines
|
||||||
|
With operator mode enabled, lists commits inside the text object/motion
|
||||||
|
- Default keymaps or your overridden `select_` keys:
|
||||||
|
- `<cr>`: checks out the currently selected commit
|
||||||
|
- `<c-v>`: opens a diff in a vertical split
|
||||||
|
- `<c-x>`: opens a diff in a horizontal split
|
||||||
|
- `<c-t>`: opens a diff in a new tab
|
||||||
|
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{opts} (table) options to pass to the picker
|
||||||
|
|
||||||
|
Options: ~
|
||||||
|
{cwd} (string) specify the path of the repo
|
||||||
|
{use_git_root} (boolean) if we should use git root as cwd or the cwd
|
||||||
|
(important for submodule) (default: true)
|
||||||
|
{current_file} (string) specify the current file that should be used
|
||||||
|
for bcommits (default: current buffer)
|
||||||
|
{git_command} (table) command that will be executed. the last
|
||||||
|
element must be "-L".
|
||||||
|
{"git","log","--pretty=oneline","--abbrev-commit","--no-patch","-L"}
|
||||||
|
{from} (number) the first line number in the range
|
||||||
|
(default: current line)
|
||||||
|
{to} (number) the last line number in the range
|
||||||
|
(default: the value of `from`)
|
||||||
|
{operator} (boolean) select lines in operator-pending mode
|
||||||
|
(default: false)
|
||||||
|
|
||||||
builtin.git_branches({opts}) *telescope.builtin.git_branches()*
|
builtin.git_branches({opts}) *telescope.builtin.git_branches()*
|
||||||
List branches for current directory, with output from `git log --oneline`
|
List branches for current directory, with output from `git log --oneline`
|
||||||
shown in the preview window
|
shown in the preview window
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ local actions = require "telescope.actions"
|
|||||||
local action_state = require "telescope.actions.state"
|
local action_state = require "telescope.actions.state"
|
||||||
local finders = require "telescope.finders"
|
local finders = require "telescope.finders"
|
||||||
local make_entry = require "telescope.make_entry"
|
local make_entry = require "telescope.make_entry"
|
||||||
|
local operators = require "telescope.operators"
|
||||||
local pickers = require "telescope.pickers"
|
local pickers = require "telescope.pickers"
|
||||||
local previewers = require "telescope.previewers"
|
local previewers = require "telescope.previewers"
|
||||||
local utils = require "telescope.utils"
|
local utils = require "telescope.utils"
|
||||||
@@ -110,23 +111,10 @@ local get_current_buf_line = function(winnr)
|
|||||||
return vim.trim(vim.api.nvim_buf_get_lines(vim.api.nvim_win_get_buf(winnr), lnum - 1, lnum, false)[1])
|
return vim.trim(vim.api.nvim_buf_get_lines(vim.api.nvim_win_get_buf(winnr), lnum - 1, lnum, false)[1])
|
||||||
end
|
end
|
||||||
|
|
||||||
git.bcommits = function(opts)
|
local bcommits_picker = function(opts, title, finder)
|
||||||
opts.current_line = (opts.current_file == nil) and get_current_buf_line(opts.winnr) or nil
|
return pickers.new(opts, {
|
||||||
opts.current_file = vim.F.if_nil(opts.current_file, vim.api.nvim_buf_get_name(opts.bufnr))
|
prompt_title = title,
|
||||||
opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_git_commits(opts))
|
finder = finder,
|
||||||
opts.git_command =
|
|
||||||
vim.F.if_nil(opts.git_command, git_command({ "log", "--pretty=oneline", "--abbrev-commit", "--follow" }, opts))
|
|
||||||
|
|
||||||
pickers
|
|
||||||
.new(opts, {
|
|
||||||
prompt_title = "Git BCommits",
|
|
||||||
finder = finders.new_oneshot_job(
|
|
||||||
vim.tbl_flatten {
|
|
||||||
opts.git_command,
|
|
||||||
opts.current_file,
|
|
||||||
},
|
|
||||||
opts
|
|
||||||
),
|
|
||||||
previewer = {
|
previewer = {
|
||||||
previewers.git_commit_diff_to_parent.new(opts),
|
previewers.git_commit_diff_to_parent.new(opts),
|
||||||
previewers.git_commit_diff_to_head.new(opts),
|
previewers.git_commit_diff_to_head.new(opts),
|
||||||
@@ -190,7 +178,65 @@ git.bcommits = function(opts)
|
|||||||
return true
|
return true
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
:find()
|
end
|
||||||
|
|
||||||
|
git.bcommits = function(opts)
|
||||||
|
opts.current_line = (opts.current_file == nil) and get_current_buf_line(opts.winnr) or nil
|
||||||
|
opts.current_file = vim.F.if_nil(opts.current_file, vim.api.nvim_buf_get_name(opts.bufnr))
|
||||||
|
opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_git_commits(opts))
|
||||||
|
opts.git_command =
|
||||||
|
vim.F.if_nil(opts.git_command, git_command({ "log", "--pretty=oneline", "--abbrev-commit", "--follow" }, opts))
|
||||||
|
|
||||||
|
local title = "Git BCommits"
|
||||||
|
local finder = finders.new_oneshot_job(
|
||||||
|
vim.tbl_flatten {
|
||||||
|
opts.git_command,
|
||||||
|
opts.current_file,
|
||||||
|
},
|
||||||
|
opts
|
||||||
|
)
|
||||||
|
bcommits_picker(opts, title, finder):find()
|
||||||
|
end
|
||||||
|
|
||||||
|
git.bcommits_range = function(opts)
|
||||||
|
opts.current_line = (opts.current_file == nil) and get_current_buf_line(opts.winnr) or nil
|
||||||
|
opts.current_file = vim.F.if_nil(opts.current_file, vim.api.nvim_buf_get_name(opts.bufnr))
|
||||||
|
opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_git_commits(opts))
|
||||||
|
opts.git_command = vim.F.if_nil(
|
||||||
|
opts.git_command,
|
||||||
|
git_command({ "log", "--pretty=oneline", "--abbrev-commit", "--no-patch", "-L" }, opts)
|
||||||
|
)
|
||||||
|
local visual = string.find(vim.fn.mode(), "[vV]") ~= nil
|
||||||
|
|
||||||
|
local line_number_first = opts.from
|
||||||
|
local line_number_last = vim.F.if_nil(opts.to, line_number_first)
|
||||||
|
if visual then
|
||||||
|
line_number_first = vim.F.if_nil(line_number_first, vim.fn.line "v")
|
||||||
|
line_number_last = vim.F.if_nil(line_number_last, vim.fn.line ".")
|
||||||
|
elseif opts.operator then
|
||||||
|
opts.operator = false
|
||||||
|
opts.operator_callback = true
|
||||||
|
operators.run_operator(git.bcommits_range, opts)
|
||||||
|
return
|
||||||
|
elseif opts.operator_callback then
|
||||||
|
line_number_first = vim.fn.line "'["
|
||||||
|
line_number_last = vim.fn.line "']"
|
||||||
|
elseif line_number_first == nil then
|
||||||
|
line_number_first = vim.F.if_nil(line_number_first, vim.fn.line ".")
|
||||||
|
line_number_last = vim.F.if_nil(line_number_last, vim.fn.line ".")
|
||||||
|
end
|
||||||
|
local line_range =
|
||||||
|
string.format("%d,%d:%s", line_number_first, line_number_last, Path:new(opts.current_file):make_relative(opts.cwd))
|
||||||
|
|
||||||
|
local title = "Git BCommits in range"
|
||||||
|
local finder = finders.new_oneshot_job(
|
||||||
|
vim.tbl_flatten {
|
||||||
|
opts.git_command,
|
||||||
|
line_range,
|
||||||
|
},
|
||||||
|
opts
|
||||||
|
)
|
||||||
|
bcommits_picker(opts, title, finder):find()
|
||||||
end
|
end
|
||||||
|
|
||||||
git.branches = function(opts)
|
git.branches = function(opts)
|
||||||
|
|||||||
@@ -172,6 +172,24 @@ builtin.git_commits = require_on_exported_call("telescope.builtin.__git").commit
|
|||||||
---@field git_command table: command that will be executed. {"git","log","--pretty=oneline","--abbrev-commit"}
|
---@field git_command table: command that will be executed. {"git","log","--pretty=oneline","--abbrev-commit"}
|
||||||
builtin.git_bcommits = require_on_exported_call("telescope.builtin.__git").bcommits
|
builtin.git_bcommits = require_on_exported_call("telescope.builtin.__git").bcommits
|
||||||
|
|
||||||
|
--- Lists commits for a range of lines in the current buffer with diff preview
|
||||||
|
--- In visual mode, lists commits for the selected lines
|
||||||
|
--- With operator mode enabled, lists commits inside the text object/motion
|
||||||
|
--- - Default keymaps or your overridden `select_` keys:
|
||||||
|
--- - `<cr>`: checks out the currently selected commit
|
||||||
|
--- - `<c-v>`: opens a diff in a vertical split
|
||||||
|
--- - `<c-x>`: opens a diff in a horizontal split
|
||||||
|
--- - `<c-t>`: opens a diff in a new tab
|
||||||
|
---@param opts table: options to pass to the picker
|
||||||
|
---@field cwd string: specify the path of the repo
|
||||||
|
---@field use_git_root boolean: if we should use git root as cwd or the cwd (important for submodule) (default: true)
|
||||||
|
---@field current_file string: specify the current file that should be used for bcommits (default: current buffer)
|
||||||
|
---@field git_command table: command that will be executed. the last element must be "-L". {"git","log","--pretty=oneline","--abbrev-commit","--no-patch","-L"}
|
||||||
|
---@field from number: the first line number in the range (default: current line)
|
||||||
|
---@field to number: the last line number in the range (default: the value of `from`)
|
||||||
|
---@field operator boolean: select lines in operator-pending mode (default: false)
|
||||||
|
builtin.git_bcommits_range = require_on_exported_call("telescope.builtin.__git").bcommits_range
|
||||||
|
|
||||||
--- List branches for current directory, with output from `git log --oneline` shown in the preview window
|
--- List branches for current directory, with output from `git log --oneline` shown in the preview window
|
||||||
--- - Default keymaps:
|
--- - Default keymaps:
|
||||||
--- - `<cr>`: checks out the currently selected branch
|
--- - `<cr>`: checks out the currently selected branch
|
||||||
|
|||||||
23
lua/telescope/operators.lua
Normal file
23
lua/telescope/operators.lua
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
local operators = {}
|
||||||
|
|
||||||
|
local last_operator = { callback = function(_) end, opts = {} }
|
||||||
|
|
||||||
|
--- Execute the last saved operator callback and options
|
||||||
|
operators.operator_callback = function()
|
||||||
|
last_operator.callback(last_operator.opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Enters operator-pending mode, then executes callback.
|
||||||
|
--- See `:h map-operator`
|
||||||
|
---
|
||||||
|
---@param callback function: the function to call after exiting operator-pending
|
||||||
|
---@param opts table: options to pass to the callback
|
||||||
|
operators.run_operator = function(callback, opts)
|
||||||
|
last_operator = { callback = callback, opts = opts }
|
||||||
|
vim.o.operatorfunc = "v:lua.require'telescope.operators'.operator_callback"
|
||||||
|
-- feed g@ to enter operator-pending mode
|
||||||
|
-- 'i' required for which-key compatibility, etc.
|
||||||
|
vim.api.nvim_feedkeys("g@", "mi", false)
|
||||||
|
end
|
||||||
|
|
||||||
|
return operators
|
||||||
Reference in New Issue
Block a user