diff --git a/doc/telescope.txt b/doc/telescope.txt index 8e38635..f6e7ec9 100644 --- a/doc/telescope.txt +++ b/doc/telescope.txt @@ -15,51 +15,6 @@ Getting started with telescope: what options these implement 6. Profit -The below flow chart illustrates a simplified telescope architecture: -┌───────────────────────────────────────────────────────────┐ -│ ┌────────┐ │ -│ │ Multi │ ┌───────+ │ -│ │ Select │ ┌───────┐ │ Entry │ │ -│ └─────┬──* │ Entry │ ┌────────+ │ Maker │ │ -│ │ ┌───│Manager│────│ Sorter │┐ └───┬───* │ -│ ▼ ▼ └───────* └────────┘│ │ │ -│ 1────────┐ 2───┴──┐ │ │ -│ ┌─────│ Picker │ │Finder│◄────┘ │ -│ ▼ └───┬────┘ └──────* │ -│ ┌────────┐ │ 3────────+ ▲ │ -│ │Selected│ └───────│ Prompt │─────────┘ │ -│ │ Entry │ └───┬────┘ │ -│ └────────* ┌───┴────┐ ┌────────┐ ┌────────┐ │ -│ │ ▲ 4─────────┐│ Prompt │ │(Attach)│ │Actions │ │ -│ ▼ └──► │ Results ││ Buffer │◄─┤Mappings│◄─┤User Fn │ │ -│5─────────┐ └─────────┘└────────┘ └────────┘ └────────┘ │ -││Previewer│ │ -│└─────────┘ telescope.nvim architecture │ -└───────────────────────────────────────────────────────────┘ - - + The `Entry Maker` at least defines - - value: "raw" result of the finder - - ordinal: string to be sorted derived from value - - display: line representation of entry in results buffer - - * The finder, entry manager, selected entry, and multi selections - comprises `entries` constructed by the `Entry Maker` from - raw results of the finder (`value`s) - - Primary components: - 1 Picker: central UI dedicated to varying use cases - (finding files, grepping, diagnostics, etc.) - see :h telescope.builtin - 2 Finder: pipe or interactively generates results to pick over - 3 Prompt: user input that triggers the finder which sorts results - in order into the entry manager - 4 Results: listed entries scored by sorter from finder results - 5 Previewer: preview of context of selected entry - see :h telescope.previewers - -A practical introduction into telescope customization is our `developers.md` -(top-level of repo) and `:h telescope.actions` that showcase how to access -information about the state of the picker (current selection, etc.). To find out more: https://github.com/nvim-telescope/telescope.nvim @@ -74,8 +29,8 @@ https://github.com/nvim-telescope/telescope.nvim :h telescope.actions.set :h telescope.actions.utils :h telescope.actions.generate - :h telescope.actions.history :h telescope.previewers + :h telescope.actions.history telescope.setup({opts}) *telescope.setup()* Setup function to be run by user. Configures the defaults, pickers and @@ -280,9 +235,7 @@ telescope.setup({opts}) *telescope.setup()* - "tail" only display the file name, and not the path - "absolute" display absolute paths - "smart" remove as much from the path as possible to only show - the difference between the displayed paths. - Warning: The nature of the algorithm might have a negative - performance impact! + the difference between the displayed paths - "shorten" only display the first character of each directory in the path - "truncate" truncates the start of the path when the whole path will @@ -354,21 +307,6 @@ telescope.setup({opts}) *telescope.setup()* Default: false - *telescope.defaults.results_title* - results_title: ~ - Defines the default title of the results window. A false value - can be used to hide the title altogether. - - Default: "Results" - - *telescope.defaults.prompt_title* - prompt_title: ~ - Defines the default title of the prompt window. A false value - can be used to hide the title altogether. Most of the times builtins - define a prompt_title which will be prefered over this default. - - Default: "Prompt" - *telescope.defaults.history* history: ~ This field handles the configuration for prompt history. @@ -388,7 +326,7 @@ telescope.setup({opts}) *telescope.setup()* default: stdpath("data")/telescope_history - limit: The amount of entries that will be written in the history. - Warning: If limit is set to nil it will grow unbound. + Warning: If limit is set to nil it will grown unbound. default: 100 - handler: A lua function that implements the history. This is meant as a developer setting for extensions to @@ -543,8 +481,7 @@ telescope.setup({opts}) *telescope.setup()* *telescope.defaults.color_devicons* color_devicons: ~ - Boolean if devicons should be enabled or not. If set to false, the - "TelescopeResultsFileIcon" highlight group is used. + Boolean if devicons should be enabled or not. Hint: Coloring only works if |termguicolors| is enabled. Default: true @@ -601,16 +538,6 @@ telescope.setup({opts}) *telescope.setup()* ..., ["jj"] = { "", type = "command" }, ["kk"] = { "echo \"Hello, World!\"", type = "command" },) - ..., - - You can also add additional options for mappings of any type - ("action" and "command"). For example: - - ..., - [""] = { - action = actions.move_selection_next, - opts = { nowait = true, silent = true } - }, ..., @@ -658,15 +585,6 @@ telescope.setup({opts}) *telescope.setup()* Default: nil - *telescope.defaults.get_selection_window* - get_selection_window: ~ - Function that takes function(picker, entry) and returns a window id. - The window ID will be used to decide what window the chosen file will - be opened in and the cursor placed in upon leaving the picker. - - Default: `function() return 0 end` - - *telescope.defaults.file_previewer* file_previewer: ~ Function pointer to the default file_previewer. It is mostly used @@ -800,7 +718,7 @@ options you want to use. Here's an example with the live_grep picker: }) < -builtin.live_grep({opts}) *telescope.builtin.live_grep()* +builtin.live_grep({opts}) *builtin.live_grep()* Search for a string and get results live as you type (respecting .gitignore) @@ -818,11 +736,6 @@ builtin.live_grep({opts}) *telescope.builtin.live_grep()* {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 @@ -831,7 +744,7 @@ builtin.live_grep({opts}) *telescope.builtin.live_grep()* (default: false) -builtin.grep_string({opts}) *telescope.builtin.grep_string()* +builtin.grep_string({opts}) *builtin.grep_string()* Searches for the string under your cursor in your current working directory @@ -858,7 +771,7 @@ builtin.grep_string({opts}) *telescope.builtin.grep_string()* line or row (default: false) -builtin.find_files({opts}) *telescope.builtin.find_files()* +builtin.find_files({opts}) *builtin.find_files()* Search for files (respecting .gitignore) @@ -881,12 +794,12 @@ builtin.find_files({opts}) *telescope.builtin.find_files()* {search_dirs} (table) directory/directories to search in -builtin.fd() *telescope.builtin.fd()* +builtin.fd() *builtin.fd()* This is an alias for the `find_files` picker -builtin.treesitter() *telescope.builtin.treesitter()* +builtin.treesitter() *builtin.treesitter()* Lists function names, variables, and other symbols from treesitter queries - Default keymaps: - ``: show autocompletion menu to prefilter your query by kind of ts @@ -903,7 +816,7 @@ builtin.treesitter() *telescope.builtin.treesitter()* hl_group -builtin.current_buffer_fuzzy_find({opts}) *telescope.builtin.current_buffer_fuzzy_find()* +builtin.current_buffer_fuzzy_find({opts}) *builtin.current_buffer_fuzzy_find()* Live fuzzy search inside of the currently open buffer @@ -915,7 +828,7 @@ builtin.current_buffer_fuzzy_find({opts}) *telescope.builtin.current_buffer_fuzz (default: false) -builtin.tags({opts}) *telescope.builtin.tags()* +builtin.tags({opts}) *builtin.tags()* 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) @@ -934,11 +847,9 @@ builtin.tags({opts}) *telescope.builtin.tags()* true) {only_sort_tags} (boolean) if true we will only sort tags (default: false) - {fname_width} (number) defines the width of the filename section - (default: 30) -builtin.current_buffer_tags({opts}) *telescope.builtin.current_buffer_tags()* +builtin.current_buffer_tags({opts}) *builtin.current_buffer_tags()* Lists all of the tags for the currently open buffer, with a preview @@ -955,11 +866,9 @@ builtin.current_buffer_tags({opts}) *telescope.builtin.current_buffer_tags()* true) {only_sort_tags} (boolean) if true we will only sort tags (default: false) - {fname_width} (number) defines the width of the filename section - (default: 30) -builtin.git_files({opts}) *telescope.builtin.git_files()* +builtin.git_files({opts}) *builtin.git_files()* Fuzzy search for files tracked by Git. This command lists the output of the `git ls-files` command, respects .gitignore, and optionally ignores untracked files @@ -985,7 +894,7 @@ builtin.git_files({opts}) *telescope.builtin.git_files()* {"git","ls-files","--exclude-standard","--cached"} -builtin.git_commits({opts}) *telescope.builtin.git_commits()* +builtin.git_commits({opts}) *builtin.git_commits()* Lists commits for current directory with diff preview - Default keymaps: - ``: checks out the currently selected commit @@ -1005,7 +914,7 @@ builtin.git_commits({opts}) *telescope.builtin.git_commits()* {"git","log","--pretty=oneline","--abbrev-commit","--","."} -builtin.git_bcommits({opts}) *telescope.builtin.git_bcommits()* +builtin.git_bcommits({opts}) *builtin.git_bcommits()* Lists commits for current buffer with diff preview - Default keymaps or your overriden `select_` keys: - ``: checks out the currently selected commit @@ -1027,7 +936,7 @@ builtin.git_bcommits({opts}) *telescope.builtin.git_bcommits()* {"git","log","--pretty=oneline","--abbrev-commit"} -builtin.git_branches({opts}) *telescope.builtin.git_branches()* +builtin.git_branches({opts}) *builtin.git_branches()* List branches for current directory, with output from `git log --oneline` shown in the preview window - Default keymaps: @@ -1051,7 +960,7 @@ builtin.git_branches({opts}) *telescope.builtin.git_branches()* {pattern} (string) specify the pattern to match all refs -builtin.git_status({opts}) *telescope.builtin.git_status()* +builtin.git_status({opts}) *builtin.git_status()* Lists git status for current directory - Default keymaps: - ``: stages or unstages the currently selected file @@ -1070,7 +979,7 @@ builtin.git_status({opts}) *telescope.builtin.git_status()* git_icon_defaults) -builtin.git_stash({opts}) *telescope.builtin.git_stash()* +builtin.git_stash({opts}) *builtin.git_stash()* Lists stash items in current repository - Default keymaps: - ``: runs `git apply` for currently selected stash @@ -1087,7 +996,7 @@ builtin.git_stash({opts}) *telescope.builtin.git_stash()* stash entries (default: true) -builtin.builtin({opts}) *telescope.builtin.builtin()* +builtin.builtin({opts}) *builtin.builtin()* Lists all of the community maintained pickers built into Telescope @@ -1099,7 +1008,7 @@ builtin.builtin({opts}) *telescope.builtin.builtin()* installed extensions (default: false) -builtin.resume({opts}) *telescope.builtin.resume()* +builtin.resume({opts}) *builtin.resume()* Opens the previous picker in the identical state (incl. multi selections) - Notes: - Requires `cache_picker` in setup or when having invoked pickers, see @@ -1114,8 +1023,8 @@ builtin.resume({opts}) *telescope.builtin.resume()* recent (default: 1) -builtin.pickers({opts}) *telescope.builtin.pickers()* - Opens a picker over previously cached pickers in their preserved states +builtin.pickers({opts}) *builtin.pickers()* + Opens a picker over previously cached pickers in there preserved states (incl. multi selections) - Default keymaps: - ``: delete the selected cached picker @@ -1128,7 +1037,7 @@ builtin.pickers({opts}) *telescope.builtin.pickers()* {opts} (table) options to pass to the picker -builtin.planets({opts}) *telescope.builtin.planets()* +builtin.planets({opts}) *builtin.planets()* Use the telescope... @@ -1140,7 +1049,7 @@ builtin.planets({opts}) *telescope.builtin.planets()* hidden feature) -builtin.symbols({opts}) *telescope.builtin.symbols()* +builtin.symbols({opts}) *builtin.symbols()* 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. We provide a couple of default symbols which @@ -1159,18 +1068,15 @@ builtin.symbols({opts}) *telescope.builtin.symbols()* this time -builtin.commands({opts}) *telescope.builtin.commands()* +builtin.commands({opts}) *builtin.commands()* Lists available plugin/user commands and runs them on `` Parameters: ~ {opts} (table) options to pass to the picker - Options: ~ - {show_buf_command} (boolean) show buf local command (Default: true) - -builtin.quickfix({opts}) *telescope.builtin.quickfix()* +builtin.quickfix({opts}) *builtin.quickfix()* Lists items in the quickfix list, jumps to location on `` @@ -1179,21 +1085,9 @@ builtin.quickfix({opts}) *telescope.builtin.quickfix()* Options: ~ {ignore_filename} (boolean) dont show filenames (default: true) - {trim_text} (boolean) trim results text (default: false) - {nr} (number) specify the quickfix list number -builtin.quickfixhistory({opts}) *telescope.builtin.quickfixhistory()* - 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 - - - Parameters: ~ - {opts} (table) options to pass to the picker - - -builtin.loclist({opts}) *telescope.builtin.loclist()* +builtin.loclist({opts}) *builtin.loclist()* Lists items from the current window's location list, jumps to location on `` @@ -1203,10 +1097,9 @@ builtin.loclist({opts}) *telescope.builtin.loclist()* Options: ~ {ignore_filename} (boolean) dont show filenames (default: true) - {trim_text} (boolean) trim results text (default: false) -builtin.oldfiles({opts}) *telescope.builtin.oldfiles()* +builtin.oldfiles({opts}) *builtin.oldfiles()* Lists previously open files, opens on `` @@ -1218,7 +1111,7 @@ builtin.oldfiles({opts}) *telescope.builtin.oldfiles()* {cwd_only} (boolean) alias for only_cwd -builtin.command_history({opts}) *telescope.builtin.command_history()* +builtin.command_history({opts}) *builtin.command_history()* Lists commands that were executed recently, and reruns them on `` - Default keymaps: - ``: open the command line with the text of the currently selected @@ -1229,7 +1122,7 @@ builtin.command_history({opts}) *telescope.builtin.command_history()* {opts} (table) options to pass to the picker -builtin.search_history({opts}) *telescope.builtin.search_history()* +builtin.search_history({opts}) *builtin.search_history()* Lists searches that were executed recently, and reruns them on `` - Default keymaps: - ``: open a search window with the text of the currently selected @@ -1240,7 +1133,7 @@ builtin.search_history({opts}) *telescope.builtin.search_history()* {opts} (table) options to pass to the picker -builtin.vim_options({opts}) *telescope.builtin.vim_options()* +builtin.vim_options({opts}) *builtin.vim_options()* Lists vim options, allows you to edit the current value on `` @@ -1248,7 +1141,7 @@ builtin.vim_options({opts}) *telescope.builtin.vim_options()* {opts} (table) options to pass to the picker -builtin.help_tags({opts}) *telescope.builtin.help_tags()* +builtin.help_tags({opts}) *builtin.help_tags()* Lists available help tags and opens a new window with the relevant help info on `` @@ -1262,7 +1155,7 @@ builtin.help_tags({opts}) *telescope.builtin.help_tags()* (default: true) -builtin.man_pages({opts}) *telescope.builtin.man_pages()* +builtin.man_pages({opts}) *builtin.man_pages()* Lists manpage entries, opens them in a help window on `` @@ -1276,7 +1169,7 @@ builtin.man_pages({opts}) *telescope.builtin.man_pages()* `apropos ""` on linux, `apropos " "` on macos) -builtin.reloader({opts}) *telescope.builtin.reloader()* +builtin.reloader({opts}) *builtin.reloader()* Lists lua modules and reloads them on `` @@ -1288,7 +1181,7 @@ builtin.reloader({opts}) *telescope.builtin.reloader()* (default: dynamic, longest module name) -builtin.buffers({opts}) *telescope.builtin.buffers()* +builtin.buffers({opts}) *builtin.buffers()* Lists open buffers in current neovim instance, opens selected buffer on `` @@ -1317,7 +1210,7 @@ builtin.buffers({opts}) *telescope.builtin.buffers()* (default: dynamic) -builtin.colorscheme({opts}) *telescope.builtin.colorscheme()* +builtin.colorscheme({opts}) *builtin.colorscheme()* Lists available colorschemes and applies them on `` @@ -1328,7 +1221,7 @@ builtin.colorscheme({opts}) *telescope.builtin.colorscheme()* {enable_preview} (boolean) if true, will preview the selected color -builtin.marks({opts}) *telescope.builtin.marks()* +builtin.marks({opts}) *builtin.marks()* Lists vim marks and their value, jumps to the mark on `` @@ -1336,7 +1229,7 @@ builtin.marks({opts}) *telescope.builtin.marks()* {opts} (table) options to pass to the picker -builtin.registers({opts}) *telescope.builtin.registers()* +builtin.registers({opts}) *builtin.registers()* Lists vim registers, pastes the contents of the register on `` - Default keymaps: - ``: edit the contents of the currently selected register @@ -1346,7 +1239,7 @@ builtin.registers({opts}) *telescope.builtin.registers()* {opts} (table) options to pass to the picker -builtin.keymaps({opts}) *telescope.builtin.keymaps()* +builtin.keymaps({opts}) *builtin.keymaps()* Lists normal mode keymappings, runs the selected keymap on `` @@ -1360,7 +1253,7 @@ builtin.keymaps({opts}) *telescope.builtin.keymaps()* "" are also shown (default: true) -builtin.filetypes({opts}) *telescope.builtin.filetypes()* +builtin.filetypes({opts}) *builtin.filetypes()* Lists all available filetypes, sets currently open buffer's filetype to selected filetype in Telescope on `` @@ -1369,7 +1262,7 @@ builtin.filetypes({opts}) *telescope.builtin.filetypes()* {opts} (table) options to pass to the picker -builtin.highlights({opts}) *telescope.builtin.highlights()* +builtin.highlights({opts}) *builtin.highlights()* Lists all available highlights @@ -1377,7 +1270,7 @@ builtin.highlights({opts}) *telescope.builtin.highlights()* {opts} (table) options to pass to the picker -builtin.autocommands({opts}) *telescope.builtin.autocommands()* +builtin.autocommands({opts}) *builtin.autocommands()* Lists vim autocommands and goes to their declaration on `` @@ -1385,7 +1278,7 @@ builtin.autocommands({opts}) *telescope.builtin.autocommands()* {opts} (table) options to pass to the picker -builtin.spell_suggest({opts}) *telescope.builtin.spell_suggest()* +builtin.spell_suggest({opts}) *builtin.spell_suggest()* Lists spelling suggestions for the current word under the cursor, replaces word with selected suggestion on `` @@ -1394,7 +1287,7 @@ builtin.spell_suggest({opts}) *telescope.builtin.spell_suggest()* {opts} (table) options to pass to the picker -builtin.tagstack({opts}) *telescope.builtin.tagstack()* +builtin.tagstack({opts}) *builtin.tagstack()* Lists the tag stack for the current window, jumps to tag on `` @@ -1403,10 +1296,9 @@ builtin.tagstack({opts}) *telescope.builtin.tagstack()* Options: ~ {ignore_filename} (boolean) dont show filenames (default: true) - {trim_text} (boolean) trim results text (default: false) -builtin.jumplist({opts}) *telescope.builtin.jumplist()* +builtin.jumplist({opts}) *builtin.jumplist()* Lists items from Vim's jumplist, jumps to location on `` @@ -1415,10 +1307,9 @@ builtin.jumplist({opts}) *telescope.builtin.jumplist()* Options: ~ {ignore_filename} (boolean) dont show filenames (default: true) - {trim_text} (boolean) trim results text (default: false) -builtin.lsp_references({opts}) *telescope.builtin.lsp_references()* +builtin.lsp_references({opts}) *builtin.lsp_references()* Lists LSP references for word under the cursor, jumps to reference on `` @@ -1426,15 +1317,8 @@ builtin.lsp_references({opts}) *telescope.builtin.lsp_references()* Parameters: ~ {opts} (table) options to pass to the picker - Options: ~ - {include_declaration} (boolean) include symbol declaration in the - lsp references (default: true) - {include_current_line} (boolean) include current line (default: - false) - {trim_text} (boolean) trim results text (default: false) - -builtin.lsp_definitions({opts}) *telescope.builtin.lsp_definitions()* +builtin.lsp_definitions({opts}) *builtin.lsp_definitions()* Goto the definition of the word under the cursor, if there's only one, otherwise show all options in Telescope @@ -1447,10 +1331,9 @@ builtin.lsp_definitions({opts}) *telescope.builtin.lsp_definitions()* one, values: "tab", "split", "vsplit", "never" {ignore_filename} (boolean) dont show filenames (default: true) - {trim_text} (boolean) trim results text (default: false) -builtin.lsp_type_definitions({opts}) *telescope.builtin.lsp_type_definitions()* +builtin.lsp_type_definitions({opts}) *builtin.lsp_type_definitions()* Goto the definition of the type of the word under the cursor, if there's only one, otherwise show all options in Telescope @@ -1459,14 +1342,15 @@ 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" + {ignore_filename} (boolean) dont show filenames (default: true) + {include_declaration} (boolean) include symbol declaration in the lsp + references (default: true) -builtin.lsp_implementations({opts}) *telescope.builtin.lsp_implementations()* +builtin.lsp_implementations({opts}) *builtin.lsp_implementations()* Goto the implementation of the word under the cursor if there's only one, otherwise show all options in Telescope @@ -1479,10 +1363,36 @@ builtin.lsp_implementations({opts}) *telescope.builtin.lsp_implementations()* only one, values: "tab", "split", "vsplit", "never" {ignore_filename} (boolean) dont show filenames (default: true) - {trim_text} (boolean) trim results text (default: false) -builtin.lsp_document_symbols({opts}) *telescope.builtin.lsp_document_symbols()* +builtin.lsp_code_actions({opts}) *builtin.lsp_code_actions()* + Lists any LSP actions for the word under the cursor which can be triggered + with `` + + + Parameters: ~ + {opts} (table) options to pass to the picker + + Options: ~ + {timeout} (number) timeout for the sync call (default: 10000) + + +builtin.lsp_range_code_actions({opts}) *builtin.lsp_range_code_actions()* + Lists any LSP actions for a given range, that can be triggered with `` + + + Parameters: ~ + {opts} (table) options to pass to the picker + + Options: ~ + {timeout} (number) timeout for the sync call (default: 10000) + {start_line} (number) where the code action starts (default: handled + by :'<,'>Telescope lsp_range_code_actions) + {end_line} (number) where the code action ends (default: handled by + :'<,'>Telescope lsp_range_code_actions) + + +builtin.lsp_document_symbols({opts}) *builtin.lsp_document_symbols()* Lists LSP document symbols in the current buffer - Default keymaps: - ``: show autocompletion menu to prefilter your query by type of @@ -1504,7 +1414,7 @@ builtin.lsp_document_symbols({opts}) *telescope.builtin.lsp_document_symbols()* with hl_group -builtin.lsp_workspace_symbols({opts}) *telescope.builtin.lsp_workspace_symbols()* +builtin.lsp_workspace_symbols({opts}) *builtin.lsp_workspace_symbols()* Lists LSP document symbols in the current workspace - Default keymaps: - ``: show autocompletion menu to prefilter your query by type of @@ -1528,7 +1438,7 @@ builtin.lsp_workspace_symbols({opts}) *telescope.builtin.lsp_workspace_symbols() with hl_group -builtin.lsp_dynamic_workspace_symbols({opts}) *telescope.builtin.lsp_dynamic_workspace_symbols()* +builtin.lsp_dynamic_workspace_symbols({opts}) *builtin.lsp_dynamic_workspace_symbols()* Dynamically lists LSP for all workspace symbols - Default keymaps: - ``: show autocompletion menu to prefilter your query by type of @@ -1550,8 +1460,8 @@ builtin.lsp_dynamic_workspace_symbols({opts}) *telescope.builtin.lsp_dynamic_wor with hl_group -builtin.diagnostics({opts}) *telescope.builtin.diagnostics()* - Lists diagnostics +builtin.diagnostics({opts}) *builtin.diagnostics()* + Lists diagnostics for current or all open buffers - Fields: - `All severity flags can be passed as `string` or `number` as per `:vim.diagnostic.severity:` @@ -1564,28 +1474,22 @@ builtin.diagnostics({opts}) *telescope.builtin.diagnostics()* {opts} (table) options to pass to the picker Options: ~ - {bufnr} (number|nil) Buffer number to get diagnostics - from. Use 0 for current buffer or - nil for all buffers - {severity} (string|number) filter diagnostics by severity name - (string) or id (number) - {severity_limit} (string|number) keep diagnostics equal or more - severe wrt severity name (string) - or id (number) - {severity_bound} (string|number) keep diagnostics equal or less - severe wrt severity name (string) - or id (number) - {root_dir} (string|boolean) if set to string, get diagnostics - only for buffers under this dir - otherwise cwd - {no_unlisted} (boolean) if true, get diagnostics only for - listed buffers - {no_sign} (boolean) hide DiagnosticSigns from Results - (default: false) - {line_width} (number) set length of diagnostic entry text - in Results - {namespace} (number) limit your diagnostics to a - specific namespace + {bufnr} (string|number) if nil get diagnostics for all open + buffers. Use 0 for current buffer + {severity} (string|number) filter diagnostics by severity name + (string) or id (number) + {severity_limit} (string|number) keep diagnostics equal or more + severe wrt severity name (string) or + id (number) + {severity_bound} (string|number) keep diagnostics equal or less + severe wrt severity name (string) or + id (number) + {no_sign} (boolean) hide DiagnosticSigns from Results + (default: false) + {line_width} (number) set length of diagnostic entry text + in Results + {namespace} (number) limit your diagnostics to a specific + namespace @@ -1597,7 +1501,7 @@ Themes are ways to combine several elements of styling together. They are helpful for managing the several different UI aspects for telescope and provide a simple interface for users to get a particular "style" of picker. -themes.get_dropdown() *telescope.themes.get_dropdown()* +themes.get_dropdown() *themes.get_dropdown()* Dropdown style theme. Usage: @@ -1609,7 +1513,7 @@ themes.get_dropdown() *telescope.themes.get_dropdown()* -themes.get_cursor() *telescope.themes.get_cursor()* +themes.get_cursor() *themes.get_cursor()* Cursor style theme. Usage: @@ -1617,12 +1521,12 @@ themes.get_cursor() *telescope.themes.get_cursor()* `local builtin = require('telescope.builtin')` `local themes = require('telescope.themes')` - `builtin.lsp_references(themes.get_cursor())` + `builtin.lsp_code_actions(themes.get_cursor())` < -themes.get_ivy() *telescope.themes.get_ivy()* +themes.get_ivy() *themes.get_ivy()* Ivy style theme. Usage: @@ -1685,7 +1589,7 @@ most resembles what you want from "./lua/telescope/pickers/layout_strategies.lua" in the telescope repo. -layout_strategies.horizontal() *telescope.layout.horizontal()* +layout_strategies.horizontal() *layout_strategies.horizontal()* Horizontal layout has two columns, one for the preview and one for the prompt and results. @@ -1729,7 +1633,7 @@ layout_strategies.horizontal() *telescope.layout.horizontal()* - See |resolver.resolve_width()| -layout_strategies.center() *telescope.layout.center()* +layout_strategies.center() *layout_strategies.center()* Centered layout with a combined block of the prompt and results aligned to the middle of the screen. The preview window is then placed in the remaining space above or below, according to `anchor` or `mirror`. @@ -1779,7 +1683,7 @@ layout_strategies.center() *telescope.layout.center()* - preview_cutoff: When lines are less than this value, the preview will be disabled -layout_strategies.cursor() *telescope.layout.cursor()* +layout_strategies.cursor() *layout_strategies.cursor()* Cursor layout dynamically positioned below the cursor if possible. If there is no place below the cursor it will be placed above. @@ -1802,7 +1706,7 @@ layout_strategies.cursor() *telescope.layout.cursor()* -layout_strategies.vertical() *telescope.layout.vertical()* +layout_strategies.vertical() *layout_strategies.vertical()* Vertical layout stacks the items on top of each other. Particularly useful with thinner windows. @@ -1846,7 +1750,7 @@ layout_strategies.vertical() *telescope.layout.vertical()* - See |resolver.resolve_height()| -layout_strategies.flex() *telescope.layout.flex()* +layout_strategies.flex() *layout_strategies.flex()* Flex layout swaps between `horizontal` and `vertical` strategies based on the window width - Supports |layout_strategies.vertical| or |layout_strategies.horizontal| @@ -1876,7 +1780,7 @@ layout_strategies.flex() *telescope.layout.flex()* - vertical: Options to pass when switching to vertical layout -layout_strategies.bottom_pane() *telescope.layout.bottom_pane()* +layout_strategies.bottom_pane() *layout_strategies.bottom_pane()* Bottom pane can be used to create layouts similar to "ivy". For an easy ivy configuration, see |themes.get_ivy()| @@ -1889,7 +1793,7 @@ layout_strategies.bottom_pane() *telescope.layout.bottom_pane()* Provides "resolver functions" to allow more customisable inputs for options. -resolver.resolve_height() *telescope.resolve.resolve_height()* +resolver.resolve_height() *resolver.resolve_height()* Converts input to a function that returns the height. The input must take one of four forms: 1. 0 <= number < 1 @@ -1909,7 +1813,7 @@ resolver.resolve_height() *telescope.resolve.resolve_height()* -resolver.resolve_width() *telescope.resolve.resolve_width()* +resolver.resolve_width() *resolver.resolve_width()* Converts input to a function that returns the width. The input must take one of four forms: 1. 0 <= number < 1 @@ -1929,7 +1833,7 @@ resolver.resolve_width() *telescope.resolve.resolve_width()* -resolver.resolve_anchor_pos() *telescope.resolve.resolve_anchor_pos()* +resolver.resolve_anchor_pos() *resolver.resolve_anchor_pos()* Calculates the adjustment required to move the picker from the middle of the screen to an edge or corner. The `anchor` can be any of the following strings: @@ -1949,53 +1853,7 @@ resolver.resolve_anchor_pos() *telescope.resolve.resolve_anchor_pos()* Actions functions that are useful for people creating their own mappings. -Actions can be either normal functions that expect the prompt_bufnr as first -argument (1) or they can be a custom telescope type called "action" (2). - -(1) The `prompt_bufnr` of a normal function denotes the identifier of your -picker which can be used to access the picker state. In practice, users most -commonly access from both picker and global state via the following: -> - -- for utility functions - local action_state = require "telescope.actions.state" - - local actions = {} - actions.do_stuff = function(prompt_bufnr) - local current_picker = action_state.get_current_picker(prompt_bufnr) -- picker state - local entry = action_state.get_selected_entry() - end -< - -See |telescope.actions.state| for more information. - -(2) To transform a module of functions into a module of "action"s, you need to -do the following: -> - local transform_mod = require("telescope.actions.mt").transform_mod - - local mod = {} - mod.a1 = function(prompt_bufnr) - -- your code goes here - -- You can access the picker/global state as described above in (1). - end - - mod.a2 = function(prompt_bufnr) - -- your code goes here - end - mod = transform_mod(mod) - - -- Now the following is possible. This means that actions a2 will be executed - -- after action a1. You can chain as many actions as you want. - local action = mod.a1 + mod.a2 - action(bufnr) -< - -Another interesing thing to do is that these actions now have functions you can -call. These functions include `:replace(f)`, `:replace_if(f, c)`, -`replace_map(tbl)` and `enhance(tbl)`. More information on these functions can -be found in the `developers.md` and `lua/tests/automated/action_spec.lua` file. - -actions.move_selection_next({prompt_bufnr}) *telescope.actions.move_selection_next()* +actions.move_selection_next({prompt_bufnr}) *actions.move_selection_next()* Move the selection to the next entry @@ -2003,7 +1861,7 @@ actions.move_selection_next({prompt_bufnr}) *telescope.actions.move_selection_ne {prompt_bufnr} (number) The prompt bufnr -actions.move_selection_previous({prompt_bufnr}) *telescope.actions.move_selection_previous()* +actions.move_selection_previous({prompt_bufnr}) *actions.move_selection_previous()* Move the selection to the previous entry @@ -2011,7 +1869,7 @@ actions.move_selection_previous({prompt_bufnr}) *telescope.actions.move_selectio {prompt_bufnr} (number) The prompt bufnr -actions.move_selection_worse({prompt_bufnr}) *telescope.actions.move_selection_worse()* +actions.move_selection_worse({prompt_bufnr}) *actions.move_selection_worse()* Move the selection to the entry that has a worse score @@ -2019,7 +1877,7 @@ actions.move_selection_worse({prompt_bufnr}) *telescope.actions.move_selection_w {prompt_bufnr} (number) The prompt bufnr -actions.move_selection_better({prompt_bufnr}) *telescope.actions.move_selection_better()* +actions.move_selection_better({prompt_bufnr}) *actions.move_selection_better()* Move the selection to the entry that has a better score @@ -2027,7 +1885,7 @@ actions.move_selection_better({prompt_bufnr}) *telescope.actions.move_selection_ {prompt_bufnr} (number) The prompt bufnr -actions.move_to_top({prompt_bufnr}) *telescope.actions.move_to_top()* +actions.move_to_top({prompt_bufnr}) *actions.move_to_top()* Move to the top of the picker @@ -2035,7 +1893,7 @@ actions.move_to_top({prompt_bufnr}) *telescope.actions.move_to_top()* {prompt_bufnr} (number) The prompt bufnr -actions.move_to_middle({prompt_bufnr}) *telescope.actions.move_to_middle()* +actions.move_to_middle({prompt_bufnr}) *actions.move_to_middle()* Move to the middle of the picker @@ -2043,7 +1901,7 @@ actions.move_to_middle({prompt_bufnr}) *telescope.actions.move_to_middle()* {prompt_bufnr} (number) The prompt bufnr -actions.move_to_bottom({prompt_bufnr}) *telescope.actions.move_to_bottom()* +actions.move_to_bottom({prompt_bufnr}) *actions.move_to_bottom()* Move to the bottom of the picker @@ -2051,7 +1909,7 @@ actions.move_to_bottom({prompt_bufnr}) *telescope.actions.move_to_bottom()* {prompt_bufnr} (number) The prompt bufnr -actions.add_selection({prompt_bufnr}) *telescope.actions.add_selection()* +actions.add_selection({prompt_bufnr}) *actions.add_selection()* Add current entry to multi select @@ -2059,7 +1917,7 @@ actions.add_selection({prompt_bufnr}) *telescope.actions.add_selection()* {prompt_bufnr} (number) The prompt bufnr -actions.remove_selection({prompt_bufnr}) *telescope.actions.remove_selection()* +actions.remove_selection({prompt_bufnr}) *actions.remove_selection()* Remove current entry from multi select @@ -2067,7 +1925,7 @@ actions.remove_selection({prompt_bufnr}) *telescope.actions.remove_selection()* {prompt_bufnr} (number) The prompt bufnr -actions.toggle_selection({prompt_bufnr}) *telescope.actions.toggle_selection()* +actions.toggle_selection({prompt_bufnr}) *actions.toggle_selection()* Toggle current entry status for multi select @@ -2075,7 +1933,7 @@ actions.toggle_selection({prompt_bufnr}) *telescope.actions.toggle_selection()* {prompt_bufnr} (number) The prompt bufnr -actions.select_all({prompt_bufnr}) *telescope.actions.select_all()* +actions.select_all({prompt_bufnr}) *actions.select_all()* Multi select all entries. - Note: selected entries may include results not visible in the results popup. @@ -2085,7 +1943,7 @@ actions.select_all({prompt_bufnr}) *telescope.actions.select_all()* {prompt_bufnr} (number) The prompt bufnr -actions.drop_all({prompt_bufnr}) *telescope.actions.drop_all()* +actions.drop_all({prompt_bufnr}) *actions.drop_all()* Drop all entries from the current multi selection. @@ -2093,7 +1951,7 @@ actions.drop_all({prompt_bufnr}) *telescope.actions.drop_all()* {prompt_bufnr} (number) The prompt bufnr -actions.toggle_all({prompt_bufnr}) *telescope.actions.toggle_all()* +actions.toggle_all({prompt_bufnr}) *actions.toggle_all()* Toggle multi selection for all entries. - Note: toggled entries may include results not visible in the results popup. @@ -2103,210 +1961,7 @@ actions.toggle_all({prompt_bufnr}) *telescope.actions.toggle_all()* {prompt_bufnr} (number) The prompt bufnr -actions.preview_scrolling_up({prompt_bufnr}) *telescope.actions.preview_scrolling_up()* - Scroll the preview window up - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.preview_scrolling_down({prompt_bufnr}) *telescope.actions.preview_scrolling_down()* - Scroll the preview window down - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.results_scrolling_up({prompt_bufnr}) *telescope.actions.results_scrolling_up()* - Scroll the results window up - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.results_scrolling_down({prompt_bufnr}) *telescope.actions.results_scrolling_down()* - Scroll the results window down - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.center({prompt_bufnr}) *telescope.actions.center()* - Center the cursor in the window, can be used after selecting a file to edit - You can just map `actions.select_default + actions.center` - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.select_default({prompt_bufnr}) *telescope.actions.select_default()* - Perform default action on selection, usually something like - `:edit ` - - i.e. open the selection in the current buffer - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.select_horizontal({prompt_bufnr}) *telescope.actions.select_horizontal()* - Perform 'horizontal' action on selection, usually something like - `:new ` - - i.e. open the selection in a new horizontal split - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.select_vertical({prompt_bufnr}) *telescope.actions.select_vertical()* - Perform 'vertical' action on selection, usually something like - `:vnew ` - - i.e. open the selection in a new vertical split - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.select_tab({prompt_bufnr}) *telescope.actions.select_tab()* - Perform 'tab' action on selection, usually something like - `:tabedit ` - - i.e. open the selection in a new tab - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.file_edit({prompt_bufnr}) *telescope.actions.file_edit()* - Perform file edit on selection, usually something like - `:edit ` - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.file_split({prompt_bufnr}) *telescope.actions.file_split()* - Perform file split on selection, usually something like - `:new ` - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.file_vsplit({prompt_bufnr}) *telescope.actions.file_vsplit()* - Perform file vsplit on selection, usually something like - `:vnew ` - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.file_tab({prompt_bufnr}) *telescope.actions.file_tab()* - Perform file tab on selection, usually something like - `:tabedit ` - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.close({prompt_bufnr}) *telescope.actions.close()* - Close the Telescope window, usually used within an action - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions._close({prompt_bufnr}) *telescope.actions._close()* - Close the Telescope window, usually used within an action - Deprecated and no longer needed, does the same as - |telescope.actions.close|. Might be removed in the future - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.edit_command_line({prompt_bufnr}) *telescope.actions.edit_command_line()* - Set a value in the command line and dont run it, making it editable. - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.set_command_line({prompt_bufnr}) *telescope.actions.set_command_line()* - Set a value in the command line and run it - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.edit_search_line({prompt_bufnr}) *telescope.actions.edit_search_line()* - Set a value in the search line and dont search for it, making it editable. - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.set_search_line({prompt_bufnr}) *telescope.actions.set_search_line()* - Set a value in the search line and search for it - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.edit_register({prompt_bufnr}) *telescope.actions.edit_register()* - Edit a register - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.paste_register({prompt_bufnr}) *telescope.actions.paste_register()* - Paste the selected register into the buffer - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.insert_symbol({prompt_bufnr}) *telescope.actions.insert_symbol()* - Insert a symbol into the current buffer (while switching to normal mode) - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.insert_symbol_i({prompt_bufnr}) *telescope.actions.insert_symbol_i()* - Insert a symbol into the current buffer and keeping the insert mode. - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.git_create_branch({prompt_bufnr}) *telescope.actions.git_create_branch()* +actions.git_create_branch({prompt_bufnr}) *actions.git_create_branch()* Create and checkout a new git branch if it doesn't already exist @@ -2314,7 +1969,7 @@ actions.git_create_branch({prompt_bufnr}) *telescope.actions.git_create_branch() {prompt_bufnr} (number) The prompt bufnr -actions.git_apply_stash({prompt_bufnr}) *telescope.actions.git_apply_stash()* +actions.git_apply_stash({prompt_bufnr}) *actions.git_apply_stash()* Applies an existing git stash @@ -2322,7 +1977,7 @@ actions.git_apply_stash({prompt_bufnr}) *telescope.actions.git_apply_stash()* {prompt_bufnr} (number) The prompt bufnr -actions.git_checkout({prompt_bufnr}) *telescope.actions.git_checkout()* +actions.git_checkout({prompt_bufnr}) *actions.git_checkout()* Checkout an existing git branch @@ -2330,7 +1985,7 @@ actions.git_checkout({prompt_bufnr}) *telescope.actions.git_checkout()* {prompt_bufnr} (number) The prompt bufnr -actions.git_switch_branch({prompt_bufnr}) *telescope.actions.git_switch_branch()* +actions.git_switch_branch({prompt_bufnr}) *actions.git_switch_branch()* Switch to git branch. If the branch already exists in local, switch to that. If the branch is only in remote, create new branch tracking remote and switch to new one. @@ -2340,7 +1995,7 @@ actions.git_switch_branch({prompt_bufnr}) *telescope.actions.git_switch_branch() {prompt_bufnr} (number) The prompt bufnr -actions.git_track_branch({prompt_bufnr}) *telescope.actions.git_track_branch()* +actions.git_track_branch({prompt_bufnr}) *actions.git_track_branch()* Tell git to track the currently selected remote branch in Telescope @@ -2348,7 +2003,7 @@ actions.git_track_branch({prompt_bufnr}) *telescope.actions.git_track_branch()* {prompt_bufnr} (number) The prompt bufnr -actions.git_delete_branch({prompt_bufnr}) *telescope.actions.git_delete_branch()* +actions.git_delete_branch({prompt_bufnr}) *actions.git_delete_branch()* Delete the currently selected branch @@ -2356,7 +2011,7 @@ actions.git_delete_branch({prompt_bufnr}) *telescope.actions.git_delete_branch() {prompt_bufnr} (number) The prompt bufnr -actions.git_merge_branch({prompt_bufnr}) *telescope.actions.git_merge_branch()* +actions.git_merge_branch({prompt_bufnr}) *actions.git_merge_branch()* Merge the currently selected branch @@ -2364,7 +2019,7 @@ actions.git_merge_branch({prompt_bufnr}) *telescope.actions.git_merge_branch()* {prompt_bufnr} (number) The prompt bufnr -actions.git_rebase_branch({prompt_bufnr}) *telescope.actions.git_rebase_branch()* +actions.git_rebase_branch({prompt_bufnr}) *actions.git_rebase_branch()* Rebase to selected git branch @@ -2372,7 +2027,7 @@ actions.git_rebase_branch({prompt_bufnr}) *telescope.actions.git_rebase_branch() {prompt_bufnr} (number) The prompt bufnr -actions.git_reset_mixed({prompt_bufnr}) *telescope.actions.git_reset_mixed()* +actions.git_reset_mixed({prompt_bufnr}) *actions.git_reset_mixed()* Reset to selected git commit using mixed mode @@ -2380,7 +2035,7 @@ actions.git_reset_mixed({prompt_bufnr}) *telescope.actions.git_reset_mixed()* {prompt_bufnr} (number) The prompt bufnr -actions.git_reset_soft({prompt_bufnr}) *telescope.actions.git_reset_soft()* +actions.git_reset_soft({prompt_bufnr}) *actions.git_reset_soft()* Reset to selected git commit using soft mode @@ -2388,7 +2043,7 @@ actions.git_reset_soft({prompt_bufnr}) *telescope.actions.git_reset_soft()* {prompt_bufnr} (number) The prompt bufnr -actions.git_reset_hard({prompt_bufnr}) *telescope.actions.git_reset_hard()* +actions.git_reset_hard({prompt_bufnr}) *actions.git_reset_hard()* Reset to selected git commit using hard mode @@ -2396,15 +2051,7 @@ actions.git_reset_hard({prompt_bufnr}) *telescope.actions.git_reset_hard()* {prompt_bufnr} (number) The prompt bufnr -actions.git_checkout_current_buffer({prompt_bufnr}) *telescope.actions.git_checkout_current_buffer()* - Checkout a specific file for a given sha - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.git_staging_toggle({prompt_bufnr}) *telescope.actions.git_staging_toggle()* +actions.git_staging_toggle({prompt_bufnr}) *actions.git_staging_toggle()* Stage/unstage selected file @@ -2412,156 +2059,85 @@ actions.git_staging_toggle({prompt_bufnr}) *telescope.actions.git_staging_toggle {prompt_bufnr} (number) The prompt bufnr -actions.send_selected_to_qflist({prompt_bufnr}) *telescope.actions.send_selected_to_qflist()* +actions.send_selected_to_qflist() *actions.send_selected_to_qflist()* Sends the selected entries to the quickfix list, replacing the previous entries. - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - -actions.add_selected_to_qflist({prompt_bufnr}) *telescope.actions.add_selected_to_qflist()* +actions.add_selected_to_qflist() *actions.add_selected_to_qflist()* Adds the selected entries to the quickfix list, keeping the previous entries. - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - -actions.send_to_qflist({prompt_bufnr}) *telescope.actions.send_to_qflist()* +actions.send_to_qflist() *actions.send_to_qflist()* Sends all entries to the quickfix list, replacing the previous entries. - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - -actions.add_to_qflist({prompt_bufnr}) *telescope.actions.add_to_qflist()* +actions.add_to_qflist() *actions.add_to_qflist()* Adds all entries to the quickfix list, keeping the previous entries. - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - -actions.send_selected_to_loclist({prompt_bufnr}) *telescope.actions.send_selected_to_loclist()* +actions.send_selected_to_loclist() *actions.send_selected_to_loclist()* Sends the selected entries to the location list, replacing the previous entries. - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - -actions.add_selected_to_loclist({prompt_bufnr}) *telescope.actions.add_selected_to_loclist()* +actions.add_selected_to_loclist() *actions.add_selected_to_loclist()* Adds the selected entries to the location list, keeping the previous entries. - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - -actions.send_to_loclist({prompt_bufnr}) *telescope.actions.send_to_loclist()* +actions.send_to_loclist() *actions.send_to_loclist()* Sends all entries to the location list, replacing the previous entries. - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - -actions.add_to_loclist({prompt_bufnr}) *telescope.actions.add_to_loclist()* +actions.add_to_loclist() *actions.add_to_loclist()* Adds all entries to the location list, keeping the previous entries. - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - -actions.smart_send_to_qflist({prompt_bufnr}) *telescope.actions.smart_send_to_qflist()* +actions.smart_send_to_qflist() *actions.smart_send_to_qflist()* Sends the selected entries to the quickfix list, replacing the previous entries. If no entry was selected, sends all entries. - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - -actions.smart_add_to_qflist({prompt_bufnr}) *telescope.actions.smart_add_to_qflist()* +actions.smart_add_to_qflist() *actions.smart_add_to_qflist()* Adds the selected entries to the quickfix list, keeping the previous entries. If no entry was selected, adds all entries. - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - -actions.smart_send_to_loclist({prompt_bufnr}) *telescope.actions.smart_send_to_loclist()* +actions.smart_send_to_loclist() *actions.smart_send_to_loclist()* Sends the selected entries to the location list, replacing the previous entries. If no entry was selected, sends all entries. - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - -actions.smart_add_to_loclist({prompt_bufnr}) *telescope.actions.smart_add_to_loclist()* +actions.smart_add_to_loclist() *actions.smart_add_to_loclist()* Adds the selected entries to the location list, keeping the previous entries. If no entry was selected, adds all entries. - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr + +actions.open_qflist() *actions.open_qflist()* + Open the quickfix list -actions.complete_tag({prompt_bufnr}) *telescope.actions.complete_tag()* - Open completion menu containing the tags which can be used to filter the - results in a faster way + +actions.open_loclist() *actions.open_loclist()* + Open the location list - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - -actions.cycle_history_next({prompt_bufnr}) *telescope.actions.cycle_history_next()* - Cycle to the next search prompt in the history - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.cycle_history_prev({prompt_bufnr}) *telescope.actions.cycle_history_prev()* - Cycle to the previous search prompt in the history - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.open_qflist({prompt_bufnr}) *telescope.actions.open_qflist()* - Open the quickfix list. It makes sense to use this in combination with one - of the send_to_qflist actions `actions.smart_send_to_qflist + - actions.open_qflist` - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.open_loclist({prompt_bufnr}) *telescope.actions.open_loclist()* - Open the location list. It makes sense to use this in combination with one - of the send_to_loclist actions `actions.smart_send_to_qflist + - actions.open_qflist` - - - Parameters: ~ - {prompt_bufnr} (number) The prompt bufnr - - -actions.delete_buffer({prompt_bufnr}) *telescope.actions.delete_buffer()* +actions.delete_buffer({prompt_bufnr}) *actions.delete_buffer()* Delete the selected buffer or all the buffers selected using multi selection. @@ -2570,7 +2146,7 @@ actions.delete_buffer({prompt_bufnr}) *telescope.actions.delete_buffer()* {prompt_bufnr} (number) The prompt bufnr -actions.cycle_previewers_next({prompt_bufnr}) *telescope.actions.cycle_previewers_next()* +actions.cycle_previewers_next({prompt_bufnr}) *actions.cycle_previewers_next()* Cycle to the next previewer if there is one available. This action is not mapped on default. @@ -2579,7 +2155,7 @@ actions.cycle_previewers_next({prompt_bufnr}) *telescope.actions.cycle_previewer {prompt_bufnr} (number) The prompt bufnr -actions.cycle_previewers_prev({prompt_bufnr}) *telescope.actions.cycle_previewers_prev()* +actions.cycle_previewers_prev({prompt_bufnr}) *actions.cycle_previewers_prev()* Cycle to the previous previewer if there is one available. This action is not mapped on default. @@ -2588,7 +2164,7 @@ actions.cycle_previewers_prev({prompt_bufnr}) *telescope.actions.cycle_previewer {prompt_bufnr} (number) The prompt bufnr -actions.remove_selected_picker({prompt_bufnr}) *telescope.actions.remove_selected_picker()* +actions.remove_selected_picker({prompt_bufnr}) *actions.remove_selected_picker()* Removes the selected picker in |builtin.pickers|. This action is not mapped by default and only intended for |builtin.pickers|. @@ -2598,7 +2174,7 @@ actions.remove_selected_picker({prompt_bufnr}) *telescope.actions.remove_selecte {prompt_bufnr} (number) The prompt bufnr -actions.which_key({prompt_bufnr}) *telescope.actions.which_key()* +actions.which_key({prompt_bufnr}) *actions.which_key()* Display the keymaps of registered actions similar to which-key.nvim. - Notes: @@ -2617,17 +2193,17 @@ Functions to be used to determine the current state of telescope. Generally used from within other |telescope.actions| -action_state.get_selected_entry() *telescope.actions.state.get_selected_entry()* +action_state.get_selected_entry() *action_state.get_selected_entry()* Get the current entry -action_state.get_current_line() *telescope.actions.state.get_current_line()* +action_state.get_current_line() *action_state.get_current_line()* Gets the current line -action_state.get_current_picker({prompt_bufnr}) *telescope.actions.state.get_current_picker()* +action_state.get_current_picker({prompt_bufnr}) *action_state.get_current_picker()* Gets the current picker @@ -2647,7 +2223,7 @@ vertical split, etc. Instead of making users have to overwrite EACH of those every time they want to change this behavior, they can instead replace the `set` itself and then it will work great and they're done. -action_set.shift_selection({prompt_bufnr}, {change}) *telescope.actions.set.shift_selection()* +action_set.shift_selection({prompt_bufnr}, {change}) *action_set.shift_selection()* Move the current selection of a picker {change} rows. Handles not overflowing / underflowing the list. @@ -2657,7 +2233,7 @@ action_set.shift_selection({prompt_bufnr}, {change}) *telescope.actions.set.shif {change} (number) The amount to shift the selection by -action_set.select({prompt_bufnr}, {type}) *telescope.actions.set.select()* +action_set.select({prompt_bufnr}, {type}) *action_set.select()* Select the current entry. This is the action set to overwrite common actions by the user. @@ -2669,7 +2245,7 @@ action_set.select({prompt_bufnr}, {type}) *telescope.actions.set.select()* {type} (string) The type of selection to make -action_set.edit({prompt_bufnr}, {command}) *telescope.actions.set.edit()* +action_set.edit({prompt_bufnr}, {command}) *action_set.edit()* Edit a file based on the current selection. @@ -2678,7 +2254,7 @@ action_set.edit({prompt_bufnr}, {command}) *telescope.actions.set.edit()* {command} (string) The command to use to open the file. -action_set.scroll_previewer({prompt_bufnr}, {direction}) *telescope.actions.set.scroll_previewer()* +action_set.scroll_previewer({prompt_bufnr}, {direction}) *action_set.scroll_previewer()* Scrolls the previewer up or down. Defaults to a half page scroll, but can be overridden using the `scroll_speed` option in `layout_config`. See |telescope.layout| for more details. @@ -2689,10 +2265,8 @@ action_set.scroll_previewer({prompt_bufnr}, {direction}) *telescope.actions.set. {direction} (number) The direction of the scrolling -action_set.scroll_results({prompt_bufnr}, {direction}) *telescope.actions.set.scroll_results()* - Scrolls the results up or down. Defaults to a half page scroll, but can be - overridden using the `scroll_speed` option in `layout_config`. See - |telescope.layout| for more details. +action_set.scroll_results({prompt_bufnr}, {direction}) *action_set.scroll_results()* + Scrolls the results up or down. Moves `count` movements. Parameters: ~ @@ -2706,7 +2280,7 @@ action_set.scroll_results({prompt_bufnr}, {direction}) *telescope.actions.set.sc The layout actions are actions to be used to change the layout of a picker. -action_layout.toggle_preview({prompt_bufnr}) *telescope.actions.layout.toggle_preview()* +action_layout.toggle_preview({prompt_bufnr}) *action_layout.toggle_preview()* Toggle preview window. - Note: preview window can be toggled even if preview is set to false. @@ -2717,7 +2291,7 @@ action_layout.toggle_preview({prompt_bufnr}) *telescope.actions.layout.toggle_pr {prompt_bufnr} (number) The prompt bufnr -action_layout.toggle_prompt_position({prompt_bufnr}) *telescope.actions.layout.toggle_prompt_position()* +action_layout.toggle_prompt_position({prompt_bufnr}) *action_layout.toggle_prompt_position()* Toggles the `prompt_position` option between "top" and "bottom". Checks if `prompt_position` is an option for the current layout. @@ -2728,7 +2302,7 @@ action_layout.toggle_prompt_position({prompt_bufnr}) *telescope.actions.layout.t {prompt_bufnr} (number) The prompt bufnr -action_layout.toggle_mirror({prompt_bufnr}) *telescope.actions.layout.toggle_mirror()* +action_layout.toggle_mirror({prompt_bufnr}) *action_layout.toggle_mirror()* Toggles the `mirror` option between `true` and `false`. Checks if `mirror` is an option for the current layout. @@ -2739,7 +2313,7 @@ action_layout.toggle_mirror({prompt_bufnr}) *telescope.actions.layout.toggle_mir {prompt_bufnr} (number) The prompt bufnr -action_layout.cycle_layout_next({prompt_bufnr}) *telescope.actions.layout.cycle_layout_next()* +action_layout.cycle_layout_next({prompt_bufnr}) *action_layout.cycle_layout_next()* Cycles to the next layout in `cycle_layout_list`. This action is not mapped by default. @@ -2749,7 +2323,7 @@ action_layout.cycle_layout_next({prompt_bufnr}) *telescope.actions.layout.cycle_ {prompt_bufnr} (number) The prompt bufnr -action_layout.cycle_layout_prev({prompt_bufnr}) *telescope.actions.layout.cycle_layout_prev()* +action_layout.cycle_layout_prev({prompt_bufnr}) *action_layout.cycle_layout_prev()* Cycles to the previous layout in `cycle_layout_list`. This action is not mapped by default. @@ -2767,7 +2341,7 @@ Utilities to wrap functions around picker selections and entries. Generally used from within other |telescope.actions| -utils.map_entries({prompt_bufnr}, {f}) *telescope.actions.utils.map_entries()* +utils.map_entries({prompt_bufnr}, {f}) *utils.map_entries()* Apply `f` to the entries of the current picker. - Notes: - Mapped entries may include results not visible in the results popup. @@ -2798,7 +2372,7 @@ utils.map_entries({prompt_bufnr}, {f}) *telescope.actions.utils.map_entries()* arguments -utils.map_selections({prompt_bufnr}, {f}) *telescope.actions.utils.map_selections()* +utils.map_selections({prompt_bufnr}, {f}) *utils.map_selections()* Apply `f` to the multi selections of the current picker and return a table of mapped selections. - Notes: @@ -2829,7 +2403,7 @@ utils.map_selections({prompt_bufnr}, {f}) *telescope.actions.utils.map_selection that takes (selection) as a viable argument -utils.get_registered_mappings({prompt_bufnr}) *telescope.actions.utils.get_registered_mappings()* +utils.get_registered_mappings({prompt_bufnr}) *utils.get_registered_mappings()* Utility to collect mappings of prompt buffer in array of `{mode, keybind, name}`. @@ -2863,7 +2437,7 @@ General usage: } < -action_generate.which_key({opts}) *telescope.actions.generate.which_key()* +action_generate.which_key({opts}) *action_generate.which_key()* Display the keymaps of registered actions similar to which-key.nvim. - Floating window: @@ -2939,7 +2513,7 @@ necessary fields. The more important ones are Previewers can be disabled for any builtin or custom picker by doing :Telescope find_files previewer=false -previewers.Previewer() *telescope.previewers.Previewer()* +previewers.Previewer() *previewers.Previewer()* This is the base table all previewers have to implement. It's possible to write a wrapper for this because most previewers need to have the same keys set. Examples of wrappers are: @@ -2976,13 +2550,13 @@ previewers.Previewer() *telescope.previewers.Previewer()* -previewers.new() *telescope.previewers.new()* +previewers.new() *previewers.new()* A shorthand for creating a new Previewer. The provided table will be forwarded to `Previewer:new(...)` -previewers.new_termopen_previewer() *telescope.previewers.new_termopen_previewer()* +previewers.new_termopen_previewer() *previewers.new_termopen_previewer()* Is a wrapper around Previewer and helps with creating a new `termopen_previewer`. @@ -3007,9 +2581,12 @@ previewers.new_termopen_previewer() *telescope.previewers.new_termopen_previewer Furthermore, it will forward all `config.set_env` environment variables to that terminal process. + While this interface is a good start, it was replaced with the way more + flexible `buffer_previewer` and is now deprecated. -previewers.cat() *telescope.previewers.cat()* + +previewers.cat() *previewers.cat()* Provides a `termopen_previewer` which has the ability to display files. It will always show the top of the file and has support for `bat`(prioritized) and `cat`. Each entry has to provide either the field `path` or `filename` @@ -3022,7 +2599,7 @@ previewers.cat() *telescope.previewers.cat()* -previewers.vimgrep() *telescope.previewers.vimgrep()* +previewers.vimgrep() *previewers.vimgrep()* Provides a `termopen_previewer` which has the ability to display files at the provided line. It has support for `bat`(prioritized) and `cat`. Each entry has to provide either the field `path` or `filename` and a `lnum` @@ -3035,7 +2612,7 @@ previewers.vimgrep() *telescope.previewers.vimgrep()* -previewers.qflist() *telescope.previewers.qflist()* +previewers.qflist() *previewers.qflist()* Provides a `termopen_previewer` which has the ability to display files at the provided line or range. It has support for `bat`(prioritized) and `cat`. Each entry has to provide either the field `path` or `filename`, @@ -3049,7 +2626,7 @@ previewers.qflist() *telescope.previewers.qflist()* -previewers.new_buffer_previewer() *telescope.previewers.new_buffer_previewer()* +previewers.new_buffer_previewer() *previewers.new_buffer_previewer()* An interface to instantiate a new `buffer_previewer`. That means that the content actually lives inside a vim buffer which enables us more control over the actual content. For example, we can use `vim.fn.search` to jump to @@ -3142,7 +2719,7 @@ previewers.new_buffer_previewer() *telescope.previewers.new_buffer_previewer()* -previewers.buffer_previewer_maker({filepath}, {bufnr}, {opts}) *telescope.previewers.buffer_previewer_maker()* +previewers.buffer_previewer_maker({filepath}, {bufnr}, {opts}) *previewers.buffer_previewer_maker()* A universal way of reading a file into a buffer previewer. It handles async reading, cache, highlighting, displaying directories and provides a callback which can be used, to jump to a line in the buffer. @@ -3154,7 +2731,7 @@ previewers.buffer_previewer_maker({filepath}, {bufnr}, {opts}) *telescope.previe {opts} (table) keys: `use_ft_detect`, `bufname` and `callback` -previewers.vim_buffer_cat() *telescope.previewers.vim_buffer_cat()* +previewers.vim_buffer_cat() *previewers.vim_buffer_cat()* A previewer that is used to display a file. It uses the `buffer_previewer` interface and won't jump to the line. To integrate this one into your own picker make sure that the field `path` or `filename` is set for each entry. @@ -3165,7 +2742,7 @@ previewers.vim_buffer_cat() *telescope.previewers.vim_buffer_cat()* -previewers.vim_buffer_vimgrep() *telescope.previewers.vim_buffer_vimgrep()* +previewers.vim_buffer_vimgrep() *previewers.vim_buffer_vimgrep()* A previewer that is used to display a file and jump to the provided line. It uses the `buffer_previewer` interface. To integrate this one into your own picker make sure that the field `path` or `filename` and `lnum` is set @@ -3177,7 +2754,7 @@ previewers.vim_buffer_vimgrep() *telescope.previewers.vim_buffer_vimgrep()* -previewers.vim_buffer_qflist() *telescope.previewers.vim_buffer_qflist()* +previewers.vim_buffer_qflist() *previewers.vim_buffer_qflist()* Is the same as `vim_buffer_vimgrep` and only exist for consistency with `term_previewers`. @@ -3188,17 +2765,17 @@ previewers.vim_buffer_qflist() *telescope.previewers.vim_buffer_qflist()* -previewers.git_branch_log() *telescope.previewers.git_branch_log()* +previewers.git_branch_log() *previewers.git_branch_log()* A previewer that shows a log of a branch as graph -previewers.git_stash_diff() *telescope.previewers.git_stash_diff()* +previewers.git_stash_diff() *previewers.git_stash_diff()* A previewer that shows a diff of a stash -previewers.git_commit_diff_to_parent() *telescope.previewers.git_commit_diff_to_parent()* +previewers.git_commit_diff_to_parent() *previewers.git_commit_diff_to_parent()* A previewer that shows a diff of a commit to a parent commit. The run command is `git --no-pager diff SHA^! -- $CURRENT_FILE` @@ -3206,7 +2783,7 @@ previewers.git_commit_diff_to_parent() *telescope.previewers.git_commit_diff_to_ -previewers.git_commit_diff_to_head() *telescope.previewers.git_commit_diff_to_head()* +previewers.git_commit_diff_to_head() *previewers.git_commit_diff_to_head()* A previewer that shows a diff of a commit to head. The run command is `git --no-pager diff --cached $SHA -- $CURRENT_FILE` @@ -3214,26 +2791,26 @@ previewers.git_commit_diff_to_head() *telescope.previewers.git_commit_diff_to_he -previewers.git_commit_diff_as_was() *telescope.previewers.git_commit_diff_as_was()* +previewers.git_commit_diff_as_was() *previewers.git_commit_diff_as_was()* A previewer that shows a diff of a commit as it was. The run command is `git --no-pager show $SHA:$CURRENT_FILE` or `git --no-pager show $SHA` -previewers.git_commit_message() *telescope.previewers.git_commit_message()* +previewers.git_commit_message() *previewers.git_commit_message()* A previewer that shows the commit message of a diff. The run command is `git --no-pager log -n 1 $SHA` -previewers.git_file_diff() *telescope.previewers.git_file_diff()* +previewers.git_file_diff() *previewers.git_file_diff()* A previewer that shows the current diff of a file. Used in git_status. The run command is `git --no-pager diff $FILE` -previewers.display_content() *telescope.previewers.display_content()* +previewers.display_content() *previewers.display_content()* A deprecated way of displaying content more easily. Was written at a time, where the buffer_previewer interface wasn't present. Nowadays it's easier to just use this. We will keep it around for backwards compatibility @@ -3261,9 +2838,9 @@ So you have a history for: - live_grep project_2 - etc -See https://github.com/nvim-telescope/telescope-smart-history.nvim +See github.com/nvim-telescope/telescope-smart-history.nvim -histories.History() *telescope.actions.history.History()* +histories.History() *histories.History()* Manages prompt history @@ -3278,7 +2855,7 @@ histories.History() *telescope.actions.history.History()* Default is #content + 1 -histories.History:new({opts}) *telescope.actions.history.History:new()* +histories.History:new({opts}) *histories.History:new()* Create a new History @@ -3295,18 +2872,18 @@ histories.History:new({opts}) *telescope.actions.history.History:new()* will be returned (optional) -histories.new() *telescope.actions.history.new()* +histories.new() *histories.new()* Shorthand to create a new history -histories.History:reset() *telescope.actions.history.History:reset()* +histories.History:reset() *histories.History:reset()* Will reset the history index to the default initial state. Will happen after the picker closed -histories.History:append({line}, {picker}, {no_reset}) *telescope.actions.history.History:append()* +histories.History:append({line}, {picker}, {no_reset}) *histories.History:append()* Append a new line to the history @@ -3317,7 +2894,7 @@ histories.History:append({line}, {picker}, {no_reset}) *telescope.actions.histor If you don't want to do this set to true -histories.History:get_next({line}, {picker}) *telescope.actions.history.History:get_next()* +histories.History:get_next({line}, {picker}) *histories.History:get_next()* Will return the next history item. Can be nil if there are no next items @@ -3329,7 +2906,7 @@ histories.History:get_next({line}, {picker}) *telescope.actions.history.History: string: the next history item -histories.History:get_prev({line}, {picker}) *telescope.actions.history.History:get_prev()* +histories.History:get_prev({line}, {picker}) *histories.History:get_prev()* Will return the previous history item. Can be nil if there are no previous items @@ -3342,7 +2919,7 @@ histories.History:get_prev({line}, {picker}) *telescope.actions.history.History: string: the previous history item -histories.get_simple_history() *telescope.actions.history.get_simple_history()* +histories.get_simple_history() *histories.get_simple_history()* A simple implementation of history. It will keep one unified history across all pickers. diff --git a/lua/telescope/actions/init.lua b/lua/telescope/actions/init.lua index 2c4624b..c2f3f9b 100644 --- a/lua/telescope/actions/init.lua +++ b/lua/telescope/actions/init.lua @@ -155,35 +155,19 @@ end actions.select_all = function(prompt_bufnr) local current_picker = action_state.get_current_picker(prompt_bufnr) action_utils.map_entries(prompt_bufnr, function(entry, _, row) - if not current_picker._multi:is_selected(entry) then - current_picker._multi:add(entry) - if current_picker:can_select_row(row) then - local caret = current_picker:update_prefix(entry, row) - if current_picker._selection_entry == entry and current_picker._selection_row == row then - current_picker.highlighter:hi_selection(row, caret:match "(.*%S)") - end - current_picker.highlighter:hi_multiselect(row, current_picker._multi:is_selected(entry)) - end - end + current_picker._multi:add(entry) end) - current_picker:get_status_updater(current_picker.prompt_win, current_picker.prompt_bufnr)() + current_picker:_redraw(true) end --- Drop all entries from the current multi selection. ---@param prompt_bufnr number: The prompt bufnr actions.drop_all = function(prompt_bufnr) local current_picker = action_state.get_current_picker(prompt_bufnr) - action_utils.map_entries(prompt_bufnr, function(entry, _, row) + action_utils.map_entries(prompt_bufnr, function(entry) current_picker._multi:drop(entry) - if current_picker:can_select_row(row) then - local caret = current_picker:update_prefix(entry, row) - if current_picker._selection_entry == entry and current_picker._selection_row == row then - current_picker.highlighter:hi_selection(row, caret:match "(.*%S)") - end - current_picker.highlighter:hi_multiselect(row, current_picker._multi:is_selected(entry)) - end end) - current_picker:get_status_updater(current_picker.prompt_win, current_picker.prompt_bufnr)() + current_picker:_redraw(true) end --- Toggle multi selection for all entries. @@ -191,17 +175,10 @@ end ---@param prompt_bufnr number: The prompt bufnr actions.toggle_all = function(prompt_bufnr) local current_picker = action_state.get_current_picker(prompt_bufnr) - action_utils.map_entries(prompt_bufnr, function(entry, _, row) + action_utils.map_entries(prompt_bufnr, function(entry) current_picker._multi:toggle(entry) - if current_picker:can_select_row(row) then - local caret = current_picker:update_prefix(entry, row) - if current_picker._selection_entry == entry and current_picker._selection_row == row then - current_picker.highlighter:hi_selection(row, caret:match "(.*%S)") - end - current_picker.highlighter:hi_multiselect(row, current_picker._multi:is_selected(entry)) - end end) - current_picker:get_status_updater(current_picker.prompt_win, current_picker.prompt_bufnr)() + current_picker:_redraw(true) end --- Scroll the preview window up diff --git a/lua/telescope/actions/set.lua b/lua/telescope/actions/set.lua index 017975b..381f3c0 100644 --- a/lua/telescope/actions/set.lua +++ b/lua/telescope/actions/set.lua @@ -193,23 +193,16 @@ action_set.scroll_previewer = function(prompt_bufnr, direction) end --- Scrolls the results up or down. ---- Defaults to a half page scroll, but can be overridden using the `scroll_speed` ---- option in `layout_config`. See |telescope.layout| for more details. +--- Moves `count` movements. ---@param prompt_bufnr number: The prompt bufnr ---@param direction number: The direction of the scrolling -- Valid directions include: "1", "-1" action_set.scroll_results = function(prompt_bufnr, direction) - local status = state.get_status(prompt_bufnr) - local default_speed = vim.api.nvim_win_get_height(status.results_win) / 2 - local speed = status.picker.layout_config.scroll_speed or default_speed + local count = vim.v.count + count = count == 0 and 1 or count + count = a.nvim_get_mode().mode == "n" and count or 1 - local input = direction > 0 and [[]] or [[]] - - vim.api.nvim_win_call(status.results_win, function() - vim.cmd([[normal! ]] .. math.floor(speed) .. input) - end) - - action_set.shift_selection(prompt_bufnr, math.floor(speed) * direction) + action_state.get_current_picker(prompt_bufnr):shift_offset(count * direction) end -- ================================================== diff --git a/lua/telescope/entry_manager.lua b/lua/telescope/entry_manager.lua index a8331e4..fddadd4 100644 --- a/lua/telescope/entry_manager.lua +++ b/lua/telescope/entry_manager.lua @@ -1,28 +1,15 @@ -local log = require "telescope.log" - local LinkedList = require "telescope.algos.linked_list" local EntryManager = {} EntryManager.__index = EntryManager -function EntryManager:new(max_results, set_entry, info) - log.trace "Creating entry_manager..." - - info = info or {} - info.looped = 0 - info.inserted = 0 - info.find_loop = 0 - - -- state contains list of - -- { entry, score } - -- Stored directly in a table, accessed as [1], [2] - set_entry = set_entry or function() end +function EntryManager:new(num_sorted) + num_sorted = num_sorted or 500 return setmetatable({ - linked_states = LinkedList:new { track_at = max_results }, - info = info, - max_results = max_results, - set_entry = set_entry, + dirty = true, + linked_states = LinkedList:new { track_at = num_sorted }, + num_sorted = num_sorted, worst_acceptable_score = math.huge, }, self) end @@ -31,12 +18,12 @@ function EntryManager:num_results() return self.linked_states.size end -function EntryManager:get_container(index) +function EntryManager:get_container(offset, index) local count = 0 for val in self.linked_states:iter() do count = count + 1 - if count == index then + if count == offset + index then return val end end @@ -44,33 +31,28 @@ function EntryManager:get_container(index) return {} end -function EntryManager:get_entry(index) - return self:get_container(index)[1] +function EntryManager:get_entry(offset, index) + return self:get_container(offset, index)[1] end -function EntryManager:get_score(index) - return self:get_container(index)[2] +function EntryManager:get_score(offset, index) + return self:get_container(offset, index)[2] end -function EntryManager:get_ordinal(index) - return self:get_entry(index).ordinal +function EntryManager:get_ordinal(offset, index) + return self:get_entry(offset, index).ordinal end function EntryManager:find_entry(entry) - local info = self.info - local count = 0 for container in self.linked_states:iter() do count = count + 1 if container[1] == entry then - info.find_loop = info.find_loop + count - return count end end - info.find_loop = info.find_loop + count return nil end @@ -84,14 +66,12 @@ end function EntryManager:_insert_container_before(picker, index, linked_node, new_container) self.linked_states:place_before(index, linked_node, new_container) - self.set_entry(picker, index, new_container[1], new_container[2], true) self:_update_score_from_tracked() end function EntryManager:_insert_container_after(picker, index, linked_node, new_container) self.linked_states:place_after(index, linked_node, new_container) - self.set_entry(picker, index, new_container[1], new_container[2], true) self:_update_score_from_tracked() end @@ -99,22 +79,15 @@ end function EntryManager:_append_container(picker, new_container, should_update) self.linked_states:append(new_container) self.worst_acceptable_score = math.min(self.worst_acceptable_score, new_container[2]) - - if should_update then - self.set_entry(picker, self.linked_states.size, new_container[1], new_container[2]) - end end function EntryManager:add_entry(picker, score, entry, prompt) score = score or 0 - local max_res = self.max_results + local num_sorted = self.num_sorted local worst_score = self.worst_acceptable_score local size = self.linked_states.size - local info = self.info - info.maxed = info.maxed or 0 - local new_container = { entry, score } -- Short circuit for bad scores -- they never need to be displayed. @@ -123,16 +96,15 @@ function EntryManager:add_entry(picker, score, entry, prompt) return self.linked_states:append(new_container) end + self.dirty = true + -- Short circuit for first entry. if size == 0 then self.linked_states:prepend(new_container) - self.set_entry(picker, 1, entry, score) return end for index, container, node in self.linked_states:ipairs() do - info.looped = info.looped + 1 - if container[2] > score then return self:_insert_container_before(picker, index, node, new_container) end @@ -142,13 +114,12 @@ function EntryManager:add_entry(picker, score, entry, prompt) end -- Don't add results that are too bad. - if index >= max_res then - info.maxed = info.maxed + 1 + if index >= num_sorted then return self:_append_container(picker, new_container, false) end end - if self.linked_states.size >= max_res then + if self.linked_states.size >= num_sorted then self.worst_acceptable_score = math.min(self.worst_acceptable_score, score) end @@ -165,4 +136,27 @@ function EntryManager:iter() end end +function EntryManager:window(start, finish) + local results = {} + + local idx = 0 + for val in self.linked_states:iter() do + idx = idx + 1 + + if val == nil then + return + end + + if idx >= start then + table.insert(results, val[1]) + end + + if idx >= finish then + break + end + end + + return results +end + return EntryManager diff --git a/lua/telescope/mappings.lua b/lua/telescope/mappings.lua index b81552e..56e1b50 100644 --- a/lua/telescope/mappings.lua +++ b/lua/telescope/mappings.lua @@ -63,6 +63,8 @@ mappings.default_mappings = config.values.default_mappings [""] = actions.preview_scrolling_up, [""] = actions.preview_scrolling_down, + [""] = actions.results_scrolling_down, + [""] = actions.results_scrolling_up, [""] = actions.results_scrolling_up, [""] = actions.results_scrolling_down, diff --git a/lua/telescope/pickers.lua b/lua/telescope/pickers.lua index 12d6209..228dcb0 100644 --- a/lua/telescope/pickers.lua +++ b/lua/telescope/pickers.lua @@ -9,16 +9,12 @@ local popup = require "plenary.popup" local actions = require "telescope.actions" local config = require "telescope.config" -local debounce = require "telescope.debounce" local deprecated = require "telescope.deprecated" local log = require "telescope.log" local mappings = require "telescope.mappings" local state = require "telescope.state" local utils = require "telescope.utils" -local entry_display = require "telescope.pickers.entry_display" -local p_highlighter = require "telescope.pickers.highlights" -local p_scroller = require "telescope.pickers.scroller" local p_window = require "telescope.pickers.window" local EntryManager = require "telescope.entry_manager" @@ -26,10 +22,8 @@ local MultiSelect = require "telescope.pickers.multi" local get_default = utils.get_default -local truncate = require("plenary.strings").truncate local strdisplaywidth = require("plenary.strings").strdisplaywidth -local ns_telescope_matching = a.nvim_create_namespace "telescope_matching" local ns_telescope_prompt = a.nvim_create_namespace "telescope_prompt" local ns_telescope_prompt_prefix = a.nvim_create_namespace "telescope_prompt_prefix" @@ -38,7 +32,16 @@ local pickers = {} -- TODO: Add overscroll option for results buffer ---@class Picker ---- Picker is the main UI that shows up to interact w/ your results. +---@field selection_strategy string +---@field sorting_strategy string +---@field entry_prefix string +---@field sorter Sorter +---@field highlighter table: TODO: Document highlighter +---@field offset number: How far we've scrolled thus far, in rows. So it's a number 0-Max +---@field num_visible number: The number of possible visible entries. Not guaranteed to have that many entries +---currently. + +-- Picker is the main UI that shows up to interact w/ your results. -- Takes a filter & a previewer local Picker = {} Picker.__index = Picker @@ -73,11 +76,7 @@ function Picker:new(opts) -- 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), initial_mode = get_default(opts.initial_mode, config.values.initial_mode), _original_mode = vim.api.nvim_get_mode().mode, @@ -101,7 +100,7 @@ function Picker:new(opts) _find_id = 0, _completion_callbacks = type(opts._completion_callbacks) == "table" and opts._completion_callbacks or {}, - manager = (type(opts.manager) == "table" and getmetatable(opts.manager) == EntryManager) and opts.manager, + -- manager = (type(opts.manager) == "table" and getmetatable(opts.manager) == EntryManager) and opts.manager, _multi = (type(opts._multi) == "table" and getmetatable(opts._multi) == getmetatable(MultiSelect:new())) and opts._multi or MultiSelect:new(), @@ -140,6 +139,26 @@ function Picker:new(opts) cache_picker = config.resolve_table_opts(opts.cache_picker, vim.deepcopy(config.values.cache_picker)), }, self) + obj._on_error = opts._on_error + + -- Separate idea, just for prompt only. Doesn't affect any of the other items. + obj.prompt_prefix = get_default(opts.prompt_prefix, config.values.prompt_prefix) + + -- These are all for each individual row. + -- TODO(1.0): I think this name should be "multiselect_icon" to more clear. + -- Maybe even something a bit different from that. + obj.multi_icon = get_default(opts.multi_icon, config.values.multi_icon) + + obj.selection_caret = get_default(opts.selection_caret, config.values.selection_caret) + obj.entry_prefix = get_default(opts.entry_prefix, config.values.entry_prefix) + + obj._prefix_width = math.max( + strdisplaywidth(obj.entry_prefix), + strdisplaywidth(obj.selection_caret), + strdisplaywidth(obj.multi_icon) + 1 + ) + obj._prefix_string = obj.entry_prefix .. string.rep(" ", obj._prefix_width - strdisplaywidth(obj.entry_prefix)) + obj.get_window_options = opts.get_window_options or p_window.get_window_options if obj.all_previewers ~= nil and obj.all_previewers ~= false then @@ -164,10 +183,8 @@ function Picker:new(opts) obj.hidden_previewer = nil end - -- TODO: It's annoying that this is create and everything else is "new" - obj.scroller = p_scroller.create(obj.scroll_strategy, obj.sorting_strategy) - - obj.highlighter = p_highlighter.new(obj) + obj.scroller = require("telescope.pickers.scroller").new(obj.scroll_strategy, obj.sorting_strategy) + obj.highlighter = require("telescope.pickers.highlights").new(obj) if opts.on_complete then for _, on_complete_item in ipairs(opts.on_complete) do @@ -186,7 +203,7 @@ function Picker:get_row(index) if self.sorting_strategy == "ascending" then return index - 1 else - return self.max_results - index + return self.num_visible - index end end @@ -198,7 +215,7 @@ function Picker:get_index(row) if self.sorting_strategy == "ascending" then return row + 1 else - return self.max_results - row + return self.num_visible - row end end @@ -208,7 +225,20 @@ function Picker:get_reset_row() if self.sorting_strategy == "ascending" then return 0 else - return self.max_results - 1 + return self.num_visible - 1 + end +end + +--- Check if the given row number can be selected +---@param row number: the number of the chosen row in the results buffer +---@return boolean +function Picker:can_select_row(row) + -- TODO(fps): Need to handle scrolling w/ offsets now. + + if self.sorting_strategy == "ascending" then + return row <= self.manager:num_results() and row < self.num_visible + else + return row >= 0 and row <= self.num_visible and row >= self.num_visible - self.manager:num_results() end end @@ -220,95 +250,6 @@ function Picker:is_done() end end ---- Clear rows that are after the final remaining entry ----@note: useful when number of remaining results is narrowed down ----@param results_bufnr number: the buffer number of the results buffer -function Picker:clear_extra_rows(results_bufnr) - if self:is_done() then - log.trace "Not clearing due to being already complete" - return - end - - if not vim.api.nvim_buf_is_valid(results_bufnr) then - log.debug("Invalid results_bufnr for clearing:", results_bufnr) - return - end - - local worst_line, ok, msg - if self.sorting_strategy == "ascending" then - local num_results = self.manager:num_results() - worst_line = self.max_results - num_results - - if worst_line <= 0 then - return - end - - ok, msg = pcall(vim.api.nvim_buf_set_lines, results_bufnr, num_results, -1, false, {}) - else - worst_line = self:get_row(self.manager:num_results()) - if worst_line <= 0 then - return - end - - local empty_lines = utils.repeated_table(worst_line, "") - ok, msg = pcall(vim.api.nvim_buf_set_lines, results_bufnr, 0, worst_line, false, empty_lines) - end - - if not ok then - log.debug("Failed to set lines:", msg) - end - - log.trace("Clearing:", worst_line) -end - ---- Highlight the entry corresponding to the given row ----@param results_bufnr number: the buffer number of the results buffer ----@param prompt table: table with information about the prompt buffer ----@param display string: the text corresponding to the given row ----@param row number: the number of the chosen row -function Picker:highlight_one_row(results_bufnr, prompt, display, row) - if not self.sorter.highlighter then - return - end - - local highlights = self.sorter:highlighter(prompt, display) - - if highlights then - for _, hl in ipairs(highlights) do - local highlight, start, finish - if type(hl) == "table" then - highlight = hl.highlight or "TelescopeMatching" - start = hl.start - finish = hl.finish or hl.start - elseif type(hl) == "number" then - highlight = "TelescopeMatching" - start = hl - finish = hl - else - error "Invalid higlighter fn" - end - - self:_increment "highlights" - - vim.api.nvim_buf_add_highlight(results_bufnr, ns_telescope_matching, highlight, row, start - 1, finish) - end - end - - local entry = self.manager:get_entry(self:get_index(row)) - self.highlighter:hi_multiselect(row, self:is_multi_selected(entry)) -end - ---- Check if the given row number can be selected ----@param row number: the number of the chosen row in the results buffer ----@return boolean -function Picker:can_select_row(row) - if self.sorting_strategy == "ascending" then - return row <= self.manager:num_results() and row < self.max_results - else - return row >= 0 and row <= self.max_results and row >= self.max_results - self.manager:num_results() - end -end - --TODO: document what `find_id` is for function Picker:_next_find_id() local find_id = self._find_id + 1 @@ -405,110 +346,132 @@ function Picker:find() self.prompt_border = prompt_opts and prompt_opts.border -- Prompt prefix - local prompt_prefix = self.prompt_prefix - a.nvim_buf_set_option(prompt_bufnr, "buftype", "prompt") - vim.fn.prompt_setprompt(prompt_bufnr, prompt_prefix) - self.prompt_prefix = prompt_prefix - self:_reset_prefix_color() - - -- TODO: This could be configurable in the future, but I don't know why you would - -- want to scroll through more than 10,000 items. + -- local prompt_prefix = self.prompt_prefix + -- a.nvim_buf_set_option(prompt_bufnr, "buftype", "prompt") + -- vim.fn.prompt_setprompt(prompt_bufnr, prompt_prefix) + -- self.prompt_prefix = prompt_prefix + -- self:_reset_prefix_color() -- - -- This just lets us stop doing stuff after tons of things. - self.max_results = 1000 + -- -- TODO: This could be configurable in the future, but I don't know why you would + -- -- want to scroll through more than 10,000 items. + -- -- + -- -- This just lets us stop doing stuff after tons of things. + -- self.max_results = 1000 + -- + -- vim.api.nvim_buf_set_lines(results_bufnr, 0, self.max_results, false, utils.repeated_table(self.max_results, "")) + -- + -- local status_updater = self:get_status_updater(prompt_win, prompt_bufnr) + -- local debounced_status = debounce.throttle_leading(status_updater, 50) + -- + -- local tx, rx = channel.mpsc() + -- self._on_lines = tx.send + -- + -- local find_id = self:_next_find_id() + -- + -- if self.default_text then + -- self:set_prompt(self.default_text) + -- end + -- + -- if vim.tbl_contains({ "insert", "normal" }, self.initial_mode) then + -- local mode = vim.fn.mode() + -- local keys + -- if self.initial_mode == "normal" then + -- -- n: A makes sure cursor is at always at end of prompt w/o default_text + -- keys = mode ~= "n" and "A" or "A" + -- else + -- -- always fully retrigger insert mode: required for going from one picker to next + -- keys = mode ~= "n" and "A" or "A" + -- end + -- a.nvim_feedkeys(a.nvim_replace_termcodes(keys, true, false, true), "n", true) + -- else + -- utils.notify( + -- "pickers.find", + -- { msg = "`initial_mode` should be one of ['normal', 'insert'] but passed " .. self.initial_mode, level = "ERROR" } + -- ) + -- end + -- + -- local main_loop = async.void(function() + -- self.sorter:_init() + -- + -- -- Do filetype last, so that users can register at the last second. + -- pcall(a.nvim_buf_set_option, prompt_bufnr, "filetype", "TelescopePrompt") + -- pcall(a.nvim_buf_set_option, results_bufnr, "filetype", "TelescopeResults") + -- + -- await_schedule() + -- + -- while true do + -- -- Wait for the next input + -- rx.last() + -- await_schedule() + -- + -- self:_reset_track() + -- + -- if not vim.api.nvim_buf_is_valid(prompt_bufnr) then + -- log.debug("ON_LINES: Invalid prompt_bufnr", prompt_bufnr) + -- return + -- end + -- + -- local start_time = vim.loop.hrtime() + -- + -- local prompt = self:_get_next_filtered_prompt() + -- + -- -- TODO: Entry manager should have a "bulk" setter. This can prevent a lot of redraws from display + -- if self.cache_picker == false or self.cache_picker.is_cached ~= true then + -- self.sorter:_start(prompt) + -- self.manager = EntryManager:new(self.max_results, self.entry_adder, self.stats) + -- + -- self:_reset_highlights() + -- local process_result = self:get_result_processor(find_id, prompt, debounced_status) + -- local process_complete = self:get_result_completor(self.results_bufnr, find_id, prompt, status_updater) + -- + -- local ok, msg = pcall(function() + -- self.finder(prompt, process_result, process_complete) + -- end) + -- + -- if not ok then + -- log.warn("Finder failed with msg: ", msg) + -- end + -- + -- local diff_time = (vim.loop.hrtime() - start_time) / 1e6 + -- if self.debounce and diff_time < self.debounce then + -- async.util.sleep(self.debounce - diff_time) + -- end + -- else + -- -- TODO(scroll): This can only happen once, I don't like where it is. + -- self:_resume_picker() + -- end + -- end + -- self:set_promptprefix(self.prompt_prefix) + -- + -- -- TODO: Probably should reset self.offset and what not when you type new keys?... hadn't thought about that before + -- self.offset = 0 + -- self.num_visible = popup_opts.results.height - vim.api.nvim_buf_set_lines(results_bufnr, 0, self.max_results, false, utils.repeated_table(self.max_results, "")) - - local status_updater = self:get_status_updater(prompt_win, prompt_bufnr) - local debounced_status = debounce.throttle_leading(status_updater, 50) - - local tx, rx = channel.mpsc() - self._on_lines = tx.send + local status_updater = function(opts) + return self:_update_status(opts) + end local find_id = self:_next_find_id() - - if self.default_text then - self:set_prompt(self.default_text) - end - - if vim.tbl_contains({ "insert", "normal" }, self.initial_mode) then - local mode = vim.fn.mode() - local keys - if self.initial_mode == "normal" then - -- n: A makes sure cursor is at always at end of prompt w/o default_text - keys = mode ~= "n" and "A" or "A" - else - -- always fully retrigger insert mode: required for going from one picker to next - keys = mode ~= "n" and "A" or "A" - end - a.nvim_feedkeys(a.nvim_replace_termcodes(keys, true, false, true), "n", true) - else - utils.notify( - "pickers.find", - { msg = "`initial_mode` should be one of ['normal', 'insert'] but passed " .. self.initial_mode, level = "ERROR" } - ) - end - - local main_loop = async.void(function() - self.sorter:_init() - - -- Do filetype last, so that users can register at the last second. - pcall(a.nvim_buf_set_option, prompt_bufnr, "filetype", "TelescopePrompt") - pcall(a.nvim_buf_set_option, results_bufnr, "filetype", "TelescopeResults") - - await_schedule() - - while true do - -- Wait for the next input - rx.last() - await_schedule() - - self:_reset_track() - - if not vim.api.nvim_buf_is_valid(prompt_bufnr) then - log.debug("ON_LINES: Invalid prompt_bufnr", prompt_bufnr) - return - end - - local start_time = vim.loop.hrtime() - - local prompt = self:_get_next_filtered_prompt() - - -- TODO: Entry manager should have a "bulk" setter. This can prevent a lot of redraws from display - if self.cache_picker == false or self.cache_picker.is_cached ~= true then - self.sorter:_start(prompt) - self.manager = EntryManager:new(self.max_results, self.entry_adder, self.stats) - - self:_reset_highlights() - local process_result = self:get_result_processor(find_id, prompt, debounced_status) - local process_complete = self:get_result_completor(self.results_bufnr, find_id, prompt, status_updater) - - local ok, msg = pcall(function() - self.finder(prompt, process_result, process_complete) - end) - - if not ok then - log.warn("Finder failed with msg: ", msg) - end - - local diff_time = (vim.loop.hrtime() - start_time) / 1e6 - if self.debounce and diff_time < self.debounce then - async.util.sleep(self.debounce - diff_time) - end - else - -- TODO(scroll): This can only happen once, I don't like where it is. - self:_resume_picker() - end - end + self.refresher = vim.loop.new_timer() + self.refresher:start(0, 100, function() + self:_redraw { do_selection = true, force = true } end) + local rx + self._tx, rx = channel.mpsc() -- Register attach vim.api.nvim_buf_attach(prompt_bufnr, false, { - on_lines = function(...) + on_lines = function() find_id = self:_next_find_id() status_updater { completed = false } - self._on_lines(...) + self._tx.send() + + --TODO: Determine if this is good because maybe this makes more sense + -- i don't think do_seleciton should happen in redraw?... not sure. + -- vim.schedule(function() + -- self:_do_selection(self:_get_prompt()) + -- end) end, on_detach = function() @@ -561,8 +524,77 @@ function Picker:find() mappings.apply_keymap(prompt_bufnr, self.attach_mappings, config.values.mappings) - tx.send() - main_loop() + async.void(function() + self.sorter:_init() + self.manager = EntryManager:new(self.num_visible) + + -- Do filetype last, so that users can register at the last second. + pcall(a.nvim_buf_set_option, prompt_bufnr, "filetype", "TelescopePrompt") + pcall(a.nvim_buf_set_option, results_bufnr, "filetype", "TelescopeResults") + + -- TODO(async): I wonder if this should actually happen _before_ we nvim_buf_attach. + -- This way the buffer would always start with what we think it should when we start the loop. + if self.initial_mode == "insert" or self.initial_mode == "normal" then + -- required for set_prompt to work adequately + vim.cmd [[startinsert!]] + if self.default_text then + self:set_prompt(self.default_text) + end + if self.initial_mode == "normal" then + -- otherwise (i) insert mode exitted faster than `picker:set_prompt`; (ii) cursor on wrong pos + await_schedule(function() + vim.cmd [[stopinsert]] + end) + end + else + error("Invalid setting for initial_mode: " .. self.initial_mode) + end + + -- await_schedule() + + while true do + -- Wait for the next input + rx.last() + await_schedule() + + self:_reset_track() + + if not vim.api.nvim_buf_is_valid(prompt_bufnr) then + return + end + + local start_time = vim.loop.hrtime() + local prompt = self:_get_next_filtered_prompt() + + if self.cache_picker == false or not (self.cache_picker.is_cached == true) then + self.sorter:_start(prompt) + self.manager = EntryManager:new(self.num_visible) + + local process_result = self:get_result_processor(find_id, prompt) + local process_complete = self:get_result_completor(self.results_bufnr, find_id, prompt, status_updater) + + local ok, msg = pcall(function() + self.finder(prompt, process_result, function(...) + return process_complete(...) + end) + end) + + if not ok then + log.warn("Finder failed with msg: ", msg) + end + + local diff_time = (vim.loop.hrtime() - start_time) / 1e6 + if self.debounce and diff_time < self.debounce then + self._sleeping = true + async.util.sleep(self.debounce - diff_time) + self._sleeping = false + end + else + -- TODO(scroll): This can only happen once, I don't like where it is. + self:_resume_picker() + end + end + end)() end --- A helper function to update picker windows when layout options are changed @@ -642,9 +674,6 @@ function Picker:recalculate_layout() popup.move(results_win, popup_opts.results) end - -- Temporarily disabled: Draw the screen ASAP. This makes things feel speedier. - -- vim.cmd [[redraw]] - -- self.max_results = popup_opts.results.height end @@ -671,7 +700,7 @@ function Picker:full_layout_update() -- update scrolled position local buf_maxline = #vim.api.nvim_buf_get_lines(self.results_bufnr, 0, -1, false) - update_scroll(self.results_win, oldinfo, oldcursor, self.sorting_strategy, buf_maxline) + -- update_scroll(self.results_win, oldinfo, oldcursor, self.sorting_strategy, buf_maxline) end -- TODO: update multi-select with the correct tag name when available @@ -732,10 +761,33 @@ function Picker:delete_selection(delete_cb) end, 50) end +-- TODO: rebase function Picker:set_prompt(text) self:reset_prompt(text) end +function Picker:set_promptprefix(str) + self.prompt_prefix = str + if self.prompt_prefix ~= "" then + a.nvim_buf_set_option(self.prompt_bufnr, "buftype", "prompt") + vim.fn.prompt_setprompt(self.prompt_bufnr, self.prompt_prefix) + else + a.nvim_buf_set_option(self.prompt_bufnr, "buftype", "") + -- TODO: Decide this + -- vim.api.nvim_buf_set_lines(self.prompt_bufnr, 0, -1, false, { self.default_text }) + end +end + +function Picker:set_prompt(str) + vim.api.nvim_buf_set_lines(self.prompt_bufnr, 0, -1, false, { "" }) + vim.api.nvim_feedkeys(str, "n", false) + self:_reset_prefix_color() + + -- TODO(conni2461): As soon as prompt_buffers are fix use this: + -- vim.api.nvim_buf_set_lines(self.prompt_bufnr, 0, -1, false, { "" }) + -- vim.api.nvim_buf_set_text(self.prompt_bufnr, 0, 0, 0, 0, { str }) +end + --- Closes the windows for the prompt, results and preview ---@param status table: table containing information on the picker --- and associated windows. Generally obtained from `state.get_status` @@ -763,54 +815,142 @@ end --- Get the row number of the current selection ---@return number function Picker:get_selection_row() - if self._selection_row then - -- If the current row is no longer selectable than reduce it to num_results - 1, so the next selectable row. - -- This makes selection_strategy `row` work much better if the selected row is no longer part of the output. - --TODO(conni2461): Maybe this can be moved to scroller. (currently in a hotfix so not viable) - if self.selection_strategy == "row" then - local num_results = self.manager:num_results() - if self.sorting_strategy == "ascending" then - if self._selection_row >= num_results then - return num_results - 1 - end - else - local max = self.max_results - num_results - if self._selection_row < max then - return self.max_results - num_results - end - end - end - return self._selection_row - end - return self.max_results + -- TODO: Rebase + -- if self._selection_row then + -- -- If the current row is no longer selectable than reduce it to num_results - 1, so the next selectable row. + -- -- This makes selection_strategy `row` work much better if the selected row is no longer part of the output. + -- --TODO(conni2461): Maybe this can be moved to scroller. (currently in a hotfix so not viable) + -- if self.selection_strategy == "row" then + -- local num_results = self.manager:num_results() + -- if self.sorting_strategy == "ascending" then + -- if self._selection_row >= num_results then + -- return num_results - 1 + -- end + -- else + -- local max = self.max_results - num_results + -- if self._selection_row < max then + -- return self.max_results - num_results + -- end + -- end + -- end + -- return self._selection_row + -- end + -- return self.max_results + + -- TODO(fps): This seems WRONG -- what if it should be the first row? very confused + return self._selection_row or self.num_visible +end + +function Picker:shift_offset(change) + self.offset = self.offset + change + self.offset = math.min(self.offset, self.manager:num_results() - self.num_visible + 1) + self.offset = math.max(self.offset, 0) + + self:_redraw { force = true } +>>>>>>> 20a1519 (feat(fps): Add refresh style display for telescope) end --- Move the current selection by `change` steps ---@param change number function Picker:move_selection(change) - self:set_selection(self:get_selection_row() + change) + -- TODO: This isn't quite right. I can get stuck :'( + -- I think we just want to do it with the change as positive or negative + -- and then also just delete a bunch of this other random stuff. + -- + -- it's so confusing :'( + + -- row = self.scroller(self.num_visible, self.manager:num_results(), row) + + -- todo: can we do this based on index?? + + if self.sorting_strategy == "ascending" then + local new_row = self:get_selection_row() + change + if new_row >= self.num_visible then + if self.offset == 0 and self.scroll_strategy == "cycle" then + error "ya" + end + + self.offset = math.min(self.offset + new_row - self.num_visible + 1, self.num_visible - 1) + self:set_selection(self.num_visible - 1) + elseif new_row < 0 then + if self.offset == 0 and self.scroll_strategy == "cycle" then + -- self.offset = math.min(self.offset + new_row - self.num_visible + 1, self.num_visible - 1) + -- self.offset = self.manager:num_results() - self.num_visible + -- self:set_selection() + -- error(vim.inspect { + -- num_results = self.manager:num_results(), + -- num_visible = self.num_visible, + -- }) + + -- print( + -- self.manager:num_results(), + -- self.num_visible, + -- math.min(self.manager:num_results() - 1, self.num_visible - 1) + -- ) + self.offset = math.max(0, self.manager:num_results() - self.num_visible) + self:_update_results {} + + self:set_selection(math.min(self.num_visible - 1, self.manager:num_results() - 1)) + else + self.offset = math.max(self.offset - 1, 0) + self:set_selection(0) + end + else + self:set_selection(new_row) + end + else + -- print(self.offset, self.num_visible, self.manager:num_results()) + + local new_row = self:get_selection_row() + change + if new_row >= self.num_visible then + self.offset = math.max(0, self.manager:num_results() - self.num_visible) + self:_update_results {} + + self:set_selection(math.max(0, self.num_visible - self.manager:num_results())) + elseif new_row < 0 then + error "oh no" + else + self:set_selection(new_row) + end + end + + self:_redraw { force = true } +end + +function Picker:_resolve_entry_display(entry) + return require("telescope.pickers.entry_display").resolve(self, entry) +end + +function Picker:_get_entry_from_row(row) + return self:_get_entry_from_index(self:get_index(row)) +end + +function Picker:_get_entry_from_index(idx) + return self.manager:get_entry(self.offset, idx) end --- Add the entry of the given row to the multi-select object ---@param row number: the number of the chosen row function Picker:add_selection(row) - local entry = self.manager:get_entry(self:get_index(row)) + local entry = self:_get_entry_from_row(row) self._multi:add(entry) - - self:update_prefix(entry, row) - self:get_status_updater(self.prompt_win, self.prompt_bufnr)() - self.highlighter:hi_multiselect(row, true) + self:_update_status() + self.highlighter:highlight(row, { + skip_display = true, + is_multi_selected = true, + }) end --- Remove the entry of the given row to the multi-select object ---@param row number: the number of the chosen row function Picker:remove_selection(row) - local entry = self.manager:get_entry(self:get_index(row)) + local entry = self:_get_entry_from_row(row) self._multi:drop(entry) - - self:update_prefix(entry, row) - self:get_status_updater(self.prompt_win, self.prompt_bufnr)() - self.highlighter:hi_multiselect(row, false) + self:_update_status() + self.highlighter:highlight(row, { + skip_display = true, + is_multi_selected = false, + }) end --- Check if the given row is in the multi-select object @@ -831,15 +971,16 @@ end --- Also updates the highlighting for the given entry ---@param row number: the number of the chosen row function Picker:toggle_selection(row) - local entry = self.manager:get_entry(self:get_index(row)) + local entry = self:_get_entry_from_row(row) if entry == nil then return end - self._multi:toggle(entry) - self:update_prefix(entry, row) - self:get_status_updater(self.prompt_win, self.prompt_bufnr)() - self.highlighter:hi_multiselect(row, self._multi:is_selected(entry)) + self._multi:toggle(entry) + self:_update_status() + self.highlighter:highlight(row, { + skip_display = true, + }) end --- Set the current selection to `nil` @@ -859,7 +1000,7 @@ function Picker:_reset_prefix_color(hl_group) self._current_prefix_hl_group or "TelescopePromptPrefix", 0, 0, - #self.prompt_prefix + strdisplaywidth(self.prompt_prefix) ) end end @@ -878,7 +1019,7 @@ function Picker:change_prompt_prefix(new_prefix, hl_group) if new_prefix ~= "" then vim.fn.prompt_setprompt(self.prompt_bufnr, new_prefix) else - vim.api.nvim_buf_set_text(self.prompt_bufnr, 0, 0, 0, #self.prompt_prefix, {}) + vim.api.nvim_buf_set_text(self.prompt_bufnr, 0, 0, 0, self._prefix_width, {}) vim.api.nvim_buf_set_option(self.prompt_bufnr, "buftype", "") end self.prompt_prefix = new_prefix @@ -893,11 +1034,12 @@ function Picker:reset_prompt(text) self:_reset_prefix_color(self._current_prefix_hl_group) if text then - vim.api.nvim_win_set_cursor(self.prompt_win, { 1, #prompt_text }) + -- vim.api.nvim_win_set_cursor(self.prompt_win, { 1, #prompt_text }) end end ----@param finder finder: telescope finder (see telescope/finders.lua) +--- Refresh the current picker +---@param finder Finder: telescope finder (see telescope/finders.lua) ---@param opts table: options to pass when refreshing the picker ---@field new_prefix string|table: either as string or { new_string, hl_group } ---@field reset_prompt bool: whether to reset the prompt @@ -917,22 +1059,30 @@ function Picker:refresh(finder, opts) self._multi = vim.F.if_nil(opts.multi, MultiSelect:new()) end + -- TODO: Rebase -- reset already triggers finder loop - if opts.reset_prompt then - self:reset_prompt() - else - self._on_lines(nil, nil, nil, 0, 1) - end + -- if opts.reset_prompt then + -- self:reset_prompt() + -- else + -- self._on_lines(nil, nil, nil, 0, 1) + -- end + + self._tx.send() end ---Set the selection to the provided `row` ---@param row number function Picker:set_selection(row) + -- print("Setting selection to:", debug.traceback(row)) + -- print("Setting selection to:", self.offset, row, "//", self.num_visible, self.manager:num_results()) + if not self.manager then return end - row = self.scroller(self.max_results, self.manager:num_results(), row) + local old_row = row + row = self.scroller(self.num_visible, self.manager:num_results(), row) + -- print("Setting row to be:", old_row, "->", row) if not self:can_select_row(row) then -- If the current selected row exceeds number of currently displayed @@ -940,7 +1090,7 @@ function Picker:set_selection(row) if not self:can_select_row(self:get_selection_row()) then row = self:get_row(self.manager:num_results()) else - log.trace("Cannot select row:", row, self.manager:num_results(), self.max_results) + error(string.format("Cannot select row: %s %s %s", row, self.manager:num_results(), self.num_visible)) return end end @@ -951,115 +1101,44 @@ function Picker:set_selection(row) end if row > a.nvim_buf_line_count(results_bufnr) then - log.debug( + log.info( string.format("Should not be possible to get row this large %s %s", row, a.nvim_buf_line_count(results_bufnr)) ) return end - local entry = self.manager:get_entry(self:get_index(row)) + local entry = self:_get_entry_from_row(row) state.set_global_key("selected_entry", entry) + -- No entries, so just be done if not entry then return end - local old_entry + -- If the entry is the current selection_entry, then just quit + -- if self._selection_entry == entry and self._selection_row == row then + -- return + -- end - -- TODO: Probably should figure out what the rows are that made this happen... - -- Probably something with setting a row that's too high for this? - -- Not sure. - local set_ok, set_errmsg = pcall(function() - local prompt = self:_get_prompt() + -- Check if previous selection is still visible and valid + -- if self._selection_entry and self.manager:find_entry(self._selection_entry) then + -- -- Find old selection, and update prefix and highlights + -- local old_entry = self._selection_entry + -- + -- local old_row = self:get_row(self.manager:find_entry(old_entry)) + -- if old_row >= 0 then + -- self.highlighter:hi_multiselect(old_row, self:is_multi_selected(old_entry)) + -- end + -- end - -- Check if previous selection is still visible - if self._selection_entry and self.manager:find_entry(self._selection_entry) then - -- Find old selection, and update prefix and highlights - old_entry = self._selection_entry - local old_row = self:get_row(self.manager:find_entry(old_entry)) - - self._selection_entry = entry - - 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 - else - self._selection_entry = entry - end - - local caret = self:update_prefix(entry, row) - - local display, _ = entry_display.resolve(self, entry) - display = caret .. display - - -- TODO: You should go back and redraw the highlights for this line from the sorter. - -- That's the only smart thing to do. - if not a.nvim_buf_is_valid(results_bufnr) then - log.debug "Invalid buf somehow..." - return - end - - -- don't highlight any whitespace at the end of caret - self.highlighter:hi_selection(row, caret:match "(.*%S)") - self.highlighter:hi_sorter(row, prompt, display) - - self.highlighter:hi_multiselect(row, self:is_multi_selected(entry)) - end) - - if not set_ok then - log.debug(set_errmsg) - return - end - - if old_entry == entry and self._selection_row == row then - return - end - - -- TODO: Get row & text in the same obj self._selection_entry = entry self._selection_row = row + self.highlighter:highlight(row, { + skip_display = true, + }) self:refresh_previewer() - - vim.api.nvim_win_set_cursor(self.results_win, { row + 1, 0 }) -end - ---- Update prefix for entry on a given row -function Picker:update_prefix(entry, row) - local prefix = function(sel, multi) - local t - if sel then - t = self.selection_caret - else - t = self.entry_prefix - end - if multi and type(self.multi_icon) == "string" then - t = truncate(t, strdisplaywidth(t) - strdisplaywidth(self.multi_icon), "") .. self.multi_icon - end - return t - end - - local line = vim.api.nvim_buf_get_lines(self.results_bufnr, row, row + 1, false)[1] - if not line then - log.warn(string.format("no line found at row %d in buffer %d", row, self.results_bufnr)) - return - end - - local old_caret = string.sub(line, 0, #prefix(true)) == prefix(true) and prefix(true) - or string.sub(line, 0, #prefix(true, true)) == prefix(true, true) and prefix(true, true) - or string.sub(line, 0, #prefix(false)) == prefix(false) and prefix(false) - or string.sub(line, 0, #prefix(false, true)) == prefix(false, true) and prefix(false, true) - if old_caret == false then - log.warn(string.format("can't identify old caret in line: %s", line)) - return - end - - local pre = prefix(entry == self._selection_entry, self:is_multi_selected(entry)) - -- Only change the first couple characters, nvim_buf_set_text leaves the existing highlights - a.nvim_buf_set_text(self.results_bufnr, row, 0, row, #old_caret, { pre }) - return pre end --- Refresh the previewer based on the current `status` of the picker @@ -1108,77 +1187,6 @@ function Picker:cycle_previewers(next) end end ---- Handler for when entries are added by `self.manager` ----@param index number: the index to add the entry at ----@param entry table: the entry that has been added to the manager ----@param insert boolean: whether the entry has been "inserted" or not -function Picker:entry_adder(index, entry, _, insert) - if not entry then - return - end - - local row = self:get_row(index) - - -- If it's less than 0, then we don't need to show it at all. - if row < 0 then - log.debug("ON_ENTRY: Weird row", row) - return - end - - local display, display_highlights = entry_display.resolve(self, entry) - if not display then - log.info("Weird entry", entry) - return - end - - -- This is the two spaces to manage the '> ' stuff. - -- Maybe someday we can use extmarks or floaty text or something to draw this and not insert here. - -- until then, insert two spaces - local prefix = self.entry_prefix - display = prefix .. display - - self:_increment "displayed" - - local offset = insert and 0 or 1 - if not vim.api.nvim_buf_is_valid(self.results_bufnr) then - log.debug "ON_ENTRY: Invalid buffer" - return - end - - -- TODO: Does this every get called? - -- local line_count = vim.api.nvim_win_get_height(self.results_win) - local line_count = vim.api.nvim_buf_line_count(self.results_bufnr) - if row > line_count then - return - end - - if insert then - if self.sorting_strategy == "descending" then - vim.api.nvim_buf_set_lines(self.results_bufnr, 0, 1, false, {}) - end - end - - local set_ok, msg = pcall(vim.api.nvim_buf_set_lines, self.results_bufnr, row, row + offset, false, { display }) - if set_ok then - if display_highlights then - self.highlighter:hi_display(row, prefix, display_highlights) - end - self:update_prefix(entry, row) - self:highlight_one_row(self.results_bufnr, self:_get_prompt(), display, row) - end - - if not set_ok then - log.debug("Failed to set lines...", msg) - end - - -- This pretty much only fails when people leave newlines in their results. - -- So we'll clean it up for them if it fails. - if not set_ok and display:find "\n" then - display = display:gsub("\n", " | ") - vim.api.nvim_buf_set_lines(self.results_bufnr, row, row + 1, false, { display }) - end -end - --- Reset tracked information for this picker function Picker:_reset_track() self.stats.processed = 0 @@ -1188,7 +1196,6 @@ function Picker:_reset_track() self.stats.status = 0 self.stats.filtered = 0 - self.stats.highlights = 0 end --- Increment the count of the tracked info at `self.stats[key]` @@ -1214,8 +1221,12 @@ function Picker:clear_completion_callbacks() end function Picker:_on_complete() + -- TODO: Should alert user that stuff broke. for _, v in ipairs(self._completion_callbacks) do - pcall(v, self) + local ok, msg = pcall(v, self) + if not ok then + self:_on_error(msg) + end end end @@ -1226,35 +1237,131 @@ function Picker:close_existing_pickers() end end +--[[ +------- +| | +| | +| | +------- + +-> self.manager:window(start, finish) +window is a sorted list of entries, 1 -> (finish - start) +window has idx for each entry +- to calculate row for idx, use self:get_row(window_idx) + +Goals: +- Redraw is _always_ scheduled, so it's safe to run (but does not + give up control while executing) +- Redraw is idemptotent (we can just keep running it and wasting cycles + but we OK) +--]] +Picker._redraw = vim.schedule_wrap(function(self, opts) + opts = opts or {} + + if not opts.force and not self.manager then + return + end + + self:_update_status { completed = false } + if not opts.force and not self.manager.dirty then + return + end + + self.manager.dirty = false + local displayed, highlights = self:_update_results() + self:_update_highlights(displayed, highlights) + + if opts.do_selection then + -- self:set_selection + -- self:_do_selection(prompt) + end + + -- vim.api.nvim_win_set_cursor + -- print("Setting win cursor", self:get_selection_row() + 1) + -- vim.api.nvim_win_set_cursor(self.results_win, { self:get_selection_row() + 1, 0 }) +end) + +local get_displayed_and_highlights = function(self, window) + -- Get the contents to display and associated highlights + local displayed, highlights = {}, {} + for window_idx, entry in ipairs(window) do + local row = self:get_row(window_idx) + displayed[row], highlights[row] = self:_resolve_entry_display(entry) + end + + return displayed, highlights +end + +function Picker:_update_highlights(displayed, highlights) + local window = self.manager:window(1 + self.offset, self.num_visible + self.offset) + + -- Only look up displays and highlights if we haven't done that already + if not displayed or not highlights then + displayed, highlights = get_displayed_and_highlights(self, window) + end + + local prompt = self:_get_prompt() + + self.highlighter:clear() + for row, display_highlights in pairs(highlights) do + self.highlighter:highlight(row, { + prompt = prompt, + entry = window[self:get_index(row)], + display = displayed[row], + display_highlights = display_highlights, + }) + end +end + +function Picker:_update_results(opts) + opts = opts or {} + + -- Dimensions + local height = vim.api.nvim_win_get_height(self.results_win) + local window = self.manager:window(1 + self.offset, self.num_visible + self.offset) + + -- Get the contents to display and associated highlights + local displayed, highlights = get_displayed_and_highlights(self, window) + + -- Push display contents into lines buffer + local lines = {} + for idx = 0, height do + lines[idx + 1] = (displayed[idx] and self._prefix_string .. displayed[idx]) or "" + end + + -- Display contents + vim.api.nvim_buf_set_lines(self.results_bufnr, 0, -1, false, lines) + + return displayed, highlights +end + --- Returns a function that sets virtual text for the count indicator --- e.g. "10/50" as "filtered"/"processed" ----@param prompt_win number ----@param prompt_bufnr number ----@return function -function Picker:get_status_updater(prompt_win, prompt_bufnr) - return function(opts) - if self.closed or not vim.api.nvim_buf_is_valid(prompt_bufnr) then - return - end +function Picker:_update_status(opts) + local prompt_win = self.prompt_win + local prompt_bufnr = self.prompt_bufnr - local current_prompt = self:_get_prompt() - if not current_prompt then - return - end - - if not vim.api.nvim_win_is_valid(prompt_win) then - return - end - - local text = self:get_status_text(opts) - vim.api.nvim_buf_clear_namespace(prompt_bufnr, ns_telescope_prompt, 0, -1) - vim.api.nvim_buf_set_extmark(prompt_bufnr, ns_telescope_prompt, 0, 0, { - virt_text = { { text, "TelescopePromptCounter" } }, - virt_text_pos = "right_align", - }) - - self:_increment "status" + if self.closed or not vim.api.nvim_buf_is_valid(prompt_bufnr) then + return end + + local current_prompt = self:_get_prompt() + if not current_prompt then + return + end + + if not vim.api.nvim_win_is_valid(prompt_win) then + return + end + + local text = self:get_status_text(opts) + vim.api.nvim_buf_clear_namespace(prompt_bufnr, ns_telescope_prompt, 0, -1) + vim.api.nvim_buf_set_extmark(prompt_bufnr, ns_telescope_prompt, 0, 0, { + virt_text = { { text, "TelescopePromptCounter" } }, + virt_text_pos = "right_align", + }) + + self:_increment "status" end --- Returns a function that will process an element. @@ -1262,15 +1369,12 @@ end --- as appropriate and runs the sorters score function ---@param find_id number ---@param prompt string ----@param status_updater function ---@return function -function Picker:get_result_processor(find_id, prompt, status_updater) +function Picker:get_result_processor(find_id, prompt) local count = 0 local cb_add = function(score, entry) - -- may need the prompt for tiebreak - self.manager:add_entry(self, score, entry, prompt) - status_updater { completed = false } + self.manager:add_entry(self, score, entry) end local cb_filter = function(_) @@ -1305,6 +1409,13 @@ function Picker:get_result_processor(find_id, prompt, status_updater) end self.sorter:score(prompt, entry, cb_add, cb_filter) + + -- Only on the first addition do we want to set the selection. + -- This allows us to handle moving the cursor to the bottom or top of the window + -- depending on the strategy. + -- if count == 1 then + -- self:_do_selection(prompt) + -- end end end @@ -1324,7 +1435,6 @@ function Picker:get_result_completor(results_bufnr, find_id, prompt, status_upda state.set_global_key("current_line", self:_get_prompt()) status_updater { completed = true } - self:clear_extra_rows(results_bufnr) self.sorter:_finish(prompt) self:_on_complete() @@ -1332,6 +1442,8 @@ function Picker:get_result_completor(results_bufnr, find_id, prompt, status_upda end function Picker:_do_selection(prompt) + self.offset = 0 + local selection_strategy = self.selection_strategy or "reset" -- TODO: Either: always leave one result or make sure we actually clean up the results when nothing matches if selection_strategy == "row" then @@ -1419,6 +1531,9 @@ function pickers.on_close_prompt(prompt_bufnr) local picker = status.picker require("telescope.actions.state").get_current_history():reset() + picker.refresher:stop() + picker.refresher:close() + if type(picker.cache_picker) == "table" then local cached_pickers = state.get_global_key "cached_pickers" or {} @@ -1435,7 +1550,7 @@ function pickers.on_close_prompt(prompt_bufnr) if picker.manager then picker.manager.linked_states:truncate(picker.cache_picker.limit_entries) else - picker.manager = EntryManager:new(picker.max_results, picker.entry_adder, picker.stats) + picker.manager = EntryManager:new(picker.num_visible) end end picker.default_text = picker:_get_prompt() @@ -1490,20 +1605,8 @@ function Picker:_get_prompt() return vim.api.nvim_buf_get_lines(self.prompt_bufnr, 0, 1, false)[1]:sub(#self.prompt_prefix + 1) end -function Picker:_reset_highlights() - self.highlighter:clear_display() - vim.api.nvim_buf_clear_namespace(self.results_bufnr, ns_telescope_matching, 0, -1) -end - function Picker:_detach() self.finder:close() - - -- TODO: Can we add a "cleanup" / "teardown" function that completely removes these. - -- self.finder = nil - -- self.previewer = nil - -- self.sorter = nil - -- self.manager = nil - self.closed = true end @@ -1526,6 +1629,8 @@ function Picker:_get_next_filtered_prompt() end function Picker:_resume_picker() + error "TJ Has not implemented resuming yet" + -- resume previous picker local index = 1 for entry in self.manager:iter() do diff --git a/lua/telescope/pickers/_test.lua b/lua/telescope/pickers/_test.lua deleted file mode 100644 index a8680d0..0000000 --- a/lua/telescope/pickers/_test.lua +++ /dev/null @@ -1,244 +0,0 @@ -local assert = require "luassert" -local builtin = require "telescope.builtin" -local log = require "telescope.log" - -local Job = require "plenary.job" -local Path = require "plenary.path" - -local tester = {} - -tester.debug = false - -local replace_terms = function(input) - return vim.api.nvim_replace_termcodes(input, true, false, true) -end - -local nvim_feed = function(text, feed_opts) - feed_opts = feed_opts or "m" - - vim.api.nvim_feedkeys(text, feed_opts, true) -end - -local writer = function(val) - if type(val) == "table" then - val = vim.json.encode(val) .. "\n" - end - - if tester.debug then - print(val) - else - io.stderr:write(val) - end -end - -local execute_test_case = function(location, key, spec) - local ok, actual = pcall(spec[2]) - - if not ok then - writer { - location = "Error: " .. location, - case = key, - expected = "To succeed and return: " .. tostring(spec[1]), - actual = actual, - - _type = spec._type, - } - else - writer { - location = location, - case = key, - expected = spec[1], - actual = actual, - - _type = spec._type, - } - end -end - -local end_test_cases = function() - vim.cmd [[qa!]] -end - -local invalid_test_case = function(k) - writer { case = k, expected = "", actual = k } - - end_test_cases() -end - -tester.picker_feed = function(input, test_cases) - input = replace_terms(input) - - return coroutine.wrap(function() - for i = 1, #input do - local char = input:sub(i, i) - nvim_feed(char, "") - - -- TODO: I'm not 100% sure this is a hack or not... - -- it's possible these characters could still have an on_complete... but i'm not sure. - if string.match(char, "%g") then - coroutine.yield() - end - - if tester.debug then - vim.wait(200) - end - end - - vim.wait(10) - - if tester.debug then - coroutine.yield() - end - - vim.defer_fn(function() - if test_cases.post_typed then - for k, v in ipairs(test_cases.post_typed) do - execute_test_case("post_typed", k, v) - end - end - - nvim_feed(replace_terms "", "") - end, 20) - - vim.defer_fn(function() - if test_cases.post_close then - for k, v in ipairs(test_cases.post_close) do - execute_test_case("post_close", k, v) - end - end - - if tester.debug then - return - end - - vim.defer_fn(end_test_cases, 20) - end, 40) - - coroutine.yield() - end) -end - -local _VALID_KEYS = { - post_typed = true, - post_close = true, -} - -tester.builtin_picker = function(builtin_key, input, test_cases, opts) - opts = opts or {} - tester.debug = opts.debug or false - - for k, _ in pairs(test_cases) do - if not _VALID_KEYS[k] then - return invalid_test_case(k) - end - end - - opts.on_complete = { - tester.picker_feed(input, test_cases), - } - - builtin[builtin_key](opts) -end - -local get_results_from_file = function(file) - local j = Job:new { - command = "nvim", - args = { - "--noplugin", - "-u", - "scripts/minimal_init.vim", - "-c", - string.format([[lua require("telescope.pickers._test")._execute("%s")]], file), - }, - } - - j:sync(10000) - - local results = j:stderr_result() - local result_table = {} - for _, v in ipairs(results) do - table.insert(result_table, vim.json.decode(v)) - end - - return result_table -end - -local asserters = { - _default = assert.are.same, - - are = assert.are.same, - are_not = assert.are_not.same, -} - -local check_results = function(results) - -- TODO: We should get all the test cases here that fail, not just the first one. - for _, v in ipairs(results) do - local assertion = asserters[v._type or "default"] - - assertion(v.expected, v.actual, string.format("Test Case: %s // %s", v.location, v.case)) - end -end - -tester.run_string = function(contents) - local tempname = vim.fn.tempname() - - contents = [[ - local tester = require('telescope.pickers._test') - local helper = require('telescope.pickers._test_helpers') - - helper.make_globals() - ]] .. contents - - vim.fn.writefile(vim.split(contents, "\n"), tempname) - local result_table = get_results_from_file(tempname) - vim.fn.delete(tempname) - - check_results(result_table) -end - -tester.run_file = function(filename) - local file = "./lua/tests/pickers/" .. filename .. ".lua" - - if not Path:new(file):exists() then - assert.are.same("", file) - end - - local result_table = get_results_from_file(file) - - check_results(result_table) -end - -tester.not_ = function(val) - val._type = "are_not" - return val -end - -tester._execute = function(filename) - -- Important so that the outputs don't get mixed - log.use_console = false - - vim.cmd(string.format("luafile %s", filename)) - - local f = loadfile(filename) - if not f then - writer { - location = "Error: " .. filename, - case = filename, - expected = "To succeed", - actual = nil, - } - end - - local ok, msg = pcall(f) - if not ok then - writer { - location = "Error: " .. msg, - case = msg, - expected = msg, - } - end - - end_test_cases() -end - -return tester diff --git a/lua/telescope/pickers/highlights.lua b/lua/telescope/pickers/highlights.lua index be693a7..0de6c81 100644 --- a/lua/telescope/pickers/highlights.lua +++ b/lua/telescope/pickers/highlights.lua @@ -2,8 +2,11 @@ local a = vim.api local log = require "telescope.log" local conf = require("telescope.config").values +local strdisplaywidth = require("plenary.strings").strdisplaywidth + local highlights = {} +local ns_telescope_matching = a.nvim_create_namespace "telescope_matching" local ns_telescope_selection = a.nvim_create_namespace "telescope_selection" local ns_telescope_multiselection = a.nvim_create_namespace "telescope_multiselection" local ns_telescope_entry = a.nvim_create_namespace "telescope_entry" @@ -14,10 +17,43 @@ Highlighter.__index = Highlighter function Highlighter:new(picker) return setmetatable({ picker = picker, + offset = picker._prefix_width, }, self) end -function Highlighter:hi_display(row, prefix, display_highlights) +local DISPLAY_HIGHLIGHTS_PRIORITY = 110 +local SORTER_HIGHLIGHTS_PRIORITY = 120 +local SELECTION_HIGHLIGHTS_PRIORITY = 130 + +function Highlighter:highlight(row, opts) + assert(row, "Must pass a row") + + local picker = self.picker + + local entry = opts.entry or picker:_get_entry_from_row(row) + local prompt = opts.prompt or picker:_get_prompt() + local is_selected = opts.is_selected or (picker._selection_row == row) + local is_multi_selected = opts.is_multi_selected or picker:is_multi_selected(entry) + + if is_selected then + self:hi_selection(row) + end + + if not opts.skip_display then + local display = opts.display + local display_highlights = opts.display_highlights + if not display then + display, display_highlights = picker:_resolve_entry_display(entry) + end + + self:hi_display(row, display_highlights) + self:hi_sorter(row, prompt, display) + end + + self:hi_multiselect(row, is_multi_selected) +end + +function Highlighter:hi_display(row, display_highlights) -- This is the bug that made my highlight fixes not work. -- We will leave the solution commented, so the test fails. if not display_highlights or vim.tbl_isempty(display_highlights) then @@ -25,95 +61,143 @@ function Highlighter:hi_display(row, prefix, display_highlights) end local results_bufnr = assert(self.picker.results_bufnr, "Must have a results bufnr") + if not a.nvim_buf_is_valid(results_bufnr) then + return + end a.nvim_buf_clear_namespace(results_bufnr, ns_telescope_entry, row, row + 1) - local len_prefix = #prefix for _, hl_block in ipairs(display_highlights) do - a.nvim_buf_add_highlight( - results_bufnr, - ns_telescope_entry, - hl_block[2], - row, - len_prefix + hl_block[1][1], - len_prefix + hl_block[1][2] - ) + a.nvim_buf_set_extmark(results_bufnr, ns_telescope_entry, row, self.offset + hl_block[1][1], { + end_col = self.offset + hl_block[1][2], + hl_group = hl_block[2], + priority = DISPLAY_HIGHLIGHTS_PRIORITY, + strict = false, + }) end end -function Highlighter:clear_display() +function Highlighter:clear() if not self or not self.picker or not self.picker.results_bufnr - or not vim.api.nvim_buf_is_valid(self.picker.results_bufnr) + or not a.nvim_buf_is_valid(self.picker.results_bufnr) then return end a.nvim_buf_clear_namespace(self.picker.results_bufnr, ns_telescope_entry, 0, -1) + a.nvim_buf_clear_namespace(self.picker.results_bufnr, ns_telescope_matching, 0, -1) end function Highlighter:hi_sorter(row, prompt, display) local picker = self.picker + local sorter = picker.sorter if not picker.sorter or not picker.sorter.highlighter then return end local results_bufnr = assert(self.picker.results_bufnr, "Must have a results bufnr") - picker:highlight_one_row(results_bufnr, prompt, display, row) + if not a.nvim_buf_is_valid(results_bufnr) then + return + end + + local sorter_highlights = sorter:highlighter(prompt, display) + + if sorter_highlights then + for _, hl in ipairs(sorter_highlights) do + local highlight, start, finish + if type(hl) == "table" then + highlight = hl.highlight or "TelescopeMatching" + start = hl.start + finish = hl.finish or hl.start + elseif type(hl) == "number" then + highlight = "TelescopeMatching" + start = hl + finish = hl + else + error "Invalid higlighter fn" + end + + a.nvim_buf_set_extmark(results_bufnr, ns_telescope_matching, row, start + self.offset - 1, { + end_col = self.offset + finish, + hl_group = highlight, + priority = SORTER_HIGHLIGHTS_PRIORITY, + strict = false, + }) + end + end end -function Highlighter:hi_selection(row, caret) - caret = vim.F.if_nil(caret, "") +function Highlighter:hi_selection(row) local results_bufnr = assert(self.picker.results_bufnr, "Must have a results bufnr") + if not a.nvim_buf_is_valid(results_bufnr) then + return + end a.nvim_buf_clear_namespace(results_bufnr, ns_telescope_selection, 0, -1) - a.nvim_buf_add_highlight(results_bufnr, ns_telescope_selection, "TelescopeSelectionCaret", row, 0, #caret) - a.nvim_buf_set_extmark( - results_bufnr, - ns_telescope_selection, - row, - #caret, - { end_line = row + 1, hl_eol = conf.hl_result_eol, hl_group = "TelescopeSelection" } - ) + -- If there isn't anything _on_ the line, then it's some edge case with + -- loading the buffer or something like that. + -- + -- We can just skip and we'll get the updates later. + if a.nvim_buf_get_lines(results_bufnr, row, row + 1, false)[1] == "" then + return + end + + -- TODO: Someone will complain about the highlighting here I'm sure. + -- I don't know what to tell them except what are you doing w/ highlighting + local caret = self.picker.selection_caret + local offset = self.offset + + -- Highlight the caret + a.nvim_buf_set_extmark(results_bufnr, ns_telescope_selection, row, 0, { + virt_text = { { caret, "TelescopeSelectionCaret" } }, + virt_text_pos = "overlay", + end_col = offset, + hl_group = "TelescopeSelectionCaret", + priority = SELECTION_HIGHLIGHTS_PRIORITY, + strict = true, + }) + + -- Highlight the text after the caret + a.nvim_buf_set_extmark(results_bufnr, ns_telescope_selection, row, offset, { + end_line = row + 1, + hl_eol = conf.hl_result_eol, + hl_group = "TelescopeSelection", + priority = SELECTION_HIGHLIGHTS_PRIORITY, + }) end function Highlighter:hi_multiselect(row, is_selected) local results_bufnr = assert(self.picker.results_bufnr, "Must have a results bufnr") + if not a.nvim_buf_is_valid(results_bufnr) then + return + end + + a.nvim_buf_clear_namespace(results_bufnr, ns_telescope_multiselection, row, row + 1) + + local line = a.nvim_buf_get_lines(results_bufnr, row, row + 1, false)[1] + if not line then + return + end if is_selected then - vim.api.nvim_buf_add_highlight(results_bufnr, ns_telescope_multiselection, "TelescopeMultiSelection", row, 0, -1) - if self.picker.multi_icon then - local line = vim.api.nvim_buf_get_lines(results_bufnr, row, row + 1, false)[1] - local pos = line:find(self.picker.multi_icon) - if pos and pos <= math.max(#self.picker.selection_caret, #self.picker.entry_prefix) then - vim.api.nvim_buf_add_highlight( - results_bufnr, - ns_telescope_multiselection, - "TelescopeMultiIcon", - row, - pos - 1, - pos - 1 + #self.picker.multi_icon - ) - end - end - else - local existing_marks = vim.api.nvim_buf_get_extmarks( - results_bufnr, - ns_telescope_multiselection, - { row, 0 }, - { row, -1 }, - {} - ) + a.nvim_buf_set_extmark(results_bufnr, ns_telescope_multiselection, row, self.offset, { + end_col = #line, + hl_group = "TelescopeMultiSelection", + }) - -- This is still kind of weird to me, since it seems like I'm erasing stuff - -- when I shouldn't... Perhaps it's about the gravity of the extmark? - if #existing_marks > 0 then - log.trace("Clearing highlight multi select row: ", row) - - vim.api.nvim_buf_clear_namespace(results_bufnr, ns_telescope_multiselection, row, row + 1) + -- TEST WITH MULTI-BYTE CHARS + if self.picker.multi_icon and self.offset > 0 then + local icon = self.picker.multi_icon + local cols = strdisplaywidth(icon) + a.nvim_buf_set_extmark(results_bufnr, ns_telescope_multiselection, row, self.offset - cols, { + end_col = self.offset, + virt_text = { { self.picker.multi_icon, "TelescopeMultiIcon" } }, + virt_text_pos = "overlay", + }) end end end diff --git a/lua/telescope/pickers/prompt.lua b/lua/telescope/pickers/prompt.lua new file mode 100644 index 0000000..097489e --- /dev/null +++ b/lua/telescope/pickers/prompt.lua @@ -0,0 +1,18 @@ +local M = {} + +M.set_prompt = function(picker) + self._current_prefix_hl_group = hl_group or nil + + if self.prompt_prefix ~= "" then + vim.api.nvim_buf_add_highlight( + self.prompt_bufnr, + ns_telescope_prompt_prefix, + self._current_prefix_hl_group or "TelescopePromptPrefix", + 0, + 0, + strdisplaywidth(self.prompt_prefix) + ) + end +end + +return M diff --git a/lua/telescope/pickers/scroller.lua b/lua/telescope/pickers/scroller.lua index a658f68..c6aa013 100644 --- a/lua/telescope/pickers/scroller.lua +++ b/lua/telescope/pickers/scroller.lua @@ -40,7 +40,7 @@ local scroll_calculators = { end, } -scroller.create = function(scroll_strategy, sorting_strategy) +scroller.new = function(scroll_strategy, sorting_strategy) local range_fn = range_calculators[sorting_strategy] if not range_fn then error(debug.traceback("Unknown sorting strategy: " .. sorting_strategy)) diff --git a/lua/telescope/pickers/_test_helpers.lua b/lua/telescope/testharness/helpers.lua similarity index 100% rename from lua/telescope/pickers/_test_helpers.lua rename to lua/telescope/testharness/helpers.lua diff --git a/lua/telescope/testharness/init.lua b/lua/telescope/testharness/init.lua new file mode 100644 index 0000000..0e7f0f1 --- /dev/null +++ b/lua/telescope/testharness/init.lua @@ -0,0 +1,116 @@ +local assert = require "luassert" + +local Path = require "plenary.path" + +local tester = {} +tester.debug = false + +local get_results_from_contents = function(content) + local nvim = vim.fn.jobstart( + { "nvim", "--noplugin", "-u", "scripts/minimal_init.vim", "--headless", "--embed" }, + { rpc = true } + ) + + local result = vim.fn.rpcrequest(nvim, "nvim_exec_lua", content, {}) + assert.are.same(true, result[1], vim.inspect(result)) + + local count = 0 + while + vim.fn.rpcrequest(nvim, "nvim_exec_lua", "return require('telescope.testharness.runner').state.done", {}) ~= true + do + count = count + 1 + vim.wait(100) + + -- TODO: Could maybe wait longer, but it's annoying to wait if the test is going to timeout. + if count > 100 then + break + end + end + + local state = vim.fn.rpcrequest(nvim, "nvim_exec_lua", "return require('telescope.testharness.runner').state", {}) + vim.fn.jobstop(nvim) + + assert.are.same(true, state.done, vim.inspect(state)) + + local result_table = {} + for _, v in ipairs(state.results) do + table.insert(result_table, v) + end + + return result_table, state +end + +local check_results = function(results, state) + assert(state, "Must pass state") + + for _, v in ipairs(results) do + local assertion + if not v._type or v._type == "are" or v._type == "_default" then + assertion = assert.are.same + else + assertion = assert.are_not.same + end + + -- TODO: I think it would be nice to be able to see the state, + -- but it clutters up the test output so much here. + -- + -- So we would have to consider how to do that I think. + assertion(v.expected, v.actual, string.format("Test Case: %s // %s", v.location, v.case)) + end +end + +tester.run_string = function(contents) + contents = [[ + return (function() + local runner = require('telescope.testharness.runner') + local helper = require('telescope.testharness.helpers') + + helper.make_globals() + local ok, msg = pcall(function() + runner.log("Loading Test") + + ]] .. contents .. [[ + end) + + return {ok, msg or runner.state} + end)() + ]] + + check_results(get_results_from_contents(contents)) +end + +tester.run_file = function(filename) + local file = "./lua/tests/pickers/" .. filename .. ".lua" + local path = Path:new(file) + + if not path:exists() then + assert.are.same("", file) + end + + local contents = string.format( + [[ + return (function() + local runner = require('telescope.testharness.runner') + local helper = require('telescope.testharness.helpers') + + helper.make_globals() + local ok, msg = pcall(function() + runner.log("Loading Test") + return loadfile("%s")() + end) + + return {ok, msg or runner.state} + end)() + ]], + path:absolute() + ) + + check_results(get_results_from_contents(contents)) +end + +tester.not_ = function(val) + val._type = "are_not" + return val +end + +return tester diff --git a/lua/telescope/testharness/runner.lua b/lua/telescope/testharness/runner.lua new file mode 100644 index 0000000..bde2b8d --- /dev/null +++ b/lua/telescope/testharness/runner.lua @@ -0,0 +1,152 @@ +local builtin = require "telescope.builtin" + +local runner = {} + +-- State is test variable +runner.state = { + done = false, + results = {}, + msgs = {}, +} + +local writer = function(val) + table.insert(runner.state.results, val) +end + +local invalid_test_case = function(k) + error { case = k, expected = "", actual = k } +end + +local _VALID_KEYS = { + post_typed = true, + post_close = true, +} + +local replace_terms = function(input) + return vim.api.nvim_replace_termcodes(input, true, false, true) +end + +runner.nvim_feed = function(text, feed_opts) + feed_opts = feed_opts or "m" + + vim.api.nvim_feedkeys(text, feed_opts, true) +end + +local end_test_cases = function() + runner.state.done = true +end + +local execute_test_case = function(location, key, spec) + local ok, actual = pcall(spec[2]) + + if not ok then + writer { + location = "Error: " .. location, + case = key, + expected = "To succeed and return: " .. tostring(spec[1]), + actual = actual, + + _type = spec._type, + } + + end_test_cases() + else + writer { + location = location, + case = key, + expected = spec[1], + actual = actual, + + _type = spec._type, + } + end + + return ok +end + +runner.log = function(msg) + table.insert(runner.state.msgs, msg) +end + +runner.picker = function(picker_name, input, test_cases, opts) + opts = opts or {} + + for k, _ in pairs(test_cases) do + if not _VALID_KEYS[k] then + return invalid_test_case(k) + end + end + + opts.on_complete = { + runner.create_on_complete(input, test_cases), + } + + opts._on_error = function(self, msg) + runner.state.done = true + writer { + location = "Error while running on complete", + expected = "To Work", + actual = msg, + } + end + + runner.log "Starting picker" + builtin[picker_name](opts) + runner.log "Called picker" +end + +runner.create_on_complete = function(input, test_cases) + input = replace_terms(input) + + local actions = {} + for i = 1, #input do + local char = input:sub(i, i) + table.insert(actions, { + cb = function() + runner.log("Inserting char: " .. char) + runner.nvim_feed(char, "") + end, + char = char, + }) + end + + return function() + local action = {} + repeat + action = table.remove(actions, 1) + if action then + action.cb() + end + until not action or string.match(action.char, "%g") + + if #actions > 0 then + return + end + + vim.defer_fn(function() + if test_cases.post_typed then + for k, v in ipairs(test_cases.post_typed) do + if not execute_test_case("post_typed", k, v) then + return + end + end + end + + runner.nvim_feed(replace_terms "", "") + + vim.defer_fn(function() + if test_cases.post_close then + for k, v in ipairs(test_cases.post_close) do + if not execute_test_case("post_close", k, v) then + return + end + end + end + + vim.defer_fn(end_test_cases, 20) + end, 20) + end, 20) + end +end + +return runner diff --git a/lua/tests/automated/entry_manager_spec.lua b/lua/tests/automated/entry_manager_spec.lua index 6d2b5d3..27f2dc6 100644 --- a/lua/tests/automated/entry_manager_spec.lua +++ b/lua/tests/automated/entry_manager_spec.lua @@ -4,7 +4,7 @@ local eq = assert.are.same describe("process_result", function() it("works with one entry", function() - local manager = EntryManager:new(5, nil) + local manager = EntryManager:new(5) manager:add_entry(nil, 1, "hello", "") @@ -12,64 +12,32 @@ describe("process_result", function() end) it("works with two entries", function() - local manager = EntryManager:new(5, nil) + local manager = EntryManager:new(5) manager:add_entry(nil, 1, "hello", "") manager:add_entry(nil, 2, "later", "") eq(2, manager.linked_states.size) - eq("hello", manager:get_entry(1)) - eq("later", manager:get_entry(2)) - end) - - it("calls functions when inserting", function() - local called_count = 0 - local manager = EntryManager:new(5, function() - called_count = called_count + 1 - end) - - assert(called_count == 0) - manager:add_entry(nil, 1, "hello", "") - assert(called_count == 1) - end) - - it("calls functions when inserting twice", function() - local called_count = 0 - local manager = EntryManager:new(5, function() - called_count = called_count + 1 - end) - - assert(called_count == 0) - manager:add_entry(nil, 1, "hello", "") - manager:add_entry(nil, 2, "world", "") - assert(called_count == 2) + eq("hello", manager:get_entry(0, 1)) + eq("later", manager:get_entry(0, 2)) end) it("correctly sorts lower scores", function() - local called_count = 0 - local manager = EntryManager:new(5, function() - called_count = called_count + 1 - end) - manager:add_entry(nil, 5, "worse result", "") - manager:add_entry(nil, 2, "better result", "") + local manager = EntryManager:new(5) + manager:add_entry(nil, 5, "worse result") + manager:add_entry(nil, 2, "better result") - eq("better result", manager:get_entry(1)) - eq("worse result", manager:get_entry(2)) - - eq(2, called_count) + eq("better result", manager:get_entry(0, 1)) + eq("worse result", manager:get_entry(0, 2)) end) it("respects max results", function() - local called_count = 0 - local manager = EntryManager:new(1, function() - called_count = called_count + 1 - end) - manager:add_entry(nil, 2, "better result", "") - manager:add_entry(nil, 5, "worse result", "") + local manager = EntryManager:new(1) + manager:add_entry(nil, 2, "better result") + manager:add_entry(nil, 5, "worse result") - eq("better result", manager:get_entry(1)) - eq(1, called_count) + eq("better result", manager:get_entry(0, 1)) end) it("should allow simple entries", function() @@ -103,31 +71,6 @@ describe("process_result", function() eq(1, counts_executed) end) - it("should not loop a bunch", function() - local info = {} - local manager = EntryManager:new(5, nil, info) - manager:add_entry(nil, 4, "better result", "") - manager:add_entry(nil, 3, "better result", "") - manager:add_entry(nil, 2, "better result", "") - - -- Loops once to find 3 < 4 - -- Loops again to find 2 < 3 - eq(2, info.looped) - end) - - it("should not loop a bunch, part 2", function() - local info = {} - local manager = EntryManager:new(5, nil, info) - manager:add_entry(nil, 4, "better result", "") - manager:add_entry(nil, 2, "better result", "") - manager:add_entry(nil, 3, "better result", "") - - -- Loops again to find 2 < 4 - -- Loops once to find 3 > 2 - -- but less than 4 - eq(3, info.looped) - end) - it("should update worst score in all append case", function() local manager = EntryManager:new(2, nil) manager:add_entry(nil, 2, "result 2", "") @@ -138,20 +81,12 @@ describe("process_result", function() end) it("should update worst score in all prepend case", function() - local called_count = 0 - local manager = EntryManager:new(2, function() - called_count = called_count + 1 - end) - manager:add_entry(nil, 5, "worse result", "") - manager:add_entry(nil, 4, "less worse result", "") - manager:add_entry(nil, 2, "better result", "") + local manager = EntryManager:new(2) + manager:add_entry(nil, 5, "worse result") + manager:add_entry(nil, 4, "less worse result") + manager:add_entry(nil, 2, "better result") - -- Once for insert 5 - -- Once for prepend 4 - -- Once for prepend 2 - eq(3, called_count) - - eq("better result", manager:get_entry(1)) + eq("better result", manager:get_entry(0, 1)) eq(4, manager.worst_acceptable_score) end) @@ -167,8 +102,8 @@ describe("process_result", function() manager:add_entry(picker, 0.5, "same same", "asdf") manager:add_entry(picker, 0.5, "same", "asdf") - eq("same", manager:get_entry(1)) - eq("same same", manager:get_entry(2)) + eq("same", manager:get_entry(0, 1)) + eq("same same", manager:get_entry(0, 2)) end) it("should call tiebreaker if score is the same, keep initial", function() @@ -183,7 +118,21 @@ describe("process_result", function() manager:add_entry(picker, 0.5, "same same", "asdf") manager:add_entry(picker, 0.5, "same", "asdf") - eq("same", manager:get_entry(2)) - eq("same same", manager:get_entry(1)) + eq("same", manager:get_entry(0, 2)) + eq("same same", manager:get_entry(0, 1)) + end) + + it(":window() should return table of resuls", function() + local manager = EntryManager:new(5, nil) + + manager:add_entry(nil, 1, "first") + manager:add_entry(nil, 2, "second") + manager:add_entry(nil, 3, "third") + manager:add_entry(nil, 4, "fourth") + manager:add_entry(nil, 5, "sixth") + + eq(5, manager.linked_states.size) + + eq({ "second", "third" }, manager:window(2, 3)) end) end) diff --git a/lua/tests/automated/pickers/find_files_spec.lua b/lua/tests/automated/pickers/find_files_spec.lua index e9094cb..c03f4a3 100644 --- a/lua/tests/automated/pickers/find_files_spec.lua +++ b/lua/tests/automated/pickers/find_files_spec.lua @@ -1,6 +1,4 @@ -require("plenary.reload").reload_module "telescope" - -local tester = require "telescope.pickers._test" +local tester = require "telescope.testharness" local disp = function(val) return vim.inspect(val, { newline = " ", indent = "" }) @@ -11,6 +9,7 @@ describe("builtin.find_files", function() tester.run_file "find_files__readme" end) +<<<<<<< HEAD it("should be able to move selections", function() tester.run_file "find_files__with_ctrl_n" end) @@ -19,6 +18,14 @@ describe("builtin.find_files", function() { sorting_strategy = "descending" }, { sorting_strategy = "ascending" }, } do +======= + for _, configuration in + ipairs { + { sorting_strategy = "descending" }, + { sorting_strategy = "ascending" }, + } + do +>>>>>>> 20a1519 (feat(fps): Add refresh style display for telescope) it("should not display devicons when disabled: " .. disp(configuration), function() tester.run_string(string.format( [[ diff --git a/lua/tests/automated/pickers/scroll_cycle_spec.lua b/lua/tests/automated/pickers/scroll_cycle_spec.lua new file mode 100644 index 0000000..73fc503 --- /dev/null +++ b/lua/tests/automated/pickers/scroll_cycle_spec.lua @@ -0,0 +1,109 @@ +local tester = require "telescope.testharness" + +--[[ +Available functions are +- fixtures/file_a.txt +- fixtures/file_abc.txt +--]] + +describe("scroll_cycle", function() + it("should be able to cycle selections: cycle", function() + tester.run_string [[ + runner.picker("find_files", "fixtures/file", { + post_close = { + { "lua/tests/fixtures/file_abc.txt", helper.get_selection_value }, + }, + }, { + sorting_strategy = "ascending", + scroll_strategy = "cycle", + }) + ]] + end) + + for _, sorting in ipairs { "ascending", "descending" } do + for _, key in ipairs { "", "" } do + it(string.format("Cycle: %sx2 %s", key, sorting), function() + tester.run_string(([[ + runner.picker("find_files", "fixtures/file%s%s", { + post_typed = { + { "lua/tests/fixtures/file_a.txt", helper.get_selection_value }, + }, + }, { + sorting_strategy = "%s", + scroll_strategy = "cycle", + } + ) ]]):format(key, key, sorting)) + end) + + it(string.format("Cycle: %sx3 %s", key, sorting), function() + tester.run_string(([[ + runner.picker("find_files", "fixtures/file%s%s%s", { + post_typed = { + { "lua/tests/fixtures/file_abc.txt", helper.get_selection_value }, + }, + }, { + sorting_strategy = "%s", + scroll_strategy = "cycle", + } + ) ]]):format(key, key, key, sorting)) + end) + end + end + + it("should be able to cycle selections: limit", function() + tester.run_string [[ + runner.picker("find_files", "fixtures/file", { + post_close = { + { "lua/tests/fixtures/file_a.txt", helper.get_selection_value }, + }, + }, { + sorting_strategy = "ascending", + scroll_strategy = "limit", + }) + ]] + end) + + it("long: cycle to top", function() + tester.run_string [[ + runner.picker("find_files", "fixtures/long", { + post_close = { + { "lua/tests/fixtures/long_11111111111.md", helper.get_selection_value }, + }, + }, { + sorting_strategy = "ascending", + scroll_strategy = "cycle", + height = 10, + }) + ]] + end) + + it("long: cycle to top", function() + tester.run_string [[ + runner.picker("find_files", "fixtures/long", { + post_close = { + { "lua/tests/fixtures/long_11111111111.md", helper.get_selection_value }, + }, + }, { + sorting_strategy = "descending", + scroll_strategy = "cycle", + height = 10, + }) + ]] + end) + + it("long: smash ", function() + tester.run_string [[ + runner.picker("find_files", "fixtures/long", { + post_typed = { + { "lua/tests/fixtures/long_111111.md", helper.get_selection_value }, + }, + }, { + sorting_strategy = "descending", + scroll_strategy = "cycle", + layout_config = { + height = 8, + }, + }) + ]] + end) +end) diff --git a/lua/tests/automated/pickers/scrolling_spec.lua b/lua/tests/automated/pickers/scrolling_spec.lua index 760d2b9..2a6eb4c 100644 --- a/lua/tests/automated/pickers/scrolling_spec.lua +++ b/lua/tests/automated/pickers/scrolling_spec.lua @@ -1,9 +1,4 @@ -require("plenary.reload").reload_module "telescope" - -local tester = require "telescope.pickers._test" - -local log = require "telescope.log" -log.use_console = false +local tester = require "telescope.testharness" describe("scrolling strategies", function() it("should handle cycling for full list", function() diff --git a/lua/tests/automated/pickers/testing_harness_spec.lua b/lua/tests/automated/pickers/testing_harness_spec.lua new file mode 100644 index 0000000..4be395d --- /dev/null +++ b/lua/tests/automated/pickers/testing_harness_spec.lua @@ -0,0 +1,39 @@ +local testharness = require "telescope.testharness" + +describe("testing harness", function() + it("should find the readme, using lowercase", function() + testharness.run_string [[ + runner.picker('find_files', 'readme.md', { + post_typed = { + { "> readme.md", GetPrompt }, + { " README.md", GetBestResult }, + }, + post_close = { + { 'README.md', GetFile }, + } + }, { + disable_devicons = true, + }) + ]] + end) + + it("should find the readme, using uppercase", function() + testharness.run_string [[ + runner.picker('find_files', 'RE', { + post_close = { + { 'README.md', GetFile }, + } + }) + ]] + end) + + it("Should find telescope prompt file", function() + testharness.run_string [[ + runner.picker('find_files', 'TelescopePrompt', { + post_close = { + { 'TelescopePrompt.lua', GetFile }, + } + }) + ]] + end) +end) diff --git a/lua/tests/fixtures/long_1.md b/lua/tests/fixtures/long_1.md new file mode 100644 index 0000000..e69de29 diff --git a/lua/tests/fixtures/long_11.md b/lua/tests/fixtures/long_11.md new file mode 100644 index 0000000..e69de29 diff --git a/lua/tests/fixtures/long_111.md b/lua/tests/fixtures/long_111.md new file mode 100644 index 0000000..e69de29 diff --git a/lua/tests/fixtures/long_1111.md b/lua/tests/fixtures/long_1111.md new file mode 100644 index 0000000..e69de29 diff --git a/lua/tests/fixtures/long_11111.md b/lua/tests/fixtures/long_11111.md new file mode 100644 index 0000000..e69de29 diff --git a/lua/tests/fixtures/long_111111.md b/lua/tests/fixtures/long_111111.md new file mode 100644 index 0000000..e69de29 diff --git a/lua/tests/fixtures/long_1111111.md b/lua/tests/fixtures/long_1111111.md new file mode 100644 index 0000000..e69de29 diff --git a/lua/tests/fixtures/long_11111111.md b/lua/tests/fixtures/long_11111111.md new file mode 100644 index 0000000..e69de29 diff --git a/lua/tests/fixtures/long_111111111.md b/lua/tests/fixtures/long_111111111.md new file mode 100644 index 0000000..e69de29 diff --git a/lua/tests/fixtures/long_1111111111.md b/lua/tests/fixtures/long_1111111111.md new file mode 100644 index 0000000..e69de29 diff --git a/lua/tests/fixtures/long_11111111111.md b/lua/tests/fixtures/long_11111111111.md new file mode 100644 index 0000000..e69de29 diff --git a/lua/tests/pickers/find_files__readme.lua b/lua/tests/pickers/find_files__readme.lua index 7ec8bcc..1b76ad6 100644 --- a/lua/tests/pickers/find_files__readme.lua +++ b/lua/tests/pickers/find_files__readme.lua @@ -1,7 +1,7 @@ -local tester = require "telescope.pickers._test" -local helper = require "telescope.pickers._test_helpers" +local helper = require "telescope.testharness.helpers" +local runner = require "telescope.testharness.runner" -tester.builtin_picker("find_files", "README.md", { +runner.picker("find_files", "README.md", { post_close = { { "README.md", helper.get_file }, }, diff --git a/lua/tests/pickers/find_files__scrolling_descending_cycle.lua b/lua/tests/pickers/find_files__scrolling_descending_cycle.lua index 4f8a3f2..ff01b5b 100644 --- a/lua/tests/pickers/find_files__scrolling_descending_cycle.lua +++ b/lua/tests/pickers/find_files__scrolling_descending_cycle.lua @@ -1,12 +1,11 @@ -require("plenary.reload").reload_module "plenary" -require("plenary.reload").reload_module "telescope" +local tester = require "telescope.testharness" +local runner = require "telescope.testharness.runner" +local helper = require "telescope.testharness.helpers" -local tester = require "telescope.pickers._test" -local helper = require "telescope.pickers._test_helpers" - -tester.builtin_picker("find_files", "telescope", { +runner.picker("find_files", "plugin", { post_close = { - tester.not_ { "plugin/telescope.vim", helper.get_file }, + tester.not_ { "telescope.vim", helper.get_file }, + { "TelescopePrompt.lua", helper.get_file }, }, }, { sorting_strategy = "descending", diff --git a/lua/tests/pickers/find_files__with_ctrl_n.lua b/lua/tests/pickers/find_files__with_ctrl_n.lua deleted file mode 100644 index 4820f34..0000000 --- a/lua/tests/pickers/find_files__with_ctrl_n.lua +++ /dev/null @@ -1,8 +0,0 @@ -local tester = require "telescope.pickers._test" -local helper = require "telescope.pickers._test_helpers" - -tester.builtin_picker("find_files", "fixtures/file", { - post_close = { - { "lua/tests/fixtures/file_abc.txt", helper.get_selection_value }, - }, -}) diff --git a/scratch/files.py b/scratch/files.py new file mode 100644 index 0000000..3e55971 --- /dev/null +++ b/scratch/files.py @@ -0,0 +1,89 @@ +from pathlib import Path +import subprocess + +something = subprocess.run(["rg", "--files"], capture_output=True) +files = something.stdout.decode('utf-8').split('\n') +files.sort() + +user_input = "lua finders/async" + +REJECTED = -1.0 +GOOD = 2.0 + +def is_subset(item, prompt) -> float: + prompt_chars = set() + for c in prompt: + prompt_chars.add(c) + + item_chars = set() + for c in item: + item_chars.add(c) + + return prompt_chars.issubset(item_chars) + +def proportion_of_contained_letters(prompt, item) -> float: + prompt_chars = set() + for c in prompt: + prompt_chars.add(c) + + item_chars = set() + for c in item: + item_chars.add(c) + + contained = 0 + for prompt_char in prompt_chars: + if prompt_char in item_chars: + contained += 1 + + return contained / len(prompt_chars) + +def jerry_match(prompt: str, item) -> float: + p = Path(item) + + split = prompt.split(" ", maxsplit=2) + language = split[0] + filter = split[1] + + if p.suffix != "." + language: + return REJECTED + + if filter in item: + return GOOD + + proprotion = proportion_of_contained_letters(filter, item) + if proprotion < 0.75: + return REJECTED + + return proprotion + +def score_results(prompt, files): + results = [] + for f in files: + score = jerry_match(prompt, f) + if score == REJECTED: + continue + + results.append({'score': score, 'item': f}) + + + results.sort(key=lambda x: x["score"], reverse=True) + return results + +while True: + i = input("Filter Phrase > ") + if not i: + break + + results = score_results(i, files) + for result in results[:10]: + print(result["item"]) + +# x = [1, 2, 3, 4, 4, 2, 1, 3] +# print(x) +# print(set(x)) + +# x = {1, 2, 3} +# y = {1} +# +# print("x.issubset(y)", x.issubset(y)) +# print("y.issubset(x)", y.issubset(x))