1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-23 13:10:04 +08:00

feat(zettelkasten): improve zettelkasten layer

This commit is contained in:
Wang Shidong 2022-10-25 18:35:51 +08:00 committed by GitHub
parent 1c1d63d923
commit ac74bffee5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 5053 additions and 6986 deletions

View File

@ -29,12 +29,17 @@ endfunction
function! SpaceVim#layers#zettelkasten#config() abort function! SpaceVim#layers#zettelkasten#config() abort
let g:_spacevim_mappings_space.m.z = {'name' : '+zettelkasten'} let g:_spacevim_mappings_space.m.z = {'name' : '+zettelkasten'}
call SpaceVim#mapping#space#def('nnoremap', ['m', 'z', 'n'], 'ZkNew', 'create-new-zettel-note', 1) call SpaceVim#mapping#space#def('nnoremap', ['m', 'z', 'n'], 'ZkNew', 'create-new-zettel-note', 1)
call SpaceVim#mapping#space#def('nnoremap', ['m', 'z', 't'], 'Telescope zettelkasten_template', 'zettel-template', 1)
call SpaceVim#mapping#space#def('nnoremap', ['m', 'z', 'b'], 'ZkBrowse', 'open-zettelkasten-browse', 1)
endfunction endfunction
function! SpaceVim#layers#zettelkasten#set_variable(var) abort function! SpaceVim#layers#zettelkasten#set_variable(var) abort
let g:zettelkasten_directory = get(a:var, let g:zettelkasten_directory = get(a:var,
\ 'zettel_dir', \ 'zettel_dir',
\ '') \ '')
let g:zettelkasten_template_directory = get(a:var,
\ 'zettel_template_dir',
\ '')
endfunction endfunction
function! SpaceVim#layers#zettelkasten#get_options() abort function! SpaceVim#layers#zettelkasten#get_options() abort

View File

@ -1 +1 @@
github: [tjdevries, Conni2461] github: [tjdevries, Conni2461, fdschmidt93]

View File

@ -29,6 +29,12 @@ body:
placeholder: "macOS 11.5" placeholder: "macOS 11.5"
validations: validations:
required: true required: true
- type: input
attributes:
label: "Telescope version / branch / rev"
placeholder: "telescope 0.1.0"
validations:
required: true
- type: textarea - type: textarea
attributes: attributes:
label: "checkhealth telescope" label: "checkhealth telescope"

View File

@ -0,0 +1,33 @@
# Description
Please include a summary of the change and which issue is fixed. Please also
include relevant motivation and context
Fixes # (issue)
## Type of change
Please delete options that are not relevant.
- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (fix or feature that would cause existing functionality to not work as expected)
- This change requires a documentation update
# How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list relevant details about your configuration
- [ ] Test A
- [ ] Test B
**Configuration**:
* Neovim version (nvim --version):
* Operating system and version:
# Checklist:
- [ ] My code follows the style guidelines of this project (stylua)
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation (lua annotations)

View File

@ -13,19 +13,19 @@ jobs:
- os: ubuntu-20.04 - os: ubuntu-20.04
url: https://github.com/neovim/neovim/releases/download/nightly/nvim-linux64.tar.gz url: https://github.com/neovim/neovim/releases/download/nightly/nvim-linux64.tar.gz
manager: sudo apt-get manager: sudo apt-get
packages: -y fd-find packages: -y ripgrep
- os: ubuntu-20.04 - os: ubuntu-20.04
url: https://github.com/neovim/neovim/releases/download/v0.7.0/nvim-linux64.tar.gz url: https://github.com/neovim/neovim/releases/download/v0.7.0/nvim-linux64.tar.gz
manager: sudo apt-get manager: sudo apt-get
packages: -y fd-find packages: -y ripgrep
- os: macos-10.15 - os: macos-10.15
url: https://github.com/neovim/neovim/releases/download/nightly/nvim-macos.tar.gz url: https://github.com/neovim/neovim/releases/download/nightly/nvim-macos.tar.gz
manager: brew manager: brew
packages: fd packages: ripgrep
- os: macos-10.15 - os: macos-10.15
url: https://github.com/neovim/neovim/releases/download/v0.7.0/nvim-macos.tar.gz url: https://github.com/neovim/neovim/releases/download/v0.7.0/nvim-macos.tar.gz
manager: brew manager: brew
packages: fd packages: ripgrep
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- run: date +%F > todays-date - run: date +%F > todays-date

View File

@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: JohnnyMorganz/stylua-action@1.0.0 - uses: JohnnyMorganz/stylua-action@v1
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
# CLI arguments # CLI arguments

View File

@ -51,7 +51,7 @@ latest neovim nightly commit is required for `telescope.nvim` to work.
### Suggested dependencies ### Suggested dependencies
- [BurntSushi/ripgrep](https://github.com/BurntSushi/ripgrep) is required for - [BurntSushi/ripgrep](https://github.com/BurntSushi/ripgrep) is required for
`live_grep` and `grep_string` `live_grep` and `grep_string` and is the first priority for `find_files`.
We also suggest you install one native telescope sorter to significantly improve We also suggest you install one native telescope sorter to significantly improve
sorting performance. Take a look at either sorting performance. Take a look at either
@ -71,24 +71,34 @@ wiki.
### Installation ### Installation
It is suggested to either use the latest release
[tag](https://github.com/nvim-telescope/telescope.nvim/tags) or our release
branch (which will get consistent updates)
[0.1.x](https://github.com/nvim-telescope/telescope.nvim/tree/0.1.x).
It is not suggested to run latest master.
Using [vim-plug](https://github.com/junegunn/vim-plug) Using [vim-plug](https://github.com/junegunn/vim-plug)
```viml ```viml
Plug 'nvim-lua/plenary.nvim' Plug 'nvim-lua/plenary.nvim'
Plug 'nvim-telescope/telescope.nvim' Plug 'nvim-telescope/telescope.nvim', { 'tag': '0.1.0' }
" or , { 'branch': '0.1.x' }
``` ```
Using [dein](https://github.com/Shougo/dein.vim) Using [dein](https://github.com/Shougo/dein.vim)
```viml ```viml
call dein#add('nvim-lua/plenary.nvim') call dein#add('nvim-lua/plenary.nvim')
call dein#add('nvim-telescope/telescope.nvim') call dein#add('nvim-telescope/telescope.nvim', { 'rev': '0.1.0' })
" or , { 'rev': '0.1.x' })
``` ```
Using [packer.nvim](https://github.com/wbthomason/packer.nvim) Using [packer.nvim](https://github.com/wbthomason/packer.nvim)
```lua ```lua
use { use {
'nvim-telescope/telescope.nvim', 'nvim-telescope/telescope.nvim', tag = '0.1.0',
-- or , branch = '0.1.x',
requires = { {'nvim-lua/plenary.nvim'} } requires = { {'nvim-lua/plenary.nvim'} }
} }
``` ```
@ -96,7 +106,7 @@ use {
### checkhealth ### checkhealth
Make sure you call `:checkhealth telescope` after installing telescope to ensure Make sure you call `:checkhealth telescope` after installing telescope to ensure
everything is setup correctly. everything is set up correctly.
After this setup you can continue reading here or switch to `:help telescope` After this setup you can continue reading here or switch to `:help telescope`
to get an understanding of how to use Telescope and how to configure it. to get an understanding of how to use Telescope and how to configure it.
@ -106,6 +116,8 @@ to get an understanding of how to use Telescope and how to configure it.
Try the command `:Telescope find_files<cr>` Try the command `:Telescope find_files<cr>`
to see if `telescope.nvim` is installed correctly. to see if `telescope.nvim` is installed correctly.
Using VimL:
```viml ```viml
" Find files using Telescope command-line sugar. " Find files using Telescope command-line sugar.
nnoremap <leader>ff <cmd>Telescope find_files<cr> nnoremap <leader>ff <cmd>Telescope find_files<cr>
@ -120,6 +132,16 @@ nnoremap <leader>fb <cmd>lua require('telescope.builtin').buffers()<cr>
nnoremap <leader>fh <cmd>lua require('telescope.builtin').help_tags()<cr> nnoremap <leader>fh <cmd>lua require('telescope.builtin').help_tags()<cr>
``` ```
Using Lua:
```lua
local builtin = require('telescope.builtin')
vim.keymap.set('n', '<leader>ff', builtin.find_files, {})
vim.keymap.set('n', '<leader>fg', builtin.live_grep, {})
vim.keymap.set('n', '<leader>fb', builtin.buffers, {})
vim.keymap.set('n', '<leader>fh', builtin.help_tags, {})
```
See [builtin pickers](#pickers) for a list of all builtin functions. See [builtin pickers](#pickers) for a list of all builtin functions.
## Customization ## Customization
@ -192,7 +214,7 @@ EOF
## Default Mappings ## Default Mappings
Mappings are fully customizable. Mappings are fully customizable.
Many familiar mapping patterns are setup as defaults. Many familiar mapping patterns are set up as defaults.
| Mappings | Action | | Mappings | Action |
|----------------|------------------------------------------------------| |----------------|------------------------------------------------------|
@ -200,7 +222,7 @@ Many familiar mapping patterns are setup as defaults.
| `<C-p>/<Up>` | Previous item | | `<C-p>/<Up>` | Previous item |
| `j/k` | Next/previous (in normal mode) | | `j/k` | Next/previous (in normal mode) |
| `H/M/L` | Select High/Middle/Low (in normal mode) | | `H/M/L` | Select High/Middle/Low (in normal mode) |
| 'gg/G' | Select the first/last item (in normal mode) | | `gg/G` | Select the first/last item (in normal mode) |
| `<CR>` | Confirm selection | | `<CR>` | Confirm selection |
| `<C-x>` | Go to file selection as a split | | `<C-x>` | Go to file selection as a split |
| `<C-v>` | Go to file selection as a vsplit | | `<C-v>` | Go to file selection as a vsplit |
@ -260,9 +282,9 @@ Built-in functions. Ready to be bound to any key you like.
| Functions | Description | | Functions | Description |
|-------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------| |-------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `builtin.find_files` | Lists files in your current working directory, respects .gitignore | | `builtin.find_files` | Lists files in your current working directory, respects .gitignore |
| `builtin.git_files` | Fuzzy search through the output of `git ls-files` command, respects .gitignore, optionally ignores untracked files | | `builtin.git_files` | Fuzzy search through the output of `git ls-files` command, respects .gitignore |
| `builtin.grep_string` | Searches for the string under your cursor in your current working directory | | `builtin.grep_string` | Searches for the string under your cursor in your current working directory |
| `builtin.live_grep` | Search for a string in your current working directory and get results live as you type (respecting .gitignore) | | `builtin.live_grep` | Search for a string in your current working directory and get results live as you type, respects .gitignore |
### Vim Pickers ### Vim Pickers
@ -299,6 +321,8 @@ Built-in functions. Ready to be bound to any key you like.
| Functions | Description | | Functions | Description |
|---------------------------------------------|---------------------------------------------------------------------------------------------------------------------------| |---------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|
| `builtin.lsp_references` | Lists LSP references for word under the cursor | | `builtin.lsp_references` | Lists LSP references for word under the cursor |
| `builtin.lsp_incoming_calls` | Lists LSP incoming calls for word under the cursor |
| `builtin.lsp_outgoing_calls` | Lists LSP outgoing calls for word under the cursor |
| `builtin.lsp_document_symbols` | Lists LSP document symbols in the current buffer | | `builtin.lsp_document_symbols` | Lists LSP document symbols in the current buffer |
| `builtin.lsp_workspace_symbols` | Lists LSP document symbols in the current workspace | | `builtin.lsp_workspace_symbols` | Lists LSP document symbols in the current workspace |
| `builtin.lsp_dynamic_workspace_symbols` | Dynamically Lists LSP for all workspace symbols | | `builtin.lsp_dynamic_workspace_symbols` | Dynamically Lists LSP for all workspace symbols |

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@
- [Oneshot job](#oneshot-job) - [Oneshot job](#oneshot-job)
- [Previewer](#previewer) - [Previewer](#previewer)
- [More examples](#more-examples) - [More examples](#more-examples)
- [Bundling as Extension](#bundling-as-extension)
- [Technical](#technical) - [Technical](#technical)
- [picker](#picker) - [picker](#picker)
- [finders](#finders) - [finders](#finders)
@ -263,7 +264,7 @@ find results and call `entry_maker` for each entry. An example usage would be
`find`. `find`.
```lua ```lua
finder = finders.new_oneshot_job { "find", opts }, finder = finders.new_oneshot_job({ "find" }, opts ),
``` ```
### More examples ### More examples
@ -278,6 +279,51 @@ more information on [gitter](https://gitter.im/nvim-telescope/community?utm_sour
and we will happily answer your questions and hopefully allow us to improve this guide. You can also and we will happily answer your questions and hopefully allow us to improve this guide. You can also
help us to improve this guide by sending a PR. help us to improve this guide by sending a PR.
### Bundling as extension
If you now want to bundle your picker as extension, so it is available as
picker via the `:Telescope` command, the following has to be done.
Structure your plugin as follows, so it can be found by telescope:
```
.
└── lua
├── plugin_name # Your actual plugin code
│ ├── init.lua
│ └── some_file.lua
└── telescope
└── _extensions # The underscore is significant
└─ plugin_name.lua # Init and register your extension
```
The `lua/telescope/_extensions/plugin_name.lua` file needs to return the
following: (see `:help telescope.register_extension`)
```lua
return require("telescope").register_extension {
setup = function(ext_config, config)
-- access extension config and user config
end,
exports = {
stuff = require("plugin_name").stuff
},
}
```
The setup function can be used to access the extension config and setup
extension specific global configuration. You also have access to the user
telescope default config, so you can override specific internal function. For
example sorters if you have an extension that provides a replacement sorter,
like
[telescope-fzf-native](https://github.com/nvim-telescope/telescope-fzf-native.nvim).
The exports table declares the exported pickers that can then be accessed via
`Telescope plugin_name stuff`. If you only provide one export it is suggested
that you name the key like the plugin, so you can access it with `Telescope
plugin_name`.
## Technical ## Technical
### Picker ### Picker

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -54,7 +54,7 @@
local a = vim.api local a = vim.api
local config = require "telescope.config" local conf = require("telescope.config").values
local state = require "telescope.state" local state = require "telescope.state"
local utils = require "telescope.utils" local utils = require "telescope.utils"
local popup = require "plenary.popup" local popup = require "plenary.popup"
@ -242,10 +242,9 @@ end
---@param prompt_bufnr number: The prompt bufnr ---@param prompt_bufnr number: The prompt bufnr
actions.select_default = { actions.select_default = {
pre = function(prompt_bufnr) pre = function(prompt_bufnr)
action_state.get_current_history():append( action_state
action_state.get_current_line(), .get_current_history()
action_state.get_current_picker(prompt_bufnr) :append(action_state.get_current_line(), action_state.get_current_picker(prompt_bufnr))
)
end, end,
action = function(prompt_bufnr) action = function(prompt_bufnr)
return action_set.select(prompt_bufnr, "default") return action_set.select(prompt_bufnr, "default")
@ -259,10 +258,9 @@ actions.select_default = {
---@param prompt_bufnr number: The prompt bufnr ---@param prompt_bufnr number: The prompt bufnr
actions.select_horizontal = { actions.select_horizontal = {
pre = function(prompt_bufnr) pre = function(prompt_bufnr)
action_state.get_current_history():append( action_state
action_state.get_current_line(), .get_current_history()
action_state.get_current_picker(prompt_bufnr) :append(action_state.get_current_line(), action_state.get_current_picker(prompt_bufnr))
)
end, end,
action = function(prompt_bufnr) action = function(prompt_bufnr)
return action_set.select(prompt_bufnr, "horizontal") return action_set.select(prompt_bufnr, "horizontal")
@ -276,10 +274,9 @@ actions.select_horizontal = {
---@param prompt_bufnr number: The prompt bufnr ---@param prompt_bufnr number: The prompt bufnr
actions.select_vertical = { actions.select_vertical = {
pre = function(prompt_bufnr) pre = function(prompt_bufnr)
action_state.get_current_history():append( action_state
action_state.get_current_line(), .get_current_history()
action_state.get_current_picker(prompt_bufnr) :append(action_state.get_current_line(), action_state.get_current_picker(prompt_bufnr))
)
end, end,
action = function(prompt_bufnr) action = function(prompt_bufnr)
return action_set.select(prompt_bufnr, "vertical") return action_set.select(prompt_bufnr, "vertical")
@ -293,16 +290,47 @@ actions.select_vertical = {
---@param prompt_bufnr number: The prompt bufnr ---@param prompt_bufnr number: The prompt bufnr
actions.select_tab = { actions.select_tab = {
pre = function(prompt_bufnr) pre = function(prompt_bufnr)
action_state.get_current_history():append( action_state
action_state.get_current_line(), .get_current_history()
action_state.get_current_picker(prompt_bufnr) :append(action_state.get_current_line(), action_state.get_current_picker(prompt_bufnr))
)
end, end,
action = function(prompt_bufnr) action = function(prompt_bufnr)
return action_set.select(prompt_bufnr, "tab") return action_set.select(prompt_bufnr, "tab")
end, end,
} }
--- Perform 'drop' action on selection, usually something like<br>
---`:drop <selection>`
---
--- i.e. open the selection in a window
---@param prompt_bufnr number: The prompt bufnr
actions.select_drop = {
pre = function(prompt_bufnr)
action_state
.get_current_history()
:append(action_state.get_current_line(), action_state.get_current_picker(prompt_bufnr))
end,
action = function(prompt_bufnr)
return action_set.select(prompt_bufnr, "drop")
end,
}
--- Perform 'tab drop' action on selection, usually something like<br>
---`:tab drop <selection>`
---
--- i.e. open the selection in a new tab
---@param prompt_bufnr number: The prompt bufnr
actions.select_tab_drop = {
pre = function(prompt_bufnr)
action_state
.get_current_history()
:append(action_state.get_current_line(), action_state.get_current_picker(prompt_bufnr))
end,
action = function(prompt_bufnr)
return action_set.select(prompt_bufnr, "tab drop")
end,
}
-- TODO: consider adding float! -- TODO: consider adding float!
-- https://github.com/nvim-telescope/telescope.nvim/issues/365 -- https://github.com/nvim-telescope/telescope.nvim/issues/365
@ -343,14 +371,17 @@ end
--- Close the Telescope window, usually used within an action --- Close the Telescope window, usually used within an action
---@param prompt_bufnr number: The prompt bufnr ---@param prompt_bufnr number: The prompt bufnr
actions.close = function(prompt_bufnr) actions.close = function(prompt_bufnr)
action_state.get_current_history():reset()
local picker = action_state.get_current_picker(prompt_bufnr) local picker = action_state.get_current_picker(prompt_bufnr)
local original_win_id = picker.original_win_id local original_win_id = picker.original_win_id
local cursor_valid, original_cursor = pcall(a.nvim_win_get_cursor, original_win_id)
actions.close_pum(prompt_bufnr) actions.close_pum(prompt_bufnr)
require("telescope.pickers").on_close_prompt(prompt_bufnr) require("telescope.pickers").on_close_prompt(prompt_bufnr)
pcall(a.nvim_set_current_win, original_win_id) pcall(a.nvim_set_current_win, original_win_id)
if cursor_valid and a.nvim_get_mode().mode == "i" and picker._original_mode ~= "i" then
pcall(a.nvim_win_set_cursor, original_win_id, { original_cursor[1], original_cursor[2] + 1 })
end
end end
--- Close the Telescope window, usually used within an action<br> --- Close the Telescope window, usually used within an action<br>
@ -428,6 +459,8 @@ actions.edit_register = function(prompt_bufnr)
end end
--- Paste the selected register into the buffer --- Paste the selected register into the buffer
---
--- Note: only meant to be used inside builtin.registers
---@param prompt_bufnr number: The prompt bufnr ---@param prompt_bufnr number: The prompt bufnr
actions.paste_register = function(prompt_bufnr) actions.paste_register = function(prompt_bufnr)
local selection = action_state.get_selected_entry() local selection = action_state.get_selected_entry()
@ -559,6 +592,7 @@ actions.git_checkout = function(prompt_bufnr)
msg = string.format("Checked out: %s", selection.value), msg = string.format("Checked out: %s", selection.value),
level = "INFO", level = "INFO",
}) })
vim.cmd "checktime"
else else
utils.notify("actions.git_checkout", { utils.notify("actions.git_checkout", {
msg = string.format( msg = string.format(
@ -601,7 +635,7 @@ actions.git_switch_branch = function(prompt_bufnr)
selection.value, selection.value,
table.concat(stderr, " ") table.concat(stderr, " ")
), ),
level = "ERORR", level = "ERROR",
}) })
end end
end end
@ -748,6 +782,7 @@ actions.git_checkout_current_buffer = function(prompt_bufnr)
end end
actions.close(prompt_bufnr) actions.close(prompt_bufnr)
utils.get_os_command_output({ "git", "checkout", selection.value, "--", selection.file }, cwd) utils.get_os_command_output({ "git", "checkout", selection.value, "--", selection.file }, cwd)
vim.cmd "checktime"
end end
--- Stage/unstage selected file --- Stage/unstage selected file
@ -1017,7 +1052,9 @@ end
actions.delete_buffer = function(prompt_bufnr) actions.delete_buffer = function(prompt_bufnr)
local current_picker = action_state.get_current_picker(prompt_bufnr) local current_picker = action_state.get_current_picker(prompt_bufnr)
current_picker:delete_selection(function(selection) current_picker:delete_selection(function(selection)
vim.api.nvim_buf_delete(selection.bufnr, { force = false }) local force = vim.api.nvim_buf_get_option(selection.bufnr, "buftype") == "terminal"
local ok = pcall(vim.api.nvim_buf_delete, selection.bufnr, { force = force })
return ok
end) end)
end end
@ -1056,22 +1093,22 @@ end
---@param prompt_bufnr number: The prompt bufnr ---@param prompt_bufnr number: The prompt bufnr
actions.which_key = function(prompt_bufnr, opts) actions.which_key = function(prompt_bufnr, opts)
opts = opts or {} opts = opts or {}
opts.max_height = utils.get_default(opts.max_height, 0.4) opts.max_height = vim.F.if_nil(opts.max_height, 0.4)
opts.only_show_current_mode = utils.get_default(opts.only_show_current_mode, true) opts.only_show_current_mode = vim.F.if_nil(opts.only_show_current_mode, true)
opts.mode_width = utils.get_default(opts.mode_width, 1) opts.mode_width = vim.F.if_nil(opts.mode_width, 1)
opts.keybind_width = utils.get_default(opts.keybind_width, 7) opts.keybind_width = vim.F.if_nil(opts.keybind_width, 7)
opts.name_width = utils.get_default(opts.name_width, 30) opts.name_width = vim.F.if_nil(opts.name_width, 30)
opts.line_padding = utils.get_default(opts.line_padding, 1) opts.line_padding = vim.F.if_nil(opts.line_padding, 1)
opts.separator = utils.get_default(opts.separator, " -> ") opts.separator = vim.F.if_nil(opts.separator, " -> ")
opts.close_with_action = utils.get_default(opts.close_with_action, true) opts.close_with_action = vim.F.if_nil(opts.close_with_action, true)
opts.normal_hl = utils.get_default(opts.normal_hl, "TelescopePrompt") opts.normal_hl = vim.F.if_nil(opts.normal_hl, "TelescopePrompt")
opts.border_hl = utils.get_default(opts.border_hl, "TelescopePromptBorder") opts.border_hl = vim.F.if_nil(opts.border_hl, "TelescopePromptBorder")
opts.winblend = utils.get_default(opts.winblend, config.values.winblend) opts.winblend = vim.F.if_nil(opts.winblend, conf.winblend)
opts.column_padding = utils.get_default(opts.column_padding, " ") opts.column_padding = vim.F.if_nil(opts.column_padding, " ")
-- Assigning into 'opts.column_indent' would override a number with a string and -- Assigning into 'opts.column_indent' would override a number with a string and
-- cause issues with subsequent calls, keep a local copy of the string instead -- cause issues with subsequent calls, keep a local copy of the string instead
local column_indent = table.concat(utils.repeated_table(utils.get_default(opts.column_indent, 4), " ")) local column_indent = table.concat(utils.repeated_table(vim.F.if_nil(opts.column_indent, 4), " "))
-- close on repeated keypress -- close on repeated keypress
local km_bufs = (function() local km_bufs = (function()
@ -1100,7 +1137,7 @@ actions.which_key = function(prompt_bufnr, opts)
local displayer = entry_display.create { local displayer = entry_display.create {
separator = opts.separator, separator = opts.separator,
items = { items = {
{ width = opts.mode_with }, { width = opts.mode_width },
{ width = opts.keybind_width }, { width = opts.keybind_width },
{ width = opts.name_width }, { width = opts.name_width },
}, },
@ -1108,9 +1145,9 @@ actions.which_key = function(prompt_bufnr, opts)
local make_display = function(mapping) local make_display = function(mapping)
return displayer { return displayer {
{ mapping.mode, utils.get_default(opts.mode_hl, "TelescopeResultsConstant") }, { mapping.mode, vim.F.if_nil(opts.mode_hl, "TelescopeResultsConstant") },
{ mapping.keybind, utils.get_default(opts.keybind_hl, "TelescopeResultsVariable") }, { mapping.keybind, vim.F.if_nil(opts.keybind_hl, "TelescopeResultsVariable") },
{ mapping.name, utils.get_default(opts.name_hl, "TelescopeResultsFunction") }, { mapping.name, vim.F.if_nil(opts.name_hl, "TelescopeResultsFunction") },
} }
end end
@ -1125,7 +1162,7 @@ actions.which_key = function(prompt_bufnr, opts)
name = name == "" and action or name .. " + " .. action name = name == "" and action or name .. " + " .. action
end end
end end
if name and name ~= "which_key" then if name and name ~= "which_key" and name ~= "nop" then
if not opts.only_show_current_mode or mode == v.mode then if not opts.only_show_current_mode or mode == v.mode then
table.insert(mappings, { mode = v.mode, keybind = v.keybind, name = name }) table.insert(mappings, { mode = v.mode, keybind = v.keybind, name = name })
end end
@ -1168,10 +1205,8 @@ actions.which_key = function(prompt_bufnr, opts)
+ opts.name_width + opts.name_width
+ (3 * #opts.separator) + (3 * #opts.separator)
local num_total_columns = math.floor((vim.o.columns - #column_indent) / entry_width) local num_total_columns = math.floor((vim.o.columns - #column_indent) / entry_width)
opts.num_rows = math.min( opts.num_rows =
math.ceil(#mappings / num_total_columns), math.min(math.ceil(#mappings / num_total_columns), resolver.resolve_height(opts.max_height)(_, _, vim.o.lines))
resolver.resolve_height(opts.max_height)(_, _, vim.o.lines)
)
local total_available_entries = opts.num_rows * num_total_columns local total_available_entries = opts.num_rows * num_total_columns
local winheight = opts.num_rows + 2 * opts.line_padding local winheight = opts.num_rows + 2 * opts.line_padding
@ -1266,6 +1301,30 @@ actions.which_key = function(prompt_bufnr, opts)
end end
end end
--- Move from a none fuzzy search to a fuzzy one<br>
--- This action is meant to be used in live_grep and lsp_dynamic_workspace_symbols
---@param prompt_bufnr number: The prompt bufnr
actions.to_fuzzy_refine = function(prompt_bufnr)
local line = action_state.get_current_line()
local prefix = (function()
local title = action_state.get_current_picker(prompt_bufnr).prompt_title
if title == "Live Grep" then
return "Find Word"
elseif title == "LSP Dynamic Workspace Symbols" then
return "LSP Workspace Symbols"
else
return "Fuzzy over"
end
end)()
require("telescope.actions.generate").refine(prompt_bufnr, {
prompt_title = string.format("%s (%s)", prefix, line),
sorter = conf.generic_sorter {},
})
end
actions.nop = function(_) end
-- ================================================== -- ==================================================
-- Transforms modules and sets the correct metatables. -- Transforms modules and sets the correct metatables.
-- ================================================== -- ==================================================

View File

@ -1,5 +1,5 @@
---@tag telescope.actions.layout ---@tag telescope.actions.layout
---@config { ["module"] = "telescope.actions.layout" } ---@config { ["module"] = "telescope.actions.layout", ["name"] = "ACTIONS_LAYOUT" }
---@brief [[ ---@brief [[
--- The layout actions are actions to be used to change the layout of a picker. --- The layout actions are actions to be used to change the layout of a picker.

View File

@ -1,5 +1,5 @@
---@tag telescope.actions.set ---@tag telescope.actions.set
---@config { ["module"] = "telescope.actions.set" } ---@config { ["module"] = "telescope.actions.set", ["name"] = "ACTIONS_SET" }
---@brief [[ ---@brief [[
--- Telescope action sets are used to provide an interface for managing --- Telescope action sets are used to provide an interface for managing
@ -67,6 +67,8 @@ end
local edit_buffer local edit_buffer
do do
local map = { local map = {
drop = "drop",
["tab drop"] = "tab drop",
edit = "buffer", edit = "buffer",
new = "sbuffer", new = "sbuffer",
vnew = "vert sbuffer", vnew = "vert sbuffer",
@ -78,7 +80,11 @@ do
if command == nil then if command == nil then
error "There was no associated buffer command" error "There was no associated buffer command"
end end
vim.cmd(string.format("%s %d", command, bufnr)) if command ~= "drop" and command ~= "tab drop" then
vim.cmd(string.format("%s %d", command, bufnr))
else
vim.cmd(string.format("%s %s", command, vim.api.nvim_buf_get_name(bufnr)))
end
end end
end end
@ -104,7 +110,7 @@ action_set.edit = function(prompt_bufnr, command)
-- TODO: Check for off-by-one -- TODO: Check for off-by-one
row = entry.row or entry.lnum row = entry.row or entry.lnum
col = entry.col col = vim.F.if_nil(entry.col, 1)
elseif not entry.bufnr then elseif not entry.bufnr then
-- TODO: Might want to remove this and force people -- TODO: Might want to remove this and force people
-- to put stuff into `filename` -- to put stuff into `filename`
@ -131,12 +137,24 @@ action_set.edit = function(prompt_bufnr, command)
local entry_bufnr = entry.bufnr local entry_bufnr = entry.bufnr
local picker = action_state.get_current_picker(prompt_bufnr) local picker = action_state.get_current_picker(prompt_bufnr)
require("telescope.actions").close(prompt_bufnr) require("telescope.pickers").on_close_prompt(prompt_bufnr)
pcall(vim.api.nvim_set_current_win, picker.original_win_id)
local win_id = picker.get_selection_window(picker, entry)
if picker.push_cursor_on_edit then if picker.push_cursor_on_edit then
vim.cmd "normal! m'" vim.cmd "normal! m'"
end end
if picker.push_tagstack_on_edit then
local from = { vim.fn.bufnr "%", vim.fn.line ".", vim.fn.col ".", 0 }
local items = { { tagname = vim.fn.expand "<cword>", from = from } }
vim.fn.settagstack(vim.fn.win_getid(), { items = items }, "t")
end
if win_id ~= 0 and a.nvim_get_current_win() ~= win_id then
vim.api.nvim_set_current_win(win_id)
end
if entry_bufnr then if entry_bufnr then
if not vim.api.nvim_buf_get_option(entry_bufnr, "buflisted") then if not vim.api.nvim_buf_get_option(entry_bufnr, "buflisted") then
vim.api.nvim_buf_set_option(entry_bufnr, "buflisted", true) vim.api.nvim_buf_set_option(entry_bufnr, "buflisted", true)
@ -167,13 +185,13 @@ end
-- Valid directions include: "1", "-1" -- Valid directions include: "1", "-1"
action_set.scroll_previewer = function(prompt_bufnr, direction) action_set.scroll_previewer = function(prompt_bufnr, direction)
local previewer = action_state.get_current_picker(prompt_bufnr).previewer local previewer = action_state.get_current_picker(prompt_bufnr).previewer
local status = state.get_status(prompt_bufnr)
-- Check if we actually have a previewer -- Check if we actually have a previewer and a preview window
if type(previewer) ~= "table" or previewer.scroll_fn == nil then if type(previewer) ~= "table" or previewer.scroll_fn == nil or status.preview_win == nil then
return return
end end
local status = state.get_status(prompt_bufnr)
local default_speed = vim.api.nvim_win_get_height(status.preview_win) / 2 local default_speed = vim.api.nvim_win_get_height(status.preview_win) / 2
local speed = status.picker.layout_config.scroll_speed or default_speed local speed = status.picker.layout_config.scroll_speed or default_speed

View File

@ -1,5 +1,5 @@
---@tag telescope.actions.state ---@tag telescope.actions.state
---@config { ["module"] = "telescope.actions.state" } ---@config { ["module"] = "telescope.actions.state", ["name"] = "ACTIONS_STATE" }
---@brief [[ ---@brief [[
--- Functions to be used to determine the current state of telescope. --- Functions to be used to determine the current state of telescope.
@ -33,6 +33,8 @@ local select_to_edit_map = {
horizontal = "new", horizontal = "new",
vertical = "vnew", vertical = "vnew",
tab = "tabedit", tab = "tabedit",
drop = "drop",
["tab drop"] = "tab drop",
} }
function action_state.select_key_to_edit_key(type) function action_state.select_key_to_edit_key(type)
return select_to_edit_map[type] return select_to_edit_map[type]

View File

@ -1,5 +1,5 @@
---@tag telescope.actions.utils ---@tag telescope.actions.utils
---@config { ["module"] = "telescope.actions.utils" } ---@config { ["module"] = "telescope.actions.utils", ["name"] = "ACTIONS_UTILS" }
---@brief [[ ---@brief [[
--- Utilities to wrap functions around picker selections and entries. --- Utilities to wrap functions around picker selections and entries.
@ -13,7 +13,7 @@ local utils = {}
--- Apply `f` to the entries of the current picker. --- Apply `f` to the entries of the current picker.
--- - Notes: --- - Notes:
--- - Mapped entries may include results not visible in the results popup. --- - Mapped entries include all currently filtered results, not just the visible onces.
--- - Indices are 1-indexed, whereas rows are 0-indexed. --- - Indices are 1-indexed, whereas rows are 0-indexed.
--- - Warning: `map_entries` has no return value. --- - Warning: `map_entries` has no return value.
--- - The below example showcases how to collect results --- - The below example showcases how to collect results
@ -96,8 +96,11 @@ function utils.get_registered_mappings(prompt_bufnr)
for _, mode in ipairs { "n", "i" } do for _, mode in ipairs { "n", "i" } do
local mode_mappings = vim.api.nvim_buf_get_keymap(prompt_bufnr, mode) local mode_mappings = vim.api.nvim_buf_get_keymap(prompt_bufnr, mode)
for _, mapping in ipairs(mode_mappings) do for _, mapping in ipairs(mode_mappings) do
local funcid = findnth(mapping.rhs, 2) -- ensure only telescope mappings
table.insert(ret, { mode = mode, keybind = mapping.lhs, func = __TelescopeKeymapStore[prompt_bufnr][funcid] }) if mapping.rhs and string.find(mapping.rhs, [[require%('telescope.mappings'%).execute_keymap]]) then
local funcid = findnth(mapping.rhs, 2)
table.insert(ret, { mode = mode, keybind = mapping.lhs, func = __TelescopeKeymapStore[prompt_bufnr][funcid] })
end
end end
end end
return ret return ret

View File

@ -122,18 +122,20 @@ diagnostics.get = function(opts)
end end
opts.path_display = vim.F.if_nil(opts.path_display, "hidden") opts.path_display = vim.F.if_nil(opts.path_display, "hidden")
pickers.new(opts, { pickers
prompt_title = opts.bufnr == nil and "Workspace Diagnostics" or "Document Diagnostics", .new(opts, {
finder = finders.new_table { prompt_title = opts.bufnr == nil and "Workspace Diagnostics" or "Document Diagnostics",
results = locations, finder = finders.new_table {
entry_maker = opts.entry_maker or make_entry.gen_from_diagnostics(opts), results = locations,
}, entry_maker = opts.entry_maker or make_entry.gen_from_diagnostics(opts),
previewer = conf.qflist_previewer(opts), },
sorter = conf.prefilter_sorter { previewer = conf.qflist_previewer(opts),
tag = "type", sorter = conf.prefilter_sorter {
sorter = conf.generic_sorter(opts), tag = "type",
}, sorter = conf.generic_sorter(opts),
}):find() },
})
:find()
end end
local function apply_checks(mod) local function apply_checks(mod)

View File

@ -1,5 +1,6 @@
local action_state = require "telescope.actions.state" local action_state = require "telescope.actions.state"
local action_set = require "telescope.actions.set" local action_set = require "telescope.actions.set"
local actions = require "telescope.actions"
local finders = require "telescope.finders" local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry" local make_entry = require "telescope.make_entry"
local pickers = require "telescope.pickers" local pickers = require "telescope.pickers"
@ -35,6 +36,29 @@ local escape_chars = function(string)
}) })
end end
local get_open_filelist = function(grep_open_files, cwd)
if not grep_open_files then
return nil
end
local bufnrs = filter(function(b)
if 1 ~= vim.fn.buflisted(b) then
return false
end
return true
end, vim.api.nvim_list_bufs())
if not next(bufnrs) then
return
end
local filelist = {}
for _, bufnr in ipairs(bufnrs) do
local file = vim.api.nvim_buf_get_name(bufnr)
table.insert(filelist, Path:new(file):make_relative(cwd))
end
return filelist
end
-- Special keys: -- Special keys:
-- opts.search_dirs -- list of directory to search in -- opts.search_dirs -- list of directory to search in
-- opts.grep_open_files -- boolean to restrict search to open files -- opts.grep_open_files -- boolean to restrict search to open files
@ -44,40 +68,32 @@ files.live_grep = function(opts)
local grep_open_files = opts.grep_open_files local grep_open_files = opts.grep_open_files
opts.cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.loop.cwd() opts.cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.loop.cwd()
local filelist = {} local filelist = get_open_filelist(grep_open_files, opts.cwd)
if search_dirs then
if grep_open_files then
local bufnrs = filter(function(b)
if 1 ~= vim.fn.buflisted(b) then
return false
end
return true
end, vim.api.nvim_list_bufs())
if not next(bufnrs) then
return
end
for _, bufnr in ipairs(bufnrs) do
local file = vim.api.nvim_buf_get_name(bufnr)
table.insert(filelist, Path:new(file):make_relative(opts.cwd))
end
elseif search_dirs then
for i, path in ipairs(search_dirs) do for i, path in ipairs(search_dirs) do
search_dirs[i] = vim.fn.expand(path) search_dirs[i] = vim.fn.expand(path)
end end
end end
local additional_args = {} local additional_args = {}
if opts.additional_args ~= nil and type(opts.additional_args) == "function" then if opts.additional_args ~= nil then
additional_args = opts.additional_args(opts) if type(opts.additional_args) == "function" then
additional_args = opts.additional_args(opts)
elseif type(opts.additional_args) == "table" then
additional_args = opts.additional_args
end
end end
if opts.type_filter then if opts.type_filter then
additional_args[#additional_args + 1] = "--type=" .. opts.type_filter additional_args[#additional_args + 1] = "--type=" .. opts.type_filter
end end
if opts.glob_pattern then if type(opts.glob_pattern) == "string" then
additional_args[#additional_args + 1] = "--glob=" .. opts.glob_pattern additional_args[#additional_args + 1] = "--glob=" .. opts.glob_pattern
elseif type(opts.glob_pattern) == "table" then
for i = 1, #opts.glob_pattern do
additional_args[#additional_args + 1] = "--glob=" .. opts.glob_pattern[i]
end
end end
local live_grepper = finders.new_job(function(prompt) local live_grepper = finders.new_job(function(prompt)
@ -89,80 +105,95 @@ files.live_grep = function(opts)
local search_list = {} local search_list = {}
if search_dirs then
table.insert(search_list, search_dirs)
end
if grep_open_files then if grep_open_files then
search_list = filelist search_list = filelist
elseif search_dirs then
search_list = search_dirs
end end
return flatten { vimgrep_arguments, additional_args, "--", prompt, search_list } return flatten { vimgrep_arguments, additional_args, "--", prompt, search_list }
end, opts.entry_maker or make_entry.gen_from_vimgrep(opts), opts.max_results, opts.cwd) end, opts.entry_maker or make_entry.gen_from_vimgrep(opts), opts.max_results, opts.cwd)
pickers.new(opts, { pickers
prompt_title = "Live Grep", .new(opts, {
finder = live_grepper, prompt_title = "Live Grep",
previewer = conf.grep_previewer(opts), finder = live_grepper,
-- TODO: It would be cool to use `--json` output for this previewer = conf.grep_previewer(opts),
-- and then we could get the highlight positions directly. -- TODO: It would be cool to use `--json` output for this
sorter = sorters.highlighter_only(opts), -- and then we could get the highlight positions directly.
}):find() sorter = sorters.highlighter_only(opts),
attach_mappings = function(_, map)
map("i", "<c-space>", actions.to_fuzzy_refine)
return true
end,
})
:find()
end end
-- Special keys:
-- opts.search -- the string to search.
-- opts.search_dirs -- list of directory to search in
-- opts.use_regex -- special characters won't be escaped
files.grep_string = function(opts) files.grep_string = function(opts)
-- TODO: This should probably check your visual selection as well, if you've got one -- TODO: This should probably check your visual selection as well, if you've got one
opts.cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.loop.cwd()
local vimgrep_arguments = opts.vimgrep_arguments or conf.vimgrep_arguments local vimgrep_arguments = vim.F.if_nil(opts.vimgrep_arguments, conf.vimgrep_arguments)
local search_dirs = opts.search_dirs local word = vim.F.if_nil(opts.search, vim.fn.expand "<cword>")
local word = opts.search or vim.fn.expand "<cword>"
local search = opts.use_regex and word or escape_chars(word) local search = opts.use_regex and word or escape_chars(word)
local word_match = opts.word_match
opts.entry_maker = opts.entry_maker or make_entry.gen_from_vimgrep(opts)
local additional_args = {} local additional_args = {}
if opts.additional_args ~= nil and type(opts.additional_args) == "function" then if opts.additional_args ~= nil then
additional_args = opts.additional_args(opts) if type(opts.additional_args) == "function" then
additional_args = opts.additional_args(opts)
elseif type(opts.additional_args) == "table" then
additional_args = opts.additional_args
end
end
if search == "" then
search = { "-v", "--", "^[[:space:]]*$" }
opts.__inverted = true
else
search = { "--", search }
end end
local args = flatten { local args = flatten {
vimgrep_arguments, vimgrep_arguments,
additional_args, additional_args,
word_match, opts.word_match,
"--",
search, search,
} }
if search_dirs then if opts.grep_open_files then
for _, path in ipairs(search_dirs) do for _, file in ipairs(get_open_filelist(opts.grep_open_files, opts.cwd)) do
table.insert(args, file)
end
elseif opts.search_dirs then
for _, path in ipairs(opts.search_dirs) do
table.insert(args, vim.fn.expand(path)) table.insert(args, vim.fn.expand(path))
end end
end end
pickers.new(opts, { opts.entry_maker = opts.entry_maker or make_entry.gen_from_vimgrep(opts)
prompt_title = "Find Word (" .. word .. ")", pickers
finder = finders.new_oneshot_job(args, opts), .new(opts, {
previewer = conf.grep_previewer(opts), prompt_title = "Find Word (" .. word:gsub("\n", "\\n") .. ")",
sorter = conf.generic_sorter(opts), finder = finders.new_oneshot_job(args, opts),
}):find() previewer = conf.grep_previewer(opts),
sorter = conf.generic_sorter(opts),
})
:find()
end end
-- TODO: Maybe just change this to `find`.
-- TODO: Support `find` and maybe let people do other stuff with it as well.
files.find_files = function(opts) files.find_files = function(opts)
local find_command = (function() local find_command = (function()
if opts.find_command then if opts.find_command then
if type(opts.find_command) == "function" then
return opts.find_command(opts)
end
return opts.find_command return opts.find_command
elseif 1 == vim.fn.executable "fd" then
return { "fd", "--type", "f" }
elseif 1 == vim.fn.executable "fdfind" then
return { "fdfind", "--type", "f" }
elseif 1 == vim.fn.executable "rg" then elseif 1 == vim.fn.executable "rg" then
return { "rg", "--files" } return { "rg", "--files", "--color", "never" }
elseif 1 == vim.fn.executable "fd" then
return { "fd", "--type", "f", "--color", "never" }
elseif 1 == vim.fn.executable "fdfind" then
return { "fdfind", "--type", "f", "--color", "never" }
elseif 1 == vim.fn.executable "find" and vim.fn.has "win32" == 0 then elseif 1 == vim.fn.executable "find" and vim.fn.has "win32" == 0 then
return { "find", ".", "-type", "f" } return { "find", ".", "-type", "f" }
elseif 1 == vim.fn.executable "where" then elseif 1 == vim.fn.executable "where" then
@ -181,8 +212,10 @@ files.find_files = function(opts)
local command = find_command[1] local command = find_command[1]
local hidden = opts.hidden local hidden = opts.hidden
local no_ignore = opts.no_ignore local no_ignore = opts.no_ignore
local no_ignore_parent = opts.no_ignore_parent
local follow = opts.follow local follow = opts.follow
local search_dirs = opts.search_dirs local search_dirs = opts.search_dirs
local search_file = opts.search_file
if search_dirs then if search_dirs then
for k, v in pairs(search_dirs) do for k, v in pairs(search_dirs) do
@ -192,21 +225,30 @@ files.find_files = function(opts)
if command == "fd" or command == "fdfind" or command == "rg" then if command == "fd" or command == "fdfind" or command == "rg" then
if hidden then if hidden then
table.insert(find_command, "--hidden") find_command[#find_command + 1] = "--hidden"
end end
if no_ignore then if no_ignore then
table.insert(find_command, "--no-ignore") find_command[#find_command + 1] = "--no-ignore"
end
if no_ignore_parent then
find_command[#find_command + 1] = "--no-ignore-parent"
end end
if follow then if follow then
table.insert(find_command, "-L") find_command[#find_command + 1] = "-L"
end
if search_file then
if command == "rg" then
find_command[#find_command + 1] = "-g"
find_command[#find_command + 1] = "*" .. search_file .. "*"
else
find_command[#find_command + 1] = search_file
end
end end
if search_dirs then if search_dirs then
if command ~= "rg" then if command ~= "rg" and not search_file then
table.insert(find_command, ".") find_command[#find_command + 1] = "."
end
for _, v in pairs(search_dirs) do
table.insert(find_command, v)
end end
vim.list_extend(find_command, search_dirs)
end end
elseif command == "find" then elseif command == "find" then
if not hidden then if not hidden then
@ -216,9 +258,16 @@ files.find_files = function(opts)
if no_ignore ~= nil then if no_ignore ~= nil then
log.warn "The `no_ignore` key is not available for the `find` command in `find_files`." log.warn "The `no_ignore` key is not available for the `find` command in `find_files`."
end end
if no_ignore_parent ~= nil then
log.warn "The `no_ignore_parent` key is not available for the `find` command in `find_files`."
end
if follow then if follow then
table.insert(find_command, 2, "-L") table.insert(find_command, 2, "-L")
end end
if search_file then
table.insert(find_command, "-name")
table.insert(find_command, "*" .. search_file .. "*")
end
if search_dirs then if search_dirs then
table.remove(find_command, 2) table.remove(find_command, 2)
for _, v in pairs(search_dirs) do for _, v in pairs(search_dirs) do
@ -232,12 +281,18 @@ files.find_files = function(opts)
if no_ignore ~= nil then if no_ignore ~= nil then
log.warn "The `no_ignore` key is not available for the Windows `where` command in `find_files`." log.warn "The `no_ignore` key is not available for the Windows `where` command in `find_files`."
end end
if no_ignore_parent ~= nil then
log.warn "The `no_ignore_parent` key is not available for the Windows `where` command in `find_files`."
end
if follow ~= nil then if follow ~= nil then
log.warn "The `follow` key is not available for the Windows `where` command in `find_files`." log.warn "The `follow` key is not available for the Windows `where` command in `find_files`."
end end
if search_dirs ~= nil then if search_dirs ~= nil then
log.warn "The `search_dirs` key is not available for the Windows `where` command in `find_files`." log.warn "The `search_dirs` key is not available for the Windows `where` command in `find_files`."
end end
if search_file ~= nil then
log.warn "The `search_file` key is not available for the Windows `where` command in `find_files`."
end
end end
if opts.cwd then if opts.cwd then
@ -246,12 +301,14 @@ files.find_files = function(opts)
opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts) opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts)
pickers.new(opts, { pickers
prompt_title = "Find Files", .new(opts, {
finder = finders.new_oneshot_job(find_command, opts), prompt_title = "Find Files",
previewer = conf.file_previewer(opts), finder = finders.new_oneshot_job(find_command, opts),
sorter = conf.file_sorter(opts), previewer = conf.file_previewer(opts),
}):find() sorter = conf.file_sorter(opts),
})
:find()
end end
local function prepare_match(entry, kind) local function prepare_match(entry, kind)
@ -270,7 +327,7 @@ end
-- TODO: finish docs for opts.show_line -- TODO: finish docs for opts.show_line
files.treesitter = function(opts) files.treesitter = function(opts)
opts.show_line = utils.get_default(opts.show_line, true) opts.show_line = vim.F.if_nil(opts.show_line, true)
local has_nvim_treesitter, _ = pcall(require, "nvim-treesitter") local has_nvim_treesitter, _ = pcall(require, "nvim-treesitter")
if not has_nvim_treesitter then if not has_nvim_treesitter then
@ -304,18 +361,20 @@ files.treesitter = function(opts)
return return
end end
pickers.new(opts, { pickers
prompt_title = "Treesitter Symbols", .new(opts, {
finder = finders.new_table { prompt_title = "Treesitter Symbols",
results = results, finder = finders.new_table {
entry_maker = opts.entry_maker or make_entry.gen_from_treesitter(opts), results = results,
}, entry_maker = opts.entry_maker or make_entry.gen_from_treesitter(opts),
previewer = conf.grep_previewer(opts), },
sorter = conf.prefilter_sorter { previewer = conf.grep_previewer(opts),
tag = "kind", sorter = conf.prefilter_sorter {
sorter = conf.generic_sorter(opts), tag = "kind",
}, sorter = conf.generic_sorter(opts),
}):find() },
})
:find()
end end
files.current_buffer_fuzzy_find = function(opts) files.current_buffer_fuzzy_find = function(opts)
@ -356,8 +415,12 @@ files.current_buffer_fuzzy_find = function(opts)
return obj return obj
end, end,
}) })
-- update to changes on Neovim master, see https://github.com/neovim/neovim/pull/19931
-- TODO(clason): remove when dropping support for Neovim 0.7
local on_nvim_master = vim.fn.has "nvim-0.8" == 1
for id, node in query:iter_captures(root, opts.bufnr, 0, -1) do for id, node in query:iter_captures(root, opts.bufnr, 0, -1) do
local hl = highlighter_query:_get_hl_from_capture(id) local hl = on_nvim_master and query.captures[id] or highlighter_query:_get_hl_from_capture(id)
if hl and type(hl) ~= "number" then if hl and type(hl) ~= "number" then
local row1, col1, row2, col2 = node:range() local row1, col1, row2, col2 = node:range()
@ -387,29 +450,34 @@ files.current_buffer_fuzzy_find = function(opts)
opts.line_highlights = line_highlights opts.line_highlights = line_highlights
end end
pickers.new(opts, { pickers
prompt_title = "Current Buffer Fuzzy", .new(opts, {
finder = finders.new_table { prompt_title = "Current Buffer Fuzzy",
results = lines_with_numbers, finder = finders.new_table {
entry_maker = opts.entry_maker or make_entry.gen_from_buffer_lines(opts), results = lines_with_numbers,
}, entry_maker = opts.entry_maker or make_entry.gen_from_buffer_lines(opts),
sorter = conf.generic_sorter(opts), },
previewer = conf.grep_previewer(opts), sorter = conf.generic_sorter(opts),
attach_mappings = function() previewer = conf.grep_previewer(opts),
action_set.select:enhance { attach_mappings = function()
post = function() action_set.select:enhance {
local selection = action_state.get_selected_entry() post = function()
vim.api.nvim_win_set_cursor(0, { selection.lnum, 0 }) local selection = action_state.get_selected_entry()
end, vim.api.nvim_win_set_cursor(0, { selection.lnum, 0 })
} end,
}
return true return true
end, end,
}):find() })
:find()
end end
files.tags = function(opts) files.tags = function(opts)
local tagfiles = opts.ctags_file and { opts.ctags_file } or vim.fn.tagfiles() local tagfiles = opts.ctags_file and { opts.ctags_file } or vim.fn.tagfiles()
for i, ctags_file in ipairs(tagfiles) do
tagfiles[i] = vim.fn.expand(ctags_file, true)
end
if vim.tbl_isempty(tagfiles) then if vim.tbl_isempty(tagfiles) then
utils.notify("builtin.tags", { utils.notify("builtin.tags", {
msg = "No tags file found. Create one with ctags -R", msg = "No tags file found. Create one with ctags -R",
@ -417,46 +485,42 @@ files.tags = function(opts)
}) })
return return
end end
opts.entry_maker = vim.F.if_nil(opts.entry_maker, make_entry.gen_from_ctags(opts))
local results = {} pickers
for _, ctags_file in ipairs(tagfiles) do .new(opts, {
for line in Path:new(vim.fn.expand(ctags_file, true)):iter() do prompt_title = "Tags",
results[#results + 1] = line finder = finders.new_oneshot_job(flatten { "cat", tagfiles }, opts),
end previewer = previewers.ctags.new(opts),
end sorter = conf.generic_sorter(opts),
attach_mappings = function()
action_set.select:enhance {
post = function()
local selection = action_state.get_selected_entry()
if not selection then
return
end
pickers.new(opts, { if selection.scode then
prompt_title = "Tags", -- un-escape / then escape required
finder = finders.new_table { -- special chars for vim.fn.search()
results = results, -- ] ~ *
entry_maker = opts.entry_maker or make_entry.gen_from_ctags(opts), local scode = selection.scode:gsub([[\/]], "/"):gsub("[%]~*]", function(x)
}, return "\\" .. x
previewer = previewers.ctags.new(opts), end)
sorter = conf.generic_sorter(opts),
attach_mappings = function()
action_set.select:enhance {
post = function()
local selection = action_state.get_selected_entry()
if selection.scode then vim.cmd "norm! gg"
-- un-escape / then escape required vim.fn.search(scode)
-- special chars for vim.fn.search() vim.cmd "norm! zz"
-- ] ~ * else
local scode = selection.scode:gsub([[\/]], "/"):gsub("[%]~*]", function(x) vim.api.nvim_win_set_cursor(0, { selection.lnum, 0 })
return "\\" .. x end
end) end,
}
vim.cmd "norm! gg" return true
vim.fn.search(scode) end,
vim.cmd "norm! zz" })
else :find()
vim.api.nvim_win_set_cursor(0, { selection.lnum, 0 })
end
end,
}
return true
end,
}):find()
end end
files.current_buffer_tags = function(opts) files.current_buffer_tags = function(opts)

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
local channel = require("plenary.async.control").channel local channel = require("plenary.async.control").channel
local actions = require "telescope.actions"
local sorters = require "telescope.sorters"
local conf = require("telescope.config").values local conf = require("telescope.config").values
local finders = require "telescope.finders" local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry" local make_entry = require "telescope.make_entry"
@ -24,7 +25,7 @@ lsp.references = function(opts)
local locations = {} local locations = {}
if result then if result then
local results = vim.lsp.util.locations_to_items(result, vim.lsp.get_client_by_id(ctx.client_id).offset_encoding) local results = vim.lsp.util.locations_to_items(result, vim.lsp.get_client_by_id(ctx.client_id).offset_encoding)
if include_current_line then if not include_current_line then
locations = vim.tbl_filter(function(v) locations = vim.tbl_filter(function(v)
-- Remove current line from result -- Remove current line from result
return not (v.filename == filepath and v.lnum == lnum) return not (v.filename == filepath and v.lnum == lnum)
@ -38,22 +39,111 @@ lsp.references = function(opts)
return return
end end
pickers.new(opts, { pickers
prompt_title = "LSP References", .new(opts, {
finder = finders.new_table { prompt_title = "LSP References",
results = locations, finder = finders.new_table {
entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts), results = locations,
}, entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts),
previewer = conf.qflist_previewer(opts), },
sorter = conf.generic_sorter(opts), previewer = conf.qflist_previewer(opts),
push_cursor_on_edit = true, sorter = conf.generic_sorter(opts),
}):find() push_cursor_on_edit = true,
push_tagstack_on_edit = true,
})
:find()
end) end)
end end
local function list_or_jump(action, title, opts) local function call_hierarchy(opts, method, title, direction, item)
opts = opts or {} vim.lsp.buf_request(opts.bufnr, method, { item = item }, function(err, result)
if err then
vim.api.nvim_err_writeln("Error handling " .. title .. ": " .. err.message)
return
end
if not result or vim.tbl_isempty(result) then
return
end
local locations = {}
for _, ch_call in pairs(result) do
local ch_item = ch_call[direction]
for _, range in pairs(ch_call.fromRanges) do
table.insert(locations, {
filename = vim.uri_to_fname(ch_item.uri),
text = ch_item.name,
lnum = range.start.line + 1,
col = range.start.character + 1,
})
end
end
pickers
.new(opts, {
prompt_title = title,
finder = finders.new_table {
results = locations,
entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.generic_sorter(opts),
push_cursor_on_edit = true,
push_tagstack_on_edit = true,
})
:find()
end)
end
local function pick_call_hierarchy_item(call_hierarchy_items)
if not call_hierarchy_items then
return
end
if #call_hierarchy_items == 1 then
return call_hierarchy_items[1]
end
local items = {}
for i, item in pairs(call_hierarchy_items) do
local entry = item.detail or item.name
table.insert(items, string.format("%d. %s", i, entry))
end
local choice = vim.fn.inputlist(items)
if choice < 1 or choice > #items then
return
end
return choice
end
local function calls(opts, direction)
local params = vim.lsp.util.make_position_params()
vim.lsp.buf_request(opts.bufnr, "textDocument/prepareCallHierarchy", params, function(err, result)
if err then
vim.api.nvim_err_writeln("Error when preparing call hierarchy: " .. err)
return
end
local call_hierarchy_item = pick_call_hierarchy_item(result)
if not call_hierarchy_item then
return
end
if direction == "from" then
call_hierarchy(opts, "callHierarchy/incomingCalls", "LSP Incoming Calls", direction, call_hierarchy_item)
else
call_hierarchy(opts, "callHierarchy/outgoingCalls", "LSP Outgoing Calls", direction, call_hierarchy_item)
end
end)
end
lsp.incoming_calls = function(opts)
calls(opts, "from")
end
lsp.outgoing_calls = function(opts)
calls(opts, "to")
end
local function list_or_jump(action, title, opts)
local params = vim.lsp.util.make_position_params(opts.winnr) local params = vim.lsp.util.make_position_params(opts.winnr)
vim.lsp.buf_request(opts.bufnr, action, params, function(err, result, ctx, _) vim.lsp.buf_request(opts.bufnr, action, params, function(err, result, ctx, _)
if err then if err then
@ -85,15 +175,19 @@ local function list_or_jump(action, title, opts)
vim.lsp.util.jump_to_location(flattened_results[1], offset_encoding) vim.lsp.util.jump_to_location(flattened_results[1], offset_encoding)
else else
local locations = vim.lsp.util.locations_to_items(flattened_results, offset_encoding) local locations = vim.lsp.util.locations_to_items(flattened_results, offset_encoding)
pickers.new(opts, { pickers
prompt_title = title, .new(opts, {
finder = finders.new_table { prompt_title = title,
results = locations, finder = finders.new_table {
entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts), results = locations,
}, entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts),
previewer = conf.qflist_previewer(opts), },
sorter = conf.generic_sorter(opts), previewer = conf.qflist_previewer(opts),
}):find() sorter = conf.generic_sorter(opts),
push_cursor_on_edit = true,
push_tagstack_on_edit = true,
})
:find()
end end
end) end)
end end
@ -141,20 +235,23 @@ lsp.document_symbols = function(opts)
return return
end end
opts.ignore_filename = opts.ignore_filename or true opts.path_display = { "hidden" }
pickers.new(opts, { pickers
prompt_title = "LSP Document Symbols", .new(opts, {
finder = finders.new_table { prompt_title = "LSP Document Symbols",
results = locations, finder = finders.new_table {
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts), results = locations,
}, entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts),
previewer = conf.qflist_previewer(opts), },
sorter = conf.prefilter_sorter { previewer = conf.qflist_previewer(opts),
tag = "symbol_type", sorter = conf.prefilter_sorter {
sorter = conf.generic_sorter(opts), tag = "symbol_type",
}, sorter = conf.generic_sorter(opts),
push_cursor_on_edit = true, },
}):find() push_cursor_on_edit = true,
push_tagstack_on_edit = true,
})
:find()
end) end)
end end
@ -182,20 +279,22 @@ lsp.workspace_symbols = function(opts)
return return
end end
opts.ignore_filename = utils.get_default(opts.ignore_filename, false) opts.ignore_filename = vim.F.if_nil(opts.ignore_filename, false)
pickers.new(opts, { pickers
prompt_title = "LSP Workspace Symbols", .new(opts, {
finder = finders.new_table { prompt_title = "LSP Workspace Symbols",
results = locations, finder = finders.new_table {
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts), results = locations,
}, entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts),
previewer = conf.qflist_previewer(opts), },
sorter = conf.prefilter_sorter { previewer = conf.qflist_previewer(opts),
tag = "symbol_type", sorter = conf.prefilter_sorter {
sorter = conf.generic_sorter(opts), tag = "symbol_type",
}, sorter = conf.generic_sorter(opts),
}):find() },
})
:find()
end) end)
end end
@ -220,15 +319,21 @@ local function get_workspace_symbols_requester(bufnr, opts)
end end
lsp.dynamic_workspace_symbols = function(opts) lsp.dynamic_workspace_symbols = function(opts)
pickers.new(opts, { pickers
prompt_title = "LSP Dynamic Workspace Symbols", .new(opts, {
finder = finders.new_dynamic { prompt_title = "LSP Dynamic Workspace Symbols",
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts), finder = finders.new_dynamic {
fn = get_workspace_symbols_requester(opts.bufnr, opts), entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts),
}, fn = get_workspace_symbols_requester(opts.bufnr, opts),
previewer = conf.qflist_previewer(opts), },
sorter = conf.generic_sorter(opts), previewer = conf.qflist_previewer(opts),
}):find() sorter = sorters.highlighter_only(opts),
attach_mappings = function(_, map)
map("i", "<c-space>", actions.to_fuzzy_refine)
return true
end,
})
:find()
end end
local function check_capabilities(feature, bufnr) local function check_capabilities(feature, bufnr)
@ -267,6 +372,8 @@ local feature_map = {
["type_definitions"] = "typeDefinitionProvider", ["type_definitions"] = "typeDefinitionProvider",
["implementations"] = "implementationProvider", ["implementations"] = "implementationProvider",
["workspace_symbols"] = "workspaceSymbolProvider", ["workspace_symbols"] = "workspaceSymbolProvider",
["incoming_calls"] = "callHierarchyProvider",
["outgoing_calls"] = "callHierarchyProvider",
} }
local function apply_checks(mod) local function apply_checks(mod)

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
local strings = require "plenary.strings" local strings = require "plenary.strings"
local deprecated = require "telescope.deprecated" local deprecated = require "telescope.deprecated"
local sorters = require "telescope.sorters" local sorters = require "telescope.sorters"
local if_nil = vim.F.if_nil
local os_sep = require("plenary.path").path.sep local os_sep = require("plenary.path").path.sep
local has_win = vim.fn.has "win32" == 1 local has_win = vim.fn.has "win32" == 1
@ -69,7 +68,7 @@ config.descriptions = {}
config.pickers = _TelescopeConfigurationPickers config.pickers = _TelescopeConfigurationPickers
function config.set_pickers(pickers) function config.set_pickers(pickers)
pickers = if_nil(pickers, {}) pickers = vim.F.if_nil(pickers, {})
for k, v in pairs(pickers) do for k, v in pairs(pickers) do
config.pickers[k] = v config.pickers[k] = v
@ -153,25 +152,6 @@ append(
- "ascending"]] - "ascending"]]
) )
append(
"tiebreak",
function(current_entry, existing_entry, _)
return #current_entry.ordinal < #existing_entry.ordinal
end,
[[
A function that determines how to break a tie when two entries have
the same score.
Having a function that always returns false would keep the entries in
the order they are found, so existing_entry before current_entry.
Vice versa always returning true would place the current_entry
before the existing_entry.
Signature: function(current_entry, existing_entry, prompt) -> boolean
Default: function that breaks the tie based on the length of the
entry's ordinal]]
)
append( append(
"selection_strategy", "selection_strategy",
"reset", "reset",
@ -182,7 +162,8 @@ append(
- "reset" (default) - "reset" (default)
- "follow" - "follow"
- "row" - "row"
- "closest"]] - "closest"
- "none"]]
) )
append( append(
@ -442,6 +423,28 @@ append(
Default: "Prompt"]] Default: "Prompt"]]
) )
append(
"mappings",
{},
[[
Your mappings to override telescope's default mappings.
See: ~
|telescope.mappings|
]]
)
append(
"default_mappings",
nil,
[[
Not recommended to use except for advanced users.
Will allow you to completely remove all of telescope's default maps
and use your own.
]]
)
append( append(
"history", "history",
{ {
@ -593,8 +596,17 @@ append(
highlighting, which falls back to regex-based highlighting. highlighting, which falls back to regex-based highlighting.
`true`: treesitter highlighting for all available filetypes `true`: treesitter highlighting for all available filetypes
`false`: regex-based highlighting for all filetypes `false`: regex-based highlighting for all filetypes
`table`: table of filetypes for which to attach treesitter `table`: following nvim-treesitters highlighting options:
highlighting It contains two keys:
- enable boolean|table: if boolean, enable all ts
highlighing with that flag,
disable still considered.
Containing a list of filetypes,
that are enabled, disabled
ignored because it doesnt make
any sense in this case.
- disable table: containing a list of filetypes
that are disabled
Default: true Default: true
- msg_bg_fillchar: Character to fill background of unpreviewable buffers with - msg_bg_fillchar: Character to fill background of unpreviewable buffers with
Default: "" Default: ""
@ -653,91 +665,12 @@ append(
true, true,
[[ [[
Boolean if devicons should be enabled or not. If set to false, the Boolean if devicons should be enabled or not. If set to false, the
"TelescopeResultsFileIcon" highlight group is used. text highlight group is used.
Hint: Coloring only works if |termguicolors| is enabled. Hint: Coloring only works if |termguicolors| is enabled.
Default: true]] Default: true]]
) )
append(
"mappings",
{},
[[
Your mappings to override telescope's default mappings.
Format is:
{
mode = { ..keys }
}
where {mode} is the one character letter for a mode
('i' for insert, 'n' for normal).
For example:
mappings = {
i = {
["<esc>"] = require('telescope.actions').close,
},
}
To disable a keymap, put [map] = false
So, to not map "<C-n>", just put
...,
["<C-n>"] = false,
...,
Into your config.
otherwise, just set the mapping to the function that you want it to
be.
...,
["<C-i>"] = require('telescope.actions').select_default,
...,
If the function you want is part of `telescope.actions`, then you can
simply give a string.
For example, the previous option is equivalent to:
...,
["<C-i>"] = "select_default",
...,
You can also add other mappings using tables with `type = "command"`.
For example:
...,
["jj"] = { "<esc>", type = "command" },
["kk"] = { "<cmd>echo \"Hello, World!\"<cr>", type = "command" },)
...,
You can also add additional options for mappings of any type
("action" and "command"). For example:
...,
["<C-j>"] = {
action = actions.move_selection_next,
opts = { nowait = true, silent = true }
},
...,
]]
)
append(
"default_mappings",
nil,
[[
Not recommended to use except for advanced users.
Will allow you to completely remove all of telescope's default maps
and use your own.
]]
)
append( append(
"file_sorter", "file_sorter",
sorters.get_fzy_sorter, sorters.get_fzy_sorter,
@ -774,6 +707,25 @@ append(
Default: require("telescope.sorters").prefilter]] Default: require("telescope.sorters").prefilter]]
) )
append(
"tiebreak",
function(current_entry, existing_entry, _)
return #current_entry.ordinal < #existing_entry.ordinal
end,
[[
A function that determines how to break a tie when two entries have
the same score.
Having a function that always returns false would keep the entries in
the order they are found, so existing_entry before current_entry.
Vice versa always returning true would place the current_entry
before the existing_entry.
Signature: function(current_entry, existing_entry, prompt) -> boolean
Default: function that breaks the tie based on the length of the
entry's ordinal]]
)
append( append(
"file_ignore_patterns", "file_ignore_patterns",
nil, nil,
@ -783,10 +735,35 @@ append(
Example: { "%.npz" } -- ignore all npz files Example: { "%.npz" } -- ignore all npz files
See: https://www.lua.org/manual/5.1/manual.html#5.4.1 for more See: https://www.lua.org/manual/5.1/manual.html#5.4.1 for more
information about lua regex information about lua regex
Note: `file_ignore_patterns` will be used in all pickers that have a
file associated. This might lead to the problem that lsp_ pickers
aren't displaying results because they might be ignored by
`file_ignore_patterns`. For example, setting up node_modules as ignored
will never show node_modules in any results, even if you are
interested in lsp_ results.
If you only want `file_ignore_patterns` for `find_files` and
`grep_string`/`live_grep` it is suggested that you setup `gitignore`
and have fd and or ripgrep installed because both tools will not show
`gitignore`d files on default.
Default: nil]] Default: nil]]
) )
append(
"get_selection_window",
function()
return 0
end,
[[
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`
]]
)
append( append(
"file_previewer", "file_previewer",
function(...) function(...)
@ -851,8 +828,8 @@ append(
-- @param tele_defaults table: (optional) a table containing all of the defaults -- @param tele_defaults table: (optional) a table containing all of the defaults
-- for telescope [defaults to `telescope_defaults`] -- for telescope [defaults to `telescope_defaults`]
function config.set_defaults(user_defaults, tele_defaults) function config.set_defaults(user_defaults, tele_defaults)
user_defaults = if_nil(user_defaults, {}) user_defaults = vim.F.if_nil(user_defaults, {})
tele_defaults = if_nil(tele_defaults, telescope_defaults) tele_defaults = vim.F.if_nil(tele_defaults, telescope_defaults)
-- Check if using layout keywords outside of `layout_config` -- Check if using layout keywords outside of `layout_config`
deprecated.options(user_defaults) deprecated.options(user_defaults)
@ -860,18 +837,21 @@ function config.set_defaults(user_defaults, tele_defaults)
local function get(name, default_val) local function get(name, default_val)
if name == "layout_config" then if name == "layout_config" then
return smarter_depth_2_extend( return smarter_depth_2_extend(
if_nil(user_defaults[name], {}), vim.F.if_nil(user_defaults[name], {}),
vim.tbl_deep_extend("keep", if_nil(config.values[name], {}), if_nil(default_val, {})) vim.tbl_deep_extend("keep", vim.F.if_nil(config.values[name], {}), vim.F.if_nil(default_val, {}))
) )
end end
if name == "history" or name == "cache_picker" or name == "preview" then if name == "history" or name == "cache_picker" or name == "preview" then
if user_defaults[name] == false or config.values[name] == false then if user_defaults[name] == false or config.values[name] == false then
return false return false
end end
if user_defaults[name] == true then
return vim.F.if_nil(config.values[name], {})
end
return smarter_depth_2_extend( return smarter_depth_2_extend(
if_nil(user_defaults[name], {}), vim.F.if_nil(user_defaults[name], {}),
vim.tbl_deep_extend("keep", if_nil(config.values[name], {}), if_nil(default_val, {})) vim.tbl_deep_extend("keep", vim.F.if_nil(config.values[name], {}), vim.F.if_nil(default_val, {}))
) )
end end
return first_non_null(user_defaults[name], config.values[name], default_val) return first_non_null(user_defaults[name], config.values[name], default_val)
@ -881,9 +861,7 @@ function config.set_defaults(user_defaults, tele_defaults)
assert(description, "Config values must always have a description") assert(description, "Config values must always have a description")
config.values[name] = get(name, default_val) config.values[name] = get(name, default_val)
if description then config.descriptions[name] = strings.dedent(description)
config.descriptions[name] = strings.dedent(description)
end
end end
for key, info in pairs(tele_defaults) do for key, info in pairs(tele_defaults) do

View File

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

View File

@ -44,7 +44,7 @@ function JobFinder:new(opts)
assert(not opts.static, "`static` should be used with finder.new_oneshot_job") assert(not opts.static, "`static` should be used with finder.new_oneshot_job")
local obj = setmetatable({ local obj = setmetatable({
entry_maker = opts.entry_maker or make_entry.gen_from_string, entry_maker = opts.entry_maker or make_entry.gen_from_string(opts),
fn_command = opts.fn_command, fn_command = opts.fn_command,
cwd = opts.cwd, cwd = opts.cwd,
writer = opts.writer, writer = opts.writer,
@ -122,7 +122,7 @@ function DynamicFinder:new(opts)
local obj = setmetatable({ local obj = setmetatable({
curr_buf = opts.curr_buf, curr_buf = opts.curr_buf,
fn = opts.fn, fn = opts.fn,
entry_maker = opts.entry_maker or make_entry.gen_from_string, entry_maker = opts.entry_maker or make_entry.gen_from_string(opts),
}, self) }, self)
return obj return obj
@ -180,7 +180,7 @@ finders.new_oneshot_job = function(command_list, opts)
local command = table.remove(command_list, 1) local command = table.remove(command_list, 1)
return async_oneshot_finder { return async_oneshot_finder {
entry_maker = opts.entry_maker or make_entry.gen_from_string(), entry_maker = opts.entry_maker or make_entry.gen_from_string(opts),
cwd = opts.cwd, cwd = opts.cwd,
maximum_results = opts.maximum_results, maximum_results = opts.maximum_results,

View File

@ -6,7 +6,7 @@ local log = require "telescope.log"
return function(opts) return function(opts)
log.trace("Creating async_job:", opts) log.trace("Creating async_job:", opts)
local entry_maker = opts.entry_maker or make_entry.gen_from_string() local entry_maker = opts.entry_maker or make_entry.gen_from_string(opts)
local fn_command = function(prompt) local fn_command = function(prompt)
local command_list = opts.command_generator(prompt) local command_list = opts.command_generator(prompt)

View File

@ -9,7 +9,7 @@ local await_count = 1000
return function(opts) return function(opts)
opts = opts or {} opts = opts or {}
local entry_maker = opts.entry_maker or make_entry.gen_from_string local entry_maker = opts.entry_maker or make_entry.gen_from_string(opts)
local cwd = opts.cwd local cwd = opts.cwd
local env = opts.env local env = opts.env
local fn_command = assert(opts.fn_command, "Must pass `fn_command`") local fn_command = assert(opts.fn_command, "Must pass `fn_command`")
@ -30,6 +30,7 @@ return function(opts)
end end
end, end,
results = results, results = results,
entry_maker = entry_maker,
}, { }, {
__call = function(_, prompt, process_result, process_complete) __call = function(_, prompt, process_result, process_complete)
if not job_started then if not job_started then

View File

@ -10,7 +10,7 @@ return function(opts)
input_results = opts.results input_results = opts.results
end end
local entry_maker = opts.entry_maker or make_entry.gen_from_string() local entry_maker = opts.entry_maker or make_entry.gen_from_string(opts)
local results = {} local results = {}
for k, v in ipairs(input_results) do for k, v in ipairs(input_results) do
@ -24,6 +24,7 @@ return function(opts)
return setmetatable({ return setmetatable({
results = results, results = results,
entry_maker = entry_maker,
close = function() end, close = function() end,
}, { }, {
__call = function(_, _, process_result, process_complete) __call = function(_, _, process_result, process_complete)

View File

@ -12,13 +12,7 @@ local from_entry = {}
function from_entry.path(entry, validate, escape) function from_entry.path(entry, validate, escape)
escape = vim.F.if_nil(escape, true) escape = vim.F.if_nil(escape, true)
local path local path = entry.path
if escape then
path = entry.path and vim.fn.fnameescape(entry.path) or nil
else
path = entry.path
end
if path == nil then if path == nil then
path = entry.filename path = entry.filename
end end
@ -30,10 +24,20 @@ function from_entry.path(entry, validate, escape)
return return
end end
if validate and not vim.fn.filereadable(path) then -- only 0 if neither filereadable nor directory
return if validate then
-- We need to expand for filereadable and isdirectory
-- TODO(conni2461): we are not going to return the expanded path because
-- this would lead to cache misses in the perviewer.
-- Requires overall refactoring in previewer interface
local expanded = vim.fn.expand(path)
if (vim.fn.filereadable(expanded) + vim.fn.isdirectory(expanded)) == 0 then
return
end
end
if escape then
return vim.fn.fnameescape(path)
end end
return path return path
end end

View File

@ -1,4 +1,4 @@
local health = require "health" local health = vim.health or require "health"
local extension_module = require "telescope._extensions" local extension_module = require "telescope._extensions"
local extension_info = require("telescope").extensions local extension_info = require("telescope").extensions
local is_win = vim.api.nvim_call_function("has", { "win32" }) == 1 local is_win = vim.api.nvim_call_function("has", { "win32" }) == 1

View File

@ -13,7 +13,7 @@ local telescope = {}
--- ---
--- Getting started with telescope: --- Getting started with telescope:
--- 1. Run `:checkhealth telescope` to make sure everything is installed. --- 1. Run `:checkhealth telescope` to make sure everything is installed.
--- 2. Evalulate it working with --- 2. Evaluate it working with
--- `:Telescope find_files` or --- `:Telescope find_files` or
--- `:lua require("telescope.builtin").find_files()` --- `:lua require("telescope.builtin").find_files()`
--- 3. Put a `require("telescope").setup() call somewhere in your neovim config. --- 3. Put a `require("telescope").setup() call somewhere in your neovim config.
@ -90,6 +90,7 @@ local telescope = {}
---@brief ]] ---@brief ]]
---@tag telescope.nvim ---@tag telescope.nvim
---@config { ["name"] = "INTRODUCTION" }
--- Setup function to be run by user. Configures the defaults, pickers and --- Setup function to be run by user. Configures the defaults, pickers and
--- extensions of telescope. --- extensions of telescope.
@ -134,12 +135,6 @@ function telescope.setup(opts)
_extensions.set_config(opts.extensions) _extensions.set_config(opts.extensions)
end end
--- Register an extension. To be used by plugin authors.
---@param mod table: Module
function telescope.register_extension(mod)
return _extensions.register(mod)
end
--- Load an extension. --- Load an extension.
--- - Notes: --- - Notes:
--- - Loading triggers ext setup via the config passed in |telescope.setup| --- - Loading triggers ext setup via the config passed in |telescope.setup|
@ -148,6 +143,12 @@ function telescope.load_extension(name)
return _extensions.load(name) return _extensions.load(name)
end end
--- Register an extension. To be used by plugin authors.
---@param mod table: Module
function telescope.register_extension(mod)
return _extensions.register(mod)
end
--- Use telescope.extensions to reference any extensions within your configuration. <br> --- Use telescope.extensions to reference any extensions within your configuration. <br>
--- While the docs currently generate this as a function, it's actually a table. Sorry. --- While the docs currently generate this as a function, it's actually a table. Sorry.
telescope.extensions = require("telescope._extensions").manager telescope.extensions = require("telescope._extensions").manager

View File

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

View File

@ -1,4 +1,125 @@
-- TODO: Customize keymap ---@tag telescope.mappings
---@brief [[
--- |telescope.mappings| is used to configure the keybindings within
--- a telescope picker. These keybinds are only local to the picker window
--- and will be cleared once you exit the picker.
---
--- We provide multiple different ways of configuring, as described below,
--- to provide an easy to use experience for changing the default behavior
--- of telescope or extending for your own purposes.
---
--- To see many of the builtin actions that you can use as values for this
--- table, see |telescope.actions|
---
--- Format is:
--- <code>
--- {
--- mode = { ..keys }
--- }
--- </code>
---
--- where {mode} is the one character letter for a mode ('i' for insert, 'n' for normal).
---
--- For example:
--- <code>
--- mappings = {
--- i = {
--- ["<esc>"] = require('telescope.actions').close,
--- },
--- }
--- </code>
---
--- To disable a keymap, put `[map] = false`<br>
--- For example:
--- <code>
--- {
--- ...,
--- ["<C-n>"] = false,
--- ...,
--- }
--- </code>
--- Into your config.
---
--- To override behavior of a key, simply set the value
--- to be a function (either by requiring an action or by writing
--- your own function)
--- <code>
--- {
--- ...,
--- ["<C-i>"] = require('telescope.actions').select_default,
--- ...,
--- }
--- </code>
---
--- If the function you want is part of `telescope.actions`, then you can
--- simply give a string.
--- For example, the previous option is equivalent to:
--- <code>
--- {
--- ...,
--- ["<C-i>"] = "select_default",
--- ...,
--- }
--- </code>
---
--- You can also add other mappings using tables with `type = "command"`.
--- For example:
--- <code>
--- {
--- ...,
--- ["jj"] = { "<esc>", type = "command" },
--- ["kk"] = { "<cmd>echo \"Hello, World!\"<cr>", type = "command" },)
--- ...,
--- }
--- </code>
---
--- You can also add additional options for mappings of any type ("action" and "command").
--- For example:
--- <code>
--- {
--- ...,
--- ["<C-j>"] = {
--- actions.move_selection_next, type = "action",
--- opts = { nowait = true, silent = true }
--- },
--- ...,
--- }
--- </code>
---
--- There are three main places you can configure |telescope.mappings|. These are
--- ordered from the lowest priority to the highest priority.
---
--- 1. |telescope.defaults.mappings|
--- 2. In the |telescope.setup()| table, inside a picker with a given name, use the `mappings` key
--- <code>
--- require("telescope").setup {
--- pickers = {
--- find_files = {
--- mappings = {
--- n = {
--- ["kj"] = "close",
--- },
--- },
--- },
--- },
--- }
--- </code>
--- 3. `attach_mappings` function for a particular picker.
--- <code>
--- require("telescope.builtin").find_files {
--- attach_mappings = function(_, map)
--- map("i", "asdf", function(_prompt_bufnr)
--- print "You typed asdf"
--- end)
--- -- needs to return true if you want to map default_mappings and
--- -- false if not
--- return true
--- end,
--- }
--- </code>
---@brief ]]
local a = vim.api local a = vim.api
local actions = require "telescope.actions" local actions = require "telescope.actions"
@ -33,8 +154,12 @@ mappings.default_mappings = config.values.default_mappings
["<C-q>"] = actions.send_to_qflist + actions.open_qflist, ["<C-q>"] = actions.send_to_qflist + actions.open_qflist,
["<M-q>"] = actions.send_selected_to_qflist + actions.open_qflist, ["<M-q>"] = actions.send_selected_to_qflist + actions.open_qflist,
["<C-l>"] = actions.complete_tag, ["<C-l>"] = actions.complete_tag,
["<C-/>"] = actions.which_key,
["<C-_>"] = actions.which_key, -- keys from pressing <C-/> ["<C-_>"] = actions.which_key, -- keys from pressing <C-/>
["<C-w>"] = { "<c-s-w>", type = "command" }, ["<C-w>"] = { "<c-s-w>", type = "command" },
-- disable c-j because we dont want to allow new lines #2123
["<C-j>"] = actions.nop,
}, },
n = { n = {
@ -95,25 +220,6 @@ local assign_function = function(prompt_bufnr, func)
return func_id return func_id
end end
--[[
Usage:
mappings.apply_keymap(42, <function>, {
n = {
["<leader>x"] = "just do this string",
["<CR>"] = function(picker, prompt_bufnr)
actions.close_prompt()
> local filename = ...
vim.cmd(string.format(":e %s", filename))
end,
},
i = {
}
})
--]]
local telescope_map = function(prompt_bufnr, mode, key_bind, key_func, opts) local telescope_map = function(prompt_bufnr, mode, key_bind, key_func, opts)
if not key_func then if not key_func then
return return
@ -147,11 +253,8 @@ local telescope_map = function(prompt_bufnr, mode, key_bind, key_func, opts)
local map_string local map_string
if opts.expr then if opts.expr then
map_string = string.format( map_string =
[[luaeval("require('telescope.mappings').execute_keymap(%s, %s)")]], string.format([[luaeval("require('telescope.mappings').execute_keymap(%s, %s)")]], prompt_bufnr, key_id)
prompt_bufnr,
key_id
)
else else
if mode == "i" and not opts.expr then if mode == "i" and not opts.expr then
prefix = "<cmd>" prefix = "<cmd>"
@ -161,12 +264,8 @@ local telescope_map = function(prompt_bufnr, mode, key_bind, key_func, opts)
prefix = ":" prefix = ":"
end end
map_string = string.format( map_string =
"%slua require('telescope.mappings').execute_keymap(%s, %s)<CR>", string.format("%slua require('telescope.mappings').execute_keymap(%s, %s)<CR>", prefix, prompt_bufnr, key_id)
prefix,
prompt_bufnr,
key_id
)
end end
a.nvim_buf_set_keymap(prompt_bufnr, mode, key_bind, map_string, opts) a.nvim_buf_set_keymap(prompt_bufnr, mode, key_bind, map_string, opts)

View File

@ -24,8 +24,6 @@ local p_window = require "telescope.pickers.window"
local EntryManager = require "telescope.entry_manager" local EntryManager = require "telescope.entry_manager"
local MultiSelect = require "telescope.pickers.multi" local MultiSelect = require "telescope.pickers.multi"
local get_default = utils.get_default
local truncate = require("plenary.strings").truncate local truncate = require("plenary.strings").truncate
local strdisplaywidth = require("plenary.strings").strdisplaywidth local strdisplaywidth = require("plenary.strings").strdisplaywidth
@ -65,25 +63,27 @@ function Picker:new(opts)
-- pcall(v.clear) -- pcall(v.clear)
-- end -- end
local layout_strategy = get_default(opts.layout_strategy, config.values.layout_strategy) local layout_strategy = vim.F.if_nil(opts.layout_strategy, config.values.layout_strategy)
local obj = setmetatable({ local obj = setmetatable({
prompt_title = get_default(opts.prompt_title, config.values.prompt_title), prompt_title = vim.F.if_nil(opts.prompt_title, config.values.prompt_title),
results_title = get_default(opts.results_title, config.values.results_title), results_title = vim.F.if_nil(opts.results_title, config.values.results_title),
-- either whats passed in by the user or whats defined by the previewer -- either whats passed in by the user or whats defined by the previewer
preview_title = opts.preview_title, preview_title = opts.preview_title,
prompt_prefix = get_default(opts.prompt_prefix, config.values.prompt_prefix), prompt_prefix = vim.F.if_nil(opts.prompt_prefix, config.values.prompt_prefix),
wrap_results = get_default(opts.wrap_results, config.values.wrap_results), wrap_results = vim.F.if_nil(opts.wrap_results, config.values.wrap_results),
selection_caret = get_default(opts.selection_caret, config.values.selection_caret), selection_caret = vim.F.if_nil(opts.selection_caret, config.values.selection_caret),
entry_prefix = get_default(opts.entry_prefix, config.values.entry_prefix), entry_prefix = vim.F.if_nil(opts.entry_prefix, config.values.entry_prefix),
multi_icon = get_default(opts.multi_icon, config.values.multi_icon), multi_icon = vim.F.if_nil(opts.multi_icon, config.values.multi_icon),
initial_mode = get_default(opts.initial_mode, config.values.initial_mode), initial_mode = vim.F.if_nil(opts.initial_mode, config.values.initial_mode),
debounce = get_default(tonumber(opts.debounce), nil), _original_mode = vim.api.nvim_get_mode().mode,
debounce = vim.F.if_nil(tonumber(opts.debounce), nil),
_finder_attached = true,
default_text = opts.default_text, default_text = opts.default_text,
get_status_text = get_default(opts.get_status_text, config.values.get_status_text), get_status_text = vim.F.if_nil(opts.get_status_text, config.values.get_status_text),
_on_input_filter_cb = opts.on_input_filter_cb or function() end, _on_input_filter_cb = opts.on_input_filter_cb or function() end,
finder = assert(opts.finder, "Finder is required."), finder = assert(opts.finder, "Finder is required."),
@ -94,6 +94,8 @@ function Picker:new(opts)
default_selection_index = opts.default_selection_index, default_selection_index = opts.default_selection_index,
get_selection_window = vim.F.if_nil(opts.get_selection_window, config.values.get_selection_window),
cwd = opts.cwd, cwd = opts.cwd,
_find_id = 0, _find_id = 0,
@ -103,37 +105,40 @@ function Picker:new(opts)
and opts._multi and opts._multi
or MultiSelect:new(), or MultiSelect:new(),
track = get_default(opts.track, false), track = vim.F.if_nil(opts.track, false),
stats = {}, stats = {},
attach_mappings = opts.attach_mappings, attach_mappings = opts.attach_mappings,
file_ignore_patterns = get_default(opts.file_ignore_patterns, config.values.file_ignore_patterns), file_ignore_patterns = vim.F.if_nil(opts.file_ignore_patterns, config.values.file_ignore_patterns),
scroll_strategy = get_default(opts.scroll_strategy, config.values.scroll_strategy), scroll_strategy = vim.F.if_nil(opts.scroll_strategy, config.values.scroll_strategy),
sorting_strategy = get_default(opts.sorting_strategy, config.values.sorting_strategy), sorting_strategy = vim.F.if_nil(opts.sorting_strategy, config.values.sorting_strategy),
tiebreak = get_default(opts.tiebreak, config.values.tiebreak), tiebreak = vim.F.if_nil(opts.tiebreak, config.values.tiebreak),
selection_strategy = get_default(opts.selection_strategy, config.values.selection_strategy), selection_strategy = vim.F.if_nil(opts.selection_strategy, config.values.selection_strategy),
push_cursor_on_edit = get_default(opts.push_cursor_on_edit, false), push_cursor_on_edit = vim.F.if_nil(opts.push_cursor_on_edit, false),
push_tagstack_on_edit = vim.F.if_nil(opts.push_tagstack_on_edit, false),
layout_strategy = layout_strategy, layout_strategy = layout_strategy,
layout_config = config.smarter_depth_2_extend(opts.layout_config or {}, config.values.layout_config or {}), layout_config = config.smarter_depth_2_extend(opts.layout_config or {}, config.values.layout_config or {}),
__cycle_layout_list = get_default(opts.cycle_layout_list, config.values.cycle_layout_list), __cycle_layout_list = vim.F.if_nil(opts.cycle_layout_list, config.values.cycle_layout_list),
window = { window = {
winblend = get_default( winblend = vim.F.if_nil(
opts.winblend, opts.winblend,
type(opts.window) == "table" and opts.window.winblend or config.values.winblend type(opts.window) == "table" and opts.window.winblend or config.values.winblend
), ),
border = get_default(opts.border, type(opts.window) == "table" and opts.window.border or config.values.border), border = vim.F.if_nil(opts.border, type(opts.window) == "table" and opts.window.border or config.values.border),
borderchars = get_default( borderchars = vim.F.if_nil(
opts.borderchars, opts.borderchars,
type(opts.window) == "table" and opts.window.borderchars or config.values.borderchars type(opts.window) == "table" and opts.window.borderchars or config.values.borderchars
), ),
}, },
cache_picker = config.resolve_table_opts(opts.cache_picker, vim.deepcopy(config.values.cache_picker)), cache_picker = config.resolve_table_opts(opts.cache_picker, vim.deepcopy(config.values.cache_picker)),
__scrolling_limit = tonumber(vim.F.if_nil(opts.temp__scrolling_limit, 250)),
}, self) }, self)
obj.get_window_options = opts.get_window_options or p_window.get_window_options obj.get_window_options = opts.get_window_options or p_window.get_window_options
@ -369,11 +374,8 @@ function Picker:find()
popup_opts.preview.titlehighlight = "TelescopePreviewTitle" popup_opts.preview.titlehighlight = "TelescopePreviewTitle"
end end
local results_win, results_opts, results_border_win = self:_create_window( local results_win, results_opts, results_border_win =
"", self:_create_window("", popup_opts.results, not self.wrap_results)
popup_opts.results,
not self.wrap_results
)
local results_bufnr = a.nvim_win_get_buf(results_win) local results_bufnr = a.nvim_win_get_buf(results_win)
pcall(a.nvim_buf_set_option, results_bufnr, "tabstop", 1) -- #1834 pcall(a.nvim_buf_set_option, results_bufnr, "tabstop", 1) -- #1834
@ -411,7 +413,7 @@ function Picker:find()
-- want to scroll through more than 10,000 items. -- want to scroll through more than 10,000 items.
-- --
-- This just lets us stop doing stuff after tons of things. -- This just lets us stop doing stuff after tons of things.
self.max_results = 1000 self.max_results = self.__scrolling_limit
vim.api.nvim_buf_set_lines(results_bufnr, 0, self.max_results, false, utils.repeated_table(self.max_results, "")) vim.api.nvim_buf_set_lines(results_bufnr, 0, self.max_results, false, utils.repeated_table(self.max_results, ""))
@ -501,10 +503,12 @@ function Picker:find()
-- Register attach -- Register attach
vim.api.nvim_buf_attach(prompt_bufnr, false, { vim.api.nvim_buf_attach(prompt_bufnr, false, {
on_lines = function(...) on_lines = function(...)
find_id = self:_next_find_id() if self._finder_attached then
find_id = self:_next_find_id()
status_updater { completed = false } status_updater { completed = false }
self._on_lines(...) self._on_lines(...)
end
end, end,
on_detach = function() on_detach = function()
@ -527,7 +531,6 @@ function Picker:find()
buffer = prompt_bufnr, buffer = prompt_bufnr,
group = "PickerInsert", group = "PickerInsert",
nested = true, nested = true,
once = true,
callback = function() callback = function()
require("telescope.pickers").on_resize_window(prompt_bufnr) require("telescope.pickers").on_resize_window(prompt_bufnr)
end, end,
@ -688,7 +691,7 @@ end
--- ---
--- Example usage in telescope: --- Example usage in telescope:
--- - `actions.delete_buffer()` --- - `actions.delete_buffer()`
---@param delete_cb function: called with each deleted selection ---@param delete_cb function: called for each selection fn(s) -> bool|nil (true|nil removes the entry from the results)
function Picker:delete_selection(delete_cb) function Picker:delete_selection(delete_cb)
vim.validate { delete_cb = { delete_cb, "f" } } vim.validate { delete_cb = { delete_cb, "f" } }
local original_selection_strategy = self.selection_strategy local original_selection_strategy = self.selection_strategy
@ -714,8 +717,10 @@ function Picker:delete_selection(delete_cb)
return x > y return x > y
end) end)
for _, index in ipairs(selection_index) do for _, index in ipairs(selection_index) do
local selection = table.remove(self.finder.results, index) local delete_cb_return = delete_cb(self.finder.results[index])
delete_cb(selection) if delete_cb_return == nil or delete_cb_return == true then
table.remove(self.finder.results, index)
end
end end
if used_multi_select then if used_multi_select then
@ -904,7 +909,7 @@ function Picker:refresh(finder, opts)
local handle = type(opts.new_prefix) == "table" and unpack or function(x) local handle = type(opts.new_prefix) == "table" and unpack or function(x)
return x return x
end end
self:change_prompt_prefix(handle(opts.new_prefix)) self:change_prompt_prefix(handle(opts.new_prefix), opts.prefix_hl_group)
end end
if finder then if finder then
@ -958,6 +963,9 @@ function Picker:set_selection(row)
state.set_global_key("selected_entry", entry) state.set_global_key("selected_entry", entry)
if not entry then if not entry then
-- also refresh previewer when there is no entry selected, so the preview window is cleared
self._selection_entry = entry
self:refresh_previewer()
return return
end end
@ -1039,7 +1047,7 @@ function Picker:update_prefix(entry, row)
local line = vim.api.nvim_buf_get_lines(self.results_bufnr, row, row + 1, false)[1] local line = vim.api.nvim_buf_get_lines(self.results_bufnr, row, row + 1, false)[1]
if not line then if not line then
log.warn(string.format("no line found at row %d in buffer %d", row, self.results_bufnr)) log.trace(string.format("no line found at row %d in buffer %d", row, self.results_bufnr))
return return
end end
@ -1061,10 +1069,6 @@ end
--- Refresh the previewer based on the current `status` of the picker --- Refresh the previewer based on the current `status` of the picker
function Picker:refresh_previewer() function Picker:refresh_previewer()
local status = state.get_status(self.prompt_bufnr) local status = state.get_status(self.prompt_bufnr)
if not self._selection_entry then
-- if selection_entry is nil there is nothing to be previewed
return
end
if self.previewer and status.preview_win and a.nvim_win_is_valid(status.preview_win) then if self.previewer and status.preview_win and a.nvim_win_is_valid(status.preview_win) then
self:_increment "previewed" self:_increment "previewed"
@ -1361,6 +1365,16 @@ function Picker:_do_selection(prompt)
else else
self:set_selection(self:get_reset_row()) self:set_selection(self:get_reset_row())
end end
elseif selection_strategy == "none" then
if self._selection_entry then
local old_entry, old_row = self._selection_entry, self._selection_row
self:reset_selection() -- required to reset selection before updating prefix
if old_row >= 0 then
self:update_prefix(old_entry, old_row)
self.highlighter:hi_multiselect(old_row, self:is_multi_selected(old_entry))
end
end
return
else else
error("Unknown selection strategy: " .. selection_strategy) error("Unknown selection strategy: " .. selection_strategy)
end end
@ -1413,6 +1427,7 @@ end
function pickers.on_close_prompt(prompt_bufnr) function pickers.on_close_prompt(prompt_bufnr)
local status = state.get_status(prompt_bufnr) local status = state.get_status(prompt_bufnr)
local picker = status.picker local picker = status.picker
require("telescope.actions.state").get_current_history():reset()
if type(picker.cache_picker) == "table" then if type(picker.cache_picker) == "table" then
local cached_pickers = state.get_global_key "cached_pickers" or {} local cached_pickers = state.get_global_key "cached_pickers" or {}
@ -1490,6 +1505,11 @@ function Picker:_reset_highlights()
vim.api.nvim_buf_clear_namespace(self.results_bufnr, ns_telescope_matching, 0, -1) vim.api.nvim_buf_clear_namespace(self.results_bufnr, ns_telescope_matching, 0, -1)
end end
-- Toggles whether finder is attached to prompt buffer input
function Picker:_toggle_finder_attach()
self._finder_attached = not self._finder_attached
end
function Picker:_detach() function Picker:_detach()
self.finder:close() self.finder:close()

View File

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

View File

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

View File

@ -152,11 +152,13 @@ local scroll_fn = function(self, direction)
end end
previewers.file_maker = function(filepath, bufnr, opts) previewers.file_maker = function(filepath, bufnr, opts)
opts = opts or {} opts = vim.F.if_nil(opts, {})
opts.preview = opts.preview or {} -- TODO(conni2461): here shouldn't be any hardcoded magic numbers ...
opts.preview = vim.F.if_nil(opts.preview, {})
opts.preview.timeout = vim.F.if_nil(opts.preview.timeout, 250) -- in ms opts.preview.timeout = vim.F.if_nil(opts.preview.timeout, 250) -- in ms
opts.preview.filesize_limit = vim.F.if_nil(opts.preview.filesize_limit, 25) -- in mb opts.preview.filesize_limit = vim.F.if_nil(opts.preview.filesize_limit, 25) -- in mb
opts.preview.msg_bg_fillchar = vim.F.if_nil(opts.preview.msg_bg_fillchar, "") -- in mb opts.preview.msg_bg_fillchar = vim.F.if_nil(opts.preview.msg_bg_fillchar, "") -- in mb
opts.preview.treesitter = vim.F.if_nil(opts.preview.treesitter, true)
if opts.use_ft_detect == nil then if opts.use_ft_detect == nil then
opts.use_ft_detect = true opts.use_ft_detect = true
end end
@ -333,7 +335,7 @@ previewers.new_buffer_previewer = function(opts)
-- Push in another buffer so the last one will not be cleaned up -- Push in another buffer so the last one will not be cleaned up
if preview_window_id then if preview_window_id then
local bufnr = vim.api.nvim_create_buf(false, true) local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_win_set_buf(preview_window_id, bufnr) utils.win_set_buf_noautocmd(preview_window_id, bufnr)
end end
end end
@ -358,14 +360,14 @@ previewers.new_buffer_previewer = function(opts)
if opts.get_buffer_by_name and get_bufnr_by_bufname(self, opts.get_buffer_by_name(self, entry)) then if opts.get_buffer_by_name and get_bufnr_by_bufname(self, opts.get_buffer_by_name(self, entry)) then
self.state.bufname = opts.get_buffer_by_name(self, entry) self.state.bufname = opts.get_buffer_by_name(self, entry)
self.state.bufnr = get_bufnr_by_bufname(self, self.state.bufname) self.state.bufnr = get_bufnr_by_bufname(self, self.state.bufname)
vim.api.nvim_win_set_buf(status.preview_win, self.state.bufnr) utils.win_set_buf_noautocmd(status.preview_win, self.state.bufnr)
else else
local bufnr = vim.api.nvim_create_buf(false, true) local bufnr = vim.api.nvim_create_buf(false, true)
set_bufnr(self, bufnr) set_bufnr(self, bufnr)
vim.schedule(function() vim.schedule(function()
if vim.api.nvim_buf_is_valid(bufnr) then if vim.api.nvim_buf_is_valid(bufnr) then
vim.api.nvim_win_set_buf(status.preview_win, bufnr) utils.win_set_buf_noautocmd(status.preview_win, bufnr)
end end
end) end)
@ -385,8 +387,16 @@ previewers.new_buffer_previewer = function(opts)
opts.define_preview(self, entry, status) opts.define_preview(self, entry, status)
putils.with_preview_window(status, nil, function() vim.schedule(function()
vim.cmd "do User TelescopePreviewerLoaded" if not self or not self.state or not self.state.bufnr then
return
end
if vim.api.nvim_buf_is_valid(self.state.bufnr) then
vim.api.nvim_buf_call(self.state.bufnr, function()
vim.cmd "do User TelescopePreviewerLoaded"
end)
end
end) end)
if opts.get_buffer_by_name then if opts.get_buffer_by_name then
@ -407,11 +417,11 @@ previewers.cat = defaulter(function(opts)
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
title = "File Preview", title = "File Preview",
dyn_title = function(_, entry) dyn_title = function(_, entry)
return Path:new(from_entry.path(entry, true)):normalize(cwd) return Path:new(from_entry.path(entry, false, false)):normalize(cwd)
end, end,
get_buffer_by_name = function(_, entry) get_buffer_by_name = function(_, entry)
return from_entry.path(entry, true) return from_entry.path(entry, false)
end, end,
define_preview = function(self, entry, status) define_preview = function(self, entry, status)
@ -446,21 +456,26 @@ previewers.vimgrep = defaulter(function(opts)
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
title = "Grep Preview", title = "Grep Preview",
dyn_title = function(_, entry) dyn_title = function(_, entry)
return Path:new(from_entry.path(entry, true)):normalize(cwd) return Path:new(from_entry.path(entry, false, false)):normalize(cwd)
end, end,
get_buffer_by_name = function(_, entry) get_buffer_by_name = function(_, entry)
return from_entry.path(entry, true) return from_entry.path(entry, false)
end, end,
define_preview = function(self, entry, status) define_preview = function(self, entry, status)
local p = from_entry.path(entry, true) -- builtin.buffers: bypass path validation for terminal buffers that don't have appropriate path
if p == nil or p == "" then local has_buftype = entry.bufnr and vim.api.nvim_buf_get_option(entry.bufnr, "buftype") ~= "" or false
return local p
if not has_buftype then
p = from_entry.path(entry, true)
if p == nil or p == "" then
return
end
end end
-- Workaround for unnamed buffer when using builtin.buffer -- Workaround for unnamed buffer when using builtin.buffer
if entry.bufnr and (p == "[No Name]" or vim.api.nvim_buf_get_option(entry.bufnr, "buftype") ~= "") then if entry.bufnr and (p == "[No Name]" or has_buftype) then
local lines = vim.api.nvim_buf_get_lines(entry.bufnr, 0, -1, false) local lines = vim.api.nvim_buf_get_lines(entry.bufnr, 0, -1, false)
vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, lines) vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, lines)
jump_to_line(self, self.state.bufnr, entry.lnum) jump_to_line(self, self.state.bufnr, entry.lnum)
@ -711,8 +726,12 @@ previewers.git_stash_diff = defaulter(function(opts)
value = entry.value, value = entry.value,
bufname = self.state.bufname, bufname = self.state.bufname,
cwd = opts.cwd, cwd = opts.cwd,
callback = function(bufnr)
if vim.api.nvim_buf_is_valid(bufnr) then
putils.regex_highlighter(bufnr, "diff")
end
end,
}) })
putils.regex_highlighter(self.state.bufnr, "diff")
end, end,
} }
end, {}) end, {})
@ -737,10 +756,12 @@ previewers.git_commit_diff_to_parent = defaulter(function(opts)
bufname = self.state.bufname, bufname = self.state.bufname,
cwd = opts.cwd, cwd = opts.cwd,
callback = function(bufnr) callback = function(bufnr)
search_cb_jump(self, bufnr, opts.current_line) if vim.api.nvim_buf_is_valid(bufnr) then
search_cb_jump(self, bufnr, opts.current_line)
putils.regex_highlighter(bufnr, "diff")
end
end, end,
}) })
putils.regex_highlighter(self.state.bufnr, "diff")
end, end,
} }
end, {}) end, {})
@ -766,10 +787,12 @@ previewers.git_commit_diff_to_head = defaulter(function(opts)
bufname = self.state.bufname, bufname = self.state.bufname,
cwd = opts.cwd, cwd = opts.cwd,
callback = function(bufnr) callback = function(bufnr)
search_cb_jump(self, bufnr, opts.current_line) if vim.api.nvim_buf_is_valid(bufnr) then
search_cb_jump(self, bufnr, opts.current_line)
putils.regex_highlighter(bufnr, "diff")
end
end, end,
}) })
putils.regex_highlighter(self.state.bufnr, "diff")
end, end,
} }
end, {}) end, {})
@ -795,10 +818,12 @@ previewers.git_commit_diff_as_was = defaulter(function(opts)
bufname = self.state.bufname, bufname = self.state.bufname,
cwd = opts.cwd, cwd = opts.cwd,
callback = function(bufnr) callback = function(bufnr)
search_cb_jump(self, bufnr, opts.current_line) if vim.api.nvim_buf_is_valid(bufnr) then
search_cb_jump(self, bufnr, opts.current_line)
putils.regex_highlighter(bufnr, ft)
end
end, end,
}) })
putils.highlighter(self.state.bufnr, ft)
end, end,
} }
end, {}) end, {})
@ -860,8 +885,12 @@ previewers.git_file_diff = defaulter(function(opts)
value = entry.value, value = entry.value,
bufname = self.state.bufname, bufname = self.state.bufname,
cwd = opts.cwd, cwd = opts.cwd,
callback = function(bufnr)
if vim.api.nvim_buf_is_valid(bufnr) then
putils.regex_highlighter(bufnr, "diff")
end
end,
}) })
putils.regex_highlighter(self.state.bufnr, "diff")
end end
end, end,
} }
@ -877,12 +906,12 @@ previewers.autocommands = defaulter(function(_)
end, end,
get_buffer_by_name = function(_, entry) get_buffer_by_name = function(_, entry)
return entry.group return entry.value.group_name
end, end,
define_preview = function(self, entry, status) define_preview = function(self, entry, status)
local results = vim.tbl_filter(function(x) local results = vim.tbl_filter(function(x)
return x.group == entry.group return x.value.group_name == entry.value.group_name
end, status.picker.finder.results) end, status.picker.finder.results)
if self.state.last_set_bufnr then if self.state.last_set_bufnr then
@ -890,9 +919,9 @@ previewers.autocommands = defaulter(function(_)
end end
local selected_row = 0 local selected_row = 0
if self.state.bufname ~= entry.group then if self.state.bufname ~= entry.value.group_name then
local display = {} local display = {}
table.insert(display, string.format(" augroup: %s - [ %d entries ]", entry.group, #results)) table.insert(display, string.format(" augroup: %s - [ %d entries ]", entry.value.group_name, #results))
-- TODO: calculate banner width/string in setup() -- TODO: calculate banner width/string in setup()
-- TODO: get column characters to be the same HL group as border -- TODO: get column characters to be the same HL group as border
table.insert(display, string.rep("", vim.fn.getwininfo(status.preview_win)[1].width)) table.insert(display, string.rep("", vim.fn.getwininfo(status.preview_win)[1].width))
@ -901,7 +930,10 @@ previewers.autocommands = defaulter(function(_)
if item == entry then if item == entry then
selected_row = idx selected_row = idx
end end
table.insert(display, string.format(" %-14s▏%-08s %s", item.event, item.ft_pattern, item.command)) table.insert(
display,
string.format(" %-14s▏%-08s %s", item.value.event, item.value.pattern, item.value.command)
)
end end
vim.api.nvim_buf_set_option(self.state.bufnr, "filetype", "vim") vim.api.nvim_buf_set_option(self.state.bufnr, "filetype", "vim")

View File

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

View File

@ -192,12 +192,12 @@ previewers.new_termopen_previewer = function(opts)
local prev_bufnr = get_bufnr_by_bufentry(self, entry) local prev_bufnr = get_bufnr_by_bufentry(self, entry)
if prev_bufnr then if prev_bufnr then
self.state.termopen_bufnr = prev_bufnr self.state.termopen_bufnr = prev_bufnr
vim.api.nvim_win_set_buf(status.preview_win, self.state.termopen_bufnr) utils.win_set_buf_noautocmd(status.preview_win, self.state.termopen_bufnr)
self.state.termopen_id = term_ids[self.state.termopen_bufnr] self.state.termopen_id = term_ids[self.state.termopen_bufnr]
else else
local bufnr = vim.api.nvim_create_buf(false, true) local bufnr = vim.api.nvim_create_buf(false, true)
set_bufnr(self, bufnr) set_bufnr(self, bufnr)
vim.api.nvim_win_set_buf(status.preview_win, bufnr) utils.win_set_buf_noautocmd(status.preview_win, bufnr)
local term_opts = { local term_opts = {
cwd = opts.cwd or vim.loop.cwd(), cwd = opts.cwd or vim.loop.cwd(),
@ -250,11 +250,11 @@ previewers.cat = defaulter(function(opts)
return previewers.new_termopen_previewer { return previewers.new_termopen_previewer {
title = "File Preview", title = "File Preview",
dyn_title = function(_, entry) dyn_title = function(_, entry)
return Path:new(from_entry.path(entry, true)):normalize(cwd) return Path:new(from_entry.path(entry, false, false)):normalize(cwd)
end, end,
get_command = function(entry) get_command = function(entry)
local p = from_entry.path(entry, true) local p = from_entry.path(entry, true, false)
if p == nil or p == "" then if p == nil or p == "" then
return return
end end
@ -273,14 +273,14 @@ previewers.vimgrep = defaulter(function(opts)
return previewers.new_termopen_previewer { return previewers.new_termopen_previewer {
title = "Grep Preview", title = "Grep Preview",
dyn_title = function(_, entry) dyn_title = function(_, entry)
return Path:new(from_entry.path(entry, true)):normalize(cwd) return Path:new(from_entry.path(entry, false, false)):normalize(cwd)
end, end,
get_command = function(entry, status) get_command = function(entry, status)
local win_id = status.preview_win local win_id = status.preview_win
local height = vim.api.nvim_win_get_height(win_id) local height = vim.api.nvim_win_get_height(win_id)
local p = from_entry.path(entry, true) local p = from_entry.path(entry, true, false)
if p == nil or p == "" then if p == nil or p == "" then
return return
end end
@ -308,14 +308,14 @@ previewers.qflist = defaulter(function(opts)
return previewers.new_termopen_previewer { return previewers.new_termopen_previewer {
title = "Grep Preview", title = "Grep Preview",
dyn_title = function(_, entry) dyn_title = function(_, entry)
return Path:new(from_entry.path(entry, true)):normalize(cwd) return Path:new(from_entry.path(entry, false, false)):normalize(cwd)
end, end,
get_command = function(entry, status) get_command = function(entry, status)
local win_id = status.preview_win local win_id = status.preview_win
local height = vim.api.nvim_win_get_height(win_id) local height = vim.api.nvim_win_get_height(win_id)
local p = from_entry.path(entry, true) local p = from_entry.path(entry, true, false)
if p == nil or p == "" then if p == nil or p == "" then
return return
end end

View File

@ -45,28 +45,26 @@ utils.job_maker = function(cmd, bufnr, opts)
end end
end)() end)()
Job Job:new({
:new({ command = command,
command = command, args = cmd,
args = cmd, env = opts.env,
env = opts.env, cwd = opts.cwd,
cwd = opts.cwd, writer = writer,
writer = writer, on_exit = vim.schedule_wrap(function(j)
on_exit = vim.schedule_wrap(function(j) if not vim.api.nvim_buf_is_valid(bufnr) then
if not vim.api.nvim_buf_is_valid(bufnr) then return
return end
end if opts.mode == "append" then
if opts.mode == "append" then vim.api.nvim_buf_set_lines(bufnr, -1, -1, false, j:result())
vim.api.nvim_buf_set_lines(bufnr, -1, -1, false, j:result()) elseif opts.mode == "insert" then
elseif opts.mode == "insert" then vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, j:result())
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, j:result()) end
end if opts.callback then
if opts.callback then opts.callback(bufnr, j:result())
opts.callback(bufnr, j:result()) end
end end),
end), }):start()
})
:start()
else else
if opts.callback then if opts.callback then
opts.callback(bufnr) opts.callback(bufnr)
@ -80,14 +78,41 @@ end
--- Attach default highlighter which will choose between regex and ts --- Attach default highlighter which will choose between regex and ts
utils.highlighter = function(bufnr, ft, opts) utils.highlighter = function(bufnr, ft, opts)
opts = opts or {} opts = vim.F.if_nil(opts, {})
opts.preview = opts.preview or {} opts.preview = vim.F.if_nil(opts.preview, {})
opts.preview.treesitter = vim.F.if_nil( opts.preview.treesitter = (function()
opts.preview.treesitter, if type(opts.preview) == "table" and opts.preview.treesitter then
type(conf.preview) == "table" and conf.preview.treesitter return opts.preview.treesitter
) end
local ts_highlighting = opts.preview.treesitter == true if type(conf.preview) == "table" and conf.preview.treesitter then
or type(opts.preview.treesitter) == "table" and vim.tbl_contains(opts.preview.treesitter, ft) return conf.preview.treesitter
end
if type(conf.preview) == "boolean" then
return conf.preview
end
-- We should never get here
return false
end)()
if type(opts.preview.treesitter) == "boolean" then
local temp = { enable = opts.preview.treesitter }
opts.preview.treesitter = temp
end
local ts_highlighting = (function()
if type(opts.preview.treesitter.enable) == "table" then
if vim.tbl_contains(opts.preview.treesitter.enable, ft) then
return true
end
return false
end
if vim.tbl_contains(vim.F.if_nil(opts.preview.treesitter.disable, {}), ft) then
return false
end
return opts.preview.treesitter.enable == nil or opts.preview.treesitter.enable == true
end)()
local ts_success local ts_success
if ts_highlighting then if ts_highlighting then
@ -114,9 +139,6 @@ local treesitter_attach = function(bufnr, ft)
end end
local config = ts_configs.get_module "highlight" local config = ts_configs.get_module "highlight"
for k, v in pairs(config.custom_captures) do
vim.treesitter.highlighter.hl_map[k] = v
end
vim.treesitter.highlighter.new(ts_parsers.get_parser(bufnr, lang)) vim.treesitter.highlighter.new(ts_parsers.get_parser(bufnr, lang))
local is_table = type(config.additional_vim_regex_highlighting) == "table" local is_table = type(config.additional_vim_regex_highlighting) == "table"
if if

View File

@ -291,17 +291,17 @@ sorters.get_fuzzy_file = function(opts)
end end
local denominator = ( local denominator = (
(10 * match_count / #prompt_lower_ngrams) (10 * match_count / #prompt_lower_ngrams)
-- biases for shorter strings -- biases for shorter strings
+ 3 * match_count * ngram_len / #line + 3 * match_count * ngram_len / #line
+ consecutive_matches + consecutive_matches
+ N / (contains_string or (2 * #line)) + N / (contains_string or (2 * #line))
-- + 30/(c1 or 2*N) -- + 30/(c1 or 2*N)
-- TODO: It might be possible that this too strongly correlates, -- TODO: It might be possible that this too strongly correlates,
-- but it's unlikely for people to type capital letters without actually -- but it's unlikely for people to type capital letters without actually
-- wanting to do something with a capital letter in it. -- wanting to do something with a capital letter in it.
+ uppers_matching + uppers_matching
) * tail_modifier ) * tail_modifier
if denominator == 0 or denominator ~= denominator then if denominator == 0 or denominator ~= denominator then
return -1 return -1
@ -430,6 +430,7 @@ sorters.fuzzy_with_index_bias = function(opts)
return math.min(math.pow(entry.index, 0.25), 2) * base_score return math.min(math.pow(entry.index, 0.25), 2) * base_score
end end
end, end,
highlighter = fuzzy_sorter.highlighter,
} }
end end
@ -602,7 +603,7 @@ end
sorters.prefilter = function(opts) sorters.prefilter = function(opts)
local sorter = opts.sorter local sorter = opts.sorter
opts.delimiter = util.get_default(opts.delimiter, ":") opts.delimiter = vim.F.if_nil(opts.delimiter, ":")
sorter._delimiter = opts.delimiter sorter._delimiter = opts.delimiter
sorter.tags = create_tag_set(opts.tag) sorter.tags = create_tag_set(opts.tag)
sorter.filter_function = filter_function(opts) sorter.filter_function = filter_function(opts)

View File

@ -0,0 +1,112 @@
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 tester = require('telescope.testharness')
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("<An existing file>", 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

View File

@ -0,0 +1,156 @@
local builtin = require "telescope.builtin"
local DELAY = vim.g.telescope_test_delay or 50
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 = "<a valid key>", 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
vim.defer_fn(function()
runner.nvim_feed(replace_terms "<CR>", "")
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, DELAY)
end, DELAY)
end, DELAY)
end, DELAY)
end
end
return runner

View File

@ -1,3 +1,10 @@
---@tag telescope.utils
---@config { ["module"] = "telescope.utils" }
---@brief [[
--- Utilities for writing telescope pickers
---@brief ]]
local Path = require "plenary.path" local Path = require "plenary.path"
local Job = require "plenary.job" local Job = require "plenary.job"
@ -12,18 +19,6 @@ utils.get_separator = function()
return Path.path.sep return Path.path.sep
end end
utils.if_nil = function(x, was_nil, was_not_nil)
if x == nil then
return was_nil
else
return was_not_nil
end
end
utils.get_default = function(x, default)
return utils.if_nil(x, default, x)
end
utils.cycle = function(i, n) utils.cycle = function(i, n)
return i % n == 0 and n or i % n return i % n == 0 and n or i % n
end end
@ -179,21 +174,23 @@ end)()
utils.path_tail = (function() utils.path_tail = (function()
local os_sep = utils.get_separator() local os_sep = utils.get_separator()
local match_string = "[^" .. os_sep .. "]*$"
return function(path) return function(path)
return string.match(path, match_string) for i = #path, 1, -1 do
if path:sub(i, i) == os_sep then
return path:sub(i + 1, -1)
end
end
return path
end end
end)() end)()
utils.is_path_hidden = function(opts, path_display) utils.is_path_hidden = function(opts, path_display)
path_display = path_display or utils.get_default(opts.path_display, require("telescope.config").values.path_display) path_display = path_display or vim.F.if_nil(opts.path_display, require("telescope.config").values.path_display)
return path_display == nil return path_display == nil
or path_display == "hidden" or path_display == "hidden"
or type(path_display) ~= "table" or type(path_display) == "table" and (vim.tbl_contains(path_display, "hidden") or path_display.hidden)
or vim.tbl_contains(path_display, "hidden")
or path_display.hidden
end end
local is_uri = function(filename) local is_uri = function(filename)
@ -206,6 +203,16 @@ local calc_result_length = function(truncate_len)
return type(truncate_len) == "number" and len - truncate_len or len return type(truncate_len) == "number" and len - truncate_len or len
end end
--- Transform path is a util function that formats a path based on path_display
--- found in `opts` or the default value from config.
--- It is meant to be used in make_entry to have a uniform interface for
--- builtins as well as extensions utilizing the same user configuration
--- Note: It is only supported inside `make_entry`/`make_display` the use of
--- this function outside of telescope might yield to undefined behavior and will
--- not be addressed by us
---@param opts table: The opts the users passed into the picker. Might contains a path_display key
---@param path string: The path that should be formated
---@return string: The transformed path ready to be displayed
utils.transform_path = function(opts, path) utils.transform_path = function(opts, path)
if path == nil then if path == nil then
return return
@ -214,7 +221,7 @@ utils.transform_path = function(opts, path)
return path return path
end end
local path_display = utils.get_default(opts.path_display, require("telescope.config").values.path_display) local path_display = vim.F.if_nil(opts.path_display, require("telescope.config").values.path_display)
local transformed_path = path local transformed_path = path
@ -253,7 +260,10 @@ utils.transform_path = function(opts, path)
if opts.__length == nil then if opts.__length == nil then
opts.__length = calc_result_length(path_display.truncate) opts.__length = calc_result_length(path_display.truncate)
end end
transformed_path = truncate(transformed_path, opts.__length, nil, -1) if opts.__prefix == nil then
opts.__prefix = 0
end
transformed_path = truncate(transformed_path, opts.__length - opts.__prefix, nil, -1)
end end
end end
@ -393,19 +403,24 @@ function utils.get_os_command_output(cmd, cwd)
end end
local command = table.remove(cmd, 1) local command = table.remove(cmd, 1)
local stderr = {} local stderr = {}
local stdout, ret = Job local stdout, ret = Job:new({
:new({ command = command,
command = command, args = cmd,
args = cmd, cwd = cwd,
cwd = cwd, on_stderr = function(_, data)
on_stderr = function(_, data) table.insert(stderr, data)
table.insert(stderr, data) end,
end, }):sync()
})
:sync()
return stdout, ret, stderr return stdout, ret, stderr
end end
function utils.win_set_buf_noautocmd(win, buf)
local save_ei = vim.o.eventignore
vim.o.eventignore = "all"
vim.api.nvim_win_set_buf(win, buf)
vim.o.eventignore = save_ei
end
local load_once = function(f) local load_once = function(f)
local resolved = nil local resolved = nil
return function(...) return function(...)
@ -431,13 +446,13 @@ utils.transform_devicons = load_once(function()
return display return display
end end
local icon, icon_highlight = devicons.get_icon(filename, string.match(filename, "%a+$"), { default = true }) local icon, icon_highlight = devicons.get_icon(utils.path_tail(filename), nil, { default = true })
local icon_display = (icon or " ") .. " " .. (display or "") local icon_display = (icon or " ") .. " " .. (display or "")
if conf.color_devicons then if conf.color_devicons then
return icon_display, icon_highlight return icon_display, icon_highlight
else else
return icon_display, "TelescopeResultsFileIcon" return icon_display, nil
end end
end end
else else
@ -461,11 +476,11 @@ utils.get_devicons = load_once(function()
return "" return ""
end end
local icon, icon_highlight = devicons.get_icon(filename, string.match(filename, "%a+$"), { default = true }) local icon, icon_highlight = devicons.get_icon(utils.path_tail(filename), nil, { default = true })
if conf.color_devicons then if conf.color_devicons then
return icon, icon_highlight return icon, icon_highlight
else else
return icon, "TelescopeResultsFileIcon" return icon, nil
end end
end end
else else

View File

@ -488,7 +488,7 @@ describe("actions", function()
eq("replaced:vnew", actions.file_vsplit()) eq("replaced:vnew", actions.file_vsplit())
end) end)
it("handles backwards compat with select and edit files", function() pending("handles backwards compat with select and edit files", function()
-- Reproduce steps: -- Reproduce steps:
-- In config, we have { ["<CR>"] = actions.select, ... } -- In config, we have { ["<CR>"] = actions.select, ... }
-- In caller, we have actions._goto:replace(...) -- In caller, we have actions._goto:replace(...)

View File

@ -1,6 +1,9 @@
require("plenary.reload").reload_module "telescope" -- Just skip on mac, it has flaky CI for some reason
if vim.fn.has "mac" == 1 then
return
end
local tester = require "telescope.pickers._test" local tester = require "telescope.testharness"
local disp = function(val) local disp = function(val)
return vim.inspect(val, { newline = " ", indent = "" }) return vim.inspect(val, { newline = " ", indent = "" })
@ -11,10 +14,6 @@ describe("builtin.find_files", function()
tester.run_file "find_files__readme" tester.run_file "find_files__readme"
end) end)
it("should be able to move selections", function()
tester.run_file "find_files__with_ctrl_n"
end)
for _, configuration in ipairs { for _, configuration in ipairs {
{ sorting_strategy = "descending" }, { sorting_strategy = "descending" },
{ sorting_strategy = "ascending" }, { sorting_strategy = "ascending" },
@ -24,7 +23,7 @@ describe("builtin.find_files", function()
[[ [[
local max_results = 5 local max_results = 5
tester.builtin_picker('find_files', 'README.md', { runner.picker('find_files', 'README.md', {
post_typed = { post_typed = {
{ "> README.md", GetPrompt }, { "> README.md", GetPrompt },
{ "> README.md", GetBestResult }, { "> README.md", GetBestResult },
@ -41,56 +40,24 @@ describe("builtin.find_files", function()
height = max_results + 1, height = max_results + 1,
width = 0.9, width = 0.9,
}, },
border = false,
}, vim.json.decode([==[%s]==]))) }, vim.json.decode([==[%s]==])))
]], ]],
vim.json.encode(configuration) vim.json.encode(configuration)
)) ))
end) end)
it("should only save one line for ascending, but many for descending", function() pending("use devicons, if it has it when enabled", function()
local expected
if configuration.sorting_strategy == "descending" then
expected = 5
else
expected = 1
end
tester.run_string(string.format(
[[
local max_results = 5
tester.builtin_picker('find_files', 'README.md', {
post_typed = {
{ %s, function() return #GetResults() end },
},
}, vim.tbl_extend("force", {
disable_devicons = true,
sorter = require('telescope.sorters').get_fzy_sorter(),
layout_strategy = 'center',
layout_config = {
height = max_results + 1,
width = 0.9,
},
border = false,
}, vim.json.decode([==[%s]==])))
]],
expected,
vim.json.encode(configuration)
))
end)
it("use devicons, if it has it when enabled", function()
if not pcall(require, "nvim-web-devicons") then if not pcall(require, "nvim-web-devicons") then
return return
end end
local md = require("nvim-web-devicons").get_icon "md"
tester.run_string(string.format( tester.run_string(string.format(
[[ [[
tester.builtin_picker('find_files', 'README.md', { runner.picker('find_files', 'README.md', {
post_typed = { post_typed = {
{ "> README.md", GetPrompt }, { "> README.md", GetPrompt },
{ "> README.md", GetBestResult } { "> %s README.md", GetBestResult }
}, },
post_close = { post_close = {
{ 'README.md', GetFile }, { 'README.md', GetFile },
@ -101,6 +68,7 @@ describe("builtin.find_files", function()
sorter = require('telescope.sorters').get_fzy_sorter(), sorter = require('telescope.sorters').get_fzy_sorter(),
}, vim.json.decode([==[%s]==]))) }, vim.json.decode([==[%s]==])))
]], ]],
md,
vim.json.encode(configuration) vim.json.encode(configuration)
)) ))
end) end)
@ -108,7 +76,7 @@ describe("builtin.find_files", function()
it("should find the readme, using lowercase", function() it("should find the readme, using lowercase", function()
tester.run_string [[ tester.run_string [[
tester.builtin_picker('find_files', 'readme.md', { runner.picker('find_files', 'readme.md', {
post_close = { post_close = {
{ 'README.md', GetFile }, { 'README.md', GetFile },
} }
@ -118,7 +86,7 @@ describe("builtin.find_files", function()
it("should find the pickers.lua, using lowercase", function() it("should find the pickers.lua, using lowercase", function()
tester.run_string [[ tester.run_string [[
tester.builtin_picker('find_files', 'pickers.lua', { runner.picker('find_files', 'pickers.lua', {
post_close = { post_close = {
{ 'pickers.lua', GetFile }, { 'pickers.lua', GetFile },
} }
@ -128,7 +96,7 @@ describe("builtin.find_files", function()
it("should find the pickers.lua", function() it("should find the pickers.lua", function()
tester.run_string [[ tester.run_string [[
tester.builtin_picker('find_files', 'pickers.lua', { runner.picker('find_files', 'pickers.lua', {
post_close = { post_close = {
{ 'pickers.lua', GetFile }, { 'pickers.lua', GetFile },
{ 'pickers.lua', GetFile }, { 'pickers.lua', GetFile },
@ -139,20 +107,13 @@ describe("builtin.find_files", function()
it("should be able to c-n the items", function() it("should be able to c-n the items", function()
tester.run_string [[ tester.run_string [[
tester.builtin_picker('find_files', 'fixtures/file<c-p>', { runner.picker('find_files', 'fixtures/file<c-n>', {
post_typed = { post_typed = {
{ {
{ {
" lua/tests/fixtures/file_abc.txt", " lua/tests/fixtures/file_a.txt",
"> lua/tests/fixtures/file_a.txt", "> lua/tests/fixtures/file_abc.txt",
}, function() }, GetResults
local res = GetResults()
return {
res[#res - 1],
res[#res],
}
end
}, },
}, },
post_close = { post_close = {
@ -160,6 +121,7 @@ describe("builtin.find_files", function()
}, },
}, { }, {
sorter = require('telescope.sorters').get_fzy_sorter(), sorter = require('telescope.sorters').get_fzy_sorter(),
sorting_strategy = "ascending",
disable_devicons = true, disable_devicons = true,
}) })
]] ]]
@ -167,7 +129,7 @@ describe("builtin.find_files", function()
it("should be able to get the current selection", function() it("should be able to get the current selection", function()
tester.run_string [[ tester.run_string [[
tester.builtin_picker('find_files', 'fixtures/file_abc', { runner.picker('find_files', 'fixtures/file_abc', {
post_typed = { post_typed = {
{ 'lua/tests/fixtures/file_abc.txt', GetSelectionValue }, { 'lua/tests/fixtures/file_abc.txt', GetSelectionValue },
} }

View File

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

View File

@ -1,7 +1,7 @@
local tester = require "telescope.pickers._test" local helper = require "telescope.testharness.helpers"
local helper = require "telescope.pickers._test_helpers" local runner = require "telescope.testharness.runner"
tester.builtin_picker("find_files", "README.md", { runner.picker("find_files", "README.md", {
post_close = { post_close = {
{ "README.md", helper.get_file }, { "README.md", helper.get_file },
}, },

View File

@ -1,10 +1,8 @@
require("plenary.reload").reload_module "plenary" local tester = require "telescope.testharness"
require("plenary.reload").reload_module "telescope" local helper = require "telescope.testharness.helpers"
local runner = require "telescope.testharness.runner"
local tester = require "telescope.pickers._test" runner.picker("find_files", "telescope<c-n>", {
local helper = require "telescope.pickers._test_helpers"
tester.builtin_picker("find_files", "telescope<c-n>", {
post_close = { post_close = {
tester.not_ { "plugin/telescope.vim", helper.get_file }, tester.not_ { "plugin/telescope.vim", helper.get_file },
}, },

View File

@ -1,8 +0,0 @@
local tester = require "telescope.pickers._test"
local helper = require "telescope.pickers._test_helpers"
tester.builtin_picker("find_files", "fixtures/file<c-p>", {
post_close = {
{ "lua/tests/fixtures/file_abc.txt", helper.get_selection_value },
},
})

View File

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

View File

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

View File

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

View File

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

View File

@ -82,7 +82,6 @@ local highlights = {
TelescopeResultsNumber = { default = true, link = "Number" }, TelescopeResultsNumber = { default = true, link = "Number" },
TelescopeResultsComment = { default = true, link = "Comment" }, TelescopeResultsComment = { default = true, link = "Comment" },
TelescopeResultsSpecialComment = { default = true, link = "SpecialComment" }, TelescopeResultsSpecialComment = { default = true, link = "SpecialComment" },
TelescopeResultsFileIcon = { default = true, link = "Normal" },
-- Used for git status Results highlighting -- Used for git status Results highlighting
TelescopeResultsDiffChange = { default = true, link = "DiffChange" }, TelescopeResultsDiffChange = { default = true, link = "DiffChange" },

View File

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

View File

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

View File

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

View File

@ -15,8 +15,12 @@ docs.test = function()
"./lua/telescope/command.lua", "./lua/telescope/command.lua",
"./lua/telescope/builtin/init.lua", "./lua/telescope/builtin/init.lua",
"./lua/telescope/themes.lua", "./lua/telescope/themes.lua",
"./lua/telescope/mappings.lua",
"./lua/telescope/pickers/layout_strategies.lua", "./lua/telescope/pickers/layout_strategies.lua",
"./lua/telescope/config/resolve.lua", "./lua/telescope/config/resolve.lua",
"./lua/telescope/make_entry.lua",
"./lua/telescope/pickers/entry_display.lua",
"./lua/telescope/utils.lua",
"./lua/telescope/actions/init.lua", "./lua/telescope/actions/init.lua",
"./lua/telescope/actions/state.lua", "./lua/telescope/actions/state.lua",
"./lua/telescope/actions/set.lua", "./lua/telescope/actions/set.lua",

View File

@ -4,3 +4,6 @@ set rtp+=../tree-sitter-lua/
runtime! plugin/plenary.vim runtime! plugin/plenary.vim
runtime! plugin/telescope.lua runtime! plugin/telescope.lua
runtime! plugin/ts_lua.vim
let g:telescope_test_delay = 100

View File

@ -1,55 +1,58 @@
if vim.b.did_ftp == true then if vim.b.did_ftp == true then
return return
end end
vim.opt_local.cursorline = true vim.opt_local.cursorline = true
vim.opt_local.modifiable = true vim.opt_local.modifiable = false
vim.opt_local.buflisted = true vim.opt_local.buflisted = false
vim.opt_local.syntax = "zkbrowser" vim.opt_local.syntax = 'zkbrowser'
vim.opt_local.buftype = "nofile" vim.opt_local.buftype = 'nofile'
vim.opt_local.swapfile = false vim.opt_local.swapfile = false
vim.opt_local.iskeyword:append(":") vim.opt_local.iskeyword:append(':')
vim.opt_local.iskeyword:append("-") vim.opt_local.iskeyword:append('-')
vim.opt_local.suffixesadd:append(".md") vim.opt_local.suffixesadd:append('.md')
vim.opt_local.errorformat = "%f:%l: %m" vim.opt_local.errorformat = '%f:%l: %m'
if vim.opt_local.keywordprg:get() == "" then if vim.opt_local.keywordprg:get() == '' then
vim.opt_local.keywordprg = ":ZkHover -preview" vim.opt_local.keywordprg = ':ZkHover -preview'
end end
if vim.opt_local.tagfunc:get() == "" then if vim.opt_local.tagfunc:get() == '' then
vim.opt_local.tagfunc = "v:lua.zettelkasten.tagfunc" vim.opt_local.tagfunc = 'v:lua.zettelkasten.tagfunc'
end end
require("zettelkasten").add_hover_command() require('zettelkasten').add_hover_command()
if vim.fn.mapcheck("[I", "n") == "" then if vim.fn.mapcheck('[I', 'n') == '' then
vim.api.nvim_buf_set_keymap( vim.api.nvim_buf_set_keymap(
0, 0,
"n", 'n',
"[I", '[I',
'<CMD>lua require("zettelkasten").show_back_references(vim.fn.expand("<cword>"))<CR>', '<CMD>lua require("zettelkasten").show_back_references(vim.fn.expand("<cword>"))<CR>',
{ noremap = true, silent = true, nowait = true } { noremap = true, silent = true, nowait = true }
) )
vim.api.nvim_buf_set_keymap(
0,
'n',
'q',
':bd!<cr>',
{ noremap = true, silent = true, nowait = true }
)
end end
local config = require("zettelkasten.config").get() local config = require('zettelkasten.config')
if config.notes_path ~= "" then if config.zettel_dir ~= '' then
vim.cmd("lcd " .. config.notes_path) vim.cmd('lcd ' .. config.zettel_dir)
end end
vim.api.nvim_create_autocmd({ "BufEnter" }, { vim.api.nvim_create_autocmd({ 'BufEnter' }, {
group = vim.api.nvim_create_augroup("zettelkasten_browser_events", { clear = true }), group = vim.api.nvim_create_augroup('zettelkasten_browser_events', { clear = true }),
buffer = vim.api.nvim_get_current_buf(), buffer = vim.api.nvim_get_current_buf(),
callback = function(opts) callback = function(opts)
vim.opt_local.syntax = "" vim.opt_local.syntax = ''
vim.api.nvim_buf_set_lines( vim.opt_local.modifiable = true
0, vim.api.nvim_buf_set_lines(0, 0, -1, false, require('zettelkasten').get_note_browser_content())
vim.fn.line("$") - 1, vim.opt_local.syntax = 'zkbrowser'
-1, vim.opt_local.modifiable = false
true, end,
require("zettelkasten").get_note_browser_content()
)
vim.opt_local.syntax = "zkbrowser"
end,
}) })

View File

@ -1,314 +1,337 @@
--=============================================================================
-- zettelkasten.lua --- zk plugin
-- Copyright (c) 2016-2022 Wang Shidong & Contributors
-- Author: Wang Shidong < wsdjeg@outlook.com >
-- URL: https://spacevim.org
-- License: GPLv3
--=============================================================================
local M = {} local M = {}
local api = vim.api local api = vim.api
local fn = vim.fn local fn = vim.fn
local log_levels = vim.log.levels local log_levels = vim.log.levels
local log = require("zettelkasten.log") local log = require('zettelkasten.log')
local config = require("zettelkasten.config") local config = require('zettelkasten.config')
local formatter = require("zettelkasten.formatter") local formatter = require('zettelkasten.formatter')
local browser = require("zettelkasten.browser") local browser = require('zettelkasten.browser')
local NOTE_ID_STRFTIME_FORMAT = "%Y-%m-%d-%H-%M-%S" local NOTE_ID_STRFTIME_FORMAT = '%Y-%m-%d-%H-%M-%S'
local function set_qflist(lines, action, bufnr, use_loclist, what) local function set_qflist(lines, action, bufnr, use_loclist, what)
what = what or {} what = what or {}
local _, local_efm = pcall(vim.api.nvim_buf_get_option, bufnr, "errorformat") local _, local_efm = pcall(vim.api.nvim_buf_get_option, bufnr, 'errorformat')
what.efm = what.efm or local_efm what.efm = what.efm or local_efm
if use_loclist then if use_loclist then
fn.setloclist(bufnr, lines, action, what) fn.setloclist(bufnr, lines, action, what)
else else
fn.setqflist(lines, action, what) fn.setqflist(lines, action, what)
end end
end end
local function read_note(file_path, line_count) local function read_note(file_path, line_count)
local file = io.open(file_path, "r") local file = io.open(file_path, 'r')
assert(file ~= nil) assert(file ~= nil)
assert(file:read(0) ~= nil) assert(file:read(0) ~= nil)
if line_count == nil then if line_count == nil then
return file:read("*all") return file:read('*all')
end
local lines = {}
while #lines < line_count do
local line = file:read('*line')
if line == nil then
break
end end
local lines = {} table.insert(lines, line)
while #lines < line_count do end
local line = file:read("*line")
if line == nil then
break
end
table.insert(lines, line) return lines
end
return lines
end end
local function get_all_tags(lookup_tag) local function get_all_tags(lookup_tag)
if lookup_tag ~= nil and #lookup_tag > 0 then if lookup_tag ~= nil and #lookup_tag > 0 then
lookup_tag = string.gsub(lookup_tag, "\\<", "") lookup_tag = string.gsub(lookup_tag, '\\<', '')
lookup_tag = string.gsub(lookup_tag, "\\>", "") lookup_tag = string.gsub(lookup_tag, '\\>', '')
end end
local tags = browser.get_tags() local tags = browser.get_tags()
if lookup_tag ~= nil and #lookup_tag > 0 then if lookup_tag ~= nil and #lookup_tag > 0 then
tags = vim.tbl_filter(function(tag) tags = vim.tbl_filter(function(tag)
return string.match(tag.name, lookup_tag) ~= nil return string.match(tag.name, lookup_tag) ~= nil
end, tags) end, tags)
end end
return tags return tags
end end
local function generate_note_id() local function generate_note_id()
return fn.strftime(NOTE_ID_STRFTIME_FORMAT) return fn.strftime(NOTE_ID_STRFTIME_FORMAT)
end end
function M.completefunc(find_start, base) function M.completefunc(find_start, base)
if find_start == 1 and base == "" then if find_start == 1 and base == '' then
local pos = api.nvim_win_get_cursor(0) local pos = api.nvim_win_get_cursor(0)
local line = api.nvim_get_current_line() local line = api.nvim_get_current_line()
local line_to_cursor = line:sub(1, pos[2]) local line_to_cursor = line:sub(1, pos[2])
return fn.match(line_to_cursor, "\\k*$") return fn.match(line_to_cursor, '\\k*$')
end end
local notes = vim.tbl_filter(function(note) local notes = vim.tbl_filter(function(note)
return string.match(note.title, base) -- here the note sometimes do not have title, then it is nil
end, browser.get_notes()) return string.match(note.title, base)
end, browser.get_notes())
local words = {} local words = {}
for _, ref in ipairs(notes) do for _, ref in ipairs(notes) do
table.insert(words, { table.insert(words, {
word = ref.id, word = ref.id,
abbr = ref.title, abbr = ref.title,
dup = 0, dup = 0,
empty = 0, empty = 0,
kind = "[zettelkasten]", kind = '[zettelkasten]',
icase = 1, icase = 1,
}) })
end end
return words return words
end end
function M.set_note_id(bufnr) function M.set_note_id(bufnr)
local first_line = vim.api.nvim_buf_get_lines(bufnr, 0, 1, true)[1] local first_line = vim.api.nvim_buf_get_lines(bufnr, 0, 1, true)[1]
local zk_id = generate_note_id() local zk_id = generate_note_id()
if #zk_id > 0 then if #zk_id > 0 then
first_line, _ = string.gsub(first_line, "# ", "") first_line, _ = string.gsub(first_line, '# ', '')
api.nvim_buf_set_lines(bufnr, 0, 1, true, { "# " .. zk_id .. " " .. first_line }) api.nvim_buf_set_lines(bufnr, 0, 1, true, { '# ' .. zk_id .. ' ' .. first_line })
vim.cmd("file " .. zk_id .. ".md") vim.cmd('file ' .. zk_id .. '.md')
else else
log.notify("There's already a note with the same ID.", log_levels.ERROR, {}) log.notify("There's already a note with the same ID.", log_levels.ERROR, {})
end end
end end
function M.tagfunc(pattern, flags, info) function M.tagfunc(pattern, flags, info)
local in_insert = string.match(flags, "i") ~= nil local in_insert = string.match(flags, 'i') ~= nil
local pattern_provided = pattern ~= "\\<\\k\\k" or pattern == "*" local pattern_provided = pattern ~= '\\<\\k\\k' or pattern == '*'
local all_tags = {} local all_tags = {}
if pattern_provided then if pattern_provided then
all_tags = get_all_tags(pattern) all_tags = get_all_tags(pattern)
else else
all_tags = get_all_tags() all_tags = get_all_tags()
end end
local tags = {} local tags = {}
for _, tag in ipairs(all_tags) do for _, tag in ipairs(all_tags) do
table.insert(tags, {
name = string.gsub(tag.name, '#', ''),
filename = tag.file_name,
cmd = tostring(tag.linenr),
kind = 'zettelkasten',
})
end
if not in_insert then
local notes = browser.get_notes()
for _, note in ipairs(notes) do
if string.find(note.id, pattern, 1, true) or not pattern_provided then
table.insert(tags, { table.insert(tags, {
name = string.gsub(tag.name, "#", ""), name = note.id,
filename = tag.file_name, filename = note.file_name,
cmd = tostring(tag.linenr), cmd = '1',
kind = "zettelkasten", kind = 'zettelkasten',
}) })
end
end end
end
if not in_insert then if #tags > 0 then
local notes = browser.get_notes() return tags
for _, note in ipairs(notes) do end
if string.find(note.id, pattern, 1, true) or not pattern_provided then
table.insert(tags, {
name = note.id,
filename = note.file_name,
cmd = "1",
kind = "zettelkasten",
})
end
end
end
if #tags > 0 then return nil
return tags
end
return nil
end end
function M.keyword_expr(word, opts) function M.keyword_expr(word, opts)
if not word then if not word then
return {} return {}
end end
opts = opts or {} opts = opts or {}
opts.preview_note = opts.preview_note or false opts.preview_note = opts.preview_note or false
opts.return_lines = opts.return_lines or false opts.return_lines = opts.return_lines or false
local note = browser.get_note(word) local note = browser.get_note(word)
if note == nil then if note == nil then
log.notify("Cannot find note.", log_levels.ERROR, {}) log.notify('Cannot find note.', log_levels.ERROR, {})
return {} return {}
end end
local lines = {} local lines = {}
if opts.preview_note and not opts.return_lines then if opts.preview_note and not opts.return_lines then
vim.cmd(config.get().preview_command .. " " .. note.file_name) vim.cmd(config.preview_command .. ' ' .. note.file_name)
elseif opts.preview_note and opts.return_lines then elseif opts.preview_note and opts.return_lines then
vim.list_extend(lines, read_note(note.file_name)) vim.list_extend(lines, read_note(note.file_name))
else else
table.insert(lines, note.title) table.insert(lines, note.title)
end end
return lines return lines
end end
function M.get_back_references(note_id) function M.get_back_references(note_id)
local note = browser.get_note(note_id) local note = browser.get_note(note_id)
if note == nil then if note == nil then
return {} return {}
end
local title_cache = {}
local get_title = function(id)
if title_cache[id] ~= nil then
return title_cache[id]
end end
local title_cache = {} title_cache[id] = browser.get_note(id).title
local get_title = function(id) return title_cache[id]
if title_cache[id] ~= nil then end
return title_cache[id]
end
title_cache[id] = browser.get_note(id).title local references = {}
return title_cache[id] for _, back_reference in ipairs(note.back_references) do
end table.insert(references, {
id = back_reference.id,
linenr = back_reference.linenr,
title = back_reference.title,
file_name = back_reference.file_name,
})
end
local references = {} return references
for _, back_reference in ipairs(note.back_references) do
table.insert(references, {
id = back_reference.id,
linenr = back_reference.linenr,
title = back_reference.title,
file_name = back_reference.file_name,
})
end
return references
end end
function M.show_back_references(cword, use_loclist) function M.show_back_references(cword, use_loclist)
use_loclist = use_loclist or false use_loclist = use_loclist or false
local references = M.get_back_references(cword) local references = M.get_back_references(cword)
if #references == 0 then if #references == 0 then
log.notify("No back references found.", log_levels.ERROR, {}) log.notify('No back references found.', log_levels.ERROR, {})
return return
end end
local lines = {} local lines = {}
for _, ref in ipairs(references) do for _, ref in ipairs(references) do
local line = {} local line = {}
table.insert(line, fn.fnamemodify(ref.file_name, ":.")) table.insert(line, fn.fnamemodify(ref.file_name, ':.'))
table.insert(line, ":") table.insert(line, ':')
table.insert(line, ref.linenr) table.insert(line, ref.linenr)
table.insert(line, ": ") table.insert(line, ': ')
table.insert(line, ref.title) table.insert(line, ref.title)
table.insert(lines, table.concat(line, "")) table.insert(lines, table.concat(line, ''))
end end
set_qflist( set_qflist(
{}, {},
" ", ' ',
vim.api.nvim_get_current_buf(), vim.api.nvim_get_current_buf(),
use_loclist, use_loclist,
{ title = "[[" .. cword .. "]] References", lines = lines } { title = '[[' .. cword .. ']] References', lines = lines }
) )
if use_loclist then if use_loclist then
vim.cmd([[botright lopen | wincmd p]]) vim.cmd([[botright lopen | wincmd p]])
else else
vim.cmd([[botright copen | wincmd p]]) vim.cmd([[botright copen | wincmd p]])
end end
end end
function M.get_toc(note_id, format) function M.get_toc(note_id, format)
format = format or "- [%h](%d)" format = format or '- [%h](%d)'
local references = M.get_back_references(note_id) local references = M.get_back_references(note_id)
local lines = {} local lines = {}
for _, note in ipairs(references) do for _, note in ipairs(references) do
table.insert(lines, { table.insert(lines, {
file_name = note.file_name, file_name = note.file_name,
id = note.id, id = note.id,
title = note.title, title = note.title,
}) })
end end
return formatter.format(lines, format) return formatter.format(lines, format)
end end
function M.get_note_browser_content() function M.get_note_browser_content()
if config.get().notes_path == "" then if config.zettel_dir == '' then
log.notify("'notes_path' option is required for note browsing.", log_levels.WARN, {}) log.notify("'notes_path' option is required for note browsing.", log_levels.WARN, {})
return {} return {}
end end
local all_notes = browser.get_notes() local all_notes = browser.get_notes()
local lines = {} local lines = {}
for _, note in ipairs(all_notes) do for _, note in ipairs(all_notes) do
table.insert(lines, { table.insert(lines, {
file_name = note.file_name, file_name = note.file_name,
id = note.id, id = note.id,
references = note.references, references = note.references,
back_references = note.back_references, back_references = note.back_references,
tags = note.tags, tags = note.tags,
title = note.title, title = note.title,
}) })
end end
return formatter.format(lines, config.get().browseformat) return formatter.format(lines, config.browseformat)
end end
function M.add_hover_command() function M.add_hover_command()
if fn.exists(":ZkHover") == 2 then if fn.exists(':ZkHover') == 2 then
return return
end end
vim.cmd( vim.cmd(
[[command -buffer -nargs=1 ZkHover :lua require"zettelkasten"._internal_execute_hover_cmd(<q-args>)]] [[command -buffer -nargs=1 ZkHover :lua require"zettelkasten"._internal_execute_hover_cmd(<q-args>)]]
) )
end end
function M._internal_execute_hover_cmd(args) function M._internal_execute_hover_cmd(args)
if args ~= nil and type(args) == "string" then if args ~= nil and type(args) == 'string' then
args = vim.split(args, " ", true) args = vim.split(args, ' ', true)
else else
args = {} args = {}
end end
local cword = "" local cword = ''
if #args == 1 then if #args == 1 then
cword = fn.expand("<cword>") cword = fn.expand('<cword>')
else else
cword = args[#args] cword = args[#args]
end end
local lines = M.keyword_expr(cword, { local lines = M.keyword_expr(cword, {
preview_note = vim.tbl_contains(args, "-preview"), preview_note = vim.tbl_contains(args, '-preview'),
return_lines = vim.tbl_contains(args, "-return-lines"), return_lines = vim.tbl_contains(args, '-return-lines'),
}) })
if #lines > 0 then if #lines > 0 then
log.notify(table.concat(lines, "\n"), log_levels.INFO, {}) log.notify(table.concat(lines, '\n'), log_levels.INFO, {})
end end
end end
function M.setup(opts) function M.zknew(opt) -- {{{
opts = opts or {} vim.cmd([[new | setlocal filetype=markdown]])
opts.notes_path = opts.notes_path or "" if config.zettel_dir ~= '' then
if vim.fn.isdirectory(config.zettel_dir) == 0 then
vim.fn.mkdir(vim.fn.expand(config.zettel_dir), 'p', '0700')
end
vim.cmd('lcd ' .. config.zettel_dir)
end
config._set(opts) vim.cmd('normal ggI# New Note')
require('zettelkasten').set_note_id(vim.api.nvim_get_current_buf())
vim.cmd('normal $')
end
-- }}}
function M.setup(opts)
opts = opts or {}
opts.notes_path = opts.notes_path or ''
config._set(opts)
end end
return M return M

View File

@ -1,215 +1,219 @@
local M = {} local M = {}
local fn = vim.fn local fn = vim.fn
local config = require("zettelkasten.config") local config = require('zettelkasten.config')
local ZK_FULL_TITLE_PATTERN = "# %d+-%d+-%d+-%d+-%d+-%d+ .+" local ZK_FULL_TITLE_PATTERN = '# %d+-%d+-%d+-%d+-%d+-%d+ .+'
local ZK_ID_PATTERN = "%d+-%d+-%d+-%d+-%d+-%d+" local ZK_ID_PATTERN = '%d+-%d+-%d+-%d+-%d+-%d+'
local ZK_FILE_NAME_PATTERN = "%d+-%d+-%d+-%d+-%d+-%d+.md" local ZK_FILE_NAME_PATTERN = '%d+-%d+-%d+-%d+-%d+-%d+.md'
local s_note_cache_with_file_path = {} local s_note_cache_with_file_path = {}
local s_note_cache_with_id = {} local s_note_cache_with_id = {}
local function get_files(folder) local function get_files(folder)
local files = fn.split(fn.globpath(folder, "*.md"), "\\n") local files = fn.split(fn.globpath(folder, '*.md'), '\\n')
files = vim.tbl_filter(function(file) files = vim.tbl_filter(function(file)
return string.match(file, ZK_FILE_NAME_PATTERN) ~= nil return string.match(file, ZK_FILE_NAME_PATTERN) ~= nil
end, files) end, files)
return files return files
end end
local function extract_id_and_title(line) local function extract_id_and_title(line)
local zk_id = string.match(line, ZK_FULL_TITLE_PATTERN) local zk_id = string.match(line, ZK_FULL_TITLE_PATTERN)
if zk_id == nil then if zk_id == nil then
return nil return nil
end end
zk_id = string.gsub(zk_id, "# ", "") zk_id = string.gsub(zk_id, '# ', '')
local note_id = string.match(zk_id, ZK_ID_PATTERN) local note_id = string.match(zk_id, ZK_ID_PATTERN)
local title = vim.trim(string.gsub(zk_id, ZK_ID_PATTERN, "")) local title = vim.trim(string.gsub(zk_id, ZK_ID_PATTERN, ''))
return { id = note_id, title = string.gsub(title, "\r", "") } return { id = note_id, title = string.gsub(title, '\r', '') }
end end
local function extract_references(line, linenr) local function extract_references(line, linenr)
assert(line ~= nil) assert(line ~= nil)
local references = {} local references = {}
for ref in string.gmatch(line, "(%[%[" .. ZK_ID_PATTERN .. "%]%])") do for ref in string.gmatch(line, '(%[%[' .. ZK_ID_PATTERN .. '%]%])') do
ref = string.gsub(ref, "%[%[", "") ref = string.gsub(ref, '%[%[', '')
ref = string.gsub(ref, "%]%]", "") ref = string.gsub(ref, '%]%]', '')
table.insert(references, { id = ref, linenr = linenr }) table.insert(references, { id = ref, linenr = linenr })
end end
return references return references
end end
local function extract_back_references(notes, note_id) local function extract_back_references(notes, note_id)
assert(note_id ~= nil) assert(note_id ~= nil)
local back_references = {} local back_references = {}
for _, note in ipairs(notes) do for _, note in ipairs(notes) do
if note.id == note_id then if note.id == note_id then
goto continue goto continue
end
local references = note.references
for _, ref in ipairs(references) do
if ref.id == note_id then
table.insert(back_references, {
id = note.id,
title = note.title,
file_name = note.file_name,
linenr = ref.linenr,
})
break
end
end
::continue::
end end
return back_references local references = note.references
for _, ref in ipairs(references) do
if ref.id == note_id then
table.insert(back_references, {
id = note.id,
title = note.title,
file_name = note.file_name,
linenr = ref.linenr,
})
break
end
end
::continue::
end
return back_references
end end
local function extract_tags(line, linenr) local function extract_tags(line, linenr)
assert(line ~= nil) assert(line ~= nil)
local tags = {} local tags = {}
for tag in string.gmatch(line, "(%#%a[%w-]+)") do for tag in string.gmatch(line, '(%#%a[%w-]+)') do
local start_pos, _ = string.find(line, tag, 1, true) local start_pos, _ = string.find(line, tag, 1, true)
local previous_char = string.sub(line, start_pos - 1, start_pos - 1) local previous_char = string.sub(line, start_pos - 1, start_pos - 1)
if previous_char == "" or previous_char == " " then if previous_char == '' or previous_char == ' ' then
table.insert(tags, { linenr = linenr, name = tag }) table.insert(tags, { linenr = linenr, name = tag })
end
end end
end
return tags return tags
end end
local function get_note_information(file_path) local function get_note_information(file_path)
local last_modified = fn.strftime("%Y-%m-%d.%H:%M:%S", fn.getftime(file_path)) local last_modified = fn.strftime('%Y-%m-%d.%H:%M:%S', fn.getftime(file_path))
if if
s_note_cache_with_file_path[file_path] ~= nil s_note_cache_with_file_path[file_path] ~= nil
and s_note_cache_with_file_path[file_path].last_modified == last_modified and s_note_cache_with_file_path[file_path].last_modified == last_modified
then then
return s_note_cache_with_file_path[file_path] return s_note_cache_with_file_path[file_path]
end
local file = io.open(file_path, 'r')
if file:read(0) == nil then
return nil
end
local info = {
id = '',
title = '',
file_name = file_path,
last_modified = last_modified,
tags = {},
references = {},
back_references = {},
}
local linenr = 0
while true do
linenr = linenr + 1
local line = file:read('*line')
if line == nil then
break
end end
local file = io.open(file_path, "r") if line == '' then
if file:read(0) == nil then goto continue
return nil
end end
local info = { if info.id == '' then
file_name = file_path, local id_title = extract_id_and_title(line)
last_modified = last_modified, if id_title then
tags = {}, info = vim.tbl_extend('force', info, id_title)
references = {}, goto continue
back_references = {}, end
}
local linenr = 0
while true do
linenr = linenr + 1
local line = file:read("*line")
if line == nil then
break
end
if line == "" then
goto continue
end
if info.id == nil then
local id_title = extract_id_and_title(line)
if id_title then
info = vim.tbl_extend("error", info, id_title)
goto continue
end
end
local refs = extract_references(line, linenr)
if refs then
vim.list_extend(info.references, refs)
end
local tags = extract_tags(line, linenr)
if tags then
vim.list_extend(info.tags, tags)
end
::continue::
end end
local refs = extract_references(line, linenr)
if refs then
vim.list_extend(info.references, refs)
end
local tags = extract_tags(line, linenr)
if tags then
vim.list_extend(info.tags, tags)
end
::continue::
end
if info.id ~= nil then
s_note_cache_with_file_path[file_path] = info s_note_cache_with_file_path[file_path] = info
s_note_cache_with_id[info.id] = info s_note_cache_with_id[info.id] = info
return info end
return info
end end
function M.get_note(id) function M.get_note(id)
if s_note_cache_with_id[id] ~= nil then if s_note_cache_with_id[id] ~= nil then
return s_note_cache_with_id[id] return s_note_cache_with_id[id]
end end
local _ = M.get_notes() local _ = M.get_notes()
if s_note_cache_with_id[id] ~= nil then if s_note_cache_with_id[id] ~= nil then
return s_note_cache_with_id[id] return s_note_cache_with_id[id]
end end
return nil return nil
end end
function M.get_notes() function M.get_notes()
local folder = config.get().notes_path local folder = config.zettel_dir
local files = get_files(folder) local files = get_files(folder)
local all_notes = {} local all_notes = {}
for _, file in ipairs(files) do for _, file in ipairs(files) do
table.insert(all_notes, get_note_information(file)) table.insert(all_notes, get_note_information(file))
end
for _, note in ipairs(all_notes) do
if note.id == nil then
goto continue
end end
for _, note in ipairs(all_notes) do local back_references = extract_back_references(all_notes, note.id)
if note.id == nil then if back_references then
goto continue -- When notes are cached, `back_references` field will have the references from before.
end -- Since the files that refer to this one might have changed, we'll overwrite it here.
-- extract_back_references() already re-processes the references.
local back_references = extract_back_references(all_notes, note.id) note.back_references = back_references
if back_references then
-- When notes are cached, `back_references` field will have the references from before.
-- Since the files that refer to this one might have changed, we'll overwrite it here.
-- extract_back_references() already re-processes the references.
note.back_references = back_references
end
::continue::
end end
return all_notes ::continue::
end
return all_notes
end end
function M.get_tags() function M.get_tags()
local notes = M.get_notes() local notes = M.get_notes()
local tags = {} local tags = {}
for _, note in ipairs(notes) do for _, note in ipairs(notes) do
if #note.tags == 0 then if #note.tags == 0 then
goto continue goto continue
end
for _, tag in ipairs(note.tags) do
table.insert(tags, {
linenr = tag.linenr,
name = tag.name,
file_name = note.file_name,
})
end
::continue::
end end
return tags for _, tag in ipairs(note.tags) do
table.insert(tags, {
linenr = tag.linenr,
name = tag.name,
file_name = note.file_name,
})
end
::continue::
end
return tags
end end
return M return M

View File

@ -14,18 +14,17 @@ else
M.zettel_dir = '~/.zettelkasten/' M.zettel_dir = '~/.zettelkasten/'
end end
local s_config = { if vim.g.zettelkasten_template_directory and vim.g.zettelkasten_template_directory ~= '' then
notes_path = "", M.templete_dir = vim.g.zettelkasten_template_directory
preview_command = "pedit", else
browseformat = "%f - %h [%r Refs] [%b B-Refs] %t", M.templete_dir = '~/.zettelkasten_template'
}
M.get = function()
return s_config
end end
M._set = function(new_config) M.browseformat = "%f - %h [%r Refs] [%b B-Refs] %t"
s_config = vim.tbl_extend("force", s_config, new_config) M.preview_command = "pedit"
M.get = function()
return nil
end end
return M return M

View File

@ -1,54 +1,55 @@
local M = {} local M = {}
local s_formatters = { local s_formatters = {
["%r"] = function(line) ['%r'] = function(line)
return #line.references return #line.references
end, end,
["%b"] = function(line) ['%b'] = function(line)
return #line.back_references return #line.back_references
end, end,
["%f"] = function(line) ['%f'] = function(line)
return vim.fn.fnamemodify(line.file_name, ":t") return vim.fn.fnamemodify(line.file_name, ':t')
end, end,
["%h"] = function(line) ['%h'] = function(line)
return line.title return line.title
end, end,
["%d"] = function(line) ['%d'] = function(line)
return line.id return line.id
end, end,
["%t"] = function(line) ['%t'] = function(line)
local tags = {} local tags = {}
for _, tag in ipairs(line.tags) do for _, tag in ipairs(line.tags) do
if vim.tbl_contains(tags, tag.name) == false then if vim.tbl_contains(tags, tag.name) == false then
table.insert(tags, tag.name) table.insert(tags, tag.name)
end end
end end
return table.concat(tags, " ") return table.concat(tags, ' ')
end, end,
} }
local function get_format_keys(format) local function get_format_keys(format)
local matches = {} local matches = {}
for w in string.gmatch(format, "%%%a") do for w in string.gmatch(format, '%%%a') do
table.insert(matches, w) table.insert(matches, w)
end end
return matches return matches
end end
function M.format(lines, format) function M.format(lines, format)
local formatted_lines = {} local formatted_lines = {}
local modifiers = get_format_keys(format) local modifiers = get_format_keys(format)
for _, line in ipairs(lines) do for _, line in ipairs(lines) do
local cmps = format local cmps = format
for _, modifier in ipairs(modifiers) do for _, modifier in ipairs(modifiers) do
cmps = string.gsub(cmps, "%" .. modifier, s_formatters[modifier](line)) local rst = s_formatters[modifier](line) or ''
end cmps = string.gsub(cmps, '%' .. modifier, rst)
table.insert(formatted_lines, cmps)
end end
return formatted_lines table.insert(formatted_lines, cmps)
end
return formatted_lines
end end
return M return M

View File

@ -1,8 +1,12 @@
local api = vim.api --=============================================================================
local s_config = require("zettelkasten.config") -- zettelkasten.lua --- init plugin for zk
-- Copyright (c) 2016-2022 Wang Shidong & Contributors
-- Author: Wang Shidong < wsdjeg@outlook.com >
-- URL: https://spacevim.org
-- License: GPLv3
--=============================================================================
if vim.fn.exists(":ZkNew") == 0 then if vim.fn.exists(":ZkNew") == 0 then
vim.cmd([[command ZkNew :lua _G.zettelkasten.zknew()]]) vim.api.nvim_create_user_command("ZkNew", ":lua require('zettelkasten').zknew({})", {})
end end
if vim.fn.exists(":ZkBrowse") == 0 then if vim.fn.exists(":ZkBrowse") == 0 then
@ -12,19 +16,7 @@ end
_G.zettelkasten = { _G.zettelkasten = {
tagfunc = require("zettelkasten").tagfunc, tagfunc = require("zettelkasten").tagfunc,
completefunc = require("zettelkasten").completefunc, completefunc = require("zettelkasten").completefunc,
zknew = function() zknew = require("zettelkasten").zknew,
vim.cmd([[new | setlocal filetype=markdown]])
if s_config.zettel_dir ~= "" then
if vim.fn.isdirectory(s_config.zettel_dir) == 0 then
vim.fn.mkdir(vim.fn.expand(s_config.zettel_dir), 'p', '0700')
end
vim.cmd("lcd " .. s_config.zettel_dir)
end
vim.cmd("normal ggI# New Note")
require("zettelkasten").set_note_id(vim.api.nvim_get_current_buf())
vim.cmd("normal $")
end,
zkbrowse = function() zkbrowse = function()
vim.cmd("edit zk://browser") vim.cmd("edit zk://browser")
end, end,

View File

@ -1,2 +1,6 @@
indent_type = "Spaces"
column_width = 100 column_width = 100
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 2
quote_style = "AutoPreferSingle"
call_parentheses = "Always"

View File

@ -3,6 +3,7 @@ lua require('telescope').load_extension('messages')
lua require('telescope').load_extension('project') lua require('telescope').load_extension('project')
lua require('telescope').load_extension('scriptnames') lua require('telescope').load_extension('scriptnames')
lua require('telescope').load_extension('neoyank') lua require('telescope').load_extension('neoyank')
lua require('telescope').load_extension('zettelkasten_template')
if filereadable(g:_spacevim_root_dir . 'bundle/telescope-fzf-native.nvim/build/libfzf.so') if filereadable(g:_spacevim_root_dir . 'bundle/telescope-fzf-native.nvim/build/libfzf.so')
\ || filereadable(g:_spacevim_root_dir . 'bundle/telescope-fzf-native.nvim/build/libfzf.dll') \ || filereadable(g:_spacevim_root_dir . 'bundle/telescope-fzf-native.nvim/build/libfzf.dll')
lua require('telescope').load_extension('fzf') lua require('telescope').load_extension('fzf')

View File

@ -20,19 +20,33 @@ This layer adds support for zettelkasten in neovim.
## Install ## Install
To use this configuration layer, update your custom configuration file with: This layer also requires `telescope` layer, so to use this configuration layer,
update your custom configuration file with:
```toml ```toml
# load the zettelkasten layer
[[layers]] [[layers]]
name = "zettelkasten" name = "zettelkasten"
# load the fuzzy finder layer: telescope
[[layers]]
name = "telescope"
``` ```
## Layer options ## Layer options
- `zettel_dir`: set the default zettelkasten directory - `zettel_dir`: set the zettelkasten directory, default is `~/.zettelkasten/`
- `zettel_template_dir`: set the zettelkasten template directory, default is `~/.zettelkasten_template`
## Key bindings ## Key bindings
| Key bindings | description | | Key bindings | description |
| ------------ | --------------- | | ------------ | ----------------------------- |
| `SPC m z n` | create new note | | `SPC m z n` | create new note |
| `SPC m z t` | create new note with template |
| `SPC m z b` | open zettelkasten browse |
In the zettelkasten browse buffer:
| key bindings | description |
| ------------ | ---------------- |
| `K` | preview the note |

View File

@ -0,0 +1,53 @@
local action_state = require("telescope.actions.state")
local actions = require("telescope.actions")
local conf = require("telescope.config").values
local entry_display = require("telescope.pickers.entry_display")
local finders = require("telescope.finders")
local pickers = require("telescope.pickers")
local zk_config = require("zettelkasten.config")
local function prepare_output_table()
local lines = {}
local result = vim.fn.globpath(zk_config.templete_dir, '**/*', 0, 1)
for _, templete in ipairs(result) do
table.insert(lines, templete)
end
return lines
end
local function show_script_names(opts)
opts = opts or {}
pickers.new(opts, {
prompt_title = "ZettelKasten Templete",
finder = finders.new_table {
results = prepare_output_table()
},
sorter = conf.generic_sorter(opts),
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
local entry = action_state.get_selected_entry()
actions.close(prompt_bufnr)
-- the file name is entry.value
-- do something with the file
vim.cmd('ZkNew')
local templete_context = vim.fn.readfile(entry.value, '')
vim.api.nvim_buf_set_lines(0, 0, -1, false, templete_context)
-- maybe this is a bug, the mode is insert mode.
vim.cmd('stopinsert')
end)
return true
end,
}):find()
end
local function run()
show_script_names()
end
return require("telescope").register_extension({
exports = {
-- Default when to argument is given, i.e. :Telescope scriptnames
zettelkasten_template = run,
},
})