feat: cycle previewers with commit and bcommit already using it (#528)

- new git previewers
- jump to line in bcommit previewer
- vimdiff for bcommits
- dynamic preview window titles
- more previewers documentation

Cycle previewers are not mapped yet. So you need to setup yourself:
```lua
require('telescope').setup {
  defaults = {
    mappings = {
      i = {
        ["<C-s>"] = actions.cycle_previewers_next,
        ["<C-a>"] = actions.cycle_previewers_prev,
      },
    },
  }
}
```

Co-authored-by: Thore Strassburg <thore@weilbier.net>
This commit is contained in:
Simon Hauser
2021-06-14 21:50:46 +02:00
committed by GitHub
parent 0c1bc129da
commit 6ac5ee0854
11 changed files with 566 additions and 76 deletions

View File

@@ -19,6 +19,15 @@ telescope.setup({opts}) *telescope.setup()*
Valid keys for {opts.defaults} Valid keys for {opts.defaults}
*telescope.defaults.dynamic_preview_title*
dynamic_preview_title: ~
Will change the title of the preview window dynamically, where it
is supported. Means the preview window will for example show the
full filename.
Default: false
*telescope.defaults.entry_prefix* *telescope.defaults.entry_prefix*
entry_prefix: ~ entry_prefix: ~
Prefix in front of each result entry. Current selection not included. Prefix in front of each result entry. Current selection not included.
@@ -283,6 +292,16 @@ actions.git_checkout({prompt_bufnr}) *actions.git_checkout()*
{prompt_bufnr} (number) The prompt bufnr {prompt_bufnr} (number) The prompt bufnr
actions.git_switch_branch({prompt_bufnr}) *actions.git_switch_branch()*
Switch to git branch.
If the branch already exists in local, switch to that. If the branch is
only in remote, create new branch tracking remote and switch to new one.
Parameters: ~
{prompt_bufnr} (number) The prompt bufnr
actions.git_track_branch({prompt_bufnr}) *actions.git_track_branch()* actions.git_track_branch({prompt_bufnr}) *actions.git_track_branch()*
Tell git to track the currently selected remote branch in Telescope Tell git to track the currently selected remote branch in Telescope
@@ -291,6 +310,30 @@ actions.git_track_branch({prompt_bufnr}) *actions.git_track_branch()*
{prompt_bufnr} (number) The prompt bufnr {prompt_bufnr} (number) The prompt bufnr
actions.git_delete_branch({prompt_bufnr}) *actions.git_delete_branch()*
Delete the currently selected branch
Parameters: ~
{prompt_bufnr} (number) The prompt bufnr
actions.git_rebase_branch({prompt_bufnr}) *actions.git_rebase_branch()*
Rebase to selected git branch
Parameters: ~
{prompt_bufnr} (number) The prompt bufnr
actions.git_checkout_current_buffer({prompt_bufnr})*actions.git_checkout_current_buffer()*
Stage/unstage selected file
Parameters: ~
{prompt_bufnr} (number) The prompt bufnr
actions.send_selected_to_qflist() *actions.send_selected_to_qflist()* actions.send_selected_to_qflist() *actions.send_selected_to_qflist()*
Sends the selected entries to the quickfix list, replacing the previous Sends the selected entries to the quickfix list, replacing the previous
entries. entries.
@@ -378,6 +421,24 @@ actions.delete_buffer({prompt_bufnr}) *actions.delete_buffer()*
{prompt_bufnr} (number) The prompt bufnr {prompt_bufnr} (number) The prompt bufnr
actions.cycle_previewers_next({prompt_bufnr})*actions.cycle_previewers_next()*
Cycle to the next previewer if there is one available.
This action is not mapped on default.
Parameters: ~
{prompt_bufnr} (number) The prompt bufnr
actions.cycle_previewers_prev({prompt_bufnr})*actions.cycle_previewers_prev()*
Cycle to the previous previewer if there is one available.
This action is not mapped on default.
Parameters: ~
{prompt_bufnr} (number) The prompt bufnr
================================================================================ ================================================================================
*telescope.builtin* *telescope.builtin*
@@ -583,16 +644,27 @@ builtin.git_commits({opts}) *builtin.git_commits()*
Parameters: ~ Parameters: ~
{opts} (table) options to pass to the picker {opts} (table) options to pass to the picker
Fields: ~
{cwd} (string) specify the path of the repo
builtin.git_bcommits({opts}) *builtin.git_bcommits()* builtin.git_bcommits({opts}) *builtin.git_bcommits()*
Lists commits for current buffer with diff preview Lists commits for current buffer with diff preview
- Default keymaps: - Default keymaps or your overriden `select_` keys:
- `<cr>`: checks out the currently selected commit - `<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: ~ Parameters: ~
{opts} (table) options to pass to the picker {opts} (table) options to pass to the picker
Fields: ~
{cwd} (string) specify the path of the repo
{current_file} (string) specify the current file that should be used
for bcommits (default: current buffer)
builtin.git_branches({opts}) *builtin.git_branches()* builtin.git_branches({opts}) *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`
@@ -1094,6 +1166,10 @@ previewers.Previewer() *previewers.Previewer()*
- `teardown` function(self): Will be called on cleanup. - `teardown` function(self): Will be called on cleanup.
- `preview_fn` function(self, entry, status): Will be called each time a - `preview_fn` function(self, entry, status): Will be called each time a
new entry was selected. new entry was selected.
- `title` function(self): Will return the static title of the previewer.
- `dynamic_title` function(self, entry): Will return the dynamic title of
the previewer. Will only be called when config value
dynamic_preview_title is true.
- `send_input` function(self, input): This is meant for - `send_input` function(self, input): This is meant for
`termopen_previewer` and it can be used to send input to the terminal `termopen_previewer` and it can be used to send input to the terminal
application, like less. application, like less.
@@ -1118,6 +1194,11 @@ previewers.new_termopen_previewer() *previewers.new_termopen_previewer()*
return { 'bat', entry.path } return { 'bat', entry.path }
end end
Additionally you can define:
- `title` a static title for example "File Preview"
- `dyn_title(self, entry)` a dynamic title function which gets called when
config value `dynamic_preview_title = true`
It's an easy way to get your first previewer going and it integrates well It's an easy way to get your first previewer going and it integrates well
with `bat` and `less`. Providing out of the box scrolling if the command with `bat` and `less`. Providing out of the box scrolling if the command
uses less. uses less.
@@ -1209,6 +1290,9 @@ previewers.new_buffer_previewer() *previewers.new_buffer_previewer()*
one file but multiple entries. This happens for grep and lsp builtins. one file but multiple entries. This happens for grep and lsp builtins.
So to make the cache work only load content if `self.state.bufname ~= So to make the cache work only load content if `self.state.bufname ~=
entry.your_unique_key` entry.your_unique_key`
- `title` a static title for example "File Preview"
- `dyn_title(self, entry)` a dynamic title function which gets called
when config value `dynamic_preview_title = true`
`self.state` table: `self.state` table:
- `self.state.bufnr` Is the current buffer number, in which you have to - `self.state.bufnr` Is the current buffer number, in which you have to
@@ -1304,6 +1388,51 @@ previewers.vim_buffer_qflist() *previewers.vim_buffer_qflist()*
previewers.git_branch_log() *previewers.git_branch_log()*
A previewer that shows a log of a branch as graph
previewers.git_stash_diff() *previewers.git_stash_diff()*
A previewer that shows a diff of a stash
previewers.git_commit_diff_to_parent()*previewers.git_commit_diff_to_parent()*
A previewer that shows a diff of a commit to a parent commit.
The run command is `git --no-pager diff SHA^! -- $CURRENT_FILE`
The current file part is optional. So is only uses it with bcommits.
previewers.git_commit_diff_to_head() *previewers.git_commit_diff_to_head()*
A previewer that shows a diff of a commit to head.
The run command is `git --no-pager diff --cached $SHA -- $CURRENT_FILE`
The current file part is optional. So is only uses it with bcommits.
previewers.git_commit_diff_as_was() *previewers.git_commit_diff_as_was()*
A previewer that shows a diff of a commit as it was.
The run command is `git --no-pager show $SHA:$CURRENT_FILE` or `git
--no-pager show $SHA`
previewers.git_commit_message() *previewers.git_commit_message()*
A previewer that shows the commit message of a diff.
The run command is `git --no-pager log -n 1 $SHA`
previewers.git_file_diff() *previewers.git_file_diff()*
A previewer that shows the current diff of a file. Used in git_status.
The run command is `git --no-pager diff $FILE`
previewers.display_content() *previewers.display_content()* previewers.display_content() *previewers.display_content()*
A deprecated way of displaying content more easily. Was written at a time, A deprecated way of displaying content more easily. Was written at a time,
where the buffer_previewer interface wasn't present. Nowadays it's easier where the buffer_previewer interface wasn't present. Nowadays it's easier

View File

@@ -202,7 +202,9 @@ actions._close = function(prompt_bufnr, keepinsert)
local original_win_id = picker.original_win_id local original_win_id = picker.original_win_id
if picker.previewer then if picker.previewer then
picker.previewer:teardown() for _, v in ipairs(picker.all_previewers) do
v:teardown()
end
end end
actions.close_pum(prompt_bufnr) actions.close_pum(prompt_bufnr)
@@ -375,11 +377,10 @@ actions.git_checkout = function(prompt_bufnr)
end end
end end
-- TODO: add this function header back once the treesitter max-query bug is resolved --- Switch to git branch.<br>
-- Switch to git branch --- If the branch already exists in local, switch to that.
-- If the branch already exists in local, switch to that. --- If the branch is only in remote, create new branch tracking remote and switch to new one.
-- If the branch is only in remote, create new branch tracking remote and switch to new one. ---@param prompt_bufnr number: The prompt bufnr
--@param prompt_bufnr number: The prompt bufnr
actions.git_switch_branch = function(prompt_bufnr) actions.git_switch_branch = function(prompt_bufnr)
local cwd = action_state.get_current_picker(prompt_bufnr).cwd local cwd = action_state.get_current_picker(prompt_bufnr).cwd
local selection = action_state.get_selected_entry() local selection = action_state.get_selected_entry()
@@ -419,9 +420,8 @@ actions.git_track_branch = function(prompt_bufnr)
end end
end end
-- TODO: add this function header back once the treesitter max-query bug is resolved --- Delete the currently selected branch
-- Delete the currently selected branch ---@param prompt_bufnr number: The prompt bufnr
-- @param prompt_bufnr number: The prompt bufnr
actions.git_delete_branch = function(prompt_bufnr) actions.git_delete_branch = function(prompt_bufnr)
local cwd = action_state.get_current_picker(prompt_bufnr).cwd local cwd = action_state.get_current_picker(prompt_bufnr).cwd
local selection = action_state.get_selected_entry() local selection = action_state.get_selected_entry()
@@ -442,9 +442,8 @@ actions.git_delete_branch = function(prompt_bufnr)
end end
end end
-- TODO: add this function header back once the treesitter max-query bug is resolved --- Rebase to selected git branch
-- Rebase to selected git branch ---@param prompt_bufnr number: The prompt bufnr
-- @param prompt_bufnr number: The prompt bufnr
actions.git_rebase_branch = function(prompt_bufnr) actions.git_rebase_branch = function(prompt_bufnr)
local cwd = action_state.get_current_picker(prompt_bufnr).cwd local cwd = action_state.get_current_picker(prompt_bufnr).cwd
local selection = action_state.get_selected_entry() local selection = action_state.get_selected_entry()
@@ -465,9 +464,15 @@ actions.git_rebase_branch = function(prompt_bufnr)
end end
end end
-- TODO: add this function header back once the treesitter max-query bug is resolved --- Stage/unstage selected file
-- Stage/unstage selected file ---@param prompt_bufnr number: The prompt bufnr
-- @param prompt_bufnr number: The prompt bufnr actions.git_checkout_current_buffer = function(prompt_bufnr)
local cwd = actions.get_current_picker(prompt_bufnr).cwd
local selection = actions.get_selected_entry()
actions.close(prompt_bufnr)
utils.get_os_command_output({ 'git', 'checkout', selection.value, '--', selection.file }, cwd)
end
actions.git_staging_toggle = function(prompt_bufnr) actions.git_staging_toggle = function(prompt_bufnr)
local cwd = action_state.get_current_picker(prompt_bufnr).cwd local cwd = action_state.get_current_picker(prompt_bufnr).cwd
local selection = action_state.get_selected_entry() local selection = action_state.get_selected_entry()
@@ -659,6 +664,20 @@ actions.delete_buffer = function(prompt_bufnr)
end) end)
end end
--- Cycle to the next previewer if there is one available.<br>
--- This action is not mapped on default.
---@param prompt_bufnr number: The prompt bufnr
actions.cycle_previewers_next = function(prompt_bufnr)
actions.get_current_picker(prompt_bufnr):cycle_previewers(1)
end
--- Cycle to the previous previewer if there is one available.<br>
--- This action is not mapped on default.
---@param prompt_bufnr number: The prompt bufnr
actions.cycle_previewers_prev = function(prompt_bufnr)
actions.get_current_picker(prompt_bufnr):cycle_previewers(-1)
end
-- ================================================== -- ==================================================
-- Transforms modules and sets the corect metatables. -- Transforms modules and sets the corect metatables.
-- ================================================== -- ==================================================

View File

@@ -7,6 +7,7 @@ local previewers = require('telescope.previewers')
local utils = require('telescope.utils') local utils = require('telescope.utils')
local entry_display = require('telescope.pickers.entry_display') local entry_display = require('telescope.pickers.entry_display')
local strings = require('plenary.strings') local strings = require('plenary.strings')
local Path = require('plenary.path')
local conf = require('telescope.config').values local conf = require('telescope.config').values
@@ -49,7 +50,12 @@ git.commits = function(opts)
results = results, results = results,
entry_maker = opts.entry_maker or make_entry.gen_from_git_commits(opts), entry_maker = opts.entry_maker or make_entry.gen_from_git_commits(opts),
}, },
previewer = previewers.git_commit_diff.new(opts), previewer = {
previewers.git_commit_diff_to_parent.new(opts),
previewers.git_commit_diff_to_head.new(opts),
previewers.git_commit_diff_as_was.new(opts),
previewers.git_commit_message.new(opts),
},
sorter = conf.file_sorter(opts), sorter = conf.file_sorter(opts),
attach_mappings = function() attach_mappings = function()
actions.select_default:replace(actions.git_checkout) actions.select_default:replace(actions.git_checkout)
@@ -77,9 +83,17 @@ git.stash = function(opts)
end end
}):find() }):find()
end end
local get_current_buf_line = function(winnr)
local lnum = vim.api.nvim_win_get_cursor(winnr)[1]
return vim.trim(vim.api.nvim_buf_get_lines(vim.api.nvim_win_get_buf(winnr), lnum - 1, lnum, false)[1])
end
git.bcommits = function(opts) git.bcommits = function(opts)
opts.current_line = (not opts.current_file) and get_current_buf_line(0) or nil
opts.current_file = opts.current_file or vim.fn.expand('%')
local results = utils.get_os_command_output({ local results = utils.get_os_command_output({
'git', 'log', '--pretty=oneline', '--abbrev-commit', vim.fn.expand('%') 'git', 'log', '--pretty=oneline', '--abbrev-commit', opts.current_file
}, opts.cwd) }, opts.cwd)
pickers.new(opts, { pickers.new(opts, {
@@ -88,10 +102,62 @@ git.bcommits = function(opts)
results = results, results = results,
entry_maker = opts.entry_maker or make_entry.gen_from_git_commits(opts), entry_maker = opts.entry_maker or make_entry.gen_from_git_commits(opts),
}, },
previewer = previewers.git_commit_diff.new(opts), previewer = {
previewers.git_commit_diff_to_parent.new(opts),
previewers.git_commit_diff_to_head.new(opts),
previewers.git_commit_diff_as_was.new(opts),
previewers.git_commit_message.new(opts),
},
sorter = conf.file_sorter(opts), sorter = conf.file_sorter(opts),
attach_mappings = function() attach_mappings = function()
actions.select_default:replace(actions.git_checkout) actions.select_default:replace(actions.git_checkout_current_buffer)
local transfrom_file = function()
return opts.current_file and Path:new(opts.current_file):make_relative(opts.cwd) or ''
end
local get_buffer_of_orig = function(selection)
local value = selection.value .. ':' .. transfrom_file()
local content = utils.get_os_command_output({ 'git', '--no-pager', 'show', value }, opts.cwd)
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, content)
vim.api.nvim_buf_set_name(bufnr, 'Original')
return bufnr
end
local vimdiff = function(selection, command)
local ft = vim.bo.filetype
vim.cmd("diffthis")
local bufnr = get_buffer_of_orig(selection)
vim.cmd(string.format("%s %s", command, bufnr))
vim.bo.filetype = ft
vim.cmd("diffthis")
vim.cmd(string.format(
"autocmd WinClosed <buffer=%s> ++nested ++once :lua vim.api.nvim_buf_delete(%s, { force = true })",
bufnr,
bufnr))
end
actions.select_vertical:replace(function(prompt_bufnr)
actions.close(prompt_bufnr)
local selection = action_state.get_selected_entry()
vimdiff(selection, 'leftabove vert sbuffer')
end)
actions.select_horizontal:replace(function(prompt_bufnr)
actions.close(prompt_bufnr)
local selection = action_state.get_selected_entry()
vimdiff(selection, 'belowright sbuffer')
end)
actions.select_tab:replace(function(prompt_bufnr)
actions.close(prompt_bufnr)
local selection = action_state.get_selected_entry()
vim.cmd('tabedit ' .. transfrom_file())
vimdiff(selection, 'leftabove vert sbuffer')
end)
return true return true
end end
}):find() }):find()

View File

@@ -145,12 +145,18 @@ builtin.git_files = require('telescope.builtin.git').files
--- - Default keymaps: --- - Default keymaps:
--- - `<cr>`: checks out the currently selected commit --- - `<cr>`: checks out the currently selected commit
---@param opts table: options to pass to the picker ---@param opts table: options to pass to the picker
---@field cwd string: specify the path of the repo
builtin.git_commits = require('telescope.builtin.git').commits builtin.git_commits = require('telescope.builtin.git').commits
--- Lists commits for current buffer with diff preview --- Lists commits for current buffer with diff preview
--- - Default keymaps: --- - Default keymaps or your overriden `select_` keys:
--- - `<cr>`: checks out the currently selected commit --- - `<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 ---@param opts table: options to pass to the picker
---@field cwd string: specify the path of the repo
---@field current_file string: specify the current file that should be used for bcommits (default: current buffer)
builtin.git_bcommits = require('telescope.builtin.git').bcommits builtin.git_bcommits = require('telescope.builtin.git').bcommits
--- 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

View File

@@ -147,6 +147,14 @@ function config.set_defaults(defaults)
set("file_ignore_patterns", nil) set("file_ignore_patterns", nil)
set("dynamic_preview_title", false, [[
Will change the title of the preview window dynamically, where it
is supported. Means the preview window will for example show the
full filename.
Default: false
]])
set("file_previewer", function(...) return require('telescope.previewers').vim_buffer_cat.new(...) end) set("file_previewer", function(...) return require('telescope.previewers').vim_buffer_cat.new(...) end)
set("grep_previewer", function(...) return require('telescope.previewers').vim_buffer_vimgrep.new(...) end) set("grep_previewer", function(...) return require('telescope.previewers').vim_buffer_vimgrep.new(...) end)
set("qflist_previewer", function(...) return require('telescope.previewers').vim_buffer_qflist.new(...) end) set("qflist_previewer", function(...) return require('telescope.previewers').vim_buffer_qflist.new(...) end)

View File

@@ -248,8 +248,7 @@ function make_entry.gen_from_git_stash()
end end
end end
function make_entry.gen_from_git_commits(opts)
function make_entry.gen_from_git_commits()
local displayer = entry_display.create { local displayer = entry_display.create {
separator = " ", separator = " ",
items = { items = {
@@ -281,7 +280,8 @@ function make_entry.gen_from_git_commits()
value = sha, value = sha,
ordinal = sha .. ' ' .. msg, ordinal = sha .. ' ' .. msg,
msg = msg, msg = msg,
display = make_display display = make_display,
current_file = opts.current_file
} }
end end
end end

View File

@@ -74,7 +74,10 @@ function Picker:new(opts)
finder = opts.finder, finder = opts.finder,
sorter = opts.sorter or require('telescope.sorters').empty(), sorter = opts.sorter or require('telescope.sorters').empty(),
previewer = opts.previewer,
all_previewers = opts.previewer,
current_previewer_index = 1,
default_selection_index = opts.default_selection_index, default_selection_index = opts.default_selection_index,
cwd = opts.cwd, cwd = opts.cwd,
@@ -124,6 +127,15 @@ function Picker:new(opts)
obj.get_window_options = opts.get_window_options or p_window.get_window_options obj.get_window_options = opts.get_window_options or p_window.get_window_options
if obj.all_previewers ~= nil and obj.all_previewers ~= false then
if obj.all_previewers[1] == nil then
obj.all_previewers = { obj.all_previewers }
end
obj.previewer = obj.all_previewers[1]
else
obj.previewer = false
end
-- TODO: It's annoying that this is create and everything else is "new" -- TODO: It's annoying that this is create and everything else is "new"
obj.scroller = p_scroller.create( obj.scroller = p_scroller.create(
get_default(opts.scroll_strategy, config.values.scroll_strategy), get_default(opts.scroll_strategy, config.values.scroll_strategy),
@@ -453,7 +465,9 @@ function Picker:find()
self.prompt_bufnr = prompt_bufnr self.prompt_bufnr = prompt_bufnr
local preview_border_win = preview_opts and preview_opts.border and preview_opts.border.win_id local preview_border = preview_opts and preview_opts.border
self.preview_border = preview_border
local preview_border_win = (preview_border and preview_border.win_id) and preview_border.win_id
state.set_status(prompt_bufnr, setmetatable({ state.set_status(prompt_bufnr, setmetatable({
prompt_bufnr = prompt_bufnr, prompt_bufnr = prompt_bufnr,
@@ -816,9 +830,31 @@ function Picker:refresh_previewer()
self._selection_entry, self._selection_entry,
status status
) )
if self.preview_border then
if config.values.dynamic_preview_title == true then
self.preview_border:change_title(self.previewer:dynamic_title(self._selection_entry))
else
self.preview_border:change_title(self.previewer:title())
end
end
end end
end end
function Picker:cycle_previewers(next)
local size = #self.all_previewers
if size == 1 then return end
self.current_previewer_index = self.current_previewer_index + next
if self.current_previewer_index > size then
self.current_previewer_index = 1
elseif self.current_previewer_index < 1 then
self.current_previewer_index = size
end
self.previewer = self.all_previewers[self.current_previewer_index]
self:refresh_previewer()
end
function Picker:entry_adder(index, entry, _, insert) function Picker:entry_adder(index, entry, _, insert)
if not entry then return end if not entry then return end

View File

@@ -59,6 +59,25 @@ local colorize_ls = function(bufnr, data, sections)
end end
end end
local search_cb_jump = function(self, bufnr, query)
if not query then return end
vim.api.nvim_buf_call(bufnr, function()
pcall(vim.fn.matchdelete, self.state.hl_id, self.state.winid)
vim.cmd "norm! gg"
vim.fn.search(query, "W")
vim.cmd "norm! zz"
self.state.hl_id = vim.fn.matchadd('TelescopePreviewMatch', query)
end)
end
local search_teardown = function(self)
if self.state and self.state.hl_id then
pcall(vim.fn.matchdelete, self.state.hl_id, self.state.hl_win)
self.state.hl_id = nil
end
end
previewers.file_maker = function(filepath, bufnr, opts) previewers.file_maker = function(filepath, bufnr, opts)
opts = opts or {} opts = opts or {}
if opts.use_ft_detect == nil then opts.use_ft_detect = true end if opts.use_ft_detect == nil then opts.use_ft_detect = true end
@@ -107,6 +126,8 @@ previewers.new_buffer_previewer = function(opts)
local opt_setup = opts.setup local opt_setup = opts.setup
local opt_teardown = opts.teardown local opt_teardown = opts.teardown
local opt_title = opts.title
local opt_dyn_title = opts.dyn_title
local old_bufs = {} local old_bufs = {}
local bufname_table = {} local bufname_table = {}
@@ -140,6 +161,24 @@ previewers.new_buffer_previewer = function(opts)
end end
end end
function opts.title(self)
if opt_title then
if type(opt_title) == 'function' then
return opt_title(self)
else
return opt_title
end
end
return "Preview"
end
function opts.dyn_title(self, entry)
if opt_dyn_title then
return opt_dyn_title(self, entry)
end
return "Preview"
end
function opts.setup(self) function opts.setup(self)
local state = {} local state = {}
if opt_setup then vim.tbl_deep_extend("force", state, opt_setup(self)) end if opt_setup then vim.tbl_deep_extend("force", state, opt_setup(self)) end
@@ -228,8 +267,15 @@ previewers.new_buffer_previewer = function(opts)
return Previewer:new(opts) return Previewer:new(opts)
end end
previewers.cat = defaulter(function(_) previewers.cat = defaulter(function(opts)
opts = opts or {}
local cwd = opts.cwd or vim.loop.cwd()
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
title = "File Preview",
dyn_title = function(_, entry)
return path.normalize(from_entry.path(entry, true), cwd)
end,
get_buffer_by_name = function(_, entry) get_buffer_by_name = function(_, entry)
return from_entry.path(entry, true) return from_entry.path(entry, true)
end, end,
@@ -244,7 +290,10 @@ previewers.cat = defaulter(function(_)
} }
end, {}) end, {})
previewers.vimgrep = defaulter(function(_) previewers.vimgrep = defaulter(function(opts)
opts = opts or {}
local cwd = opts.cwd or vim.loop.cwd()
local jump_to_line = function(self, bufnr, lnum) local jump_to_line = function(self, bufnr, lnum)
if lnum and lnum > 0 then if lnum and lnum > 0 then
pcall(vim.api.nvim_buf_add_highlight, bufnr, ns_previewer, "TelescopePreviewLine", lnum - 1, 0, -1) pcall(vim.api.nvim_buf_add_highlight, bufnr, ns_previewer, "TelescopePreviewLine", lnum - 1, 0, -1)
@@ -256,10 +305,13 @@ previewers.vimgrep = defaulter(function(_)
end end
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
title = "Grep Preview",
dyn_title = function(_, entry)
return path.normalize(from_entry.path(entry, true), cwd)
end,
setup = function() setup = function()
return { return { last_set_bufnr = nil }
last_set_bufnr = nil
}
end, end,
teardown = function(self) teardown = function(self)
@@ -326,6 +378,7 @@ previewers.ctags = defaulter(function(_)
end end
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
title = "Tags Preview",
teardown = function(self) teardown = function(self)
if self.state and self.state.hl_id then if self.state and self.state.hl_id then
pcall(vim.fn.matchdelete, self.state.hl_id, self.state.hl_win) pcall(vim.fn.matchdelete, self.state.hl_id, self.state.hl_win)
@@ -354,16 +407,8 @@ end, {})
previewers.builtin = defaulter(function(_) previewers.builtin = defaulter(function(_)
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
setup = function() title = "Grep Preview",
return {} teardown = search_teardown,
end,
teardown = function(self)
if self.state and self.state.hl_id then
pcall(vim.fn.matchdelete, self.state.hl_id, self.state.hl_win)
self.state.hl_id = nil
end
end,
get_buffer_by_name = function(_, entry) get_buffer_by_name = function(_, entry)
return entry.filename return entry.filename
@@ -381,14 +426,7 @@ previewers.builtin = defaulter(function(_)
conf.buffer_previewer_maker(entry.filename, self.state.bufnr, { conf.buffer_previewer_maker(entry.filename, self.state.bufnr, {
bufname = self.state.bufname, bufname = self.state.bufname,
callback = function(bufnr) callback = function(bufnr)
vim.api.nvim_buf_call(bufnr, function() search_cb_jump(self, bufnr, text)
pcall(vim.fn.matchdelete, self.state.hl_id, self.state.winid)
vim.cmd "norm! gg"
vim.fn.search(text, "W")
vim.cmd "norm! zz"
self.state.hl_id = vim.fn.matchadd('TelescopePreviewMatch', text)
end)
end end
}) })
end end
@@ -397,16 +435,8 @@ end, {})
previewers.help = defaulter(function(_) previewers.help = defaulter(function(_)
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
setup = function() title = "Help Preview",
return {} teardown = search_teardown,
end,
teardown = function(self)
if self.state and self.state.hl_id then
pcall(vim.fn.matchdelete, self.state.hl_id, self.state.hl_win)
self.state.hl_id = nil
end
end,
get_buffer_by_name = function(_, entry) get_buffer_by_name = function(_, entry)
return entry.filename return entry.filename
@@ -420,16 +450,8 @@ previewers.help = defaulter(function(_)
conf.buffer_previewer_maker(entry.filename, self.state.bufnr, { conf.buffer_previewer_maker(entry.filename, self.state.bufnr, {
bufname = self.state.bufname, bufname = self.state.bufname,
callback = function(bufnr) callback = function(bufnr)
vim.api.nvim_buf_call(bufnr, function() putils.regex_highlighter(bufnr, 'help')
vim.cmd(':ownsyntax help') search_cb_jump(self, bufnr, query)
pcall(vim.fn.matchdelete, self.state.hl_id, self.state.winid)
vim.cmd "norm! gg"
vim.fn.search(query, "W")
vim.cmd "norm! zz"
self.state.hl_id = vim.fn.matchadd('TelescopePreviewMatch', query)
end)
end end
}) })
end end
@@ -441,6 +463,7 @@ previewers.man = defaulter(function(opts)
return vim.fn.executable('col') == 1 and 'col -bx' or '' return vim.fn.executable('col') == 1 and 'col -bx' or ''
end) end)
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
title = "Man Preview",
get_buffer_by_name = function(_, entry) get_buffer_by_name = function(_, entry)
return entry.value return entry.value
end, end,
@@ -483,6 +506,7 @@ previewers.git_branch_log = defaulter(function(opts)
end end
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
title = "Git Branch Preview",
get_buffer_by_name = function(_, entry) get_buffer_by_name = function(_, entry)
return entry.value return entry.value
end, end,
@@ -506,6 +530,7 @@ end, {})
previewers.git_stash_diff = defaulter(function(opts) previewers.git_stash_diff = defaulter(function(opts)
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
title = "Git Stash Preview",
get_buffer_by_name = function(_, entry) get_buffer_by_name = function(_, entry)
return entry.value return entry.value
end, end,
@@ -521,25 +546,128 @@ previewers.git_stash_diff = defaulter(function(opts)
} }
end, {}) end, {})
previewers.git_commit_diff = defaulter(function(opts) previewers.git_commit_diff_to_parent = defaulter(function(opts)
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
title = "Git Diff to Parent Preview",
teardown = search_teardown,
get_buffer_by_name = function(_, entry) get_buffer_by_name = function(_, entry)
return entry.value return entry.value
end, end,
define_preview = function(self, entry, status) define_preview = function(self, entry, status)
putils.job_maker({ 'git', '--no-pager', 'diff', entry.value .. '^!' }, self.state.bufnr, { local cmd = { 'git', '--no-pager', 'diff', entry.value .. '^!' }
if opts.current_file then
table.insert(cmd, '--')
table.insert(cmd, opts.current_file)
end
putils.job_maker(cmd, self.state.bufnr, {
value = entry.value, value = entry.value,
bufname = self.state.bufname, bufname = self.state.bufname,
cwd = opts.cwd cwd = opts.cwd,
callback = function(bufnr)
search_cb_jump(self, bufnr, opts.current_line)
end
}) })
putils.regex_highlighter(self.state.bufnr, 'diff') putils.regex_highlighter(self.state.bufnr, 'diff')
end end
} }
end, {}) end, {})
previewers.git_commit_diff_to_head = defaulter(function(opts)
return previewers.new_buffer_previewer {
title = "Git Diff to Head Preview",
teardown = search_teardown,
get_buffer_by_name = function(_, entry)
return entry.value
end,
define_preview = function(self, entry, status)
local cmd = { 'git', '--no-pager', 'diff', '--cached', entry.value }
if opts.current_file then
table.insert(cmd, '--')
table.insert(cmd, opts.current_file)
end
putils.job_maker(cmd, self.state.bufnr, {
value = entry.value,
bufname = self.state.bufname,
cwd = opts.cwd,
callback = function(bufnr)
search_cb_jump(self, bufnr, opts.current_line)
end
})
putils.regex_highlighter(self.state.bufnr, 'diff')
end
}
end, {})
previewers.git_commit_diff_as_was = defaulter(function(opts)
return previewers.new_buffer_previewer {
title = "Git Show Preview",
teardown = search_teardown,
get_buffer_by_name = function(_, entry)
return entry.value
end,
define_preview = function(self, entry, status)
local cmd = { 'git', '--no-pager', 'show' }
local cf = opts.current_file and path.make_relative(opts.current_file, opts.cwd)
local value = cf and (entry.value .. ':' .. cf) or (entry.value)
local ft = cf and pfiletype.detect(value) or 'diff'
table.insert(cmd, value)
putils.job_maker(cmd, self.state.bufnr, {
value = entry.value,
bufname = self.state.bufname,
cwd = opts.cwd,
callback = function(bufnr)
search_cb_jump(self, bufnr, opts.current_line)
end
})
putils.highlighter(self.state.bufnr, ft)
end
}
end, {})
previewers.git_commit_message = defaulter(function(opts)
local hl_map = {
'TelescopeResultsIdentifier',
'TelescopePreviewUser',
'TelescopePreviewDate'
}
return previewers.new_buffer_previewer {
title = "Git Message",
get_buffer_by_name = function(_, entry)
return entry.value
end,
define_preview = function(self, entry, status)
local cmd = { 'git', '--no-pager', 'log', '-n 1', entry.value }
putils.job_maker(cmd, self.state.bufnr, {
value = entry.value,
bufname = self.state.bufname,
cwd = opts.cwd,
callback = function(bufnr, content)
if not content then return end
for k, v in ipairs(hl_map) do
local _, s = content[k]:find('%s')
if s then
vim.api.nvim_buf_add_highlight(bufnr, ns_previewer, v, k - 1, s, #content[k])
end
end
end
})
end
}
end, {})
previewers.git_file_diff = defaulter(function(opts) previewers.git_file_diff = defaulter(function(opts)
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
title = "Git File Diff Preview",
get_buffer_by_name = function(_, entry) get_buffer_by_name = function(_, entry)
return entry.value return entry.value
end, end,
@@ -565,6 +693,7 @@ end, {})
previewers.autocommands = defaulter(function(_) previewers.autocommands = defaulter(function(_)
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
title = "Autocommands Preview",
teardown = function(self) teardown = function(self)
if self.state and self.state.last_set_bufnr and vim.api.nvim_buf_is_valid(self.state.last_set_bufnr) then if self.state and self.state.last_set_bufnr and vim.api.nvim_buf_is_valid(self.state.last_set_bufnr) then
pcall(vim.api.nvim_buf_clear_namespace, self.state.last_set_bufnr, ns_previewer, 0, -1) pcall(vim.api.nvim_buf_clear_namespace, self.state.last_set_bufnr, ns_previewer, 0, -1)
@@ -623,6 +752,7 @@ end, {})
previewers.highlights = defaulter(function(_) previewers.highlights = defaulter(function(_)
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
title = "Highlights Preview",
teardown = function(self) teardown = function(self)
if self.state and self.state.last_set_bufnr and vim.api.nvim_buf_is_valid(self.state.last_set_bufnr) then if self.state and self.state.last_set_bufnr and vim.api.nvim_buf_is_valid(self.state.last_set_bufnr) then
vim.api.nvim_buf_clear_namespace(self.state.last_set_bufnr, ns_previewer, 0, -1) vim.api.nvim_buf_clear_namespace(self.state.last_set_bufnr, ns_previewer, 0, -1)

View File

@@ -53,6 +53,11 @@ local previewers = {}
--- - `teardown` function(self): Will be called on cleanup. --- - `teardown` function(self): Will be called on cleanup.
--- - `preview_fn` function(self, entry, status): Will be called each time --- - `preview_fn` function(self, entry, status): Will be called each time
--- a new entry was selected. --- a new entry was selected.
--- - `title` function(self): Will return the static title of the previewer.
--- - `dynamic_title` function(self, entry): Will return the dynamic title of
--- the previewer. Will only be called
--- when config value dynamic_preview_title
--- is true.
--- - `send_input` function(self, input): This is meant for --- - `send_input` function(self, input): This is meant for
--- `termopen_previewer` and it can be --- `termopen_previewer` and it can be
--- used to send input to the terminal --- used to send input to the terminal
@@ -78,6 +83,11 @@ end
--- end --- end
--- </pre> --- </pre>
--- ---
--- Additionally you can define:
--- - `title` a static title for example "File Preview"
--- - `dyn_title(self, entry)` a dynamic title function which gets called
--- when config value `dynamic_preview_title = true`
---
--- It's an easy way to get your first previewer going and it integrates well --- It's an easy way to get your first previewer going and it integrates well
--- with `bat` and `less`. Providing out of the box scrolling if the command --- with `bat` and `less`. Providing out of the box scrolling if the command
--- uses less. --- uses less.
@@ -166,6 +176,9 @@ previewers.qflist = term_previewer.qflist
--- useful if you have one file but multiple entries. This happens for grep --- useful if you have one file but multiple entries. This happens for grep
--- and lsp builtins. So to make the cache work only load content if --- and lsp builtins. So to make the cache work only load content if
--- `self.state.bufname ~= entry.your_unique_key` --- `self.state.bufname ~= entry.your_unique_key`
--- - `title` a static title for example "File Preview"
--- - `dyn_title(self, entry)` a dynamic title function which gets called
--- when config value `dynamic_preview_title = true`
--- ---
--- `self.state` table: --- `self.state` table:
--- - `self.state.bufnr` --- - `self.state.bufnr`
@@ -259,11 +272,35 @@ previewers.vim_buffer_vimgrep = buffer_previewer.vimgrep
--- case it's configured that way. --- case it's configured that way.
previewers.vim_buffer_qflist = buffer_previewer.qflist previewers.vim_buffer_qflist = buffer_previewer.qflist
--- A previewer that shows a log of a branch as graph
previewers.git_branch_log = buffer_previewer.git_branch_log
previewers.git_branch_log = buffer_previewer.git_branch_log --- A previewer that shows a diff of a stash
previewers.git_commit_diff = buffer_previewer.git_commit_diff previewers.git_stash_diff = buffer_previewer.git_stash_diff
previewers.git_file_diff = buffer_previewer.git_file_diff
previewers.git_stash_diff = buffer_previewer.git_stash_diff --- A previewer that shows a diff of a commit to a parent commit.<br>
--- The run command is `git --no-pager diff SHA^! -- $CURRENT_FILE`
---
--- The current file part is optional. So is only uses it with bcommits.
previewers.git_commit_diff_to_parent = buffer_previewer.git_commit_diff_to_parent
--- A previewer that shows a diff of a commit to head.<br>
--- The run command is `git --no-pager diff --cached $SHA -- $CURRENT_FILE`
---
--- The current file part is optional. So is only uses it with bcommits.
previewers.git_commit_diff_to_head = buffer_previewer.git_commit_diff_to_head
--- A previewer that shows a diff of a commit as it was.<br>
--- The run command is `git --no-pager show $SHA:$CURRENT_FILE` or `git --no-pager show $SHA`
previewers.git_commit_diff_as_was = buffer_previewer.git_commit_diff_as_was
--- A previewer that shows the commit message of a diff.<br>
--- The run command is `git --no-pager log -n 1 $SHA`
previewers.git_commit_message = buffer_previewer.git_commit_message
--- A previewer that shows the current diff of a file. Used in git_status.<br>
--- The run command is `git --no-pager diff $FILE`
previewers.git_file_diff = buffer_previewer.git_file_diff
previewers.ctags = buffer_previewer.ctags previewers.ctags = buffer_previewer.ctags

View File

@@ -6,6 +6,8 @@ function Previewer:new(opts)
return setmetatable({ return setmetatable({
state = nil, state = nil,
_title_fn = opts.title,
_dyn_title_fn = opts.dyn_title,
_setup_func = opts.setup, _setup_func = opts.setup,
_teardown_func = opts.teardown, _teardown_func = opts.teardown,
_send_input = opts.send_input, _send_input = opts.send_input,
@@ -30,6 +32,20 @@ function Previewer:preview(entry, status)
return self:preview_fn(entry, status) return self:preview_fn(entry, status)
end end
function Previewer:title()
if self._title_fn then
return self:_title_fn()
end
return "Preview"
end
function Previewer:dynamic_title(entry)
if self._title_fn then
return self:_dyn_title_fn(entry)
end
return "Preview"
end
function Previewer:teardown() function Previewer:teardown()
if self._teardown_func then if self._teardown_func then
self:_teardown_func() self:_teardown_func()

View File

@@ -1,5 +1,6 @@
local conf = require('telescope.config').values local conf = require('telescope.config').values
local utils = require('telescope.utils') local utils = require('telescope.utils')
local path = require('telescope.path')
local putils = require('telescope.previewers.utils') local putils = require('telescope.previewers.utils')
local from_entry = require('telescope.from_entry') local from_entry = require('telescope.from_entry')
local Previewer = require('telescope.previewers.previewer') local Previewer = require('telescope.previewers.previewer')
@@ -112,6 +113,8 @@ previewers.new_termopen_previewer = function(opts)
local opt_setup = opts.setup local opt_setup = opts.setup
local opt_teardown = opts.teardown local opt_teardown = opts.teardown
local opt_title = opts.title
local opt_dyn_title = opts.dyn_title
local old_bufs = {} local old_bufs = {}
@@ -135,6 +138,24 @@ previewers.new_termopen_previewer = function(opts)
if self.state then self.state.termopen_bufnr = value end if self.state then self.state.termopen_bufnr = value end
end end
function opts.title(self)
if opt_title then
if type(opt_title) == 'function' then
return opt_title(self)
else
return opt_title
end
end
return "Preview"
end
function opts.dyn_title(self, entry)
if opt_dyn_title then
return opt_dyn_title(self, entry)
end
return "Preview"
end
function opts.setup(self) function opts.setup(self)
local state = {} local state = {}
if opt_setup then vim.tbl_deep_extend("force", state, opt_setup(self)) end if opt_setup then vim.tbl_deep_extend("force", state, opt_setup(self)) end
@@ -210,9 +231,17 @@ previewers.new_termopen_previewer = function(opts)
end end
previewers.cat = defaulter(function(opts) previewers.cat = defaulter(function(opts)
opts = opts or {}
local maker = get_maker(opts) local maker = get_maker(opts)
local cwd = opts.cwd or vim.loop.cwd()
return previewers.new_termopen_previewer { return previewers.new_termopen_previewer {
title = "File Preview",
dyn_title = function(_, entry)
return path.normalize(from_entry.path(entry, true), cwd)
end,
get_command = function(entry) get_command = function(entry)
local p = from_entry.path(entry, true) local p = from_entry.path(entry, true)
if p == nil or p == '' then return end if p == nil or p == '' then return end
@@ -223,9 +252,17 @@ previewers.cat = defaulter(function(opts)
end, {}) end, {})
previewers.vimgrep = defaulter(function(opts) previewers.vimgrep = defaulter(function(opts)
opts = opts or {}
local maker = get_maker(opts) local maker = get_maker(opts)
local cwd = opts.cwd or vim.loop.cwd()
return previewers.new_termopen_previewer { return previewers.new_termopen_previewer {
title = "Grep Preview",
dyn_title = function(_, entry)
return path.normalize(from_entry.path(entry, true), cwd)
end,
get_command = function(entry, status) get_command = function(entry, status)
local win_id = status.preview_win local win_id = status.preview_win
local height = vim.api.nvim_win_get_height(win_id) local height = vim.api.nvim_win_get_height(win_id)
@@ -251,8 +288,14 @@ previewers.qflist = defaulter(function(opts)
opts = opts or {} opts = opts or {}
local maker = get_maker(opts) local maker = get_maker(opts)
local cwd = opts.cwd or vim.loop.cwd()
return previewers.new_termopen_previewer { return previewers.new_termopen_previewer {
title = "Grep Preview",
dyn_title = function(_, entry)
return path.normalize(from_entry.path(entry, true), cwd)
end,
get_command = function(entry, status) get_command = function(entry, status)
local win_id = status.preview_win local win_id = status.preview_win
local height = vim.api.nvim_win_get_height(win_id) local height = vim.api.nvim_win_get_height(win_id)