diff --git a/doc/telescope.txt b/doc/telescope.txt index 779abab..ebb0e04 100644 --- a/doc/telescope.txt +++ b/doc/telescope.txt @@ -19,6 +19,15 @@ telescope.setup({opts}) *telescope.setup()* 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* entry_prefix: ~ 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 +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()* 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 +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()* Sends the selected entries to the quickfix list, replacing the previous entries. @@ -378,6 +421,24 @@ actions.delete_buffer({prompt_bufnr}) *actions.delete_buffer()* {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* @@ -583,16 +644,27 @@ builtin.git_commits({opts}) *builtin.git_commits()* Parameters: ~ {opts} (table) options to pass to the picker + Fields: ~ + {cwd} (string) specify the path of the repo + builtin.git_bcommits({opts}) *builtin.git_bcommits()* Lists commits for current buffer with diff preview - - Default keymaps: + - Default keymaps or your overriden `select_` keys: - ``: checks out the currently selected commit + - ``: opens a diff in a vertical split + - ``: opens a diff in a horizontal split + - ``: opens a diff in a new tab Parameters: ~ {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()* 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. - `preview_fn` function(self, entry, status): Will be called each time 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 `termopen_previewer` and it can be used to send input to the terminal application, like less. @@ -1118,6 +1194,11 @@ previewers.new_termopen_previewer() *previewers.new_termopen_previewer()* return { 'bat', entry.path } 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 with `bat` and `less`. Providing out of the box scrolling if the command 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. So to make the cache work only load content if `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.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()* 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 diff --git a/lua/telescope/actions/init.lua b/lua/telescope/actions/init.lua index 8a2f2d7..d9b3096 100644 --- a/lua/telescope/actions/init.lua +++ b/lua/telescope/actions/init.lua @@ -202,7 +202,9 @@ actions._close = function(prompt_bufnr, keepinsert) local original_win_id = picker.original_win_id if picker.previewer then - picker.previewer:teardown() + for _, v in ipairs(picker.all_previewers) do + v:teardown() + end end actions.close_pum(prompt_bufnr) @@ -375,11 +377,10 @@ actions.git_checkout = function(prompt_bufnr) end end --- TODO: add this function header back once the treesitter max-query bug is resolved --- 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. ---@param prompt_bufnr number: The prompt bufnr +--- 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. +---@param prompt_bufnr number: The prompt bufnr actions.git_switch_branch = function(prompt_bufnr) local cwd = action_state.get_current_picker(prompt_bufnr).cwd local selection = action_state.get_selected_entry() @@ -419,9 +420,8 @@ actions.git_track_branch = function(prompt_bufnr) end end --- TODO: add this function header back once the treesitter max-query bug is resolved --- Delete the currently selected branch --- @param prompt_bufnr number: The prompt bufnr +--- Delete the currently selected branch +---@param prompt_bufnr number: The prompt bufnr actions.git_delete_branch = function(prompt_bufnr) local cwd = action_state.get_current_picker(prompt_bufnr).cwd local selection = action_state.get_selected_entry() @@ -442,9 +442,8 @@ actions.git_delete_branch = function(prompt_bufnr) end end --- TODO: add this function header back once the treesitter max-query bug is resolved --- Rebase to selected git branch --- @param prompt_bufnr number: The prompt bufnr +--- Rebase to selected git branch +---@param prompt_bufnr number: The prompt bufnr actions.git_rebase_branch = function(prompt_bufnr) local cwd = action_state.get_current_picker(prompt_bufnr).cwd local selection = action_state.get_selected_entry() @@ -465,9 +464,15 @@ actions.git_rebase_branch = function(prompt_bufnr) end end --- TODO: add this function header back once the treesitter max-query bug is resolved --- Stage/unstage selected file --- @param prompt_bufnr number: The prompt bufnr +--- Stage/unstage selected file +---@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) local cwd = action_state.get_current_picker(prompt_bufnr).cwd local selection = action_state.get_selected_entry() @@ -659,6 +664,20 @@ actions.delete_buffer = function(prompt_bufnr) end) end +--- Cycle to the next previewer if there is one available.
+--- 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.
+--- 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. -- ================================================== diff --git a/lua/telescope/builtin/git.lua b/lua/telescope/builtin/git.lua index 418379d..b9438ce 100644 --- a/lua/telescope/builtin/git.lua +++ b/lua/telescope/builtin/git.lua @@ -7,6 +7,7 @@ local previewers = require('telescope.previewers') local utils = require('telescope.utils') local entry_display = require('telescope.pickers.entry_display') local strings = require('plenary.strings') +local Path = require('plenary.path') local conf = require('telescope.config').values @@ -49,7 +50,12 @@ git.commits = function(opts) results = results, 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), attach_mappings = function() actions.select_default:replace(actions.git_checkout) @@ -77,9 +83,17 @@ git.stash = function(opts) end }):find() 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) + 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({ - 'git', 'log', '--pretty=oneline', '--abbrev-commit', vim.fn.expand('%') + 'git', 'log', '--pretty=oneline', '--abbrev-commit', opts.current_file }, opts.cwd) pickers.new(opts, { @@ -88,10 +102,62 @@ git.bcommits = function(opts) results = results, 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), 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 ++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 end }):find() diff --git a/lua/telescope/builtin/init.lua b/lua/telescope/builtin/init.lua index 17cdf88..016d5ec 100644 --- a/lua/telescope/builtin/init.lua +++ b/lua/telescope/builtin/init.lua @@ -145,12 +145,18 @@ builtin.git_files = require('telescope.builtin.git').files --- - Default keymaps: --- - ``: checks out the currently selected commit ---@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 --- Lists commits for current buffer with diff preview ---- - Default keymaps: +--- - Default keymaps or your overriden `select_` keys: --- - ``: checks out the currently selected commit +--- - ``: opens a diff in a vertical split +--- - ``: opens a diff in a horizontal split +--- - ``: 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 current_file string: specify the current file that should be used for bcommits (default: current buffer) builtin.git_bcommits = require('telescope.builtin.git').bcommits --- List branches for current directory, with output from `git log --oneline` shown in the preview window diff --git a/lua/telescope/config.lua b/lua/telescope/config.lua index 4ca3d0a..da4c561 100644 --- a/lua/telescope/config.lua +++ b/lua/telescope/config.lua @@ -147,6 +147,14 @@ function config.set_defaults(defaults) 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("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) diff --git a/lua/telescope/make_entry.lua b/lua/telescope/make_entry.lua index 9c3ab14..288a471 100644 --- a/lua/telescope/make_entry.lua +++ b/lua/telescope/make_entry.lua @@ -248,8 +248,7 @@ function make_entry.gen_from_git_stash() end end - -function make_entry.gen_from_git_commits() +function make_entry.gen_from_git_commits(opts) local displayer = entry_display.create { separator = " ", items = { @@ -281,7 +280,8 @@ function make_entry.gen_from_git_commits() value = sha, ordinal = sha .. ' ' .. msg, msg = msg, - display = make_display + display = make_display, + current_file = opts.current_file } end end diff --git a/lua/telescope/pickers.lua b/lua/telescope/pickers.lua index 9d1377a..a0e443a 100644 --- a/lua/telescope/pickers.lua +++ b/lua/telescope/pickers.lua @@ -74,7 +74,10 @@ function Picker:new(opts) finder = opts.finder, 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, 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 + 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" obj.scroller = p_scroller.create( get_default(opts.scroll_strategy, config.values.scroll_strategy), @@ -453,7 +465,9 @@ function Picker:find() 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({ prompt_bufnr = prompt_bufnr, @@ -816,9 +830,31 @@ function Picker:refresh_previewer() self._selection_entry, 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 +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) if not entry then return end diff --git a/lua/telescope/previewers/buffer_previewer.lua b/lua/telescope/previewers/buffer_previewer.lua index 52710d8..f2f49b9 100644 --- a/lua/telescope/previewers/buffer_previewer.lua +++ b/lua/telescope/previewers/buffer_previewer.lua @@ -59,6 +59,25 @@ local colorize_ls = function(bufnr, data, sections) 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) opts = opts or {} 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_teardown = opts.teardown + local opt_title = opts.title + local opt_dyn_title = opts.dyn_title local old_bufs = {} local bufname_table = {} @@ -140,6 +161,24 @@ previewers.new_buffer_previewer = function(opts) 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) local state = {} 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) 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 { + title = "File Preview", + dyn_title = function(_, entry) + return path.normalize(from_entry.path(entry, true), cwd) + end, + get_buffer_by_name = function(_, entry) return from_entry.path(entry, true) end, @@ -244,7 +290,10 @@ previewers.cat = defaulter(function(_) } 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) if lnum and lnum > 0 then pcall(vim.api.nvim_buf_add_highlight, bufnr, ns_previewer, "TelescopePreviewLine", lnum - 1, 0, -1) @@ -256,10 +305,13 @@ previewers.vimgrep = defaulter(function(_) end return previewers.new_buffer_previewer { + title = "Grep Preview", + dyn_title = function(_, entry) + return path.normalize(from_entry.path(entry, true), cwd) + end, + setup = function() - return { - last_set_bufnr = nil - } + return { last_set_bufnr = nil } end, teardown = function(self) @@ -326,6 +378,7 @@ previewers.ctags = defaulter(function(_) end return previewers.new_buffer_previewer { + title = "Tags Preview", teardown = function(self) if self.state and self.state.hl_id then pcall(vim.fn.matchdelete, self.state.hl_id, self.state.hl_win) @@ -354,16 +407,8 @@ end, {}) previewers.builtin = defaulter(function(_) return previewers.new_buffer_previewer { - setup = function() - return {} - 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, + title = "Grep Preview", + teardown = search_teardown, get_buffer_by_name = function(_, entry) return entry.filename @@ -381,14 +426,7 @@ previewers.builtin = defaulter(function(_) conf.buffer_previewer_maker(entry.filename, self.state.bufnr, { bufname = self.state.bufname, callback = function(bufnr) - 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(text, "W") - vim.cmd "norm! zz" - - self.state.hl_id = vim.fn.matchadd('TelescopePreviewMatch', text) - end) + search_cb_jump(self, bufnr, text) end }) end @@ -397,16 +435,8 @@ end, {}) previewers.help = defaulter(function(_) return previewers.new_buffer_previewer { - setup = function() - return {} - 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, + title = "Help Preview", + teardown = search_teardown, get_buffer_by_name = function(_, entry) return entry.filename @@ -420,16 +450,8 @@ previewers.help = defaulter(function(_) conf.buffer_previewer_maker(entry.filename, self.state.bufnr, { bufname = self.state.bufname, callback = function(bufnr) - vim.api.nvim_buf_call(bufnr, function() - vim.cmd(':ownsyntax help') - - 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) + putils.regex_highlighter(bufnr, 'help') + search_cb_jump(self, bufnr, query) end }) end @@ -441,6 +463,7 @@ previewers.man = defaulter(function(opts) return vim.fn.executable('col') == 1 and 'col -bx' or '' end) return previewers.new_buffer_previewer { + title = "Man Preview", get_buffer_by_name = function(_, entry) return entry.value end, @@ -483,6 +506,7 @@ previewers.git_branch_log = defaulter(function(opts) end return previewers.new_buffer_previewer { + title = "Git Branch Preview", get_buffer_by_name = function(_, entry) return entry.value end, @@ -506,6 +530,7 @@ end, {}) previewers.git_stash_diff = defaulter(function(opts) return previewers.new_buffer_previewer { + title = "Git Stash Preview", get_buffer_by_name = function(_, entry) return entry.value end, @@ -521,25 +546,128 @@ previewers.git_stash_diff = defaulter(function(opts) } end, {}) -previewers.git_commit_diff = defaulter(function(opts) +previewers.git_commit_diff_to_parent = defaulter(function(opts) return previewers.new_buffer_previewer { + title = "Git Diff to Parent Preview", + teardown = search_teardown, get_buffer_by_name = function(_, entry) return entry.value end, 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, 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') 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) return previewers.new_buffer_previewer { + title = "Git File Diff Preview", get_buffer_by_name = function(_, entry) return entry.value end, @@ -565,6 +693,7 @@ end, {}) previewers.autocommands = defaulter(function(_) return previewers.new_buffer_previewer { + title = "Autocommands Preview", 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 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(_) return previewers.new_buffer_previewer { + title = "Highlights Preview", 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 vim.api.nvim_buf_clear_namespace(self.state.last_set_bufnr, ns_previewer, 0, -1) diff --git a/lua/telescope/previewers/init.lua b/lua/telescope/previewers/init.lua index 853ad5b..3f13dc3 100644 --- a/lua/telescope/previewers/init.lua +++ b/lua/telescope/previewers/init.lua @@ -53,6 +53,11 @@ local previewers = {} --- - `teardown` function(self): Will be called on cleanup. --- - `preview_fn` function(self, entry, status): Will be called each time --- 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 --- `termopen_previewer` and it can be --- used to send input to the terminal @@ -78,6 +83,11 @@ 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 --- with `bat` and `less`. Providing out of the box scrolling if the command --- uses less. @@ -166,6 +176,9 @@ previewers.qflist = term_previewer.qflist --- 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 --- `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.bufnr` @@ -259,11 +272,35 @@ previewers.vim_buffer_vimgrep = buffer_previewer.vimgrep --- case it's configured that way. 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 -previewers.git_commit_diff = buffer_previewer.git_commit_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 stash +previewers.git_stash_diff = buffer_previewer.git_stash_diff + +--- 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_parent = buffer_previewer.git_commit_diff_to_parent + +--- 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_to_head = buffer_previewer.git_commit_diff_to_head + +--- 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_diff_as_was = buffer_previewer.git_commit_diff_as_was + +--- A previewer that shows the commit message of a diff.
+--- 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.
+--- The run command is `git --no-pager diff $FILE` +previewers.git_file_diff = buffer_previewer.git_file_diff previewers.ctags = buffer_previewer.ctags diff --git a/lua/telescope/previewers/previewer.lua b/lua/telescope/previewers/previewer.lua index 00d25e8..b4a3e47 100644 --- a/lua/telescope/previewers/previewer.lua +++ b/lua/telescope/previewers/previewer.lua @@ -6,6 +6,8 @@ function Previewer:new(opts) return setmetatable({ state = nil, + _title_fn = opts.title, + _dyn_title_fn = opts.dyn_title, _setup_func = opts.setup, _teardown_func = opts.teardown, _send_input = opts.send_input, @@ -30,6 +32,20 @@ function Previewer:preview(entry, status) return self:preview_fn(entry, status) 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() if self._teardown_func then self:_teardown_func() diff --git a/lua/telescope/previewers/term_previewer.lua b/lua/telescope/previewers/term_previewer.lua index cf4690b..299b52e 100644 --- a/lua/telescope/previewers/term_previewer.lua +++ b/lua/telescope/previewers/term_previewer.lua @@ -1,5 +1,6 @@ local conf = require('telescope.config').values local utils = require('telescope.utils') +local path = require('telescope.path') local putils = require('telescope.previewers.utils') local from_entry = require('telescope.from_entry') local Previewer = require('telescope.previewers.previewer') @@ -112,6 +113,8 @@ previewers.new_termopen_previewer = function(opts) local opt_setup = opts.setup local opt_teardown = opts.teardown + local opt_title = opts.title + local opt_dyn_title = opts.dyn_title local old_bufs = {} @@ -135,6 +138,24 @@ previewers.new_termopen_previewer = function(opts) if self.state then self.state.termopen_bufnr = value 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) local state = {} 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 previewers.cat = defaulter(function(opts) + opts = opts or {} + local maker = get_maker(opts) + local cwd = opts.cwd or vim.loop.cwd() 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) local p = from_entry.path(entry, true) if p == nil or p == '' then return end @@ -223,9 +252,17 @@ previewers.cat = defaulter(function(opts) end, {}) previewers.vimgrep = defaulter(function(opts) + opts = opts or {} + local maker = get_maker(opts) + local cwd = opts.cwd or vim.loop.cwd() 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) local win_id = status.preview_win local height = vim.api.nvim_win_get_height(win_id) @@ -251,8 +288,14 @@ previewers.qflist = defaulter(function(opts) opts = opts or {} local maker = get_maker(opts) + local cwd = opts.cwd or vim.loop.cwd() 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) local win_id = status.preview_win local height = vim.api.nvim_win_get_height(win_id)