Merge pull request #1945 from nvim-telescope/dev

full changelog `:help telescope.changelog-1945`
This commit is contained in:
Simon Hauser
2022-07-01 23:29:24 +02:00
committed by GitHub
40 changed files with 3938 additions and 6672 deletions

View File

@@ -299,6 +299,8 @@ Built-in functions. Ready to be bound to any key you like.
| Functions | Description |
|---------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|
| `builtin.lsp_references` | Lists LSP references for word under the cursor |
| `builtin.lsp_incoming_calls` | Lists LSP incoming calls for word under the cursor |
| `builtin.lsp_outgoing_calls` | Lists LSP outgoing calls for word under the cursor |
| `builtin.lsp_document_symbols` | Lists LSP document symbols in the current buffer |
| `builtin.lsp_workspace_symbols` | Lists LSP document symbols in the current workspace |
| `builtin.lsp_dynamic_workspace_symbols` | Dynamically Lists LSP for all workspace symbols |

File diff suppressed because it is too large Load Diff

View File

@@ -142,6 +142,7 @@ telescope.setup({opts}) *telescope.setup()*
- "follow"
- "row"
- "closest"
- "none"
*telescope.defaults.scroll_strategy*
scroll_strategy: ~
@@ -496,8 +497,17 @@ telescope.setup({opts}) *telescope.setup()*
highlighting, which falls back to regex-based highlighting.
`true`: treesitter highlighting for all available filetypes
`false`: regex-based highlighting for all filetypes
`table`: table of filetypes for which to attach treesitter
highlighting
`table`: following nvim-treesitters highlighting options:
It contains two keys:
- enable boolean|table: if boolean, enable all ts
highlighing with that flag,
disable still considered.
Containing a list of filetypes,
that are enabled, disabled
ignored because it doesnt make
any sense in this case.
- disable table: containing a list of filetypes
that are disabled
Default: true
- msg_bg_fillchar: Character to fill background of unpreviewable buffers with
Default: ""
@@ -655,6 +665,17 @@ telescope.setup({opts}) *telescope.setup()*
Example: { "%.npz" } -- ignore all npz files
See: https://www.lua.org/manual/5.1/manual.html#5.4.1 for more
information about lua regex
Note: `file_ignore_patterns` will be used in all pickers that have a
file associated. This might lead to the problem that lsp_ pickers
aren't displaying results because they might be ignored by
`file_ignore_patterns`. For example, setting up node_modules as ignored
will never show node_modules in any results, even if you are
interested in lsp_ results.
If you only want `file_ignore_patterns` for `find_files` and
`grep_string`/`live_grep` it is suggested that you setup `gitignore`
and have fd and or ripgrep installed because both tools will not show
`gitignore`d files on default.
Default: nil
@@ -809,26 +830,28 @@ builtin.live_grep({opts}) *telescope.builtin.live_grep()*
{opts} (table) options to pass to the picker
Options: ~
{cwd} (string) root dir to search from (default:
cwd, use utils.buffer_dir() to
search relative to open buffer)
{grep_open_files} (boolean) if true, restrict search to open
files only, mutually exclusive with
`search_dirs`
{search_dirs} (table) directory/directories to search in,
mutually exclusive with
`grep_open_files`
{glob_pattern} (string) argument to be used with `--glob`,
e.g. "*.toml", can use the opposite
"!*.toml"
{type_filter} (string) argument to be used with `--type`,
e.g. "rust", see `rg --type-list`
{additional_args} (function) function(opts) which returns a table
of additional arguments to be passed
on
{max_results} (number) define a upper result value
{disable_coordinates} (boolean) don't show the line & row numbers
(default: false)
{cwd} (string) root dir to search from
(default: cwd, use
utils.buffer_dir() to search
relative to open buffer)
{grep_open_files} (boolean) if true, restrict search to open
files only, mutually exclusive
with `search_dirs`
{search_dirs} (table) directory/directories/files to
search, mutually exclusive with
`grep_open_files`
{glob_pattern} (string|table) argument to be used with
`--glob`, e.g. "*.toml", can use
the opposite "!*.toml"
{type_filter} (string) argument to be used with
`--type`, e.g. "rust", see `rg
--type-list`
{additional_args} (function) function(opts) which returns a
table of additional arguments to
be passed on
{max_results} (number) define a upper result value
{disable_coordinates} (boolean) don't show the line & row
numbers (default: false)
builtin.grep_string({opts}) *telescope.builtin.grep_string()*
@@ -843,7 +866,8 @@ builtin.grep_string({opts}) *telescope.builtin.grep_string()*
cwd, use utils.buffer_dir() to
search relative to open buffer)
{search} (string) the query to search
{search_dirs} (table) directory/directories to search in
{search_dirs} (table) directory/directories/files to
search
{use_regex} (boolean) if true, special characters won't be
escaped, allows for using regex
(default: false)
@@ -866,19 +890,25 @@ builtin.find_files({opts}) *telescope.builtin.find_files()*
{opts} (table) options to pass to the picker
Options: ~
{cwd} (string) root dir to search from (default: cwd, use
utils.buffer_dir() to search relative to
open buffer)
{find_command} (table) command line arguments for `find_files` to
use for the search, overrides default:
config
{follow} (boolean) if true, follows symlinks (i.e. uses `-L`
flag for the `find` command)
{hidden} (boolean) determines whether to show hidden files or
not (default: false)
{no_ignore} (boolean) show files ignored by .gitignore, .ignore,
etc. (default: false)
{search_dirs} (table) directory/directories to search in
{cwd} (string) root dir to search from (default:
cwd, use utils.buffer_dir() to
search relative to open buffer)
{find_command} (function|table) cmd to use for the search. Can be
a fn(opts) -> tbl (default:
autodetect)
{follow} (boolean) if true, follows symlinks (i.e.
uses `-L` flag for the `find`
command)
{hidden} (boolean) determines whether to show hidden
files or not (default: false)
{no_ignore} (boolean) show files ignored by .gitignore,
.ignore, etc. (default: false)
{no_ignore_parent} (boolean) show files ignored by .gitignore,
.ignore, etc. in parent dirs.
(default: false)
{search_dirs} (table) directory/directories/files to
search
{search_file} (string) specify a filename to search for
builtin.fd() *telescope.builtin.fd()*
@@ -977,7 +1007,7 @@ builtin.git_files({opts}) *telescope.builtin.git_files()*
(default: true)
{show_untracked} (boolean) if true, adds `--others` flag to
command and shows untracked files
(default: true)
(default: false)
{recurse_submodules} (boolean) if true, adds the
`--recurse-submodules` flag to command
(default: false)
@@ -1097,6 +1127,8 @@ builtin.builtin({opts}) *telescope.builtin.builtin()*
Options: ~
{include_extensions} (boolean) if true will show the pickers of the
installed extensions (default: false)
{use_default_opts} (boolean) if the selected picker should use its
default options (default: false)
builtin.resume({opts}) *telescope.builtin.resume()*
@@ -1178,9 +1210,11 @@ builtin.quickfix({opts}) *telescope.builtin.quickfix()*
{opts} (table) options to pass to the picker
Options: ~
{ignore_filename} (boolean) dont show filenames (default: true)
{trim_text} (boolean) trim results text (default: false)
{nr} (number) specify the quickfix list number
{show_line} (boolean) show results text (default: true)
{trim_text} (boolean) trim results text (default: false)
{fname_width} (number) defines the width of the filename section
(default: 30)
{nr} (number) specify the quickfix list number
builtin.quickfixhistory({opts}) *telescope.builtin.quickfixhistory()*
@@ -1202,8 +1236,10 @@ builtin.loclist({opts}) *telescope.builtin.loclist()*
{opts} (table) options to pass to the picker
Options: ~
{ignore_filename} (boolean) dont show filenames (default: true)
{trim_text} (boolean) trim results text (default: false)
{show_line} (boolean) show results text (default: true)
{trim_text} (boolean) trim results text (default: false)
{fname_width} (number) defines the width of the filename section
(default: 30)
builtin.oldfiles({opts}) *telescope.builtin.oldfiles()*
@@ -1402,8 +1438,10 @@ builtin.tagstack({opts}) *telescope.builtin.tagstack()*
{opts} (table) options to pass to the picker
Options: ~
{ignore_filename} (boolean) dont show filenames (default: true)
{trim_text} (boolean) trim results text (default: false)
{show_line} (boolean) show results text (default: true)
{trim_text} (boolean) trim results text (default: false)
{fname_width} (number) defines the width of the filename section
(default: 30)
builtin.jumplist({opts}) *telescope.builtin.jumplist()*
@@ -1414,8 +1452,10 @@ builtin.jumplist({opts}) *telescope.builtin.jumplist()*
{opts} (table) options to pass to the picker
Options: ~
{ignore_filename} (boolean) dont show filenames (default: true)
{trim_text} (boolean) trim results text (default: false)
{show_line} (boolean) show results text (default: true)
{trim_text} (boolean) trim results text (default: false)
{fname_width} (number) defines the width of the filename section
(default: 30)
builtin.lsp_references({opts}) *telescope.builtin.lsp_references()*
@@ -1432,6 +1472,34 @@ builtin.lsp_references({opts}) *telescope.builtin.lsp_references()*
{include_current_line} (boolean) include current line (default:
false)
{trim_text} (boolean) trim results text (default: false)
{fname_width} (number) defines the width of the filename
section (default: 30)
builtin.lsp_incoming_calls({opts}) *telescope.builtin.lsp_incoming_calls()*
Lists LSP incoming calls for word under the cursor, jumps to reference on
`<cr>`
Parameters: ~
{opts} (table) options to pass to the picker
Options: ~
{show_line} (boolean) show results text (default: true)
{trim_text} (boolean) trim results text (default: false)
builtin.lsp_outgoing_calls({opts}) *telescope.builtin.lsp_outgoing_calls()*
Lists LSP outgoing calls for word under the cursor, jumps to reference on
`<cr>`
Parameters: ~
{opts} (table) options to pass to the picker
Options: ~
{show_line} (boolean) show results text (default: true)
{trim_text} (boolean) trim results text (default: false)
builtin.lsp_definitions({opts}) *telescope.builtin.lsp_definitions()*
@@ -1443,11 +1511,12 @@ builtin.lsp_definitions({opts}) *telescope.builtin.lsp_definitions()*
{opts} (table) options to pass to the picker
Options: ~
{jump_type} (string) how to goto definition if there is only
one, values: "tab", "split", "vsplit",
"never"
{ignore_filename} (boolean) dont show filenames (default: true)
{trim_text} (boolean) trim results text (default: false)
{jump_type} (string) how to goto definition if there is only one,
values: "tab", "split", "vsplit", "never"
{show_line} (boolean) show results text (default: true)
{trim_text} (boolean) trim results text (default: false)
{fname_width} (number) defines the width of the filename section
(default: 30)
builtin.lsp_type_definitions({opts}) *telescope.builtin.lsp_type_definitions()*
@@ -1459,11 +1528,12 @@ builtin.lsp_type_definitions({opts}) *telescope.builtin.lsp_type_definitions()*
{opts} (table) options to pass to the picker
Options: ~
{jump_type} (string) how to goto definition if there is only
one, values: "tab", "split", "vsplit",
"never"
{ignore_filename} (boolean) dont show filenames (default: true)
{trim_text} (boolean) trim results text (default: false)
{jump_type} (string) how to goto definition if there is only one,
values: "tab", "split", "vsplit", "never"
{show_line} (boolean) show results text (default: true)
{trim_text} (boolean) trim results text (default: false)
{fname_width} (number) defines the width of the filename section
(default: 30)
builtin.lsp_implementations({opts}) *telescope.builtin.lsp_implementations()*
@@ -1475,11 +1545,13 @@ builtin.lsp_implementations({opts}) *telescope.builtin.lsp_implementations()*
{opts} (table) options to pass to the picker
Options: ~
{jump_type} (string) how to goto implementation if there is
only one, values: "tab", "split",
"vsplit", "never"
{ignore_filename} (boolean) dont show filenames (default: true)
{trim_text} (boolean) trim results text (default: false)
{jump_type} (string) how to goto implementation if there is only
one, values: "tab", "split", "vsplit",
"never"
{show_line} (boolean) show results text (default: true)
{trim_text} (boolean) trim results text (default: false)
{fname_width} (number) defines the width of the filename section
(default: 30)
builtin.lsp_document_symbols({opts}) *telescope.builtin.lsp_document_symbols()*
@@ -1493,8 +1565,6 @@ builtin.lsp_document_symbols({opts}) *telescope.builtin.lsp_document_symbols()*
{opts} (table) options to pass to the picker
Options: ~
{ignore_filename} (boolean) dont show filenames (default:
true)
{show_line} (boolean) if true, shows the content of the
line the tag is found on (default:
false)
@@ -1517,8 +1587,6 @@ builtin.lsp_workspace_symbols({opts}) *telescope.builtin.lsp_workspace_symbols()
Options: ~
{query} (string) for what to query the workspace
(default: "")
{ignore_filename} (boolean) dont show filenames (default:
false)
{show_line} (boolean) if true, shows the content of the
line the tag is found on (default:
false)
@@ -1539,8 +1607,6 @@ builtin.lsp_dynamic_workspace_symbols({opts}) *telescope.builtin.lsp_dynamic_wor
{opts} (table) options to pass to the picker
Options: ~
{ignore_filename} (boolean) dont show filenames (default:
false)
{show_line} (boolean) if true, shows the content of the
line the symbol is found on
(default: false)
@@ -1891,14 +1957,17 @@ Provides "resolver functions" to allow more customisable inputs for options.
resolver.resolve_height() *telescope.resolve.resolve_height()*
Converts input to a function that returns the height. The input must take
one of four forms:
one of five forms:
1. 0 <= number < 1
This means total height as a percentage.
2. 1 <= number
This means total height as a fixed number.
3. function
Must have signature: function(self, max_columns, max_lines): number
4. table of the form: {padding = `foo`}
4. table of the form: { val, max = ..., min = ... }
val has to be in the first form 0 <= val < 1 and only one is given,
`min` or `max` as fixed number
5. table of the form: {padding = `foo`}
where `foo` has one of the previous three forms.
The height is then set to be the remaining space after padding. For
example, if the window has height 50, and the input is {padding = 5},
@@ -1911,14 +1980,17 @@ resolver.resolve_height() *telescope.resolve.resolve_height()*
resolver.resolve_width() *telescope.resolve.resolve_width()*
Converts input to a function that returns the width. The input must take
one of four forms:
one of five forms:
1. 0 <= number < 1
This means total width as a percentage.
2. 1 <= number
This means total width as a fixed number.
3. function
Must have signature: function(self, max_columns, max_lines): number
4. table of the form: {padding = `foo`}
4. table of the form: { val, max = ..., min = ... }
val has to be in the first form 0 <= val < 1 and only one is given,
`min` or `max` as fixed number
5. table of the form: {padding = `foo`}
where `foo` has one of the previous three forms.
The width is then set to be the remaining space after padding. For
example, if the window has width 100, and the input is {padding = 5},
@@ -1944,6 +2016,134 @@ resolver.resolve_anchor_pos() *telescope.resolve.resolve_anchor_pos()*
================================================================================
*telescope.make_entry*
Each picker has a finder made up of two parts, the results which are the data
to be displayed, and the entry_maker. These entry_makers are functions returned
from make_entry functions. These will be referrd to as entry_makers in the
following documentation.
Every entry maker returns a function which accepts the data to be used for an
entry. This function will return an entry table (or nil, meaning skip this
entry) which contains of the - following important keys:
- value any: value key can be anything but still required
- valid bool: is an optional key because it defaults to true but if the key is
set to false it will not be displayed by the picker. (optional)
- ordinal string: is the text that is used for filtering (required)
- display string|function: is either a string of the text that is being
displayed or a function receiving the entry at a later stage, when the entry
is actually being displayed. A function can be useful here if complex
calculation have to be done. `make_entry` can also return a second value a
highlight array which will then apply to the line. Highlight entry in this
array has the following signature `{ { start_col, end_col }, hl_group }`
(required).
- filename string: will be interpreted by the default `<cr>` action as open
this file (optional)
- bufnr number: will be interpreted by the default `<cr>` action as open this
buffer (optional)
- lnum number: lnum value which will be interpreted by the default `<cr>`
action as a jump to this line (optional)
- col number: col value which will be interpreted by the default `<cr>` action
as a jump to this column (optional)
More information on easier displaying, see |telescope.pickers.entry_display|
TODO: Document something we call `entry_index`
================================================================================
*telescope.pickers.entry_display*
Entry Display is used to format each entry shown in the result panel.
Entry Display create() will give us a function based on the configuration of
column widths we pass into it. We then can use this function n times to return
a string based on structured input.
Note that if you call `create()` inside `make_display` it will be called for
every single entry. So it is suggested to do this outside of `make_display` for
the best performance.
The create function will use the column widths passed to it in
configaration.items. Each item in that table is the number of characters in the
column. It's also possible for the final column to not have a fixed width, this
will be shown in the configuartion as 'remaining = true'.
An example of this configuration is shown for the buffers picker
>
local displayer = entry_display.create {
separator = " ",
items = {
{ width = opts.bufnr_width },
{ width = 4 },
{ width = icon_width },
{ remaining = true },
},
}
<
This shows 4 columns, the first is defined in the opts as the width we'll use
when display_string the number of the buffer. The second has a fixed width of 4
and the 3rd column's widht will be decided by the width of the icons we use.
The fourth column will use the remaining space. Finally we have also defined
the seperator between each column will be the space " ".
An example of how the display reference will be used is shown, again for the
buffers picker:
>
return displayer {
{ entry.bufnr, "TelescopeResultsNumber" },
{ entry.indicator, "TelescopeResultsComment" },
{ icon, hl_group },
display_bufname .. ":" .. entry.lnum,
}
<
There are two types of values each column can have. Either a simple String or a
table containing the String as well as the hl_group.
The displayer can return values, string and an optional highlights. String is
all the text to be displayed for this entry as a single string. If parts of the
string are to be highlighted they will be described in the highlights table.
For better understanding of how create() and displayer are used it's best to
look at the code in make_entry.lua.
================================================================================
*telescope.utils*
Utilities for writing telescope pickers
utils.transform_path({opts}, {path}) *telescope.utils.transform_path()*
Transform path is a util function that formats a path based on path_display
found in `opts` or the default value from config. It is meant to be used in
make_entry to have a uniform interface for builtins as well as extensions
utilizing the same user configuration Note: It is only supported inside
`make_entry`/`make_display` the use of this function outside of telescope
might yield to undefined behavior and will not be addressed by us
Parameters: ~
{opts} (table) The opts the users passed into the picker. Might
contains a path_display key
{path} (string) The path that should be formated
Return: ~
string: The transformed path ready to be displayed
utils.notify({funname}, {opts}) *telescope.utils.notify()*
Telescope Wrapper around vim.notify
Parameters: ~
{funname} (string) name of the function that will be
{opts} (table) opts.level string, opts.msg string, opts.once bool
================================================================================
*telescope.actions*
@@ -2285,6 +2485,8 @@ actions.edit_register({prompt_bufnr}) *telescope.actions.edit_register()*
actions.paste_register({prompt_bufnr}) *telescope.actions.paste_register()*
Paste the selected register into the buffer
Note: only meant to be used inside builtin.registers
Parameters: ~
{prompt_bufnr} (number) The prompt bufnr
@@ -2770,7 +2972,8 @@ Generally used from within other |telescope.actions|
utils.map_entries({prompt_bufnr}, {f}) *telescope.actions.utils.map_entries()*
Apply `f` to the entries of the current picker.
- Notes:
- Mapped entries may include results not visible in the results popup.
- Mapped entries include all currently filtered results, not just the
visible onces.
- Indices are 1-indexed, whereas rows are 0-indexed.
- Warning: `map_entries` has no return value.
- The below example showcases how to collect results

View File

@@ -195,5 +195,64 @@ https://github.com/stevearc/dressing.nvim which has support for multiple
different backends including telescope.
*telescope.changelog-1945*
Date: July 01, 2022
PR: https://github.com/nvim-telescope/telescope.nvim/pull/1945
This is our dev branch which contains a lot of PRs, a lot of fixes,
refactoring and general quality of life improvements. It also contains new
features, the most noteworthy are the following (mostly developed by the
community):
- feat: none strategy & control attachment (#1867)
- feat: force buffer delete for terminal and improvements for
Picker:delete_selection (#1943)
- feat(tags): process tagfiles on the fly (#1989)
- feat(builtin.lsp): implement builtin handlers for
lsp.(incoming|outgoing)_calls (#1484)
- feat: clear previewer if no item is selected (#2004)
- feat: add min max boundary to width, height resolver (#2002)
- feat: Add entry_index for entry_makers (#1850)
- feat: refine with new_table (#1115)
The last one is one of the most existing new features, because it allows you
to go from live_grep into a fuzzy environment with the following mapping
`<C-Space>`. It's a general interface we now implemented for `live_grep` and
`lsp_dynamic_workspace_symbols` but it could also be easily implemented for
other builtins, by us or the user. It's now available for extension developers.
We will add documentation in the next couple of days and improve it by adding
more options to configure it after the initial 0.1 release.
But with all longer development phases, there are also some breaking changes.
This is the main reason we moved development to a separate branch, for the
past two months. We can't promise that there won't be more breaking changes,
but it is the plan that this is the last set of breaking changes prior to the
0.1 release on July, 12. We are deeply sorry for the inconvenience. The
following breaking changes are included in this PR:
- break(git_files): change `show_untracked` default to false. Can be changed
back with `:Telescope git_files show_untracked=true`
- break: deprecate `utils.get_default` `utils.if_nil`, will be removed prior
to 0.1, so if you use it in your config, please move to `vim.F.if_nil`
- break: drops `ignore_filename` option, use `path_display= { "hidden" }`
instead
- break: prefix internal interfaces with __ so
`require("telescope.builtin.files").find_files` will show a notify error but
still works for now. The error will be removed prior to 0.1! You should use
`require("telescope.builtin").find_files` because we wrap all the functions
that are exposed in this module.
- break: defaults.preview.treesitter rework that allows you to either enable a
list of languages, or enable all and disable some. Please read
`:help telescope.defaults.preview` for more information.
Something like this is now possible:
>
treesitter = {
enable = false,
-- or
enable = { "c" },
-- disable can be set if enable isn't set
disable = { "perl", "javascript" },
},
<
vim:tw=78:ts=8:ft=help:norl:

View File

@@ -24,6 +24,10 @@
---@brief ]]
local actions = require "telescope.actions"
local config = require "telescope.config"
local action_state = require "telescope.actions.state"
local finders = require "telescope.finders"
local action_generate = {}
--- Display the keymaps of registered actions similar to which-key.nvim.<br>
@@ -54,4 +58,56 @@ action_generate.which_key = function(opts)
end
end
action_generate.refine = function(prompt_bufnr, opts)
opts = opts or {}
opts.prompt_to_prefix = vim.F.if_nil(opts.prompt_to_prefix, false)
opts.prefix_hl_group = vim.F.if_nil(opts.prompt_hl_group, "TelescopePromptPrefix")
opts.prompt_prefix = vim.F.if_nil(opts.promt_prefix, config.values.prompt_prefix)
opts.reset_multi_selection = vim.F.if_nil(opts.reset_multi_selection, false)
opts.reset_prompt = vim.F.if_nil(opts.reset_prompt, true)
opts.sorter = vim.F.if_nil(opts.sorter, config.values.generic_sorter {})
local current_picker = action_state.get_current_picker(prompt_bufnr)
-- title
if opts.prompt_title then
current_picker.prompt_border:change_title(opts.prompt_title)
end
if opts.results_title then
current_picker.results_border:change_title(opts.results_title)
end
local results = {}
for entry in current_picker.manager:iter() do
table.insert(results, entry)
end
-- if opts.sorter == false, keep older sorter
if opts.sorter then
current_picker.sorter:_destroy()
current_picker.sorter = opts.sorter
current_picker.sorter:_init()
end
local new_finder = finders.new_table {
results = results,
entry_maker = function(x)
return x
end,
}
if not opts.reset_multi_selection and action_state.get_current_line() ~= "" then
opts.multi = current_picker._multi
end
if opts.prompt_to_prefix then
local prompt = action_state.get_current_line()
local current_prefix = current_picker.prompt_prefix
local suffix = current_prefix ~= opts.prompt_prefix and current_prefix or ""
opts.new_prefix = suffix .. prompt .. " " .. opts.prompt_prefix
end
current_picker:refresh(new_finder, opts)
end
return action_generate

View File

@@ -431,6 +431,8 @@ actions.edit_register = function(prompt_bufnr)
end
--- Paste the selected register into the buffer
---
--- Note: only meant to be used inside builtin.registers
---@param prompt_bufnr number: The prompt bufnr
actions.paste_register = function(prompt_bufnr)
local selection = action_state.get_selected_entry()
@@ -1020,7 +1022,9 @@ end
actions.delete_buffer = function(prompt_bufnr)
local current_picker = action_state.get_current_picker(prompt_bufnr)
current_picker:delete_selection(function(selection)
vim.api.nvim_buf_delete(selection.bufnr, { force = false })
local force = vim.api.nvim_buf_get_option(selection.bufnr, "buftype") == "terminal"
local ok = pcall(vim.api.nvim_buf_delete, selection.bufnr, { force = force })
return ok
end)
end
@@ -1059,22 +1063,22 @@ end
---@param prompt_bufnr number: The prompt bufnr
actions.which_key = function(prompt_bufnr, opts)
opts = opts or {}
opts.max_height = utils.get_default(opts.max_height, 0.4)
opts.only_show_current_mode = utils.get_default(opts.only_show_current_mode, true)
opts.mode_width = utils.get_default(opts.mode_width, 1)
opts.keybind_width = utils.get_default(opts.keybind_width, 7)
opts.name_width = utils.get_default(opts.name_width, 30)
opts.line_padding = utils.get_default(opts.line_padding, 1)
opts.separator = utils.get_default(opts.separator, " -> ")
opts.close_with_action = utils.get_default(opts.close_with_action, true)
opts.normal_hl = utils.get_default(opts.normal_hl, "TelescopePrompt")
opts.border_hl = utils.get_default(opts.border_hl, "TelescopePromptBorder")
opts.winblend = utils.get_default(opts.winblend, config.values.winblend)
opts.column_padding = utils.get_default(opts.column_padding, " ")
opts.max_height = vim.F.if_nil(opts.max_height, 0.4)
opts.only_show_current_mode = vim.F.if_nil(opts.only_show_current_mode, true)
opts.mode_width = vim.F.if_nil(opts.mode_width, 1)
opts.keybind_width = vim.F.if_nil(opts.keybind_width, 7)
opts.name_width = vim.F.if_nil(opts.name_width, 30)
opts.line_padding = vim.F.if_nil(opts.line_padding, 1)
opts.separator = vim.F.if_nil(opts.separator, " -> ")
opts.close_with_action = vim.F.if_nil(opts.close_with_action, true)
opts.normal_hl = vim.F.if_nil(opts.normal_hl, "TelescopePrompt")
opts.border_hl = vim.F.if_nil(opts.border_hl, "TelescopePromptBorder")
opts.winblend = vim.F.if_nil(opts.winblend, config.values.winblend)
opts.column_padding = vim.F.if_nil(opts.column_padding, " ")
-- Assigning into 'opts.column_indent' would override a number with a string and
-- cause issues with subsequent calls, keep a local copy of the string instead
local column_indent = table.concat(utils.repeated_table(utils.get_default(opts.column_indent, 4), " "))
local column_indent = table.concat(utils.repeated_table(vim.F.if_nil(opts.column_indent, 4), " "))
-- close on repeated keypress
local km_bufs = (function()
@@ -1111,9 +1115,9 @@ actions.which_key = function(prompt_bufnr, opts)
local make_display = function(mapping)
return displayer {
{ mapping.mode, utils.get_default(opts.mode_hl, "TelescopeResultsConstant") },
{ mapping.keybind, utils.get_default(opts.keybind_hl, "TelescopeResultsVariable") },
{ mapping.name, utils.get_default(opts.name_hl, "TelescopeResultsFunction") },
{ mapping.mode, vim.F.if_nil(opts.mode_hl, "TelescopeResultsConstant") },
{ mapping.keybind, vim.F.if_nil(opts.keybind_hl, "TelescopeResultsVariable") },
{ mapping.name, vim.F.if_nil(opts.name_hl, "TelescopeResultsFunction") },
}
end

View File

@@ -13,7 +13,7 @@ local utils = {}
--- Apply `f` to the entries of the current picker.
--- - Notes:
--- - Mapped entries may include results not visible in the results popup.
--- - Mapped entries include all currently filtered results, not just the visible onces.
--- - Indices are 1-indexed, whereas rows are 0-indexed.
--- - Warning: `map_entries` has no return value.
--- - The below example showcases how to collect results

View File

@@ -0,0 +1,150 @@
local conf = require("telescope.config").values
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local pickers = require "telescope.pickers"
local utils = require "telescope.utils"
local diagnostics = {}
local convert_diagnostic_type = function(severities, severity)
-- convert from string to int
if type(severity) == "string" then
-- make sure that e.g. error is uppercased to ERROR
return severities[severity:upper()]
end
-- otherwise keep original value, incl. nil
return severity
end
local diagnostics_to_tbl = function(opts)
opts = vim.F.if_nil(opts, {})
local items = {}
local severities = vim.diagnostic.severity
local current_buf = vim.api.nvim_get_current_buf()
opts.severity = convert_diagnostic_type(severities, opts.severity)
opts.severity_limit = convert_diagnostic_type(severities, opts.severity_limit)
opts.severity_bound = convert_diagnostic_type(severities, opts.severity_bound)
local diagnosis_opts = { severity = {}, namespace = opts.namespace }
if opts.severity ~= nil then
if opts.severity_limit ~= nil or opts.severity_bound ~= nil then
utils.notify("builtin.diagnostics", {
msg = "Invalid severity parameters. Both a specific severity and a limit/bound is not allowed",
level = "ERROR",
})
return {}
end
diagnosis_opts.severity = opts.severity
else
if opts.severity_limit ~= nil then
diagnosis_opts.severity["min"] = opts.severity_limit
end
if opts.severity_bound ~= nil then
diagnosis_opts.severity["max"] = opts.severity_bound
end
end
opts.root_dir = opts.root_dir == true and vim.loop.cwd() or opts.root_dir
local bufnr_name_map = {}
local filter_diag = function(diagnostic)
if bufnr_name_map[diagnostic.bufnr] == nil then
bufnr_name_map[diagnostic.bufnr] = vim.api.nvim_buf_get_name(diagnostic.bufnr)
end
local root_dir_test = not opts.root_dir
or string.sub(bufnr_name_map[diagnostic.bufnr], 1, #opts.root_dir) == opts.root_dir
local listed_test = not opts.no_unlisted or vim.api.nvim_buf_get_option(diagnostic.bufnr, "buflisted")
return root_dir_test and listed_test
end
local preprocess_diag = function(diagnostic)
return {
bufnr = diagnostic.bufnr,
filename = bufnr_name_map[diagnostic.bufnr],
lnum = diagnostic.lnum + 1,
col = diagnostic.col + 1,
text = vim.trim(diagnostic.message:gsub("[\n]", "")),
type = severities[diagnostic.severity] or severities[1],
}
end
for _, d in ipairs(vim.diagnostic.get(opts.bufnr, diagnosis_opts)) do
if filter_diag(d) then
table.insert(items, preprocess_diag(d))
end
end
-- sort results by bufnr (prioritize cur buf), severity, lnum
table.sort(items, function(a, b)
if a.bufnr == b.bufnr then
if a.type == b.type then
return a.lnum < b.lnum
else
return a.type < b.type
end
else
-- prioritize for current bufnr
if a.bufnr == current_buf then
return true
end
if b.bufnr == current_buf then
return false
end
return a.bufnr < b.bufnr
end
end)
return items
end
diagnostics.get = function(opts)
if opts.bufnr ~= 0 then
opts.bufnr = nil
end
if opts.bufnr == nil then
opts.path_display = vim.F.if_nil(opts.path_display, {})
end
if type(opts.bufnr) == "string" then
opts.bufnr = tonumber(opts.bufnr)
end
local locations = diagnostics_to_tbl(opts)
if vim.tbl_isempty(locations) then
utils.notify("builtin.diagnostics", {
msg = "No diagnostics found",
level = "INFO",
})
return
end
opts.path_display = vim.F.if_nil(opts.path_display, "hidden")
pickers.new(opts, {
prompt_title = opts.bufnr == nil and "Workspace Diagnostics" or "Document Diagnostics",
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_diagnostics(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.prefilter_sorter {
tag = "type",
sorter = conf.generic_sorter(opts),
},
}):find()
end
local function apply_checks(mod)
for k, v in pairs(mod) do
mod[k] = function(opts)
opts = opts or {}
v(opts)
end
end
return mod
end
return apply_checks(diagnostics)

View File

@@ -0,0 +1,522 @@
local action_state = require "telescope.actions.state"
local action_set = require "telescope.actions.set"
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local pickers = require "telescope.pickers"
local previewers = require "telescope.previewers"
local sorters = require "telescope.sorters"
local utils = require "telescope.utils"
local conf = require("telescope.config").values
local log = require "telescope.log"
local Path = require "plenary.path"
local flatten = vim.tbl_flatten
local filter = vim.tbl_filter
local files = {}
local escape_chars = function(string)
return string.gsub(string, "[%(|%)|\\|%[|%]|%-|%{%}|%?|%+|%*|%^|%$|%.]", {
["\\"] = "\\\\",
["-"] = "\\-",
["("] = "\\(",
[")"] = "\\)",
["["] = "\\[",
["]"] = "\\]",
["{"] = "\\{",
["}"] = "\\}",
["?"] = "\\?",
["+"] = "\\+",
["*"] = "\\*",
["^"] = "\\^",
["$"] = "\\$",
["."] = "\\.",
})
end
-- Special keys:
-- opts.search_dirs -- list of directory to search in
-- opts.grep_open_files -- boolean to restrict search to open files
files.live_grep = function(opts)
local vimgrep_arguments = opts.vimgrep_arguments or conf.vimgrep_arguments
local search_dirs = opts.search_dirs
local grep_open_files = opts.grep_open_files
opts.cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.loop.cwd()
local filelist = {}
if grep_open_files then
local bufnrs = filter(function(b)
if 1 ~= vim.fn.buflisted(b) then
return false
end
return true
end, vim.api.nvim_list_bufs())
if not next(bufnrs) then
return
end
for _, bufnr in ipairs(bufnrs) do
local file = vim.api.nvim_buf_get_name(bufnr)
table.insert(filelist, Path:new(file):make_relative(opts.cwd))
end
elseif search_dirs then
for i, path in ipairs(search_dirs) do
search_dirs[i] = vim.fn.expand(path)
end
end
local additional_args = {}
if opts.additional_args ~= nil and type(opts.additional_args) == "function" then
additional_args = opts.additional_args(opts)
end
if opts.type_filter then
additional_args[#additional_args + 1] = "--type=" .. opts.type_filter
end
if type(opts.glob_pattern) == "string" then
additional_args[#additional_args + 1] = "--glob=" .. opts.glob_pattern
elseif type(opts.glob_pattern) == "table" then
for i = 1, #opts.glob_pattern do
additional_args[#additional_args + 1] = "--glob=" .. opts.glob_pattern[i]
end
end
local live_grepper = finders.new_job(function(prompt)
-- TODO: Probably could add some options for smart case and whatever else rg offers.
if not prompt or prompt == "" then
return nil
end
local search_list = {}
if search_dirs then
table.insert(search_list, search_dirs)
end
if grep_open_files then
search_list = filelist
end
return flatten { vimgrep_arguments, additional_args, "--", prompt, search_list }
end, opts.entry_maker or make_entry.gen_from_vimgrep(opts), opts.max_results, opts.cwd)
pickers.new(opts, {
prompt_title = "Live Grep",
finder = live_grepper,
previewer = conf.grep_previewer(opts),
-- TODO: It would be cool to use `--json` output for this
-- and then we could get the highlight positions directly.
sorter = sorters.highlighter_only(opts),
attach_mappings = function(_, map)
map("i", "<c-space>", function(prompt_bufnr)
local line = action_state.get_current_line()
require("telescope.actions.generate").refine(prompt_bufnr, {
prompt_title = "Find Word (" .. line .. ")",
sorter = conf.generic_sorter(opts),
})
end)
return true
end,
}):find()
end
-- Special keys:
-- opts.search -- the string to search.
-- opts.search_dirs -- list of directory to search in
-- opts.use_regex -- special characters won't be escaped
files.grep_string = function(opts)
-- TODO: This should probably check your visual selection as well, if you've got one
local vimgrep_arguments = opts.vimgrep_arguments or conf.vimgrep_arguments
local search_dirs = opts.search_dirs
local word = opts.search or vim.fn.expand "<cword>"
local search = opts.use_regex and word or escape_chars(word)
local word_match = opts.word_match
opts.entry_maker = opts.entry_maker or make_entry.gen_from_vimgrep(opts)
local title_word = word:gsub("\n", "\\n")
local additional_args = {}
if opts.additional_args ~= nil and type(opts.additional_args) == "function" then
additional_args = opts.additional_args(opts)
end
local args = flatten {
vimgrep_arguments,
additional_args,
word_match,
"--",
search,
}
if search_dirs then
for _, path in ipairs(search_dirs) do
table.insert(args, vim.fn.expand(path))
end
end
pickers.new(opts, {
prompt_title = "Find Word (" .. title_word .. ")",
finder = finders.new_oneshot_job(args, opts),
previewer = conf.grep_previewer(opts),
sorter = conf.generic_sorter(opts),
}):find()
end
files.find_files = function(opts)
local find_command = (function()
if opts.find_command then
if type(opts.find_command) == "function" then
return opts.find_command(opts)
end
return opts.find_command
elseif 1 == vim.fn.executable "fd" then
return { "fd", "--type", "f" }
elseif 1 == vim.fn.executable "fdfind" then
return { "fdfind", "--type", "f" }
elseif 1 == vim.fn.executable "rg" then
return { "rg", "--files" }
elseif 1 == vim.fn.executable "find" and vim.fn.has "win32" == 0 then
return { "find", ".", "-type", "f" }
elseif 1 == vim.fn.executable "where" then
return { "where", "/r", ".", "*" }
end
end)()
if not find_command then
utils.notify("builtin.find_files", {
msg = "You need to install either find, fd, or rg",
level = "ERROR",
})
return
end
local command = find_command[1]
local hidden = opts.hidden
local no_ignore = opts.no_ignore
local no_ignore_parent = opts.no_ignore_parent
local follow = opts.follow
local search_dirs = opts.search_dirs
local search_file = opts.search_file
if search_dirs then
for k, v in pairs(search_dirs) do
search_dirs[k] = vim.fn.expand(v)
end
end
if command == "fd" or command == "fdfind" or command == "rg" then
if hidden then
table.insert(find_command, "--hidden")
end
if no_ignore then
table.insert(find_command, "--no-ignore")
end
if no_ignore_parent then
table.insert(find_command, "--no-ignore-parent")
end
if follow then
table.insert(find_command, "-L")
end
if search_file then
if command == "rg" then
table.insert(find_command, "-g")
table.insert(find_command, "*" .. search_file .. "*")
else
table.insert(find_command, search_file)
end
end
if search_dirs then
if command ~= "rg" and not search_file then
table.insert(find_command, ".")
end
for _, v in pairs(search_dirs) do
table.insert(find_command, v)
end
end
elseif command == "find" then
if not hidden then
table.insert(find_command, { "-not", "-path", "*/.*" })
find_command = flatten(find_command)
end
if no_ignore ~= nil then
log.warn "The `no_ignore` key is not available for the `find` command in `find_files`."
end
if no_ignore_parent ~= nil then
log.warn "The `no_ignore_parent` key is not available for the `find` command in `find_files`."
end
if follow then
table.insert(find_command, 2, "-L")
end
if search_file then
table.insert(find_command, "-name")
table.insert(find_command, "*" .. search_file .. "*")
end
if search_dirs then
table.remove(find_command, 2)
for _, v in pairs(search_dirs) do
table.insert(find_command, 2, v)
end
end
elseif command == "where" then
if hidden ~= nil then
log.warn "The `hidden` key is not available for the Windows `where` command in `find_files`."
end
if no_ignore ~= nil then
log.warn "The `no_ignore` key is not available for the Windows `where` command in `find_files`."
end
if no_ignore_parent ~= nil then
log.warn "The `no_ignore_parent` key is not available for the Windows `where` command in `find_files`."
end
if follow ~= nil then
log.warn "The `follow` key is not available for the Windows `where` command in `find_files`."
end
if search_dirs ~= nil then
log.warn "The `search_dirs` key is not available for the Windows `where` command in `find_files`."
end
if search_file ~= nil then
log.warn "The `search_file` key is not available for the Windows `where` command in `find_files`."
end
end
if opts.cwd then
opts.cwd = vim.fn.expand(opts.cwd)
end
opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts)
pickers.new(opts, {
prompt_title = "Find Files",
finder = finders.new_oneshot_job(find_command, opts),
previewer = conf.file_previewer(opts),
sorter = conf.file_sorter(opts),
}):find()
end
local function prepare_match(entry, kind)
local entries = {}
if entry.node then
table.insert(entries, entry)
else
for name, item in pairs(entry) do
vim.list_extend(entries, prepare_match(item, name))
end
end
return entries
end
-- TODO: finish docs for opts.show_line
files.treesitter = function(opts)
opts.show_line = vim.F.if_nil(opts.show_line, true)
local has_nvim_treesitter, _ = pcall(require, "nvim-treesitter")
if not has_nvim_treesitter then
utils.notify("builtin.treesitter", {
msg = "User need to install nvim-treesitter needs to be installed",
level = "ERROR",
})
return
end
local parsers = require "nvim-treesitter.parsers"
if not parsers.has_parser(parsers.get_buf_lang(opts.bufnr)) then
utils.notify("builtin.treesitter", {
msg = "No parser for the current buffer",
level = "ERROR",
})
return
end
local ts_locals = require "nvim-treesitter.locals"
local results = {}
for _, definition in ipairs(ts_locals.get_definitions(opts.bufnr)) do
local entries = prepare_match(ts_locals.get_local_nodes(definition))
for _, entry in ipairs(entries) do
entry.kind = vim.F.if_nil(entry.kind, "")
table.insert(results, entry)
end
end
if vim.tbl_isempty(results) then
return
end
pickers.new(opts, {
prompt_title = "Treesitter Symbols",
finder = finders.new_table {
results = results,
entry_maker = opts.entry_maker or make_entry.gen_from_treesitter(opts),
},
previewer = conf.grep_previewer(opts),
sorter = conf.prefilter_sorter {
tag = "kind",
sorter = conf.generic_sorter(opts),
},
}):find()
end
files.current_buffer_fuzzy_find = function(opts)
-- All actions are on the current buffer
local filename = vim.fn.expand(vim.api.nvim_buf_get_name(opts.bufnr))
local filetype = vim.api.nvim_buf_get_option(opts.bufnr, "filetype")
local lines = vim.api.nvim_buf_get_lines(opts.bufnr, 0, -1, false)
local lines_with_numbers = {}
for lnum, line in ipairs(lines) do
table.insert(lines_with_numbers, {
lnum = lnum,
bufnr = opts.bufnr,
filename = filename,
text = line,
})
end
local ts_ok, ts_parsers = pcall(require, "nvim-treesitter.parsers")
if ts_ok then
filetype = ts_parsers.ft_to_lang(filetype)
end
local _, ts_configs = pcall(require, "nvim-treesitter.configs")
local parser_ok, parser = pcall(vim.treesitter.get_parser, opts.bufnr, filetype)
local query_ok, query = pcall(vim.treesitter.get_query, filetype, "highlights")
if parser_ok and query_ok and ts_ok and ts_configs.is_enabled("highlight", filetype, opts.bufnr) then
local root = parser:parse()[1]:root()
local highlighter = vim.treesitter.highlighter.new(parser)
local highlighter_query = highlighter:get_query(filetype)
local line_highlights = setmetatable({}, {
__index = function(t, k)
local obj = {}
rawset(t, k, obj)
return obj
end,
})
for id, node in query:iter_captures(root, opts.bufnr, 0, -1) do
local hl = highlighter_query:_get_hl_from_capture(id)
if hl and type(hl) ~= "number" then
local row1, col1, row2, col2 = node:range()
if row1 == row2 then
local row = row1 + 1
for index = col1, col2 do
line_highlights[row][index] = hl
end
else
local row = row1 + 1
for index = col1, #lines[row] do
line_highlights[row][index] = hl
end
while row < row2 + 1 do
row = row + 1
for index = 0, #(lines[row] or {}) do
line_highlights[row][index] = hl
end
end
end
end
end
opts.line_highlights = line_highlights
end
pickers.new(opts, {
prompt_title = "Current Buffer Fuzzy",
finder = finders.new_table {
results = lines_with_numbers,
entry_maker = opts.entry_maker or make_entry.gen_from_buffer_lines(opts),
},
sorter = conf.generic_sorter(opts),
previewer = conf.grep_previewer(opts),
attach_mappings = function()
action_set.select:enhance {
post = function()
local selection = action_state.get_selected_entry()
vim.api.nvim_win_set_cursor(0, { selection.lnum, 0 })
end,
}
return true
end,
}):find()
end
files.tags = function(opts)
local tagfiles = opts.ctags_file and { opts.ctags_file } or vim.fn.tagfiles()
for i, ctags_file in ipairs(tagfiles) do
tagfiles[i] = vim.fn.expand(ctags_file, true)
end
if vim.tbl_isempty(tagfiles) then
utils.notify("builtin.tags", {
msg = "No tags file found. Create one with ctags -R",
level = "ERROR",
})
return
end
opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_ctags(opts))
pickers.new(opts, {
prompt_title = "Tags",
finder = finders.new_oneshot_job(flatten { "cat", tagfiles }, opts),
previewer = previewers.ctags.new(opts),
sorter = conf.generic_sorter(opts),
attach_mappings = function()
action_set.select:enhance {
post = function()
local selection = action_state.get_selected_entry()
if not selection then
return
end
if selection.scode then
-- un-escape / then escape required
-- special chars for vim.fn.search()
-- ] ~ *
local scode = selection.scode:gsub([[\/]], "/"):gsub("[%]~*]", function(x)
return "\\" .. x
end)
vim.cmd "norm! gg"
vim.fn.search(scode)
vim.cmd "norm! zz"
else
vim.api.nvim_win_set_cursor(0, { selection.lnum, 0 })
end
end,
}
return true
end,
}):find()
end
files.current_buffer_tags = function(opts)
return files.tags(vim.tbl_extend("force", {
prompt_title = "Current Buffer Tags",
only_current_file = true,
path_display = "hidden",
}, opts))
end
local function apply_checks(mod)
for k, v in pairs(mod) do
mod[k] = function(opts)
opts = opts or {}
v(opts)
end
end
return mod
end
return apply_checks(files)

View File

@@ -0,0 +1,411 @@
local actions = require "telescope.actions"
local action_state = require "telescope.actions.state"
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local pickers = require "telescope.pickers"
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
local git = {}
git.files = function(opts)
if opts.is_bare then
utils.notify("builtin.git_files", {
msg = "This operation must be run in a work tree",
level = "ERROR",
})
return
end
local show_untracked = vim.F.if_nil(opts.show_untracked, false)
local recurse_submodules = vim.F.if_nil(opts.recurse_submodules, false)
if show_untracked and recurse_submodules then
utils.notify("builtin.git_files", {
msg = "Git does not support both --others and --recurse-submodules",
level = "ERROR",
})
return
end
-- By creating the entry maker after the cwd options,
-- we ensure the maker uses the cwd options when being created.
opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_file(opts))
local git_command = vim.F.if_nil(opts.git_command, { "git", "ls-files", "--exclude-standard", "--cached" })
pickers.new(opts, {
prompt_title = "Git Files",
finder = finders.new_oneshot_job(
vim.tbl_flatten {
git_command,
show_untracked and "--others" or nil,
recurse_submodules and "--recurse-submodules" or nil,
},
opts
),
previewer = conf.file_previewer(opts),
sorter = conf.file_sorter(opts),
}):find()
end
git.commits = function(opts)
opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_git_commits(opts))
local git_command = vim.F.if_nil(opts.git_command, { "git", "log", "--pretty=oneline", "--abbrev-commit", "--", "." })
pickers.new(opts, {
prompt_title = "Git Commits",
finder = finders.new_oneshot_job(git_command, 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(_, map)
actions.select_default:replace(actions.git_checkout)
map("i", "<c-r>m", actions.git_reset_mixed)
map("n", "<c-r>m", actions.git_reset_mixed)
map("i", "<c-r>s", actions.git_reset_soft)
map("n", "<c-r>s", actions.git_reset_soft)
map("i", "<c-r>h", actions.git_reset_hard)
map("n", "<c-r>h", actions.git_reset_hard)
return true
end,
}):find()
end
git.stash = function(opts)
opts.show_branch = vim.F.if_nil(opts.show_branch, true)
opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_git_stash(opts))
pickers.new(opts, {
prompt_title = "Git Stash",
finder = finders.new_oneshot_job(
vim.tbl_flatten {
"git",
"--no-pager",
"stash",
"list",
},
opts
),
previewer = previewers.git_stash_diff.new(opts),
sorter = conf.file_sorter(opts),
attach_mappings = function()
actions.select_default:replace(actions.git_apply_stash)
return true
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 = (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))
local git_command = vim.F.if_nil(
opts.git_command,
{ "git", "log", "--pretty=oneline", "--abbrev-commit", "--follow" }
)
pickers.new(opts, {
prompt_title = "Git BCommits",
finder = finders.new_oneshot_job(
vim.tbl_flatten {
git_command,
opts.current_file,
},
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_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.api.nvim_create_autocmd("WinClosed", {
buffer = bufnr,
nested = true,
once = true,
callback = function()
vim.api.nvim_buf_delete(bufnr, { force = true })
end,
})
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()
end
git.branches = function(opts)
local format = "%(HEAD)"
.. "%(refname)"
.. "%(authorname)"
.. "%(upstream:lstrip=2)"
.. "%(committerdate:format-local:%Y/%m/%d %H:%M:%S)"
local output = utils.get_os_command_output(
{ "git", "for-each-ref", "--perl", "--format", format, opts.pattern },
opts.cwd
)
local results = {}
local widths = {
name = 0,
authorname = 0,
upstream = 0,
committerdate = 0,
}
local unescape_single_quote = function(v)
return string.gsub(v, "\\([\\'])", "%1")
end
local parse_line = function(line)
local fields = vim.split(string.sub(line, 2, -2), "''", true)
local entry = {
head = fields[1],
refname = unescape_single_quote(fields[2]),
authorname = unescape_single_quote(fields[3]),
upstream = unescape_single_quote(fields[4]),
committerdate = fields[5],
}
local prefix
if vim.startswith(entry.refname, "refs/remotes/") then
prefix = "refs/remotes/"
elseif vim.startswith(entry.refname, "refs/heads/") then
prefix = "refs/heads/"
else
return
end
local index = 1
if entry.head ~= "*" then
index = #results + 1
end
entry.name = string.sub(entry.refname, string.len(prefix) + 1)
for key, value in pairs(widths) do
widths[key] = math.max(value, strings.strdisplaywidth(entry[key] or ""))
end
if string.len(entry.upstream) > 0 then
widths.upstream_indicator = 2
end
table.insert(results, index, entry)
end
for _, line in ipairs(output) do
parse_line(line)
end
if #results == 0 then
return
end
local displayer = entry_display.create {
separator = " ",
items = {
{ width = 1 },
{ width = widths.name },
{ width = widths.authorname },
{ width = widths.upstream_indicator },
{ width = widths.upstream },
{ width = widths.committerdate },
},
}
local make_display = function(entry)
return displayer {
{ entry.head },
{ entry.name, "TelescopeResultsIdentifier" },
{ entry.authorname },
{ string.len(entry.upstream) > 0 and "=>" or "" },
{ entry.upstream, "TelescopeResultsIdentifier" },
{ entry.committerdate },
}
end
pickers.new(opts, {
prompt_title = "Git Branches",
finder = finders.new_table {
results = results,
entry_maker = function(entry)
entry.value = entry.name
entry.ordinal = entry.name
entry.display = make_display
return make_entry.set_default_entry_mt(entry, opts)
end,
},
previewer = previewers.git_branch_log.new(opts),
sorter = conf.file_sorter(opts),
attach_mappings = function(_, map)
actions.select_default:replace(actions.git_checkout)
map("i", "<c-t>", actions.git_track_branch)
map("n", "<c-t>", actions.git_track_branch)
map("i", "<c-r>", actions.git_rebase_branch)
map("n", "<c-r>", actions.git_rebase_branch)
map("i", "<c-a>", actions.git_create_branch)
map("n", "<c-a>", actions.git_create_branch)
map("i", "<c-s>", actions.git_switch_branch)
map("n", "<c-s>", actions.git_switch_branch)
map("i", "<c-d>", actions.git_delete_branch)
map("n", "<c-d>", actions.git_delete_branch)
map("i", "<c-y>", actions.git_merge_branch)
map("n", "<c-y>", actions.git_merge_branch)
return true
end,
}):find()
end
git.status = function(opts)
if opts.is_bare then
utils.notify("builtin.git_status", {
msg = "This operation must be run in a work tree",
level = "ERROR",
})
return
end
local gen_new_finder = function()
local expand_dir = vim.F.if_nil(opts.expand_dir, true)
local git_cmd = { "git", "status", "-s", "--", "." }
if expand_dir then
table.insert(git_cmd, #git_cmd - 1, "-u")
end
local output = utils.get_os_command_output(git_cmd, opts.cwd)
if #output == 0 then
print "No changes found"
utils.notify("builtin.git_status", {
msg = "No changes found",
level = "WARN",
})
return
end
return finders.new_table {
results = output,
entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_git_status(opts)),
}
end
local initial_finder = gen_new_finder()
if not initial_finder then
return
end
pickers.new(opts, {
prompt_title = "Git Status",
finder = initial_finder,
previewer = previewers.git_file_diff.new(opts),
sorter = conf.file_sorter(opts),
attach_mappings = function(prompt_bufnr, map)
actions.git_staging_toggle:enhance {
post = function()
action_state.get_current_picker(prompt_bufnr):refresh(gen_new_finder(), { reset_prompt = true })
end,
}
map("i", "<tab>", actions.git_staging_toggle)
map("n", "<tab>", actions.git_staging_toggle)
return true
end,
}):find()
end
local set_opts_cwd = function(opts)
if opts.cwd then
opts.cwd = vim.fn.expand(opts.cwd)
else
opts.cwd = vim.loop.cwd()
end
-- Find root of git directory and remove trailing newline characters
local git_root, ret = utils.get_os_command_output({ "git", "rev-parse", "--show-toplevel" }, opts.cwd)
local use_git_root = vim.F.if_nil(opts.use_git_root, true)
if ret ~= 0 then
local in_worktree = utils.get_os_command_output({ "git", "rev-parse", "--is-inside-work-tree" }, opts.cwd)
local in_bare = utils.get_os_command_output({ "git", "rev-parse", "--is-bare-repository" }, opts.cwd)
if in_worktree[1] ~= "true" and in_bare[1] ~= "true" then
error(opts.cwd .. " is not a git directory")
elseif in_worktree[1] ~= "true" and in_bare[1] == "true" then
opts.is_bare = true
end
else
if use_git_root then
opts.cwd = git_root[1]
end
end
end
local function apply_checks(mod)
for k, v in pairs(mod) do
mod[k] = function(opts)
opts = vim.F.if_nil(opts, {})
set_opts_cwd(opts)
v(opts)
end
end
return mod
end
return apply_checks(git)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,389 @@
local channel = require("plenary.async.control").channel
local action_state = require "telescope.actions.state"
local sorters = require "telescope.sorters"
local conf = require("telescope.config").values
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local pickers = require "telescope.pickers"
local utils = require "telescope.utils"
local lsp = {}
lsp.references = function(opts)
local filepath = vim.api.nvim_buf_get_name(opts.bufnr)
local lnum = vim.api.nvim_win_get_cursor(opts.winnr)[1]
local params = vim.lsp.util.make_position_params(opts.winnr)
local include_current_line = vim.F.if_nil(opts.include_current_line, false)
params.context = { includeDeclaration = vim.F.if_nil(opts.include_declaration, true) }
vim.lsp.buf_request(opts.bufnr, "textDocument/references", params, function(err, result, ctx, _)
if err then
vim.api.nvim_err_writeln("Error when finding references: " .. err.message)
return
end
local locations = {}
if result then
local results = vim.lsp.util.locations_to_items(result, vim.lsp.get_client_by_id(ctx.client_id).offset_encoding)
if include_current_line then
locations = vim.tbl_filter(function(v)
-- Remove current line from result
return not (v.filename == filepath and v.lnum == lnum)
end, vim.F.if_nil(results, {}))
else
locations = vim.F.if_nil(results, {})
end
end
if vim.tbl_isempty(locations) then
return
end
pickers.new(opts, {
prompt_title = "LSP References",
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.generic_sorter(opts),
push_cursor_on_edit = true,
push_tagstack_on_edit = true,
}):find()
end)
end
local function call_hierarchy(opts, method, title, direction, item)
vim.lsp.buf_request(opts.bufnr, method, { item = item }, function(err, result)
if err then
vim.api.nvim_err_writeln("Error handling " .. title .. ": " .. err)
return
end
if not result or vim.tbl_isempty(result) then
return
end
local locations = {}
for _, ch_call in pairs(result) do
local ch_item = ch_call[direction]
for _, range in pairs(ch_call.fromRanges) do
table.insert(locations, {
filename = vim.uri_to_fname(ch_item.uri),
text = ch_item.name,
lnum = range.start.line + 1,
col = range.start.character + 1,
})
end
end
pickers.new(opts, {
prompt_title = title,
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.generic_sorter(opts),
push_cursor_on_edit = true,
push_tagstack_on_edit = true,
}):find()
end)
end
local function pick_call_hierarchy_item(call_hierarchy_items)
if not call_hierarchy_items then
return
end
if #call_hierarchy_items == 1 then
return call_hierarchy_items[1]
end
local items = {}
for i, item in pairs(call_hierarchy_items) do
local entry = item.detail or item.name
table.insert(items, string.format("%d. %s", i, entry))
end
local choice = vim.fn.inputlist(items)
if choice < 1 or choice > #items then
return
end
return choice
end
local function calls(opts, direction)
local params = vim.lsp.util.make_position_params()
vim.lsp.buf_request(opts.bufnr, "textDocument/prepareCallHierarchy", params, function(err, result)
if err then
vim.api.nvim_err_writeln("Error when preparing call hierarchy: " .. err)
return
end
local call_hierarchy_item = pick_call_hierarchy_item(result)
if not call_hierarchy_item then
return
end
if direction == "from" then
call_hierarchy(opts, "callHierarchy/incomingCalls", "LSP Incoming Calls", direction, call_hierarchy_item)
else
call_hierarchy(opts, "callHierarchy/outgoingCalls", "LSP Outgoing Calls", direction, call_hierarchy_item)
end
end)
end
lsp.incoming_calls = function(opts)
calls(opts, "from")
end
lsp.outgoing_calls = function(opts)
calls(opts, "to")
end
local function list_or_jump(action, title, opts)
local params = vim.lsp.util.make_position_params(opts.winnr)
vim.lsp.buf_request(opts.bufnr, action, params, function(err, result, ctx, _)
if err then
vim.api.nvim_err_writeln("Error when executing " .. action .. " : " .. err.message)
return
end
local flattened_results = {}
if result then
-- textDocument/definition can return Location or Location[]
if not vim.tbl_islist(result) then
flattened_results = { result }
end
vim.list_extend(flattened_results, result)
end
local offset_encoding = vim.lsp.get_client_by_id(ctx.client_id).offset_encoding
if #flattened_results == 0 then
return
elseif #flattened_results == 1 and opts.jump_type ~= "never" then
if opts.jump_type == "tab" then
vim.cmd "tabedit"
elseif opts.jump_type == "split" then
vim.cmd "new"
elseif opts.jump_type == "vsplit" then
vim.cmd "vnew"
end
vim.lsp.util.jump_to_location(flattened_results[1], offset_encoding)
else
local locations = vim.lsp.util.locations_to_items(flattened_results, offset_encoding)
pickers.new(opts, {
prompt_title = title,
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.generic_sorter(opts),
push_cursor_on_edit = true,
push_tagstack_on_edit = true,
}):find()
end
end)
end
lsp.definitions = function(opts)
return list_or_jump("textDocument/definition", "LSP Definitions", opts)
end
lsp.type_definitions = function(opts)
return list_or_jump("textDocument/typeDefinition", "LSP Type Definitions", opts)
end
lsp.implementations = function(opts)
return list_or_jump("textDocument/implementation", "LSP Implementations", opts)
end
lsp.document_symbols = function(opts)
local params = vim.lsp.util.make_position_params(opts.winnr)
vim.lsp.buf_request(opts.bufnr, "textDocument/documentSymbol", params, function(err, result, _, _)
if err then
vim.api.nvim_err_writeln("Error when finding document symbols: " .. err.message)
return
end
if not result or vim.tbl_isempty(result) then
utils.notify("builtin.lsp_document_symbols", {
msg = "No results from textDocument/documentSymbol",
level = "INFO",
})
return
end
local locations = vim.lsp.util.symbols_to_items(result or {}, opts.bufnr) or {}
locations = utils.filter_symbols(locations, opts)
if locations == nil then
-- error message already printed in `utils.filter_symbols`
return
end
if vim.tbl_isempty(locations) then
utils.notify("builtin.lsp_document_symbols", {
msg = "No document_symbol locations found",
level = "INFO",
})
return
end
opts.path_display = { "hidden" }
pickers.new(opts, {
prompt_title = "LSP Document Symbols",
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.prefilter_sorter {
tag = "symbol_type",
sorter = conf.generic_sorter(opts),
},
push_cursor_on_edit = true,
push_tagstack_on_edit = true,
}):find()
end)
end
lsp.workspace_symbols = function(opts)
local params = { query = opts.query or "" }
vim.lsp.buf_request(opts.bufnr, "workspace/symbol", params, function(err, server_result, _, _)
if err then
vim.api.nvim_err_writeln("Error when finding workspace symbols: " .. err.message)
return
end
local locations = vim.lsp.util.symbols_to_items(server_result or {}, opts.bufnr) or {}
locations = utils.filter_symbols(locations, opts)
if locations == nil then
-- error message already printed in `utils.filter_symbols`
return
end
if vim.tbl_isempty(locations) then
utils.notify("builtin.lsp_workspace_symbols", {
msg = "No results from workspace/symbol. Maybe try a different query: "
.. "'Telescope lsp_workspace_symbols query=example'",
level = "INFO",
})
return
end
opts.ignore_filename = vim.F.if_nil(opts.ignore_filename, false)
pickers.new(opts, {
prompt_title = "LSP Workspace Symbols",
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.prefilter_sorter {
tag = "symbol_type",
sorter = conf.generic_sorter(opts),
},
}):find()
end)
end
local function get_workspace_symbols_requester(bufnr, opts)
local cancel = function() end
return function(prompt)
local tx, rx = channel.oneshot()
cancel()
_, cancel = vim.lsp.buf_request(bufnr, "workspace/symbol", { query = prompt }, tx)
-- Handle 0.5 / 0.5.1 handler situation
local err, res = rx()
assert(not err, err)
local locations = vim.lsp.util.symbols_to_items(res or {}, bufnr) or {}
if not vim.tbl_isempty(locations) then
locations = utils.filter_symbols(locations, opts) or {}
end
return locations
end
end
lsp.dynamic_workspace_symbols = function(opts)
pickers.new(opts, {
prompt_title = "LSP Dynamic Workspace Symbols",
finder = finders.new_dynamic {
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts),
fn = get_workspace_symbols_requester(opts.bufnr, opts),
},
previewer = conf.qflist_previewer(opts),
sorter = sorters.highlighter_only(opts),
attach_mappings = function(_, map)
map("i", "<c-space>", function(prompt_bufnr)
local line = action_state.get_current_line()
require("telescope.actions.generate").refine(prompt_bufnr, {
prompt_title = "LSP Workspace Symbols (" .. line .. ")",
sorter = conf.generic_sorter(opts),
})
end)
return true
end,
}):find()
end
local function check_capabilities(feature, bufnr)
local clients = vim.lsp.buf_get_clients(bufnr)
local supported_client = false
for _, client in pairs(clients) do
supported_client = client.server_capabilities[feature]
if supported_client then
break
end
end
if supported_client then
return true
else
if #clients == 0 then
utils.notify("builtin.lsp_*", {
msg = "no client attached",
level = "INFO",
})
else
utils.notify("builtin.lsp_*", {
msg = "server does not support " .. feature,
level = "INFO",
})
end
return false
end
end
local feature_map = {
["document_symbols"] = "documentSymbolProvider",
["references"] = "referencesProvider",
["definitions"] = "definitionProvider",
["type_definitions"] = "typeDefinitionProvider",
["implementations"] = "implementationProvider",
["workspace_symbols"] = "workspaceSymbolProvider",
["incoming_calls"] = "callHierarchyProvider",
["outgoing_calls"] = "callHierarchyProvider",
}
local function apply_checks(mod)
for k, v in pairs(mod) do
mod[k] = function(opts)
opts = opts or {}
local feature_name = feature_map[k]
if feature_name and not check_capabilities(feature_name, opts.bufnr) then
return
end
v(opts)
end
end
return mod
end
return apply_checks(lsp)

View File

@@ -1,150 +1,17 @@
local conf = require("telescope.config").values
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local pickers = require "telescope.pickers"
local utils = require "telescope.utils"
local diagnostics = {}
local convert_diagnostic_type = function(severities, severity)
-- convert from string to int
if type(severity) == "string" then
-- make sure that e.g. error is uppercased to ERROR
return severities[severity:upper()]
end
-- otherwise keep original value, incl. nil
return severity
end
local diagnostics_to_tbl = function(opts)
opts = vim.F.if_nil(opts, {})
local items = {}
local severities = vim.diagnostic.severity
local current_buf = vim.api.nvim_get_current_buf()
opts.severity = convert_diagnostic_type(severities, opts.severity)
opts.severity_limit = convert_diagnostic_type(severities, opts.severity_limit)
opts.severity_bound = convert_diagnostic_type(severities, opts.severity_bound)
local diagnosis_opts = { severity = {}, namespace = opts.namespace }
if opts.severity ~= nil then
if opts.severity_limit ~= nil or opts.severity_bound ~= nil then
utils.notify("builtin.diagnostics", {
msg = "Invalid severity parameters. Both a specific severity and a limit/bound is not allowed",
level = "ERROR",
})
return {}
end
diagnosis_opts.severity = opts.severity
else
if opts.severity_limit ~= nil then
diagnosis_opts.severity["min"] = opts.severity_limit
end
if opts.severity_bound ~= nil then
diagnosis_opts.severity["max"] = opts.severity_bound
end
end
opts.root_dir = opts.root_dir == true and vim.loop.cwd() or opts.root_dir
local bufnr_name_map = {}
local filter_diag = function(diagnostic)
if bufnr_name_map[diagnostic.bufnr] == nil then
bufnr_name_map[diagnostic.bufnr] = vim.api.nvim_buf_get_name(diagnostic.bufnr)
end
local root_dir_test = not opts.root_dir
or string.sub(bufnr_name_map[diagnostic.bufnr], 1, #opts.root_dir) == opts.root_dir
local listed_test = not opts.no_unlisted or vim.api.nvim_buf_get_option(diagnostic.bufnr, "buflisted")
return root_dir_test and listed_test
end
local preprocess_diag = function(diagnostic)
return {
bufnr = diagnostic.bufnr,
filename = bufnr_name_map[diagnostic.bufnr],
lnum = diagnostic.lnum + 1,
col = diagnostic.col + 1,
text = vim.trim(diagnostic.message:gsub("[\n]", "")),
type = severities[diagnostic.severity] or severities[1],
}
end
for _, d in ipairs(vim.diagnostic.get(opts.bufnr, diagnosis_opts)) do
if filter_diag(d) then
table.insert(items, preprocess_diag(d))
end
end
-- sort results by bufnr (prioritize cur buf), severity, lnum
table.sort(items, function(a, b)
if a.bufnr == b.bufnr then
if a.type == b.type then
return a.lnum < b.lnum
else
return a.type < b.type
end
else
-- prioritize for current bufnr
if a.bufnr == current_buf then
return true
end
if b.bufnr == current_buf then
return false
end
return a.bufnr < b.bufnr
end
end)
return items
end
diagnostics.get = function(opts)
if opts.bufnr ~= 0 then
opts.bufnr = nil
end
if opts.bufnr == nil then
opts.path_display = vim.F.if_nil(opts.path_display, {})
end
if type(opts.bufnr) == "string" then
opts.bufnr = tonumber(opts.bufnr)
end
local locations = diagnostics_to_tbl(opts)
if vim.tbl_isempty(locations) then
utils.notify("builtin.diagnostics", {
msg = "No diagnostics found",
level = "INFO",
local m = setmetatable({}, {
__index = function(_, k)
local utils = require "telescope.utils"
utils.notify("builtin", {
msg = string.format(
'You are using an internal interface. Do not use `require("telescope.builtin.diagnostics").%s`,'
.. ' please use `require("telescope.builtin").diagnostics`! We will remove this endpoint soon!',
k,
k
),
level = "ERROR",
})
return
end
return require("telescope.builtin").diagnostics
end,
})
opts.path_display = vim.F.if_nil(opts.path_display, "hidden")
pickers.new(opts, {
prompt_title = opts.bufnr == nil and "Workspace Diagnostics" or "Document Diagnostics",
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_diagnostics(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.prefilter_sorter {
tag = "type",
sorter = conf.generic_sorter(opts),
},
}):find()
end
local function apply_checks(mod)
for k, v in pairs(mod) do
mod[k] = function(opts)
opts = opts or {}
v(opts)
end
end
return mod
end
return apply_checks(diagnostics)
return m

View File

@@ -1,484 +1,17 @@
local action_state = require "telescope.actions.state"
local action_set = require "telescope.actions.set"
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local pickers = require "telescope.pickers"
local previewers = require "telescope.previewers"
local sorters = require "telescope.sorters"
local utils = require "telescope.utils"
local conf = require("telescope.config").values
local log = require "telescope.log"
local Path = require "plenary.path"
local flatten = vim.tbl_flatten
local filter = vim.tbl_filter
local files = {}
local escape_chars = function(string)
return string.gsub(string, "[%(|%)|\\|%[|%]|%-|%{%}|%?|%+|%*|%^|%$|%.]", {
["\\"] = "\\\\",
["-"] = "\\-",
["("] = "\\(",
[")"] = "\\)",
["["] = "\\[",
["]"] = "\\]",
["{"] = "\\{",
["}"] = "\\}",
["?"] = "\\?",
["+"] = "\\+",
["*"] = "\\*",
["^"] = "\\^",
["$"] = "\\$",
["."] = "\\.",
})
end
-- Special keys:
-- opts.search_dirs -- list of directory to search in
-- opts.grep_open_files -- boolean to restrict search to open files
files.live_grep = function(opts)
local vimgrep_arguments = opts.vimgrep_arguments or conf.vimgrep_arguments
local search_dirs = opts.search_dirs
local grep_open_files = opts.grep_open_files
opts.cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.loop.cwd()
local filelist = {}
if grep_open_files then
local bufnrs = filter(function(b)
if 1 ~= vim.fn.buflisted(b) then
return false
end
return true
end, vim.api.nvim_list_bufs())
if not next(bufnrs) then
return
end
for _, bufnr in ipairs(bufnrs) do
local file = vim.api.nvim_buf_get_name(bufnr)
table.insert(filelist, Path:new(file):make_relative(opts.cwd))
end
elseif search_dirs then
for i, path in ipairs(search_dirs) do
search_dirs[i] = vim.fn.expand(path)
end
end
local additional_args = {}
if opts.additional_args ~= nil and type(opts.additional_args) == "function" then
additional_args = opts.additional_args(opts)
end
if opts.type_filter then
additional_args[#additional_args + 1] = "--type=" .. opts.type_filter
end
if opts.glob_pattern then
additional_args[#additional_args + 1] = "--glob=" .. opts.glob_pattern
end
local live_grepper = finders.new_job(function(prompt)
-- TODO: Probably could add some options for smart case and whatever else rg offers.
if not prompt or prompt == "" then
return nil
end
local search_list = {}
if search_dirs then
table.insert(search_list, search_dirs)
end
if grep_open_files then
search_list = filelist
end
return flatten { vimgrep_arguments, additional_args, "--", prompt, search_list }
end, opts.entry_maker or make_entry.gen_from_vimgrep(opts), opts.max_results, opts.cwd)
pickers.new(opts, {
prompt_title = "Live Grep",
finder = live_grepper,
previewer = conf.grep_previewer(opts),
-- TODO: It would be cool to use `--json` output for this
-- and then we could get the highlight positions directly.
sorter = sorters.highlighter_only(opts),
}):find()
end
-- Special keys:
-- opts.search -- the string to search.
-- opts.search_dirs -- list of directory to search in
-- opts.use_regex -- special characters won't be escaped
files.grep_string = function(opts)
-- TODO: This should probably check your visual selection as well, if you've got one
local vimgrep_arguments = opts.vimgrep_arguments or conf.vimgrep_arguments
local search_dirs = opts.search_dirs
local word = opts.search or vim.fn.expand "<cword>"
local search = opts.use_regex and word or escape_chars(word)
local word_match = opts.word_match
opts.entry_maker = opts.entry_maker or make_entry.gen_from_vimgrep(opts)
local title_word = word:gsub("\n", "\\n")
local additional_args = {}
if opts.additional_args ~= nil and type(opts.additional_args) == "function" then
additional_args = opts.additional_args(opts)
end
local args = flatten {
vimgrep_arguments,
additional_args,
word_match,
"--",
search,
}
if search_dirs then
for _, path in ipairs(search_dirs) do
table.insert(args, vim.fn.expand(path))
end
end
pickers.new(opts, {
prompt_title = "Find Word (" .. title_word .. ")",
finder = finders.new_oneshot_job(args, opts),
previewer = conf.grep_previewer(opts),
sorter = conf.generic_sorter(opts),
}):find()
end
-- TODO: Maybe just change this to `find`.
-- TODO: Support `find` and maybe let people do other stuff with it as well.
files.find_files = function(opts)
local find_command = (function()
if opts.find_command then
return opts.find_command
elseif 1 == vim.fn.executable "fd" then
return { "fd", "--type", "f" }
elseif 1 == vim.fn.executable "fdfind" then
return { "fdfind", "--type", "f" }
elseif 1 == vim.fn.executable "rg" then
return { "rg", "--files" }
elseif 1 == vim.fn.executable "find" and vim.fn.has "win32" == 0 then
return { "find", ".", "-type", "f" }
elseif 1 == vim.fn.executable "where" then
return { "where", "/r", ".", "*" }
end
end)()
if not find_command then
utils.notify("builtin.find_files", {
msg = "You need to install either find, fd, or rg",
local m = setmetatable({}, {
__index = function(_, k)
local utils = require "telescope.utils"
utils.notify("builtin", {
msg = string.format(
'You are using an internal interface. Do not use `require("telescope.builtin.files").%s`,'
.. ' please use `require("telescope.builtin").%s`! We will remove this endpoint soon!',
k,
k
),
level = "ERROR",
})
return
end
return require("telescope.builtin")[k]
end,
})
local command = find_command[1]
local hidden = opts.hidden
local no_ignore = opts.no_ignore
local follow = opts.follow
local search_dirs = opts.search_dirs
if search_dirs then
for k, v in pairs(search_dirs) do
search_dirs[k] = vim.fn.expand(v)
end
end
if command == "fd" or command == "fdfind" or command == "rg" then
if hidden then
table.insert(find_command, "--hidden")
end
if no_ignore then
table.insert(find_command, "--no-ignore")
end
if follow then
table.insert(find_command, "-L")
end
if search_dirs then
if command ~= "rg" then
table.insert(find_command, ".")
end
for _, v in pairs(search_dirs) do
table.insert(find_command, v)
end
end
elseif command == "find" then
if not hidden then
table.insert(find_command, { "-not", "-path", "*/.*" })
find_command = flatten(find_command)
end
if no_ignore ~= nil then
log.warn "The `no_ignore` key is not available for the `find` command in `find_files`."
end
if follow then
table.insert(find_command, 2, "-L")
end
if search_dirs then
table.remove(find_command, 2)
for _, v in pairs(search_dirs) do
table.insert(find_command, 2, v)
end
end
elseif command == "where" then
if hidden ~= nil then
log.warn "The `hidden` key is not available for the Windows `where` command in `find_files`."
end
if no_ignore ~= nil then
log.warn "The `no_ignore` key is not available for the Windows `where` command in `find_files`."
end
if follow ~= nil then
log.warn "The `follow` key is not available for the Windows `where` command in `find_files`."
end
if search_dirs ~= nil then
log.warn "The `search_dirs` key is not available for the Windows `where` command in `find_files`."
end
end
if opts.cwd then
opts.cwd = vim.fn.expand(opts.cwd)
end
opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts)
pickers.new(opts, {
prompt_title = "Find Files",
finder = finders.new_oneshot_job(find_command, opts),
previewer = conf.file_previewer(opts),
sorter = conf.file_sorter(opts),
}):find()
end
local function prepare_match(entry, kind)
local entries = {}
if entry.node then
table.insert(entries, entry)
else
for name, item in pairs(entry) do
vim.list_extend(entries, prepare_match(item, name))
end
end
return entries
end
-- TODO: finish docs for opts.show_line
files.treesitter = function(opts)
opts.show_line = utils.get_default(opts.show_line, true)
local has_nvim_treesitter, _ = pcall(require, "nvim-treesitter")
if not has_nvim_treesitter then
utils.notify("builtin.treesitter", {
msg = "User need to install nvim-treesitter needs to be installed",
level = "ERROR",
})
return
end
local parsers = require "nvim-treesitter.parsers"
if not parsers.has_parser(parsers.get_buf_lang(opts.bufnr)) then
utils.notify("builtin.treesitter", {
msg = "No parser for the current buffer",
level = "ERROR",
})
return
end
local ts_locals = require "nvim-treesitter.locals"
local results = {}
for _, definition in ipairs(ts_locals.get_definitions(opts.bufnr)) do
local entries = prepare_match(ts_locals.get_local_nodes(definition))
for _, entry in ipairs(entries) do
entry.kind = vim.F.if_nil(entry.kind, "")
table.insert(results, entry)
end
end
if vim.tbl_isempty(results) then
return
end
pickers.new(opts, {
prompt_title = "Treesitter Symbols",
finder = finders.new_table {
results = results,
entry_maker = opts.entry_maker or make_entry.gen_from_treesitter(opts),
},
previewer = conf.grep_previewer(opts),
sorter = conf.prefilter_sorter {
tag = "kind",
sorter = conf.generic_sorter(opts),
},
}):find()
end
files.current_buffer_fuzzy_find = function(opts)
-- All actions are on the current buffer
local filename = vim.fn.expand(vim.api.nvim_buf_get_name(opts.bufnr))
local filetype = vim.api.nvim_buf_get_option(opts.bufnr, "filetype")
local lines = vim.api.nvim_buf_get_lines(opts.bufnr, 0, -1, false)
local lines_with_numbers = {}
for lnum, line in ipairs(lines) do
table.insert(lines_with_numbers, {
lnum = lnum,
bufnr = opts.bufnr,
filename = filename,
text = line,
})
end
local ts_ok, ts_parsers = pcall(require, "nvim-treesitter.parsers")
if ts_ok then
filetype = ts_parsers.ft_to_lang(filetype)
end
local _, ts_configs = pcall(require, "nvim-treesitter.configs")
local parser_ok, parser = pcall(vim.treesitter.get_parser, opts.bufnr, filetype)
local query_ok, query = pcall(vim.treesitter.get_query, filetype, "highlights")
if parser_ok and query_ok and ts_ok and ts_configs.is_enabled("highlight", filetype, opts.bufnr) then
local root = parser:parse()[1]:root()
local highlighter = vim.treesitter.highlighter.new(parser)
local highlighter_query = highlighter:get_query(filetype)
local line_highlights = setmetatable({}, {
__index = function(t, k)
local obj = {}
rawset(t, k, obj)
return obj
end,
})
for id, node in query:iter_captures(root, opts.bufnr, 0, -1) do
local hl = highlighter_query:_get_hl_from_capture(id)
if hl and type(hl) ~= "number" then
local row1, col1, row2, col2 = node:range()
if row1 == row2 then
local row = row1 + 1
for index = col1, col2 do
line_highlights[row][index] = hl
end
else
local row = row1 + 1
for index = col1, #lines[row] do
line_highlights[row][index] = hl
end
while row < row2 + 1 do
row = row + 1
for index = 0, #(lines[row] or {}) do
line_highlights[row][index] = hl
end
end
end
end
end
opts.line_highlights = line_highlights
end
pickers.new(opts, {
prompt_title = "Current Buffer Fuzzy",
finder = finders.new_table {
results = lines_with_numbers,
entry_maker = opts.entry_maker or make_entry.gen_from_buffer_lines(opts),
},
sorter = conf.generic_sorter(opts),
previewer = conf.grep_previewer(opts),
attach_mappings = function()
action_set.select:enhance {
post = function()
local selection = action_state.get_selected_entry()
vim.api.nvim_win_set_cursor(0, { selection.lnum, 0 })
end,
}
return true
end,
}):find()
end
files.tags = function(opts)
local tagfiles = opts.ctags_file and { opts.ctags_file } or vim.fn.tagfiles()
if vim.tbl_isempty(tagfiles) then
utils.notify("builtin.tags", {
msg = "No tags file found. Create one with ctags -R",
level = "ERROR",
})
return
end
local results = {}
for _, ctags_file in ipairs(tagfiles) do
for line in Path:new(vim.fn.expand(ctags_file, true)):iter() do
results[#results + 1] = line
end
end
pickers.new(opts, {
prompt_title = "Tags",
finder = finders.new_table {
results = results,
entry_maker = opts.entry_maker or make_entry.gen_from_ctags(opts),
},
previewer = previewers.ctags.new(opts),
sorter = conf.generic_sorter(opts),
attach_mappings = function()
action_set.select:enhance {
post = function()
local selection = action_state.get_selected_entry()
if selection.scode then
-- un-escape / then escape required
-- special chars for vim.fn.search()
-- ] ~ *
local scode = selection.scode:gsub([[\/]], "/"):gsub("[%]~*]", function(x)
return "\\" .. x
end)
vim.cmd "norm! gg"
vim.fn.search(scode)
vim.cmd "norm! zz"
else
vim.api.nvim_win_set_cursor(0, { selection.lnum, 0 })
end
end,
}
return true
end,
}):find()
end
files.current_buffer_tags = function(opts)
return files.tags(vim.tbl_extend("force", {
prompt_title = "Current Buffer Tags",
only_current_file = true,
path_display = "hidden",
}, opts))
end
local function apply_checks(mod)
for k, v in pairs(mod) do
mod[k] = function(opts)
opts = opts or {}
v(opts)
end
end
return mod
end
return apply_checks(files)
return m

View File

@@ -1,408 +1,17 @@
local actions = require "telescope.actions"
local action_state = require "telescope.actions.state"
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local pickers = require "telescope.pickers"
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
local git = {}
git.files = function(opts)
if opts.is_bare then
utils.notify("builtin.git_files", {
msg = "This operation must be run in a work tree",
local m = setmetatable({}, {
__index = function(_, k)
local utils = require "telescope.utils"
utils.notify("builtin", {
msg = string.format(
'You are using an internal interface. Do not use `require("telescope.builtin.git").%s`,'
.. ' please use `require("telescope.builtin").git_%s`! We will remove this endpoint soon!',
k,
k
),
level = "ERROR",
})
return
end
return require("telescope.builtin")["git_" .. k]
end,
})
local show_untracked = utils.get_default(opts.show_untracked, true)
local recurse_submodules = utils.get_default(opts.recurse_submodules, false)
if show_untracked and recurse_submodules then
utils.notify("builtin.git_files", {
msg = "Git does not support both --others and --recurse-submodules",
level = "ERROR",
})
return
end
-- By creating the entry maker after the cwd options,
-- we ensure the maker uses the cwd options when being created.
opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_file(opts))
local git_command = vim.F.if_nil(opts.git_command, { "git", "ls-files", "--exclude-standard", "--cached" })
pickers.new(opts, {
prompt_title = "Git Files",
finder = finders.new_oneshot_job(
vim.tbl_flatten {
git_command,
show_untracked and "--others" or nil,
recurse_submodules and "--recurse-submodules" or nil,
},
opts
),
previewer = conf.file_previewer(opts),
sorter = conf.file_sorter(opts),
}):find()
end
git.commits = function(opts)
opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_git_commits(opts))
local git_command = vim.F.if_nil(opts.git_command, { "git", "log", "--pretty=oneline", "--abbrev-commit", "--", "." })
pickers.new(opts, {
prompt_title = "Git Commits",
finder = finders.new_oneshot_job(git_command, 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(_, map)
actions.select_default:replace(actions.git_checkout)
map("i", "<c-r>m", actions.git_reset_mixed)
map("n", "<c-r>m", actions.git_reset_mixed)
map("i", "<c-r>s", actions.git_reset_soft)
map("n", "<c-r>s", actions.git_reset_soft)
map("i", "<c-r>h", actions.git_reset_hard)
map("n", "<c-r>h", actions.git_reset_hard)
return true
end,
}):find()
end
git.stash = function(opts)
opts.show_branch = vim.F.if_nil(opts.show_branch, true)
opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_git_stash(opts))
pickers.new(opts, {
prompt_title = "Git Stash",
finder = finders.new_oneshot_job(
vim.tbl_flatten {
"git",
"--no-pager",
"stash",
"list",
},
opts
),
previewer = previewers.git_stash_diff.new(opts),
sorter = conf.file_sorter(opts),
attach_mappings = function()
actions.select_default:replace(actions.git_apply_stash)
return true
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 = (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))
local git_command = vim.F.if_nil(opts.git_command, { "git", "log", "--pretty=oneline", "--abbrev-commit" })
pickers.new(opts, {
prompt_title = "Git BCommits",
finder = finders.new_oneshot_job(
vim.tbl_flatten {
git_command,
opts.current_file,
},
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_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.api.nvim_create_autocmd("WinClosed", {
buffer = bufnr,
nested = true,
once = true,
callback = function()
vim.api.nvim_buf_delete(bufnr, { force = true })
end,
})
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()
end
git.branches = function(opts)
local format = "%(HEAD)"
.. "%(refname)"
.. "%(authorname)"
.. "%(upstream:lstrip=2)"
.. "%(committerdate:format-local:%Y/%m/%d %H:%M:%S)"
local output = utils.get_os_command_output(
{ "git", "for-each-ref", "--perl", "--format", format, opts.pattern },
opts.cwd
)
local results = {}
local widths = {
name = 0,
authorname = 0,
upstream = 0,
committerdate = 0,
}
local unescape_single_quote = function(v)
return string.gsub(v, "\\([\\'])", "%1")
end
local parse_line = function(line)
local fields = vim.split(string.sub(line, 2, -2), "''", true)
local entry = {
head = fields[1],
refname = unescape_single_quote(fields[2]),
authorname = unescape_single_quote(fields[3]),
upstream = unescape_single_quote(fields[4]),
committerdate = fields[5],
}
local prefix
if vim.startswith(entry.refname, "refs/remotes/") then
prefix = "refs/remotes/"
elseif vim.startswith(entry.refname, "refs/heads/") then
prefix = "refs/heads/"
else
return
end
local index = 1
if entry.head ~= "*" then
index = #results + 1
end
entry.name = string.sub(entry.refname, string.len(prefix) + 1)
for key, value in pairs(widths) do
widths[key] = math.max(value, strings.strdisplaywidth(entry[key] or ""))
end
if string.len(entry.upstream) > 0 then
widths.upstream_indicator = 2
end
table.insert(results, index, entry)
end
for _, line in ipairs(output) do
parse_line(line)
end
if #results == 0 then
return
end
local displayer = entry_display.create {
separator = " ",
items = {
{ width = 1 },
{ width = widths.name },
{ width = widths.authorname },
{ width = widths.upstream_indicator },
{ width = widths.upstream },
{ width = widths.committerdate },
},
}
local make_display = function(entry)
return displayer {
{ entry.head },
{ entry.name, "TelescopeResultsIdentifier" },
{ entry.authorname },
{ string.len(entry.upstream) > 0 and "=>" or "" },
{ entry.upstream, "TelescopeResultsIdentifier" },
{ entry.committerdate },
}
end
pickers.new(opts, {
prompt_title = "Git Branches",
finder = finders.new_table {
results = results,
entry_maker = function(entry)
entry.value = entry.name
entry.ordinal = entry.name
entry.display = make_display
return entry
end,
},
previewer = previewers.git_branch_log.new(opts),
sorter = conf.file_sorter(opts),
attach_mappings = function(_, map)
actions.select_default:replace(actions.git_checkout)
map("i", "<c-t>", actions.git_track_branch)
map("n", "<c-t>", actions.git_track_branch)
map("i", "<c-r>", actions.git_rebase_branch)
map("n", "<c-r>", actions.git_rebase_branch)
map("i", "<c-a>", actions.git_create_branch)
map("n", "<c-a>", actions.git_create_branch)
map("i", "<c-s>", actions.git_switch_branch)
map("n", "<c-s>", actions.git_switch_branch)
map("i", "<c-d>", actions.git_delete_branch)
map("n", "<c-d>", actions.git_delete_branch)
map("i", "<c-y>", actions.git_merge_branch)
map("n", "<c-y>", actions.git_merge_branch)
return true
end,
}):find()
end
git.status = function(opts)
if opts.is_bare then
utils.notify("builtin.git_status", {
msg = "This operation must be run in a work tree",
level = "ERROR",
})
return
end
local gen_new_finder = function()
local expand_dir = utils.if_nil(opts.expand_dir, true, opts.expand_dir)
local git_cmd = { "git", "status", "-s", "--", "." }
if expand_dir then
table.insert(git_cmd, #git_cmd - 1, "-u")
end
local output = utils.get_os_command_output(git_cmd, opts.cwd)
if #output == 0 then
print "No changes found"
utils.notify("builtin.git_status", {
msg = "No changes found",
level = "WARN",
})
return
end
return finders.new_table {
results = output,
entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_git_status(opts)),
}
end
local initial_finder = gen_new_finder()
if not initial_finder then
return
end
pickers.new(opts, {
prompt_title = "Git Status",
finder = initial_finder,
previewer = previewers.git_file_diff.new(opts),
sorter = conf.file_sorter(opts),
attach_mappings = function(prompt_bufnr, map)
actions.git_staging_toggle:enhance {
post = function()
action_state.get_current_picker(prompt_bufnr):refresh(gen_new_finder(), { reset_prompt = true })
end,
}
map("i", "<tab>", actions.git_staging_toggle)
map("n", "<tab>", actions.git_staging_toggle)
return true
end,
}):find()
end
local set_opts_cwd = function(opts)
if opts.cwd then
opts.cwd = vim.fn.expand(opts.cwd)
else
opts.cwd = vim.loop.cwd()
end
-- Find root of git directory and remove trailing newline characters
local git_root, ret = utils.get_os_command_output({ "git", "rev-parse", "--show-toplevel" }, opts.cwd)
local use_git_root = utils.get_default(opts.use_git_root, true)
if ret ~= 0 then
local in_worktree = utils.get_os_command_output({ "git", "rev-parse", "--is-inside-work-tree" }, opts.cwd)
local in_bare = utils.get_os_command_output({ "git", "rev-parse", "--is-bare-repository" }, opts.cwd)
if in_worktree[1] ~= "true" and in_bare[1] ~= "true" then
error(opts.cwd .. " is not a git directory")
elseif in_worktree[1] ~= "true" and in_bare[1] == "true" then
opts.is_bare = true
end
else
if use_git_root then
opts.cwd = git_root[1]
end
end
end
local function apply_checks(mod)
for k, v in pairs(mod) do
mod[k] = function(opts)
opts = vim.F.if_nil(opts, {})
set_opts_cwd(opts)
v(opts)
end
end
return mod
end
return apply_checks(git)
return m

View File

@@ -54,35 +54,37 @@ end
---@param opts table: options to pass to the picker
---@field cwd string: root dir to search from (default: cwd, use utils.buffer_dir() to search relative to open buffer)
---@field grep_open_files boolean: if true, restrict search to open files only, mutually exclusive with `search_dirs`
---@field search_dirs table: directory/directories to search in, mutually exclusive with `grep_open_files`
---@field glob_pattern string: argument to be used with `--glob`, e.g. "*.toml", can use the opposite "!*.toml"
---@field search_dirs table: directory/directories/files to search, mutually exclusive with `grep_open_files`
---@field glob_pattern string|table: argument to be used with `--glob`, e.g. "*.toml", can use the opposite "!*.toml"
---@field type_filter string: argument to be used with `--type`, e.g. "rust", see `rg --type-list`
---@field additional_args function: function(opts) which returns a table of additional arguments to be passed on
---@field max_results number: define a upper result value
---@field disable_coordinates boolean: don't show the line & row numbers (default: false)
builtin.live_grep = require_on_exported_call("telescope.builtin.files").live_grep
builtin.live_grep = require_on_exported_call("telescope.builtin.__files").live_grep
--- Searches for the string under your cursor in your current working directory
---@param opts table: options to pass to the picker
---@field cwd string: root dir to search from (default: cwd, use utils.buffer_dir() to search relative to open buffer)
---@field search string: the query to search
---@field search_dirs table: directory/directories to search in
---@field search_dirs table: directory/directories/files to search
---@field use_regex boolean: if true, special characters won't be escaped, allows for using regex (default: false)
---@field word_match string: can be set to `-w` to enable exact word matches
---@field additional_args function: function(opts) which returns a table of additional arguments to be passed on
---@field disable_coordinates boolean: don't show the line and row numbers (default: false)
---@field only_sort_text boolean: only sort the text, not the file, line or row (default: false)
builtin.grep_string = require_on_exported_call("telescope.builtin.files").grep_string
builtin.grep_string = require_on_exported_call("telescope.builtin.__files").grep_string
--- Search for files (respecting .gitignore)
---@param opts table: options to pass to the picker
---@field cwd string: root dir to search from (default: cwd, use utils.buffer_dir() to search relative to open buffer)
---@field find_command table: command line arguments for `find_files` to use for the search, overrides default: config
---@field find_command function|table: cmd to use for the search. Can be a fn(opts) -> tbl (default: autodetect)
---@field follow boolean: if true, follows symlinks (i.e. uses `-L` flag for the `find` command)
---@field hidden boolean: determines whether to show hidden files or not (default: false)
---@field no_ignore boolean: show files ignored by .gitignore, .ignore, etc. (default: false)
---@field search_dirs table: directory/directories to search in
builtin.find_files = require_on_exported_call("telescope.builtin.files").find_files
---@field no_ignore_parent boolean: show files ignored by .gitignore, .ignore, etc. in parent dirs. (default: false)
---@field search_dirs table: directory/directories/files to search
---@field search_file string: specify a filename to search for
builtin.find_files = require_on_exported_call("telescope.builtin.__files").find_files
--- This is an alias for the `find_files` picker
builtin.fd = builtin.find_files
@@ -93,12 +95,12 @@ builtin.fd = builtin.find_files
---@field show_line boolean: if true, shows the row:column that the result is found at (default: true)
---@field bufnr number: specify the buffer number where treesitter should run. (default: current buffer)
---@field symbol_highlights table: string -> string. Matches symbol with hl_group
builtin.treesitter = require_on_exported_call("telescope.builtin.files").treesitter
builtin.treesitter = require_on_exported_call("telescope.builtin.__files").treesitter
--- Live fuzzy search inside of the currently open buffer
---@param opts table: options to pass to the picker
---@field skip_empty_lines boolean: if true we dont display empty lines (default: false)
builtin.current_buffer_fuzzy_find = require_on_exported_call("telescope.builtin.files").current_buffer_fuzzy_find
builtin.current_buffer_fuzzy_find = require_on_exported_call("telescope.builtin.__files").current_buffer_fuzzy_find
--- Lists tags in current directory with tag location file preview (users are required to run ctags -R to generate tags
--- or update when introducing new changes)
@@ -108,7 +110,7 @@ builtin.current_buffer_fuzzy_find = require_on_exported_call("telescope.builtin.
---@field show_line boolean: if true, shows the content of the line the tag is found on in the picker (default: true)
---@field only_sort_tags boolean: if true we will only sort tags (default: false)
---@field fname_width number: defines the width of the filename section (default: 30)
builtin.tags = require_on_exported_call("telescope.builtin.files").tags
builtin.tags = require_on_exported_call("telescope.builtin.__files").tags
--- Lists all of the tags for the currently open buffer, with a preview
---@param opts table: options to pass to the picker
@@ -117,7 +119,7 @@ builtin.tags = require_on_exported_call("telescope.builtin.files").tags
---@field show_line boolean: if true, shows the content of the line the tag is found on in the picker (default: true)
---@field only_sort_tags boolean: if true we will only sort tags (default: false)
---@field fname_width number: defines the width of the filename section (default: 30)
builtin.current_buffer_tags = require_on_exported_call("telescope.builtin.files").current_buffer_tags
builtin.current_buffer_tags = require_on_exported_call("telescope.builtin.__files").current_buffer_tags
--
--
@@ -132,10 +134,10 @@ builtin.current_buffer_tags = require_on_exported_call("telescope.builtin.files"
---@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 show_untracked boolean: if true, adds `--others` flag to command and shows untracked files (default: true)
---@field show_untracked boolean: if true, adds `--others` flag to command and shows untracked files (default: false)
---@field recurse_submodules boolean: if true, adds the `--recurse-submodules` flag to command (default: false)
---@field git_command table: command that will be exectued. {"git","ls-files","--exclude-standard","--cached"}
builtin.git_files = require_on_exported_call("telescope.builtin.git").files
builtin.git_files = require_on_exported_call("telescope.builtin.__git").files
--- Lists commits for current directory with diff preview
--- - Default keymaps:
@@ -147,7 +149,7 @@ builtin.git_files = require_on_exported_call("telescope.builtin.git").files
---@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 git_command table: command that will be exectued. {"git","log","--pretty=oneline","--abbrev-commit","--","."}
builtin.git_commits = require_on_exported_call("telescope.builtin.git").commits
builtin.git_commits = require_on_exported_call("telescope.builtin.__git").commits
--- Lists commits for current buffer with diff preview
--- - Default keymaps or your overriden `select_` keys:
@@ -160,7 +162,7 @@ builtin.git_commits = require_on_exported_call("telescope.builtin.git").commits
---@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 exectued. {"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
--- List branches for current directory, with output from `git log --oneline` shown in the preview window
--- - Default keymaps:
@@ -174,7 +176,7 @@ builtin.git_bcommits = require_on_exported_call("telescope.builtin.git").bcommit
---@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 pattern string: specify the pattern to match all refs
builtin.git_branches = require_on_exported_call("telescope.builtin.git").branches
builtin.git_branches = require_on_exported_call("telescope.builtin.__git").branches
--- Lists git status for current directory
--- - Default keymaps:
@@ -184,7 +186,7 @@ builtin.git_branches = require_on_exported_call("telescope.builtin.git").branche
---@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 git_icons table: string -> string. Matches name with icon (see source code, make_entry.lua git_icon_defaults)
builtin.git_status = require_on_exported_call("telescope.builtin.git").status
builtin.git_status = require_on_exported_call("telescope.builtin.__git").status
--- Lists stash items in current repository
--- - Default keymaps:
@@ -193,7 +195,7 @@ builtin.git_status = require_on_exported_call("telescope.builtin.git").status
---@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 show_branch boolean: if we should display the branch name for git stash entries (default: true)
builtin.git_stash = require_on_exported_call("telescope.builtin.git").stash
builtin.git_stash = require_on_exported_call("telescope.builtin.__git").stash
--
--
@@ -204,14 +206,15 @@ builtin.git_stash = require_on_exported_call("telescope.builtin.git").stash
--- Lists all of the community maintained pickers built into Telescope
---@param opts table: options to pass to the picker
---@field include_extensions boolean: if true will show the pickers of the installed extensions (default: false)
builtin.builtin = require_on_exported_call("telescope.builtin.internal").builtin
---@field use_default_opts boolean: if the selected picker should use its default options (default: false)
builtin.builtin = require_on_exported_call("telescope.builtin.__internal").builtin
--- Opens the previous picker in the identical state (incl. multi selections)
--- - Notes:
--- - Requires `cache_picker` in setup or when having invoked pickers, see |telescope.defaults.cache_picker|
---@param opts table: options to pass to the picker
---@field cache_index number: what picker to resume, where 1 denotes most recent (default: 1)
builtin.resume = require_on_exported_call("telescope.builtin.internal").resume
builtin.resume = require_on_exported_call("telescope.builtin.__internal").resume
--- Opens a picker over previously cached pickers in their preserved states (incl. multi selections)
--- - Default keymaps:
@@ -219,12 +222,12 @@ builtin.resume = require_on_exported_call("telescope.builtin.internal").resume
--- - Notes:
--- - Requires `cache_picker` in setup or when having invoked pickers, see |telescope.defaults.cache_picker|
---@param opts table: options to pass to the picker
builtin.pickers = require_on_exported_call("telescope.builtin.internal").pickers
builtin.pickers = require_on_exported_call("telescope.builtin.__internal").pickers
--- Use the telescope...
---@param opts table: options to pass to the picker
---@field show_pluto boolean: we love pluto (default: false, because its a hidden feature)
builtin.planets = require_on_exported_call("telescope.builtin.internal").planets
builtin.planets = require_on_exported_call("telescope.builtin.__internal").planets
--- Lists symbols inside of `data/telescope-sources/*.json` found in your runtime path
--- or found in `stdpath("data")/telescope/symbols/*.json`. The second path can be customized.
@@ -234,69 +237,71 @@ builtin.planets = require_on_exported_call("telescope.builtin.internal").planets
---@param opts table: options to pass to the picker
---@field symbol_path string: specify the second path. Default: `stdpath("data")/telescope/symbols/*.json`
---@field sources table: specify a table of sources you want to load this time
builtin.symbols = require_on_exported_call("telescope.builtin.internal").symbols
builtin.symbols = require_on_exported_call("telescope.builtin.__internal").symbols
--- Lists available plugin/user commands and runs them on `<cr>`
---@param opts table: options to pass to the picker
---@field show_buf_command boolean: show buf local command (Default: true)
builtin.commands = require_on_exported_call("telescope.builtin.internal").commands
builtin.commands = require_on_exported_call("telescope.builtin.__internal").commands
--- Lists items in the quickfix list, jumps to location on `<cr>`
---@param opts table: options to pass to the picker
---@field ignore_filename boolean: dont show filenames (default: true)
---@field show_line boolean: show results text (default: true)
---@field trim_text boolean: trim results text (default: false)
---@field fname_width number: defines the width of the filename section (default: 30)
---@field nr number: specify the quickfix list number
builtin.quickfix = require_on_exported_call("telescope.builtin.internal").quickfix
builtin.quickfix = require_on_exported_call("telescope.builtin.__internal").quickfix
--- Lists all quickfix lists in your history and open them with `builtin.quickfix`. It seems that neovim
--- only keeps the full history for 10 lists
---@param opts table: options to pass to the picker
builtin.quickfixhistory = require_on_exported_call("telescope.builtin.internal").quickfixhistory
builtin.quickfixhistory = require_on_exported_call("telescope.builtin.__internal").quickfixhistory
--- Lists items from the current window's location list, jumps to location on `<cr>`
---@param opts table: options to pass to the picker
---@field ignore_filename boolean: dont show filenames (default: true)
---@field show_line boolean: show results text (default: true)
---@field trim_text boolean: trim results text (default: false)
builtin.loclist = require_on_exported_call("telescope.builtin.internal").loclist
---@field fname_width number: defines the width of the filename section (default: 30)
builtin.loclist = require_on_exported_call("telescope.builtin.__internal").loclist
--- Lists previously open files, opens on `<cr>`
---@param opts table: options to pass to the picker
---@field only_cwd boolean: show only files in the cwd (default: false)
---@field cwd_only boolean: alias for only_cwd
builtin.oldfiles = require_on_exported_call("telescope.builtin.internal").oldfiles
builtin.oldfiles = require_on_exported_call("telescope.builtin.__internal").oldfiles
--- Lists commands that were executed recently, and reruns them on `<cr>`
--- - Default keymaps:
--- - `<C-e>`: open the command line with the text of the currently selected result populated in it
---@param opts table: options to pass to the picker
builtin.command_history = require_on_exported_call("telescope.builtin.internal").command_history
builtin.command_history = require_on_exported_call("telescope.builtin.__internal").command_history
--- Lists searches that were executed recently, and reruns them on `<cr>`
--- - Default keymaps:
--- - `<C-e>`: open a search window with the text of the currently selected search result populated in it
---@param opts table: options to pass to the picker
builtin.search_history = require_on_exported_call("telescope.builtin.internal").search_history
builtin.search_history = require_on_exported_call("telescope.builtin.__internal").search_history
--- Lists vim options, allows you to edit the current value on `<cr>`
---@param opts table: options to pass to the picker
builtin.vim_options = require_on_exported_call("telescope.builtin.internal").vim_options
builtin.vim_options = require_on_exported_call("telescope.builtin.__internal").vim_options
--- Lists available help tags and opens a new window with the relevant help info on `<cr>`
---@param opts table: options to pass to the picker
---@field lang string: specify language (default: vim.o.helplang)
---@field fallback boolean: fallback to en if language isn't installed (default: true)
builtin.help_tags = require_on_exported_call("telescope.builtin.internal").help_tags
builtin.help_tags = require_on_exported_call("telescope.builtin.__internal").help_tags
--- Lists manpage entries, opens them in a help window on `<cr>`
---@param opts table: options to pass to the picker
---@field sections table: a list of sections to search, use `{ "ALL" }` to search in all sections (default: { "1" })
---@field man_cmd function: that returns the man command. (Default: `apropos ""` on linux, `apropos " "` on macos)
builtin.man_pages = require_on_exported_call("telescope.builtin.internal").man_pages
builtin.man_pages = require_on_exported_call("telescope.builtin.__internal").man_pages
--- Lists lua modules and reloads them on `<cr>`
---@param opts table: options to pass to the picker
---@field column_len number: define the max column len for the module name (default: dynamic, longest module name)
builtin.reloader = require_on_exported_call("telescope.builtin.internal").reloader
builtin.reloader = require_on_exported_call("telescope.builtin.__internal").reloader
--- Lists open buffers in current neovim instance, opens selected buffer on `<cr>`
---@param opts table: options to pass to the picker
@@ -307,56 +312,58 @@ builtin.reloader = require_on_exported_call("telescope.builtin.internal").reload
---@field sort_lastused boolean: Sorts current and last buffer to the top and selects the lastused (default: false)
---@field sort_mru boolean: Sorts all buffers after most recent used. Not just the current and last one (default: false)
---@field bufnr_width number: Defines the width of the buffer numbers in front of the filenames (default: dynamic)
builtin.buffers = require_on_exported_call("telescope.builtin.internal").buffers
builtin.buffers = require_on_exported_call("telescope.builtin.__internal").buffers
--- Lists available colorschemes and applies them on `<cr>`
---@param opts table: options to pass to the picker
---@field enable_preview boolean: if true, will preview the selected color
builtin.colorscheme = require_on_exported_call("telescope.builtin.internal").colorscheme
builtin.colorscheme = require_on_exported_call("telescope.builtin.__internal").colorscheme
--- Lists vim marks and their value, jumps to the mark on `<cr>`
---@param opts table: options to pass to the picker
builtin.marks = require_on_exported_call("telescope.builtin.internal").marks
builtin.marks = require_on_exported_call("telescope.builtin.__internal").marks
--- Lists vim registers, pastes the contents of the register on `<cr>`
--- - Default keymaps:
--- - `<C-e>`: edit the contents of the currently selected register
---@param opts table: options to pass to the picker
builtin.registers = require_on_exported_call("telescope.builtin.internal").registers
builtin.registers = require_on_exported_call("telescope.builtin.__internal").registers
--- Lists normal mode keymappings, runs the selected keymap on `<cr>`
---@param opts table: options to pass to the picker
---@field modes table: a list of short-named keymap modes to search (default: { "n", "i", "c", "x" })
---@field show_plug boolean: if true, the keymaps for which the lhs contains "<Plug>" are also shown (default: true)
builtin.keymaps = require_on_exported_call("telescope.builtin.internal").keymaps
builtin.keymaps = require_on_exported_call("telescope.builtin.__internal").keymaps
--- Lists all available filetypes, sets currently open buffer's filetype to selected filetype in Telescope on `<cr>`
---@param opts table: options to pass to the picker
builtin.filetypes = require_on_exported_call("telescope.builtin.internal").filetypes
builtin.filetypes = require_on_exported_call("telescope.builtin.__internal").filetypes
--- Lists all available highlights
---@param opts table: options to pass to the picker
builtin.highlights = require_on_exported_call("telescope.builtin.internal").highlights
builtin.highlights = require_on_exported_call("telescope.builtin.__internal").highlights
--- Lists vim autocommands and goes to their declaration on `<cr>`
---@param opts table: options to pass to the picker
builtin.autocommands = require_on_exported_call("telescope.builtin.internal").autocommands
builtin.autocommands = require_on_exported_call("telescope.builtin.__internal").autocommands
--- Lists spelling suggestions for the current word under the cursor, replaces word with selected suggestion on `<cr>`
---@param opts table: options to pass to the picker
builtin.spell_suggest = require_on_exported_call("telescope.builtin.internal").spell_suggest
builtin.spell_suggest = require_on_exported_call("telescope.builtin.__internal").spell_suggest
--- Lists the tag stack for the current window, jumps to tag on `<cr>`
---@param opts table: options to pass to the picker
---@field ignore_filename boolean: dont show filenames (default: true)
---@field show_line boolean: show results text (default: true)
---@field trim_text boolean: trim results text (default: false)
builtin.tagstack = require_on_exported_call("telescope.builtin.internal").tagstack
---@field fname_width number: defines the width of the filename section (default: 30)
builtin.tagstack = require_on_exported_call("telescope.builtin.__internal").tagstack
--- Lists items from Vim's jumplist, jumps to location on `<cr>`
---@param opts table: options to pass to the picker
---@field ignore_filename boolean: dont show filenames (default: true)
---@field show_line boolean: show results text (default: true)
---@field trim_text boolean: trim results text (default: false)
builtin.jumplist = require_on_exported_call("telescope.builtin.internal").jumplist
---@field fname_width number: defines the width of the filename section (default: 30)
builtin.jumplist = require_on_exported_call("telescope.builtin.__internal").jumplist
--
--
@@ -369,63 +376,76 @@ builtin.jumplist = require_on_exported_call("telescope.builtin.internal").jumpli
---@field include_declaration boolean: include symbol declaration in the lsp references (default: true)
---@field include_current_line boolean: include current line (default: false)
---@field trim_text boolean: trim results text (default: false)
builtin.lsp_references = require_on_exported_call("telescope.builtin.lsp").references
---@field fname_width number: defines the width of the filename section (default: 30)
builtin.lsp_references = require_on_exported_call("telescope.builtin.__lsp").references
--- Lists LSP incoming calls for word under the cursor, jumps to reference on `<cr>`
---@param opts table: options to pass to the picker
---@field show_line boolean: show results text (default: true)
---@field trim_text boolean: trim results text (default: false)
builtin.lsp_incoming_calls = require_on_exported_call("telescope.builtin.__lsp").incoming_calls
--- Lists LSP outgoing calls for word under the cursor, jumps to reference on `<cr>`
---@param opts table: options to pass to the picker
---@field show_line boolean: show results text (default: true)
---@field trim_text boolean: trim results text (default: false)
builtin.lsp_outgoing_calls = require_on_exported_call("telescope.builtin.__lsp").outgoing_calls
--- Goto the definition of the word under the cursor, if there's only one, otherwise show all options in Telescope
---@param opts table: options to pass to the picker
---@field jump_type string: how to goto definition if there is only one, values: "tab", "split", "vsplit", "never"
---@field ignore_filename boolean: dont show filenames (default: true)
---@field show_line boolean: show results text (default: true)
---@field trim_text boolean: trim results text (default: false)
builtin.lsp_definitions = require_on_exported_call("telescope.builtin.lsp").definitions
---@field fname_width number: defines the width of the filename section (default: 30)
builtin.lsp_definitions = require_on_exported_call("telescope.builtin.__lsp").definitions
--- Goto the definition of the type of the word under the cursor, if there's only one,
--- otherwise show all options in Telescope
---@param opts table: options to pass to the picker
---@field jump_type string: how to goto definition if there is only one, values: "tab", "split", "vsplit", "never"
---@field ignore_filename boolean: dont show filenames (default: true)
---@field show_line boolean: show results text (default: true)
---@field trim_text boolean: trim results text (default: false)
builtin.lsp_type_definitions = require("telescope.builtin.lsp").type_definitions
---@field fname_width number: defines the width of the filename section (default: 30)
builtin.lsp_type_definitions = require("telescope.builtin.__lsp").type_definitions
--- Goto the implementation of the word under the cursor if there's only one, otherwise show all options in Telescope
---@param opts table: options to pass to the picker
---@field jump_type string: how to goto implementation if there is only one, values: "tab", "split", "vsplit", "never"
---@field ignore_filename boolean: dont show filenames (default: true)
---@field show_line boolean: show results text (default: true)
---@field trim_text boolean: trim results text (default: false)
builtin.lsp_implementations = require_on_exported_call("telescope.builtin.lsp").implementations
---@field fname_width number: defines the width of the filename section (default: 30)
builtin.lsp_implementations = require_on_exported_call("telescope.builtin.__lsp").implementations
--- Lists LSP document symbols in the current buffer
--- - Default keymaps:
--- - `<C-l>`: show autocompletion menu to prefilter your query by type of symbol you want to see (i.e. `:variable:`)
---@param opts table: options to pass to the picker
---@field ignore_filename boolean: dont show filenames (default: true)
---@field show_line boolean: if true, shows the content of the line the tag is found on (default: false)
---@field symbols string|table: filter results by symbol kind(s)
---@field ignore_symbols string|table: list of symbols to ignore
---@field symbol_highlights table: string -> string. Matches symbol with hl_group
builtin.lsp_document_symbols = require_on_exported_call("telescope.builtin.lsp").document_symbols
builtin.lsp_document_symbols = require_on_exported_call("telescope.builtin.__lsp").document_symbols
--- Lists LSP document symbols in the current workspace
--- - Default keymaps:
--- - `<C-l>`: show autocompletion menu to prefilter your query by type of symbol you want to see (i.e. `:variable:`)
---@param opts table: options to pass to the picker
---@field query string: for what to query the workspace (default: "")
---@field ignore_filename boolean: dont show filenames (default: false)
---@field show_line boolean: if true, shows the content of the line the tag is found on (default: false)
---@field symbols string|table: filter results by symbol kind(s)
---@field ignore_symbols string|table: list of symbols to ignore
---@field symbol_highlights table: string -> string. Matches symbol with hl_group
builtin.lsp_workspace_symbols = require_on_exported_call("telescope.builtin.lsp").workspace_symbols
builtin.lsp_workspace_symbols = require_on_exported_call("telescope.builtin.__lsp").workspace_symbols
--- Dynamically lists LSP for all workspace symbols
--- - Default keymaps:
--- - `<C-l>`: show autocompletion menu to prefilter your query by type of symbol you want to see (i.e. `:variable:`)
---@param opts table: options to pass to the picker
---@field ignore_filename boolean: dont show filenames (default: false)
---@field show_line boolean: if true, shows the content of the line the symbol is found on (default: false)
---@field symbols string|table: filter results by symbol kind(s)
---@field ignore_symbols string|table: list of symbols to ignore
---@field symbol_highlights table: string -> string. Matches symbol with hl_group
builtin.lsp_dynamic_workspace_symbols = require_on_exported_call("telescope.builtin.lsp").dynamic_workspace_symbols
builtin.lsp_dynamic_workspace_symbols = require_on_exported_call("telescope.builtin.__lsp").dynamic_workspace_symbols
--
--
@@ -448,7 +468,7 @@ builtin.lsp_dynamic_workspace_symbols = require_on_exported_call("telescope.buil
---@field no_sign boolean: hide DiagnosticSigns from Results (default: false)
---@field line_width number: set length of diagnostic entry text in Results
---@field namespace number: limit your diagnostics to a specific namespace
builtin.diagnostics = require_on_exported_call("telescope.builtin.diagnostics").get
builtin.diagnostics = require_on_exported_call("telescope.builtin.__diagnostics").get
local apply_config = function(mod)
local pickers_conf = require("telescope.config").pickers

File diff suppressed because it is too large Load Diff

View File

@@ -1,292 +1,17 @@
local channel = require("plenary.async.control").channel
local m = setmetatable({}, {
__index = function(_, k)
local utils = require "telescope.utils"
utils.notify("builtin", {
msg = string.format(
'You are using an internal interface. Do not use `require("telescope.builtin.lsp").%s`,'
.. ' please use `require("telescope.builtin").lsp_%s`! We will remove this endpoint soon!',
k,
k
),
level = "ERROR",
})
return require("telescope.builtin")["lsp_" .. k]
end,
})
local conf = require("telescope.config").values
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local pickers = require "telescope.pickers"
local utils = require "telescope.utils"
local lsp = {}
lsp.references = function(opts)
local filepath = vim.api.nvim_buf_get_name(opts.bufnr)
local lnum = vim.api.nvim_win_get_cursor(opts.winnr)[1]
local params = vim.lsp.util.make_position_params(opts.winnr)
local include_current_line = vim.F.if_nil(opts.include_current_line, false)
params.context = { includeDeclaration = vim.F.if_nil(opts.include_declaration, true) }
vim.lsp.buf_request(opts.bufnr, "textDocument/references", params, function(err, result, ctx, _)
if err then
vim.api.nvim_err_writeln("Error when finding references: " .. err.message)
return
end
local locations = {}
if result then
local results = vim.lsp.util.locations_to_items(result, vim.lsp.get_client_by_id(ctx.client_id).offset_encoding)
if include_current_line then
locations = vim.tbl_filter(function(v)
-- Remove current line from result
return not (v.filename == filepath and v.lnum == lnum)
end, vim.F.if_nil(results, {}))
else
locations = vim.F.if_nil(results, {})
end
end
if vim.tbl_isempty(locations) then
return
end
pickers.new(opts, {
prompt_title = "LSP References",
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.generic_sorter(opts),
push_cursor_on_edit = true,
push_tagstack_on_edit = true,
}):find()
end)
end
local function list_or_jump(action, title, opts)
opts = opts or {}
local params = vim.lsp.util.make_position_params(opts.winnr)
vim.lsp.buf_request(opts.bufnr, action, params, function(err, result, ctx, _)
if err then
vim.api.nvim_err_writeln("Error when executing " .. action .. " : " .. err.message)
return
end
local flattened_results = {}
if result then
-- textDocument/definition can return Location or Location[]
if not vim.tbl_islist(result) then
flattened_results = { result }
end
vim.list_extend(flattened_results, result)
end
local offset_encoding = vim.lsp.get_client_by_id(ctx.client_id).offset_encoding
if #flattened_results == 0 then
return
elseif #flattened_results == 1 and opts.jump_type ~= "never" then
if opts.jump_type == "tab" then
vim.cmd "tabedit"
elseif opts.jump_type == "split" then
vim.cmd "new"
elseif opts.jump_type == "vsplit" then
vim.cmd "vnew"
end
vim.lsp.util.jump_to_location(flattened_results[1], offset_encoding)
else
local locations = vim.lsp.util.locations_to_items(flattened_results, offset_encoding)
pickers.new(opts, {
prompt_title = title,
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.generic_sorter(opts),
push_cursor_on_edit = true,
push_tagstack_on_edit = true,
}):find()
end
end)
end
lsp.definitions = function(opts)
return list_or_jump("textDocument/definition", "LSP Definitions", opts)
end
lsp.type_definitions = function(opts)
return list_or_jump("textDocument/typeDefinition", "LSP Type Definitions", opts)
end
lsp.implementations = function(opts)
return list_or_jump("textDocument/implementation", "LSP Implementations", opts)
end
lsp.document_symbols = function(opts)
local params = vim.lsp.util.make_position_params(opts.winnr)
vim.lsp.buf_request(opts.bufnr, "textDocument/documentSymbol", params, function(err, result, _, _)
if err then
vim.api.nvim_err_writeln("Error when finding document symbols: " .. err.message)
return
end
if not result or vim.tbl_isempty(result) then
utils.notify("builtin.lsp_document_symbols", {
msg = "No results from textDocument/documentSymbol",
level = "INFO",
})
return
end
local locations = vim.lsp.util.symbols_to_items(result or {}, opts.bufnr) or {}
locations = utils.filter_symbols(locations, opts)
if locations == nil then
-- error message already printed in `utils.filter_symbols`
return
end
if vim.tbl_isempty(locations) then
utils.notify("builtin.lsp_document_symbols", {
msg = "No document_symbol locations found",
level = "INFO",
})
return
end
opts.ignore_filename = opts.ignore_filename or true
pickers.new(opts, {
prompt_title = "LSP Document Symbols",
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.prefilter_sorter {
tag = "symbol_type",
sorter = conf.generic_sorter(opts),
},
push_cursor_on_edit = true,
push_tagstack_on_edit = true,
}):find()
end)
end
lsp.workspace_symbols = function(opts)
local params = { query = opts.query or "" }
vim.lsp.buf_request(opts.bufnr, "workspace/symbol", params, function(err, server_result, _, _)
if err then
vim.api.nvim_err_writeln("Error when finding workspace symbols: " .. err.message)
return
end
local locations = vim.lsp.util.symbols_to_items(server_result or {}, opts.bufnr) or {}
locations = utils.filter_symbols(locations, opts)
if locations == nil then
-- error message already printed in `utils.filter_symbols`
return
end
if vim.tbl_isempty(locations) then
utils.notify("builtin.lsp_workspace_symbols", {
msg = "No results from workspace/symbol. Maybe try a different query: "
.. "'Telescope lsp_workspace_symbols query=example'",
level = "INFO",
})
return
end
opts.ignore_filename = utils.get_default(opts.ignore_filename, false)
pickers.new(opts, {
prompt_title = "LSP Workspace Symbols",
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.prefilter_sorter {
tag = "symbol_type",
sorter = conf.generic_sorter(opts),
},
}):find()
end)
end
local function get_workspace_symbols_requester(bufnr, opts)
local cancel = function() end
return function(prompt)
local tx, rx = channel.oneshot()
cancel()
_, cancel = vim.lsp.buf_request(bufnr, "workspace/symbol", { query = prompt }, tx)
-- Handle 0.5 / 0.5.1 handler situation
local err, res = rx()
assert(not err, err)
local locations = vim.lsp.util.symbols_to_items(res or {}, bufnr) or {}
if not vim.tbl_isempty(locations) then
locations = utils.filter_symbols(locations, opts) or {}
end
return locations
end
end
lsp.dynamic_workspace_symbols = function(opts)
pickers.new(opts, {
prompt_title = "LSP Dynamic Workspace Symbols",
finder = finders.new_dynamic {
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts),
fn = get_workspace_symbols_requester(opts.bufnr, opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.generic_sorter(opts),
}):find()
end
local function check_capabilities(feature, bufnr)
local clients = vim.lsp.buf_get_clients(bufnr)
local supported_client = false
for _, client in pairs(clients) do
supported_client = client.server_capabilities[feature]
if supported_client then
break
end
end
if supported_client then
return true
else
if #clients == 0 then
utils.notify("builtin.lsp_*", {
msg = "no client attached",
level = "INFO",
})
else
utils.notify("builtin.lsp_*", {
msg = "server does not support " .. feature,
level = "INFO",
})
end
return false
end
end
local feature_map = {
["document_symbols"] = "documentSymbolProvider",
["references"] = "referencesProvider",
["definitions"] = "definitionProvider",
["type_definitions"] = "typeDefinitionProvider",
["implementations"] = "implementationProvider",
["workspace_symbols"] = "workspaceSymbolProvider",
}
local function apply_checks(mod)
for k, v in pairs(mod) do
mod[k] = function(opts)
opts = opts or {}
local feature_name = feature_map[k]
if feature_name and not check_capabilities(feature_name, opts.bufnr) then
return
end
v(opts)
end
end
return mod
end
return apply_checks(lsp)
return m

View File

@@ -1,7 +1,6 @@
local strings = require "plenary.strings"
local deprecated = require "telescope.deprecated"
local sorters = require "telescope.sorters"
local if_nil = vim.F.if_nil
local os_sep = require("plenary.path").path.sep
local has_win = vim.fn.has "win32" == 1
@@ -69,7 +68,7 @@ config.descriptions = {}
config.pickers = _TelescopeConfigurationPickers
function config.set_pickers(pickers)
pickers = if_nil(pickers, {})
pickers = vim.F.if_nil(pickers, {})
for k, v in pairs(pickers) do
config.pickers[k] = v
@@ -182,7 +181,8 @@ append(
- "reset" (default)
- "follow"
- "row"
- "closest"]]
- "closest"
- "none"]]
)
append(
@@ -593,8 +593,17 @@ append(
highlighting, which falls back to regex-based highlighting.
`true`: treesitter highlighting for all available filetypes
`false`: regex-based highlighting for all filetypes
`table`: table of filetypes for which to attach treesitter
highlighting
`table`: following nvim-treesitters highlighting options:
It contains two keys:
- enable boolean|table: if boolean, enable all ts
highlighing with that flag,
disable still considered.
Containing a list of filetypes,
that are enabled, disabled
ignored because it doesnt make
any sense in this case.
- disable table: containing a list of filetypes
that are disabled
Default: true
- msg_bg_fillchar: Character to fill background of unpreviewable buffers with
Default: ""
@@ -783,6 +792,17 @@ append(
Example: { "%.npz" } -- ignore all npz files
See: https://www.lua.org/manual/5.1/manual.html#5.4.1 for more
information about lua regex
Note: `file_ignore_patterns` will be used in all pickers that have a
file associated. This might lead to the problem that lsp_ pickers
aren't displaying results because they might be ignored by
`file_ignore_patterns`. For example, setting up node_modules as ignored
will never show node_modules in any results, even if you are
interested in lsp_ results.
If you only want `file_ignore_patterns` for `find_files` and
`grep_string`/`live_grep` it is suggested that you setup `gitignore`
and have fd and or ripgrep installed because both tools will not show
`gitignore`d files on default.
Default: nil]]
)
@@ -865,8 +885,8 @@ append(
-- @param tele_defaults table: (optional) a table containing all of the defaults
-- for telescope [defaults to `telescope_defaults`]
function config.set_defaults(user_defaults, tele_defaults)
user_defaults = if_nil(user_defaults, {})
tele_defaults = if_nil(tele_defaults, telescope_defaults)
user_defaults = vim.F.if_nil(user_defaults, {})
tele_defaults = vim.F.if_nil(tele_defaults, telescope_defaults)
-- Check if using layout keywords outside of `layout_config`
deprecated.options(user_defaults)
@@ -874,8 +894,8 @@ function config.set_defaults(user_defaults, tele_defaults)
local function get(name, default_val)
if name == "layout_config" then
return smarter_depth_2_extend(
if_nil(user_defaults[name], {}),
vim.tbl_deep_extend("keep", if_nil(config.values[name], {}), if_nil(default_val, {}))
vim.F.if_nil(user_defaults[name], {}),
vim.tbl_deep_extend("keep", vim.F.if_nil(config.values[name], {}), vim.F.if_nil(default_val, {}))
)
end
if name == "history" or name == "cache_picker" or name == "preview" then
@@ -884,8 +904,8 @@ function config.set_defaults(user_defaults, tele_defaults)
end
return smarter_depth_2_extend(
if_nil(user_defaults[name], {}),
vim.tbl_deep_extend("keep", if_nil(config.values[name], {}), if_nil(default_val, {}))
vim.F.if_nil(user_defaults[name], {}),
vim.tbl_deep_extend("keep", vim.F.if_nil(config.values[name], {}), vim.F.if_nil(default_val, {}))
)
end
return first_non_null(user_defaults[name], config.values[name], default_val)

View File

@@ -91,8 +91,6 @@ That's the next step to scrolling.
--]]
local get_default = require("telescope.utils").get_default
local resolver = {}
local _resolve_map = {}
@@ -129,9 +127,6 @@ end] = function(selector, val)
end
end
-- Tables TODO:
-- ... {70, max}
-- function:
-- Function must have same signature as get_window_layout
-- function(self, max_columns, max_lines): number
@@ -143,6 +138,26 @@ end] = function(_, val)
return val
end
_resolve_map[function(val)
return type(val) == "table" and val[1] >= 0 and val[1] < 1 and val["max"] ~= nil
end] =
function(selector, val)
return function(...)
local selected = select(selector, ...)
return math.min(math.floor(val[1] * selected), val["max"])
end
end
_resolve_map[function(val)
return type(val) == "table" and val[1] >= 0 and val[1] < 1 and val["min"] ~= nil
end] =
function(selector, val)
return function(...)
local selected = select(selector, ...)
return math.max(math.floor(val[1] * selected), val["min"])
end
end
-- Add padding option
_resolve_map[function(val)
return type(val) == "table" and val["padding"] ~= nil
@@ -164,7 +179,7 @@ end] = function(selector, val)
end
--- Converts input to a function that returns the height.
--- The input must take one of four forms:
--- The input must take one of five forms:
--- 1. 0 <= number < 1 <br>
--- This means total height as a percentage.
--- 2. 1 <= number <br>
@@ -172,7 +187,10 @@ end
--- 3. function <br>
--- Must have signature:
--- function(self, max_columns, max_lines): number
--- 4. table of the form: {padding = `foo`} <br>
--- 4. table of the form: { val, max = ..., min = ... } <br>
--- val has to be in the first form 0 <= val < 1 and only one is given,
--- `min` or `max` as fixed number
--- 5. table of the form: {padding = `foo`} <br>
--- where `foo` has one of the previous three forms. <br>
--- The height is then set to be the remaining space after padding.
--- For example, if the window has height 50, and the input is {padding = 5},
@@ -190,7 +208,7 @@ resolver.resolve_height = function(val)
end
--- Converts input to a function that returns the width.
--- The input must take one of four forms:
--- The input must take one of five forms:
--- 1. 0 <= number < 1 <br>
--- This means total width as a percentage.
--- 2. 1 <= number <br>
@@ -198,7 +216,10 @@ end
--- 3. function <br>
--- Must have signature:
--- function(self, max_columns, max_lines): number
--- 4. table of the form: {padding = `foo`} <br>
--- 4. table of the form: { val, max = ..., min = ... } <br>
--- val has to be in the first form 0 <= val < 1 and only one is given,
--- `min` or `max` as fixed number
--- 5. table of the form: {padding = `foo`} <br>
--- where `foo` has one of the previous three forms. <br>
--- The width is then set to be the remaining space after padding.
--- For example, if the window has width 100, and the input is {padding = 5},
@@ -286,9 +307,9 @@ resolver.win_option = function(val, default)
end
return {
preview = get_default(val.preview, val_to_set),
results = get_default(val.results, val_to_set),
prompt = get_default(val.prompt, val_to_set),
preview = vim.F.if_nil(val.preview, val_to_set),
results = vim.F.if_nil(val.results, val_to_set),
prompt = vim.F.if_nil(val.prompt, val_to_set),
}
end
end

View File

@@ -30,6 +30,7 @@ return function(opts)
end
end,
results = results,
entry_maker = entry_maker,
}, {
__call = function(_, prompt, process_result, process_complete)
if not job_started then

View File

@@ -24,6 +24,7 @@ return function(opts)
return setmetatable({
results = results,
entry_maker = entry_maker,
close = function() end,
}, {
__call = function(_, _, process_result, process_complete)

View File

@@ -1,3 +1,40 @@
---@tag telescope.make_entry
---@brief [[
---
--- Each picker has a finder made up of two parts, the results which are the
--- data to be displayed, and the entry_maker. These entry_makers are functions
--- returned from make_entry functions. These will be referrd to as
--- entry_makers in the following documentation.
---
--- Every entry maker returns a function which accepts the data to be used for
--- an entry. This function will return an entry table (or nil, meaning skip
--- this entry) which contains of the - following important keys:
--- - value any: value key can be anything but still required
--- - valid bool: is an optional key because it defaults to true but if the key
--- is set to false it will not be displayed by the picker. (optional)
--- - ordinal string: is the text that is used for filtering (required)
--- - display string|function: is either a string of the text that is being
--- displayed or a function receiving the entry at a later stage, when the entry
--- is actually being displayed. A function can be useful here if complex
--- calculation have to be done. `make_entry` can also return a second value
--- a highlight array which will then apply to the line. Highlight entry in
--- this array has the following signature `{ { start_col, end_col }, hl_group }`
--- (required).
--- - filename string: will be interpreted by the default `<cr>` action as
--- open this file (optional)
--- - bufnr number: will be interpreted by the default `<cr>` action as open
--- this buffer (optional)
--- - lnum number: lnum value which will be interpreted by the default `<cr>`
--- action as a jump to this line (optional)
--- - col number: col value which will be interpreted by the default `<cr>`
--- action as a jump to this column (optional)
---
--- More information on easier displaying, see |telescope.pickers.entry_display|
---
--- TODO: Document something we call `entry_index`
---@brief ]]
local entry_display = require "telescope.pickers.entry_display"
local utils = require "telescope.utils"
local strings = require "plenary.strings"
@@ -26,8 +63,55 @@ local lsp_type_highlight = {
["Variable"] = "TelescopeResultsVariable",
}
local get_filename_fn = function()
local bufnr_name_cache = {}
return function(bufnr)
bufnr = vim.F.if_nil(bufnr, 0)
local c = bufnr_name_cache[bufnr]
if c then
return c
end
local n = vim.api.nvim_buf_get_name(bufnr)
bufnr_name_cache[bufnr] = n
return n
end
end
local handle_entry_index = function(opts, t, k)
local override = ((opts or {}).entry_index or {})[k]
if not override then
return
end
local val, save = override(t, opts)
if save then
rawset(t, k, val)
end
return val
end
local make_entry = {}
make_entry.set_default_entry_mt = function(tbl, opts)
return setmetatable({}, {
__index = function(t, k)
local override = handle_entry_index(opts, t, k)
if override then
return override
end
-- Only hit tbl once
local val = tbl[k]
if val then
rawset(t, k, val)
end
return val
end,
})
end
do
local lookup_keys = {
display = 1,
@@ -35,13 +119,18 @@ do
value = 1,
}
local mt_string_entry = {
__index = function(t, k)
return rawget(t, rawget(lookup_keys, k))
end,
}
function make_entry.gen_from_string(opts)
local mt_string_entry = {
__index = function(t, k)
local override = handle_entry_index(opts, t, k)
if override then
return override
end
return rawget(t, rawget(lookup_keys, k))
end,
}
function make_entry.gen_from_string()
return function(line)
return setmetatable({
line,
@@ -82,6 +171,11 @@ do
end
mt_file_entry.__index = function(t, k)
local override = handle_entry_index(opts, t, k)
if override then
return override
end
local raw = rawget(mt_file_entry, k)
if raw then
return raw
@@ -133,9 +227,6 @@ do
return { filename, lnum, col, text }
end
--- Special options:
--- - disable_coordinates: Don't show the line & row numbers
--- - only_sort_text: Only sort via the text. Ignore filename and other items
function make_entry.gen_from_vimgrep(opts)
local mt_vimgrep_entry
@@ -205,6 +296,11 @@ do
end,
__index = function(t, k)
local override = handle_entry_index(opts, t, k)
if override then
return override
end
local raw = rawget(mt_vimgrep_entry, k)
if raw then
return raw
@@ -257,13 +353,13 @@ function make_entry.gen_from_git_stash(opts)
local _, branch_name = string.match(splitted[2], "^([WIP on|On]+) (.+)")
local commit_info = splitted[3]
return {
return make_entry.set_default_entry_mt({
value = stash_idx,
ordinal = commit_info,
branch_name = branch_name,
commit_info = commit_info,
display = make_display,
}
}, opts)
end
end
@@ -297,52 +393,61 @@ function make_entry.gen_from_git_commits(opts)
msg = "<empty commit message>"
end
return {
return make_entry.set_default_entry_mt({
value = sha,
ordinal = sha .. " " .. msg,
msg = msg,
display = make_display,
current_file = opts.current_file,
}
}, opts)
end
end
function make_entry.gen_from_quickfix(opts)
opts = opts or {}
local show_line = vim.F.if_nil(opts.show_line, true)
local displayer = entry_display.create {
separator = "",
items = {
{ width = 8 },
{ width = 0.45 },
{ remaining = true },
},
local hidden = utils.is_path_hidden(opts)
local items = {
{ width = vim.F.if_nil(opts.fname_width, 30) },
{ remaining = true },
}
local make_display = function(entry)
local filename = utils.transform_path(opts, entry.filename)
local line_info = { table.concat({ entry.lnum, entry.col }, ":"), "TelescopeResultsLineNr" }
if opts.trim_text then
entry.text = entry.text:gsub("^%s*(.-)%s*$", "%1")
end
return displayer {
line_info,
entry.text:gsub(".* | ", ""),
filename,
}
if hidden then
items[1] = 8
end
if not show_line then
table.remove(items, 1)
end
local displayer = entry_display.create { separator = "", items = items }
local make_display = function(entry)
local input = {}
if not hidden then
table.insert(input, string.format("%s:%d:%d", utils.transform_path(opts, entry.filename), entry.lnum, entry.col))
else
table.insert(input, string.format("%4d:%2d", entry.lnum, entry.col))
end
if show_line then
local text = entry.text
if opts.trim_text then
text = text:gsub("^%s*(.-)%s*$", "%1")
end
text = text:gsub(".* | ", "")
table.insert(input, text)
end
return displayer(input)
end
local get_filename = get_filename_fn()
return function(entry)
local filename = entry.filename or vim.api.nvim_buf_get_name(entry.bufnr)
return {
valid = true,
local filename = vim.F.if_nil(entry.filename, get_filename(entry.bufnr))
return make_entry.set_default_entry_mt({
value = entry,
ordinal = (not opts.ignore_filename and filename or "") .. " " .. entry.text,
ordinal = (not hidden and filename or "") .. " " .. entry.text,
display = make_display,
bufnr = entry.bufnr,
@@ -352,7 +457,7 @@ function make_entry.gen_from_quickfix(opts)
text = entry.text,
start = entry.start,
finish = entry.finish,
}
}, opts)
end
end
@@ -361,14 +466,22 @@ function make_entry.gen_from_lsp_symbols(opts)
local bufnr = opts.bufnr or vim.api.nvim_get_current_buf()
-- Default we have two columns, symbol and type(unbound)
-- If path is not hidden then its, filepath, symbol and type(still unbound)
-- If show_line is also set, type is bound to len 8
local display_items = {
{ width = opts.symbol_width or 25 }, -- symbol
{ width = opts.symbol_type_width or 8 }, -- symbol type
{ remaining = true }, -- filename{:optional_lnum+col} OR content preview
{ width = opts.symbol_width or 25 },
{ remaining = true },
}
if opts.ignore_filename and opts.show_line then
table.insert(display_items, 2, { width = 6 })
local hidden = utils.is_path_hidden(opts)
if not hidden then
table.insert(display_items, 1, { width = vim.F.if_nil(opts.fname_width, 30) })
end
if opts.show_line then
-- bound type to len 8 or custom
table.insert(display_items, #display_items, { width = opts.symbol_type_width or 8 })
end
local displayer = entry_display.create {
@@ -376,51 +489,42 @@ function make_entry.gen_from_lsp_symbols(opts)
hl_chars = { ["["] = "TelescopeBorder", ["]"] = "TelescopeBorder" },
items = display_items,
}
local type_highlight = vim.F.if_nil(opts.symbol_highlights or lsp_type_highlight)
local make_display = function(entry)
local msg
-- what to show in the last column: filename or symbol information
if opts.ignore_filename then -- ignore the filename and show line preview instead
-- TODO: fixme - if ignore_filename is set for workspace, bufnr will be incorrect
msg = vim.api.nvim_buf_get_lines(bufnr, entry.lnum - 1, entry.lnum, false)[1] or ""
msg = vim.trim(msg)
if opts.show_line then
msg = vim.trim(vim.F.if_nil(vim.api.nvim_buf_get_lines(bufnr, entry.lnum - 1, entry.lnum, false)[1], ""))
end
if hidden then
return displayer {
entry.symbol_name,
{ entry.symbol_type:lower(), type_highlight[entry.symbol_type] },
msg,
}
else
local filename = utils.transform_path(opts, entry.filename)
if opts.show_line then -- show inline line info
filename = filename .. " [" .. entry.lnum .. ":" .. entry.col .. "]"
end
msg = filename
return displayer {
utils.transform_path(opts, entry.filename),
entry.symbol_name,
{ entry.symbol_type:lower(), type_highlight[entry.symbol_type] },
msg,
}
end
local type_highlight = opts.symbol_highlights or lsp_type_highlight
local display_columns = {
entry.symbol_name,
{ entry.symbol_type:lower(), type_highlight[entry.symbol_type], type_highlight[entry.symbol_type] },
msg,
}
if opts.ignore_filename and opts.show_line then
table.insert(display_columns, 2, { entry.lnum .. ":" .. entry.col, "TelescopeResultsLineNr" })
end
return displayer(display_columns)
end
local get_filename = get_filename_fn()
return function(entry)
local filename = entry.filename or vim.api.nvim_buf_get_name(entry.bufnr)
local filename = vim.F.if_nil(entry.filename, get_filename(entry.bufnr))
local symbol_msg = entry.text
local symbol_type, symbol_name = symbol_msg:match "%[(.+)%]%s+(.*)"
local ordinal = ""
if not opts.ignore_filename and filename then
if not hidden and filename then
ordinal = filename .. " "
end
ordinal = ordinal .. symbol_name .. " " .. (symbol_type or "unknown")
return {
valid = true,
return make_entry.set_default_entry_mt({
value = entry,
ordinal = ordinal,
display = make_display,
@@ -432,7 +536,7 @@ function make_entry.gen_from_lsp_symbols(opts)
symbol_type = symbol_type,
start = entry.start,
finish = entry.finish,
}
}, opts)
end
end
@@ -460,8 +564,9 @@ function make_entry.gen_from_buffer(opts)
local cwd = vim.fn.expand(opts.cwd or vim.loop.cwd())
local make_display = function(entry)
-- bufnr_width + modes + icon + 3 spaces + : + lnum
opts.__prefix = opts.bufnr_width + 4 + icon_width + 3 + 1 + #tostring(entry.lnum)
local display_bufname = utils.transform_path(opts, entry.filename)
local icon, hl_group = utils.get_devicons(entry.filename, disable_devicons)
return displayer {
@@ -483,9 +588,7 @@ function make_entry.gen_from_buffer(opts)
local indicator = entry.flag .. hidden .. readonly .. changed
local line_count = vim.api.nvim_buf_line_count(entry.bufnr)
return {
valid = true,
return make_entry.set_default_entry_mt({
value = bufname,
ordinal = entry.bufnr .. " : " .. bufname,
display = make_display,
@@ -495,7 +598,7 @@ function make_entry.gen_from_buffer(opts)
-- account for potentially stale lnum as getbufinfo might not be updated or from resuming buffers picker
lnum = entry.info.lnum ~= 0 and math.max(math.min(entry.info.lnum, line_count), 1) or 1,
indicator = indicator,
}
}, opts)
end
end
@@ -537,13 +640,12 @@ function make_entry.gen_from_treesitter(opts)
return displayer(display_columns)
end
local get_filename = get_filename_fn()
return function(entry)
local ts_utils = require "nvim-treesitter.ts_utils"
local start_row, start_col, end_row, _ = ts_utils.get_node_range(entry.node)
local node_text = vim.treesitter.get_node_text(entry.node, bufnr)
return {
valid = true,
return make_entry.set_default_entry_mt({
value = entry.node,
kind = entry.kind,
ordinal = node_text .. " " .. (entry.kind or "unknown"),
@@ -551,14 +653,14 @@ function make_entry.gen_from_treesitter(opts)
node_text = node_text,
filename = vim.api.nvim_buf_get_name(bufnr),
filename = get_filename(bufnr),
-- need to add one since the previewer substacts one
lnum = start_row + 1,
col = start_col,
text = node_text,
start = start_row,
finish = end_row,
}
}, opts)
end
end
@@ -573,14 +675,12 @@ function make_entry.gen_from_packages(opts)
end
return function(module_name)
local entry = {
return make_entry.set_default_entry_mt({
valid = module_name ~= "",
value = module_name,
ordinal = module_name,
}
entry.display = make_display(module_name)
return entry
display = make_display(module_name),
}, opts)
end
end
@@ -622,21 +722,21 @@ function make_entry.gen_from_apropos(opts)
cmd = vim.split(cmd, ",")[1]
return keyword
and sections[section]
and {
and make_entry.set_default_entry_mt({
value = cmd,
description = desc,
ordinal = cmd,
display = make_display,
section = section,
keyword = keyword,
}
}, opts)
or nil
end
end
function make_entry.gen_from_marks(_)
function make_entry.gen_from_marks(opts)
return function(item)
return {
return make_entry.set_default_entry_mt({
value = item.line,
ordinal = item.line,
display = item.line,
@@ -644,11 +744,11 @@ function make_entry.gen_from_marks(_)
col = item.col,
start = item.lnum,
filename = item.filename,
}
}, opts)
end
end
function make_entry.gen_from_registers(_)
function make_entry.gen_from_registers(opts)
local displayer = entry_display.create {
separator = " ",
hl_chars = { ["["] = "TelescopeBorder", ["]"] = "TelescopeBorder" },
@@ -667,13 +767,12 @@ function make_entry.gen_from_registers(_)
end
return function(entry)
return {
valid = true,
return make_entry.set_default_entry_mt({
value = entry,
ordinal = entry,
content = vim.fn.getreg(entry),
display = make_display,
}
}, opts)
end
end
@@ -706,7 +805,7 @@ function make_entry.gen_from_keymaps(opts)
end
return function(entry)
return {
return make_entry.set_default_entry_mt({
mode = entry.mode,
lhs = get_lhs(entry),
desc = get_desc(entry),
@@ -715,22 +814,22 @@ function make_entry.gen_from_keymaps(opts)
value = entry,
ordinal = entry.mode .. " " .. get_lhs(entry) .. " " .. get_desc(entry),
display = make_display,
}
}, opts)
end
end
function make_entry.gen_from_highlights()
function make_entry.gen_from_highlights(opts)
local make_display = function(entry)
local display = entry.value
return display, { { { 0, #display }, display } }
end
return function(entry)
return {
return make_entry.set_default_entry_mt({
value = entry,
display = make_display,
ordinal = entry,
}
}, opts)
end
end
@@ -751,12 +850,12 @@ function make_entry.gen_from_picker(opts)
end
return function(entry)
return {
return make_entry.set_default_entry_mt({
value = entry,
text = entry.prompt_title,
ordinal = string.format("%s %s", entry.prompt_title, utils.get_default(entry.default_text, "")),
ordinal = string.format("%s %s", entry.prompt_title, vim.F.if_nil(entry.default_text, "")),
display = make_display,
}
}, opts)
end
end
@@ -799,117 +898,61 @@ function make_entry.gen_from_buffer_lines(opts)
return
end
return {
valid = true,
return make_entry.set_default_entry_mt({
ordinal = entry.text,
display = make_display,
filename = entry.filename,
lnum = entry.lnum,
text = entry.text,
}
}, opts)
end
end
function make_entry.gen_from_vimoptions()
local process_one_opt = function(o)
local ok, value_origin
local option = {
name = "",
description = "",
current_value = "",
default_value = "",
value_type = "",
set_by_user = false,
last_set_from = "",
}
local is_global = false
for _, v in ipairs(o.scope) do
if v == "global" then
is_global = true
end
end
if not is_global then
return
end
if is_global then
option.name = o.full_name
ok, option.current_value = pcall(vim.api.nvim_get_option, o.full_name)
if not ok then
return
end
local str_funcname = o.short_desc()
option.description = assert(loadstring(str_funcname))()
-- if #option.description > opts.desc_col_length then
-- opts.desc_col_length = #option.description
-- end
if o.defaults ~= nil then
option.default_value = o.defaults.if_true.vim or o.defaults.if_true.vi
end
if type(option.default_value) == "function" then
option.default_value = "Macro: " .. option.default_value()
end
option.value_type = (type(option.current_value) == "boolean" and "bool" or type(option.current_value))
if option.current_value ~= option.default_value then
option.set_by_user = true
value_origin = vim.fn.execute("verbose set " .. o.full_name .. "?")
if string.match(value_origin, "Last set from") then
-- TODO: parse file and line number as separate items
option.last_set_from = value_origin:gsub("^.*Last set from ", "")
end
end
return option
end
end
function make_entry.gen_from_vimoptions(opts)
local displayer = entry_display.create {
separator = "",
hl_chars = { ["["] = "TelescopeBorder", ["]"] = "TelescopeBorder" },
items = {
{ width = 25 },
{ width = 12 },
{ width = 11 },
{ remaining = true },
},
}
local make_display = function(entry)
return displayer {
{ entry.name, "Keyword" },
{ "[" .. entry.value_type .. "]", "Type" },
utils.display_termcodes(tostring(entry.current_value)),
entry.description,
{ entry.value.name, "Keyword" },
{ "[" .. entry.value.type .. "]", "Type" },
{ "[" .. entry.value.scope .. "]", "Identifier" },
utils.display_termcodes(tostring(entry.value.value)),
}
end
return function(line)
local entry = process_one_opt(line)
if not entry then
return
return function(o)
local entry = {
display = make_display,
value = {
name = o.name,
value = o.default,
type = o.type,
scope = o.scope,
},
ordinal = string.format("%s %s %s", o.name, o.type, o.scope),
}
local ok, value = pcall(vim.api.nvim_get_option, o.name)
if ok then
entry.value.value = value
entry.ordinal = entry.ordinal .. " " .. utils.display_termcodes(tostring(value))
else
entry.ordinal = entry.ordinal .. " " .. utils.display_termcodes(tostring(o.default))
end
entry.valid = true
entry.display = make_display
entry.value = line
entry.ordinal = line.full_name
-- entry.raw_value = d.raw_value
-- entry.last_set_from = d.last_set_from
return entry
return make_entry.set_default_entry_mt(entry, opts)
end
end
--- Special options:
--- - only_sort_tags: Only sort via tag name. Ignore filename and other items
function make_entry.gen_from_ctags(opts)
opts = opts or {}
@@ -960,6 +1003,11 @@ function make_entry.gen_from_ctags(opts)
local mt = {}
mt.__index = function(t, k)
local override = handle_entry_index(opts, t, k)
if override then
return override
end
if k == "path" then
local retpath = Path:new({ t.filename }):absolute()
if not vim.loop.fs_access(retpath, "R", nil) then
@@ -969,6 +1017,7 @@ function make_entry.gen_from_ctags(opts)
end
end
local current_file_cache = {}
return function(line)
if line == "" or line:sub(1, 1) == "!" then
return nil
@@ -986,8 +1035,14 @@ function make_entry.gen_from_ctags(opts)
file = string.gsub(file, "/", "\\")
end
if opts.only_current_file and file ~= current_file then
return nil
if opts.only_current_file then
if current_file_cache[file] == nil then
current_file_cache[file] = Path:new(file):normalize(cwd) == current_file
end
if current_file_cache[file] == false then
return nil
end
end
local tag_entry = {}
@@ -1031,11 +1086,12 @@ function make_entry.gen_from_diagnostics(opts)
end)()
local display_items = {
{ width = utils.if_nil(signs, 8, 10) },
{ width = signs ~= nil and 10 or 8 },
{ remaining = true },
}
local line_width = vim.F.if_nil(opts.line_width, 0.5)
if not utils.is_path_hidden(opts) then
local hidden = utils.is_path_hidden(opts)
if not hidden then
table.insert(display_items, 2, { width = line_width })
end
local displayer = entry_display.create {
@@ -1053,10 +1109,6 @@ function make_entry.gen_from_diagnostics(opts)
"Diagnostic" .. entry.type,
}
--TODO(conni2461): I dont like that this is symbol lnum:col | msg | filename
-- i want: symbol filename:lnum:col | msg
-- or : symbol lnum:col | msg
-- I think this is more natural
return displayer {
line_info,
entry.text,
@@ -1065,20 +1117,20 @@ function make_entry.gen_from_diagnostics(opts)
end
return function(entry)
return {
return make_entry.set_default_entry_mt({
value = entry,
ordinal = ("%s %s"):format(not opts.ignore_filename and entry.filename or "", entry.text),
ordinal = ("%s %s"):format(not hidden and entry.filename or "", entry.text),
display = make_display,
filename = entry.filename,
type = entry.type,
lnum = entry.lnum,
col = entry.col,
text = entry.text,
}
}, opts)
end
end
function make_entry.gen_from_autocommands(_)
function make_entry.gen_from_autocommands(opts)
local displayer = entry_display.create {
separator = "",
items = {
@@ -1091,32 +1143,30 @@ function make_entry.gen_from_autocommands(_)
local make_display = function(entry)
return displayer {
{ entry.event, "vimAutoEvent" },
{ entry.group, "vimAugroup" },
{ entry.ft_pattern, "vimAutoCmdSfxList" },
entry.command,
{ entry.value.event, "vimAutoEvent" },
{ entry.value.group_name, "vimAugroup" },
{ entry.value.pattern, "vimAutoCmdSfxList" },
entry.value.command,
}
end
-- TODO: <action> dump current filtered items to buffer
return function(entry)
return {
event = entry.event,
group = entry.group,
ft_pattern = entry.ft_pattern,
command = entry.command,
value = string.format("+%d %s", entry.source_lnum, entry.source_file),
source_file = entry.source_file,
source_lnum = entry.source_lnum,
local group_name = vim.F.if_nil(entry.group_name, "<anonymous>")
return make_entry.set_default_entry_mt({
value = {
event = entry.event,
group_name = group_name,
pattern = entry.pattern,
command = entry.command,
},
--
valid = true,
ordinal = entry.event .. " " .. entry.group .. " " .. entry.ft_pattern .. " " .. entry.command,
ordinal = entry.event .. " " .. group_name .. " " .. entry.pattern .. " " .. entry.command,
display = make_display,
}
}, opts)
end
end
function make_entry.gen_from_commands(_)
function make_entry.gen_from_commands(opts)
local displayer = entry_display.create {
separator = "",
items = {
@@ -1149,7 +1199,7 @@ function make_entry.gen_from_commands(_)
end
return function(entry)
return {
return make_entry.set_default_entry_mt({
name = entry.name,
bang = entry.bang,
nargs = entry.nargs,
@@ -1157,10 +1207,9 @@ function make_entry.gen_from_commands(_)
definition = entry.definition,
--
value = entry,
valid = true,
ordinal = entry.name,
display = make_display,
}
}, opts)
end
end
@@ -1219,13 +1268,13 @@ function make_entry.gen_from_git_status(opts)
end
local mod, file = string.match(entry, "(..).*%s[->%s]?(.+)")
return {
return setmetatable({
value = file,
status = mod,
ordinal = entry,
display = make_display,
path = Path:new({ opts.cwd, file }):absolute(),
}
}, opts)
end
end

View File

@@ -24,8 +24,6 @@ local p_window = require "telescope.pickers.window"
local EntryManager = require "telescope.entry_manager"
local MultiSelect = require "telescope.pickers.multi"
local get_default = utils.get_default
local truncate = require("plenary.strings").truncate
local strdisplaywidth = require("plenary.strings").strdisplaywidth
@@ -65,26 +63,27 @@ function Picker:new(opts)
-- pcall(v.clear)
-- end
local layout_strategy = get_default(opts.layout_strategy, config.values.layout_strategy)
local layout_strategy = vim.F.if_nil(opts.layout_strategy, config.values.layout_strategy)
local obj = setmetatable({
prompt_title = get_default(opts.prompt_title, config.values.prompt_title),
results_title = get_default(opts.results_title, config.values.results_title),
prompt_title = vim.F.if_nil(opts.prompt_title, config.values.prompt_title),
results_title = vim.F.if_nil(opts.results_title, config.values.results_title),
-- either whats passed in by the user or whats defined by the previewer
preview_title = opts.preview_title,
prompt_prefix = get_default(opts.prompt_prefix, config.values.prompt_prefix),
wrap_results = get_default(opts.wrap_results, config.values.wrap_results),
selection_caret = get_default(opts.selection_caret, config.values.selection_caret),
entry_prefix = get_default(opts.entry_prefix, config.values.entry_prefix),
multi_icon = get_default(opts.multi_icon, config.values.multi_icon),
prompt_prefix = vim.F.if_nil(opts.prompt_prefix, config.values.prompt_prefix),
wrap_results = vim.F.if_nil(opts.wrap_results, config.values.wrap_results),
selection_caret = vim.F.if_nil(opts.selection_caret, config.values.selection_caret),
entry_prefix = vim.F.if_nil(opts.entry_prefix, config.values.entry_prefix),
multi_icon = vim.F.if_nil(opts.multi_icon, config.values.multi_icon),
initial_mode = get_default(opts.initial_mode, config.values.initial_mode),
initial_mode = vim.F.if_nil(opts.initial_mode, config.values.initial_mode),
_original_mode = vim.api.nvim_get_mode().mode,
debounce = get_default(tonumber(opts.debounce), nil),
debounce = vim.F.if_nil(tonumber(opts.debounce), nil),
_finder_attached = true,
default_text = opts.default_text,
get_status_text = get_default(opts.get_status_text, config.values.get_status_text),
get_status_text = vim.F.if_nil(opts.get_status_text, config.values.get_status_text),
_on_input_filter_cb = opts.on_input_filter_cb or function() end,
finder = assert(opts.finder, "Finder is required."),
@@ -95,7 +94,7 @@ function Picker:new(opts)
default_selection_index = opts.default_selection_index,
get_selection_window = get_default(opts.get_selection_window, config.values.get_selection_window),
get_selection_window = vim.F.if_nil(opts.get_selection_window, config.values.get_selection_window),
cwd = opts.cwd,
@@ -106,32 +105,32 @@ function Picker:new(opts)
and opts._multi
or MultiSelect:new(),
track = get_default(opts.track, false),
track = vim.F.if_nil(opts.track, false),
stats = {},
attach_mappings = opts.attach_mappings,
file_ignore_patterns = get_default(opts.file_ignore_patterns, config.values.file_ignore_patterns),
file_ignore_patterns = vim.F.if_nil(opts.file_ignore_patterns, config.values.file_ignore_patterns),
scroll_strategy = get_default(opts.scroll_strategy, config.values.scroll_strategy),
sorting_strategy = get_default(opts.sorting_strategy, config.values.sorting_strategy),
tiebreak = get_default(opts.tiebreak, config.values.tiebreak),
selection_strategy = get_default(opts.selection_strategy, config.values.selection_strategy),
scroll_strategy = vim.F.if_nil(opts.scroll_strategy, config.values.scroll_strategy),
sorting_strategy = vim.F.if_nil(opts.sorting_strategy, config.values.sorting_strategy),
tiebreak = vim.F.if_nil(opts.tiebreak, config.values.tiebreak),
selection_strategy = vim.F.if_nil(opts.selection_strategy, config.values.selection_strategy),
push_cursor_on_edit = get_default(opts.push_cursor_on_edit, false),
push_tagstack_on_edit = get_default(opts.push_tagstack_on_edit, false),
push_cursor_on_edit = vim.F.if_nil(opts.push_cursor_on_edit, false),
push_tagstack_on_edit = vim.F.if_nil(opts.push_tagstack_on_edit, false),
layout_strategy = layout_strategy,
layout_config = config.smarter_depth_2_extend(opts.layout_config or {}, config.values.layout_config or {}),
__cycle_layout_list = get_default(opts.cycle_layout_list, config.values.cycle_layout_list),
__cycle_layout_list = vim.F.if_nil(opts.cycle_layout_list, config.values.cycle_layout_list),
window = {
winblend = get_default(
winblend = vim.F.if_nil(
opts.winblend,
type(opts.window) == "table" and opts.window.winblend or config.values.winblend
),
border = get_default(opts.border, type(opts.window) == "table" and opts.window.border or config.values.border),
borderchars = get_default(
border = vim.F.if_nil(opts.border, type(opts.window) == "table" and opts.window.border or config.values.border),
borderchars = vim.F.if_nil(
opts.borderchars,
type(opts.window) == "table" and opts.window.borderchars or config.values.borderchars
),
@@ -505,10 +504,12 @@ function Picker:find()
-- Register attach
vim.api.nvim_buf_attach(prompt_bufnr, false, {
on_lines = function(...)
find_id = self:_next_find_id()
if self._finder_attached then
find_id = self:_next_find_id()
status_updater { completed = false }
self._on_lines(...)
status_updater { completed = false }
self._on_lines(...)
end
end,
on_detach = function()
@@ -692,7 +693,7 @@ end
---
--- Example usage in telescope:
--- - `actions.delete_buffer()`
---@param delete_cb function: called with each deleted selection
---@param delete_cb function: called for each selection fn(s) -> bool|nil (true|nil removes the entry from the results)
function Picker:delete_selection(delete_cb)
vim.validate { delete_cb = { delete_cb, "f" } }
local original_selection_strategy = self.selection_strategy
@@ -718,8 +719,10 @@ function Picker:delete_selection(delete_cb)
return x > y
end)
for _, index in ipairs(selection_index) do
local selection = table.remove(self.finder.results, index)
delete_cb(selection)
local delete_cb_return = delete_cb(self.finder.results[index])
if delete_cb_return == nil or delete_cb_return == true then
table.remove(self.finder.results, index)
end
end
if used_multi_select then
@@ -908,7 +911,7 @@ function Picker:refresh(finder, opts)
local handle = type(opts.new_prefix) == "table" and unpack or function(x)
return x
end
self:change_prompt_prefix(handle(opts.new_prefix))
self:change_prompt_prefix(handle(opts.new_prefix), opts.prefix_hl_group)
end
if finder then
@@ -962,6 +965,9 @@ function Picker:set_selection(row)
state.set_global_key("selected_entry", entry)
if not entry then
-- also refresh previewer when there is no entry selected, so the preview window is cleared
self._selection_entry = entry
self:refresh_previewer()
return
end
@@ -1065,10 +1071,6 @@ end
--- Refresh the previewer based on the current `status` of the picker
function Picker:refresh_previewer()
local status = state.get_status(self.prompt_bufnr)
if not self._selection_entry then
-- if selection_entry is nil there is nothing to be previewed
return
end
if self.previewer and status.preview_win and a.nvim_win_is_valid(status.preview_win) then
self:_increment "previewed"
@@ -1365,6 +1367,16 @@ function Picker:_do_selection(prompt)
else
self:set_selection(self:get_reset_row())
end
elseif selection_strategy == "none" then
if self._selection_entry then
local old_entry, old_row = self._selection_entry, self._selection_row
self:reset_selection() -- required to reset selection before updating prefix
if old_row >= 0 then
self:update_prefix(old_entry, old_row)
self.highlighter:hi_multiselect(old_row, self:is_multi_selected(old_entry))
end
end
return
else
error("Unknown selection strategy: " .. selection_strategy)
end
@@ -1495,6 +1507,11 @@ function Picker:_reset_highlights()
vim.api.nvim_buf_clear_namespace(self.results_bufnr, ns_telescope_matching, 0, -1)
end
-- Toggles whether finder is attached to prompt buffer input
function Picker:_toggle_finder_attach()
self._finder_attached = not self._finder_attached
end
function Picker:_detach()
self.finder:close()

View File

@@ -1,3 +1,63 @@
---@tag telescope.pickers.entry_display
---@brief [[
--- Entry Display is used to format each entry shown in the result panel.
---
--- Entry Display create() will give us a function based on the configuration
--- of column widths we pass into it. We then can use this function n times to
--- return a string based on structured input.
---
--- Note that if you call `create()` inside `make_display` it will be called for
--- every single entry. So it is suggested to do this outside of `make_display`
--- for the best performance.
---
--- The create function will use the column widths passed to it in
--- configaration.items. Each item in that table is the number of characters in
--- the column. It's also possible for the final column to not have a fixed
--- width, this will be shown in the configuartion as 'remaining = true'.
---
--- An example of this configuration is shown for the buffers picker
--- <code>
--- local displayer = entry_display.create {
--- separator = " ",
--- items = {
--- { width = opts.bufnr_width },
--- { width = 4 },
--- { width = icon_width },
--- { remaining = true },
--- },
--- }
--- </code>
---
--- This shows 4 columns, the first is defined in the opts as the width we'll
--- use when display_string the number of the buffer. The second has a fixed
--- width of 4 and the 3rd column's widht will be decided by the width of the
--- icons we use. The fourth column will use the remaining space. Finally we
--- have also defined the seperator between each column will be the space " ".
---
--- An example of how the display reference will be used is shown, again for
--- the buffers picker:
--- <code>
--- return displayer {
--- { entry.bufnr, "TelescopeResultsNumber" },
--- { entry.indicator, "TelescopeResultsComment" },
--- { icon, hl_group },
--- display_bufname .. ":" .. entry.lnum,
--- }
--- </code>
---
--- There are two types of values each column can have. Either a simple String
--- or a table containing the String as well as the hl_group.
---
--- The displayer can return values, string and an optional highlights.
--- String is all the text to be displayed for this entry as a single string. If
--- parts of the string are to be highlighted they will be described in the
--- highlights table.
---
--- For better understanding of how create() and displayer are used it's best to look
--- at the code in make_entry.lua.
---@brief ]]
local strings = require "plenary.strings"
local state = require "telescope.state"
local resolve = require "telescope.config.resolve"

View File

@@ -53,7 +53,6 @@
local resolve = require "telescope.config.resolve"
local p_window = require "telescope.pickers.window"
local if_nil = vim.F.if_nil
local get_border_size = function(opts)
if opts.window.border == false then
@@ -125,7 +124,7 @@ local function validate_layout_config(strategy_name, configuration, values, defa
local valid_configuration_keys = get_valid_configuration_keys(configuration)
-- If no default_layout_config provided, check Telescope's config values
default_layout_config = if_nil(default_layout_config, require("telescope.config").values.layout_config)
default_layout_config = vim.F.if_nil(default_layout_config, require("telescope.config").values.layout_config)
local result = {}
local get_value = function(k)
@@ -263,7 +262,7 @@ local function make_documented_layout(name, layout_config, layout)
validate_layout_config(
name,
layout_config,
vim.tbl_deep_extend("keep", if_nil(override_layout, {}), if_nil(self.layout_config, {}))
vim.tbl_deep_extend("keep", vim.F.if_nil(override_layout, {}), vim.F.if_nil(self.layout_config, {}))
)
)
end
@@ -320,7 +319,7 @@ layout_strategies.horizontal = make_documented_layout(
-- Cap over/undersized width (with previewer)
width, w_space = calc_size_and_spacing(width, max_columns, bs, 2, 4, 1)
preview.width = resolve.resolve_width(if_nil(layout_config.preview_width, function(_, cols)
preview.width = resolve.resolve_width(vim.F.if_nil(layout_config.preview_width, function(_, cols)
if cols < 150 then
return math.floor(cols * 0.4)
elseif cols < 200 then
@@ -588,7 +587,7 @@ layout_strategies.cursor = make_documented_layout(
-- Cap over/undersized width (with preview)
width, w_space = calc_size_and_spacing(width, max_columns, bs, 2, 4, 0)
preview.width = resolve.resolve_width(if_nil(layout_config.preview_width, 2 / 3))(self, width, max_lines)
preview.width = resolve.resolve_width(vim.F.if_nil(layout_config.preview_width, 2 / 3))(self, width, max_lines)
prompt.width = width - preview.width - w_space
results.width = prompt.width
else
@@ -694,7 +693,11 @@ layout_strategies.vertical = make_documented_layout(
-- Cap over/undersized height (with previewer)
height, h_space = calc_size_and_spacing(height, max_lines, bs, 3, 6, 2)
preview.height = resolve.resolve_height(if_nil(layout_config.preview_height, 0.5))(self, max_columns, height)
preview.height = resolve.resolve_height(vim.F.if_nil(layout_config.preview_height, 0.5))(
self,
max_columns,
height
)
else
-- Cap over/undersized height (without previewer)
height, h_space = calc_size_and_spacing(height, max_lines, bs, 2, 4, 1)
@@ -764,8 +767,8 @@ layout_strategies.flex = make_documented_layout(
horizontal = "Options to pass when switching to horizontal layout",
}),
function(self, max_columns, max_lines, layout_config)
local flip_columns = if_nil(layout_config.flip_columns, 100)
local flip_lines = if_nil(layout_config.flip_lines, 20)
local flip_columns = vim.F.if_nil(layout_config.flip_columns, 100)
local flip_lines = vim.F.if_nil(layout_config.flip_lines, 20)
if max_columns < flip_columns and max_lines > flip_lines then
self.__flex_strategy = "vertical"
@@ -851,7 +854,7 @@ layout_strategies.bottom_pane = make_documented_layout(
local tbln
max_lines, tbln = calc_tabline(max_lines)
local height = if_nil(resolve.resolve_height(layout_config.height)(self, max_columns, max_lines), 25)
local height = vim.F.if_nil(resolve.resolve_height(layout_config.height)(self, max_columns, max_lines), 25)
if type(layout_config.height) == "table" and type(layout_config.height.padding) == "number" then
-- Since bottom_pane only has padding at the top, we only need half as much padding in total
-- This doesn't match the vim help for `resolve.resolve_height`, but it matches expectations
@@ -874,7 +877,7 @@ layout_strategies.bottom_pane = make_documented_layout(
-- Cap over/undersized width (with preview)
local width, w_space = calc_size_and_spacing(max_columns, max_columns, bs, 2, 4, 0)
preview.width = resolve.resolve_width(if_nil(layout_config.preview_width, 0.5))(self, width, max_lines)
preview.width = resolve.resolve_width(vim.F.if_nil(layout_config.preview_width, 0.5))(self, width, max_lines)
results.width = width - preview.width - w_space
else
results.width = prompt.width

View File

@@ -386,6 +386,10 @@ previewers.new_buffer_previewer = function(opts)
opts.define_preview(self, entry, status)
vim.schedule(function()
if not self or not self.state or not self.state.bufnr then
return
end
if vim.api.nvim_buf_is_valid(self.state.bufnr) then
vim.api.nvim_buf_call(self.state.bufnr, function()
vim.cmd "do User TelescopePreviewerLoaded"
@@ -715,8 +719,12 @@ previewers.git_stash_diff = defaulter(function(opts)
value = entry.value,
bufname = self.state.bufname,
cwd = opts.cwd,
callback = function(bufnr)
if vim.api.nvim_buf_is_valid(bufnr) then
putils.regex_highlighter(bufnr, "diff")
end
end,
})
putils.regex_highlighter(self.state.bufnr, "diff")
end,
}
end, {})
@@ -741,10 +749,12 @@ previewers.git_commit_diff_to_parent = defaulter(function(opts)
bufname = self.state.bufname,
cwd = opts.cwd,
callback = function(bufnr)
search_cb_jump(self, bufnr, opts.current_line)
if vim.api.nvim_buf_is_valid(bufnr) then
search_cb_jump(self, bufnr, opts.current_line)
putils.regex_highlighter(bufnr, "diff")
end
end,
})
putils.regex_highlighter(self.state.bufnr, "diff")
end,
}
end, {})
@@ -770,10 +780,12 @@ previewers.git_commit_diff_to_head = defaulter(function(opts)
bufname = self.state.bufname,
cwd = opts.cwd,
callback = function(bufnr)
search_cb_jump(self, bufnr, opts.current_line)
if vim.api.nvim_buf_is_valid(bufnr) then
search_cb_jump(self, bufnr, opts.current_line)
putils.regex_highlighter(bufnr, "diff")
end
end,
})
putils.regex_highlighter(self.state.bufnr, "diff")
end,
}
end, {})
@@ -799,10 +811,12 @@ previewers.git_commit_diff_as_was = defaulter(function(opts)
bufname = self.state.bufname,
cwd = opts.cwd,
callback = function(bufnr)
search_cb_jump(self, bufnr, opts.current_line)
if vim.api.nvim_buf_is_valid(bufnr) then
search_cb_jump(self, bufnr, opts.current_line)
putils.regex_highlighter(bufnr, ft)
end
end,
})
putils.highlighter(self.state.bufnr, ft)
end,
}
end, {})
@@ -864,8 +878,12 @@ previewers.git_file_diff = defaulter(function(opts)
value = entry.value,
bufname = self.state.bufname,
cwd = opts.cwd,
callback = function(bufnr)
if vim.api.nvim_buf_is_valid(bufnr) then
putils.regex_highlighter(bufnr, "diff")
end
end,
})
putils.regex_highlighter(self.state.bufnr, "diff")
end
end,
}
@@ -881,12 +899,12 @@ previewers.autocommands = defaulter(function(_)
end,
get_buffer_by_name = function(_, entry)
return entry.group
return entry.value.group_name
end,
define_preview = function(self, entry, status)
local results = vim.tbl_filter(function(x)
return x.group == entry.group
return x.value.group_name == entry.value.group_name
end, status.picker.finder.results)
if self.state.last_set_bufnr then
@@ -894,9 +912,9 @@ previewers.autocommands = defaulter(function(_)
end
local selected_row = 0
if self.state.bufname ~= entry.group then
if self.state.bufname ~= entry.value.group_name then
local display = {}
table.insert(display, string.format(" augroup: %s - [ %d entries ]", entry.group, #results))
table.insert(display, string.format(" augroup: %s - [ %d entries ]", entry.value.group_name, #results))
-- TODO: calculate banner width/string in setup()
-- TODO: get column characters to be the same HL group as border
table.insert(display, string.rep("", vim.fn.getwininfo(status.preview_win)[1].width))
@@ -905,7 +923,10 @@ previewers.autocommands = defaulter(function(_)
if item == entry then
selected_row = idx
end
table.insert(display, string.format(" %-14s▏%-08s %s", item.event, item.ft_pattern, item.command))
table.insert(
display,
string.format(" %-14s▏%-08s %s", item.value.event, item.value.ft_pattern, item.value.command)
)
end
vim.api.nvim_buf_set_option(self.state.bufnr, "filetype", "vim")

View File

@@ -1,3 +1,5 @@
local utils = require "telescope.utils"
local Previewer = {}
Previewer.__index = Previewer
@@ -25,11 +27,19 @@ function Previewer:new(opts)
_send_input = opts.send_input,
_scroll_fn = opts.scroll_fn,
preview_fn = opts.preview_fn,
_empty_bufnr = nil,
}, Previewer)
end
function Previewer:preview(entry, status)
if not entry then
if not self._empty_bufnr then
self._empty_bufnr = vim.api.nvim_create_buf(false, true)
end
if vim.api.nvim_buf_is_valid(self._empty_bufnr) then
vim.api.nvim_win_set_buf(status.preview_win, self._empty_bufnr)
end
return
end
@@ -47,7 +57,11 @@ end
function Previewer:title(entry, dynamic)
if dynamic == true and self._dyn_title_fn ~= nil then
if entry == nil then
return nil
if self._title_fn ~= nil then
return self:_title_fn()
else
return ""
end
end
return self:_dyn_title_fn(entry)
end
@@ -57,6 +71,9 @@ function Previewer:title(entry, dynamic)
end
function Previewer:teardown()
if self._empty_bufnr then
utils.buf_delete(self._empty_bufnr)
end
if self._teardown_func then
self:_teardown_func()
end

View File

@@ -82,12 +82,26 @@ end
utils.highlighter = function(bufnr, ft, opts)
opts = opts or {}
opts.preview = opts.preview or {}
opts.preview.treesitter = vim.F.if_nil(
opts.preview.treesitter,
type(conf.preview) == "table" and conf.preview.treesitter
)
local ts_highlighting = opts.preview.treesitter == true
or type(opts.preview.treesitter) == "table" and vim.tbl_contains(opts.preview.treesitter, ft)
opts.preview.treesitter = vim.F.if_nil(opts.preview.treesitter, conf.preview.treesitter)
if type(opts.preview.treesitter) == "boolean" then
local temp = { enable = opts.preview.treesitter }
opts.preview.treesitter = temp
end
local ts_highlighting = (function()
if type(opts.preview.treesitter.enable) == "table" then
if vim.tbl_contains(opts.preview.treesitter.enable, ft) then
return true
end
return false
end
if vim.tbl_contains(vim.F.if_nil(opts.preview.treesitter.disable, {}), ft) then
return false
end
return opts.preview.treesitter.enable == nil or opts.preview.treesitter.enable == true
end)()
local ts_success
if ts_highlighting then

View File

@@ -602,7 +602,7 @@ end
sorters.prefilter = function(opts)
local sorter = opts.sorter
opts.delimiter = util.get_default(opts.delimiter, ":")
opts.delimiter = vim.F.if_nil(opts.delimiter, ":")
sorter._delimiter = opts.delimiter
sorter.tags = create_tag_set(opts.tag)
sorter.filter_function = filter_function(opts)

View File

@@ -1,3 +1,10 @@
---@tag telescope.utils
---@config { ["module"] = "telescope.utils" }
---@brief [[
--- Utilities for writing telescope pickers
---@brief ]]
local Path = require "plenary.path"
local Job = require "plenary.job"
@@ -13,6 +20,7 @@ utils.get_separator = function()
end
utils.if_nil = function(x, was_nil, was_not_nil)
log.error "telescope.utils.if_nil is deprecated and will be removed. Please use vim.F.if_nil"
if x == nil then
return was_nil
else
@@ -21,6 +29,7 @@ utils.if_nil = function(x, was_nil, was_not_nil)
end
utils.get_default = function(x, default)
log.error "telescope.utils.get_default is deprecated and will be removed. Please use vim.F.if_nil"
return utils.if_nil(x, default, x)
end
@@ -191,7 +200,7 @@ utils.path_tail = (function()
end)()
utils.is_path_hidden = function(opts, path_display)
path_display = path_display or utils.get_default(opts.path_display, require("telescope.config").values.path_display)
path_display = path_display or vim.F.if_nil(opts.path_display, require("telescope.config").values.path_display)
return path_display == nil
or path_display == "hidden"
@@ -210,6 +219,16 @@ local calc_result_length = function(truncate_len)
return type(truncate_len) == "number" and len - truncate_len or len
end
--- Transform path is a util function that formats a path based on path_display
--- found in `opts` or the default value from config.
--- It is meant to be used in make_entry to have a uniform interface for
--- builtins as well as extensions utilizing the same user configuration
--- Note: It is only supported inside `make_entry`/`make_display` the use of
--- this function outside of telescope might yield to undefined behavior and will
--- not be addressed by us
---@param opts table: The opts the users passed into the picker. Might contains a path_display key
---@param path string: The path that should be formated
---@return string: The transformed path ready to be displayed
utils.transform_path = function(opts, path)
if path == nil then
return
@@ -218,7 +237,7 @@ utils.transform_path = function(opts, path)
return path
end
local path_display = utils.get_default(opts.path_display, require("telescope.config").values.path_display)
local path_display = vim.F.if_nil(opts.path_display, require("telescope.config").values.path_display)
local transformed_path = path
@@ -257,7 +276,10 @@ utils.transform_path = function(opts, path)
if opts.__length == nil then
opts.__length = calc_result_length(path_display.truncate)
end
transformed_path = truncate(transformed_path, opts.__length, nil, -1)
if opts.__prefix == nil then
opts.__prefix = 0
end
transformed_path = truncate(transformed_path, opts.__length - opts.__prefix, nil, -1)
end
end

View File

@@ -75,6 +75,14 @@ describe("telescope.config.resolve", function()
end
end)
it("should handle percentages with min/max boundary", function()
eq(20, resolve.resolve_width { 0.1, min = 20 }(nil, 40, 120))
eq(30, resolve.resolve_height { 0.1, min = 20 }(nil, 40, 300))
eq(24, resolve.resolve_width { 0.4, max = 80 }(nil, 60, 60))
eq(80, resolve.resolve_height { 0.4, max = 80 }(nil, 60, 300))
end)
it("should handle fixed size", function()
local fixed = { 5, 8, 13, 21, 34 }
for _, s in ipairs(test_sizes) do

View File

@@ -1,47 +0,0 @@
local finders = require('telescope.finders')
local previewers = require('telescope.previewers')
local pickers = require('telescope.pickers')
local sorters = require('telescope.sorters')
-- Get all the items from v:oldfiles that are valid files
local valid_oldfiles = vim.tbl_filter(function(val)
return 0 ~= vim.fn.filereadable(val)
end, vim.v.oldfiles)
-- print(vim.inspect(valid_oldfiles))
-- => {
-- "/home/tj/blah.txt",
-- "/home/tj/another_dir/file.py",
-- ...
-- }
-- Create a finder from a Lua list.
local oldfiles_finder = finders.new_table(valid_oldfiles)
-- Get a pre-defined sorter.
-- Sorters return a "score" for each "Entry" found by a finder.
--
-- This sorter is optimized to best find files in a fuzzy manner.
local oldfiles_sorter = sorters.get_fuzzy_file()
-- Get a pre-defined previewer.
-- Previewers take the currently selected entry,
-- and put a preview of it in a floating window
local oldfiles_previewer = previewers.cat
-- Create and run a Picker.
-- Pickers are the main entry point to telescope.
-- They manage the interactions between:
-- Finder,
-- Sorter,
-- Previewer
--
-- And provide the UI for the user.
pickers.new {
prompt = 'Oldfiles',
finder = oldfiles_finder,
sorter = oldfiles_sorter,
previewer = oldfiles_previewer,
}:find()

View File

@@ -1,30 +0,0 @@
local finders = require('telescope.finders')
local previewers = require('telescope.previewers')
local pickers = require('telescope.pickers')
-- Create a new finder.
-- This finder, rather than taking a Lua list,
-- generates a shell command that should be run.
--
-- Each line of the shell command is converted to an entry,
-- and is possible to preview with builtin previews.
--
-- In this example, we use ripgrep to search over your entire directory
-- live as you type.
local live_grepper = finders.new_job(function(prompt)
if not prompt or prompt == "" then
return nil
end
return { 'rg', "--vimgrep", prompt}
end)
-- Create and run the Picker.
--
-- NOTE: No sorter is needed to be passed.
-- Results will be returned in the order they are received.
pickers.new({
prompt = 'Live Grep',
finder = live_grepper,
previewer = previewers.vimgrep,
}):find()

View File

@@ -1,34 +0,0 @@
### Simple demo to show the rg stuff
## key_delay 1
## feed_full
:e! ./scratch/simple_rg.lua\<CR>
:set foldlevel=100\<CR>
:luafile %\<CR>
## pause
## key_delay 80
Finder
## key_delay 150
\<c-n>
## pause
\<c-n>
## pause
\<c-n>
## pause
\<cr>
## pause
\<esc>
:" Went to the file!\<esc>
## pause
## feed_full
:qa!\<CR>

View File

@@ -1,26 +0,0 @@
+-------------------------------------------------------------------+
| Picker:find()--------------------+ +------>Picker |
| | ^ | | |
| | | v | |
| | +----------------+ +----------------+ |
| +->| Finder + | Sorter | |
| +----------------+ +----------------+ |
| [1] |
| |
| |
| |
| |
| |
| |
+-------------------------------------------------------------------+
Picker starts a `finder`.
Finder returns a list of `entries` to Picker.
Picker can optionally sort w/ `Sorter`.
Picker can optionally preview selected with `Previewer`
Then you can map stuff in the picker to decide what to do next.

View File

@@ -1,55 +0,0 @@
local actions = require('telescope.actions')
local finders = require('telescope.finders')
local previewers = require('telescope.previewers')
local pickers = require('telescope.pickers')
local sorters = require('telescope.sorters')
local utils = require('telescope.utils')
local Job = require('plenary.job')
-- local live_grepper = finders.new {
-- fn_command = function(_, prompt)
-- -- TODO: Make it so that we can start searching on the first character.
-- if not prompt or prompt == "" then
-- return nil
-- end
-- return {
-- command = 'rg',
-- args = {"--vimgrep", prompt},
-- }
-- end
-- }
local f = function(prompt, process_result, process_complete)
local fzf = Job:new {
command = 'fzf';
writer = Job:new {
command = "fdfind",
args = nil,
cwd = "/home/tj/build/neovim",
enable_handlers = false,
},
-- Still doesn't work if you don't pass these args and just run `fzf`
args = {'--no-sort', '--filter', prompt};
}
local start = vim.fn.reltime()
print(vim.inspect(fzf:sync()), vim.fn.reltimestr(vim.fn.reltime(start)))
end
-- Process all the files
-- f("", nil, nil)
-- Filter on nvimexec
f("nvim/executor", nil, nil)
-- pickers.new({}, {
-- prompt = 'Live Grep',
-- finder = f,
-- previewer = previewers.vimgrep,
-- }):find()

View File

@@ -1,33 +0,0 @@
RELOAD('telescope')
RELOAD('plenary')
local finders = require('telescope.finders')
local make_entry = require('telescope.make_entry')
local pickers = require('telescope.pickers')
local sorters = require('telescope.sorters')
local Job = require('plenary.job')
pickers.new {
prompt = "Piped FZF",
finder = finders._new {
fn_command = function(_, prompt)
return {
command = 'fzf',
args = {'--no-sort', '--filter', prompt or ''},
writer = Job:new {
command = 'rg',
args = {'--files'},
cwd = '/home/tj/',
enable_handlers = false,
},
}
end,
entry_maker = make_entry.gen_from_file(),
sorter = sorters.get_fuzzy_file(),
},
}:find()

View File

@@ -1,11 +0,0 @@
echo "hello"
sleep 1
echo "help"
sleep 1
echo "hi"
sleep 1
echo "husband"
sleep 1
echo "helper"

View File

@@ -17,6 +17,9 @@ docs.test = function()
"./lua/telescope/themes.lua",
"./lua/telescope/pickers/layout_strategies.lua",
"./lua/telescope/config/resolve.lua",
"./lua/telescope/make_entry.lua",
"./lua/telescope/pickers/entry_display.lua",
"./lua/telescope/utils.lua",
"./lua/telescope/actions/init.lua",
"./lua/telescope/actions/state.lua",
"./lua/telescope/actions/set.lua",