diff options
| author | Simon Hauser <Simon-Hauser@outlook.de> | 2021-09-13 22:03:41 +0200 |
|---|---|---|
| committer | Simon Hauser <Simon-Hauser@outlook.de> | 2021-09-16 11:12:12 +0200 |
| commit | 5131df7df17d640191201ddb462e863022d7a61b (patch) | |
| tree | b5eeb8435cf1d5e76e36808bfe2ef7887342191b /developers.md | |
| parent | aaffa84ebb0d411eafe2347e2ee0424af1199219 (diff) | |
docs: rewrite readme and add missing config values + builtin opts
Diffstat (limited to 'developers.md')
| -rw-r--r-- | developers.md | 312 |
1 files changed, 306 insertions, 6 deletions
diff --git a/developers.md b/developers.md index 37b02ff..7284727 100644 --- a/developers.md +++ b/developers.md @@ -1,15 +1,311 @@ +# Developers +- [Introduction](#introduction) +- [Guide to your first Picker](#guide-to-your-first-picker) + - [Requires](#requires) + - [First Picker](#first-picker) + - [Replacing Actions](#replacing-actions) + - [Entry Maker](#entry-maker) + - [Oneshot job](#oneshot-job) + - [Previewer](#previewer) + - [More examples](#more-examples) +- [Technical](#technical) + - [picker](#picker) + - [finders](#finders) + - [actions](#actions) + - [previewers](#previewers) -## Overriding actions/action_set +## Introduction + +So you want to develop your own picker and/or extension for telescope? Then you +are in the right place! This file will first present an introduction on how to +do this. After that, this document will present a technical explanation of +pickers, finders, actions, and the previewer. You will find more information +in specific help pages and we likely will move some of the technical stuff to +our vim help docs in the future. + +This guide is mainly for telescope so it will assume that a lua knowledge is +present. You can find information for lua here: +- [Lua 5.1 Manual](https://www.lua.org/manual/5.1/) +- [Getting started using Lua in Neovim](https://github.com/nanotee/nvim-lua-guide) + +## Guide to your first Picker + +To guide you along the way to first picker we will do the following. We will +open a empty lua scratch file in which we will develop the picker and run it +each time using `:luafile %`. Later this file then be bundled as extension. + +### Requires + +The most important includes are the following modules: +```lua +local pickers = require "telescope.pickers" +local finders = require "telescope.finders" +local conf = require("telescope.config").values +``` + +- `pickers` is the main module which is used to create a new picker. +- `finders` provides interfaces to fill the picker with items. +- `config` which is used for user configuration and the `values` table holds + these configurations. So to make it easier we only get this table in `conf`. + +### First Picker + +We will now make the most simplest color picker. (Note that the previous snippet +is also required. We will approach this example step by step). + +```lua +-- our picker function: colors +local colors = function(opts) + pickers.new(opts, { + prompt_title = "colors", + finder = finders.new_table { + results = { "red", "green", "blue" } + }, + sorter = conf.generic_sorter(opts), + }):find() +end + +-- to execute the function +colors() +``` + +Running this file should open a telescope picker with the entries `red`, +`green`, `blue`. Pressing enter will open a new file, depending which element is +selected, in this case this is not what we want so we will address this after +explaining this snippet. + +We will define a new function which will take in a table `opts`. This is good +practice because now the user can define the behavior of the picker, for example +change the theme. That the user is able to change the theme we need to pass in +`opts` as the first argument to `pickers.new`. The second argument is a table +that defines the default behavior of the picker. + +We can define a `prompt_title`, this option is not required, default will be +`Prompt` if not set. + +`finder` is a required field that needs to be set to the result of a `finders` +function. In this case we take `new_table` which allows us to define a static +set of values, `results`, which is a array of elements, in this case our colors +as strings. It doesn't have to be a array of strings, it can also be a array of +tables. More to this later. + +`sorter` on the other hand is not a required field but its good practice to +define it, because the default value will set it to `empty()`, meaning no sorter +is attached and you can't filter the results. Good practice is to set the sorter +to either `conf.generic_sorter(opts)` or `conf.file_sorter(opts)`. Setting it to +a `conf` value will respect user configuration, so if a user has setup +`fzf-native` as sorter then this decision will be respected and the fzf sorter +will be attached. Its also suggested to pass in opts here because the sorter +could make use of it. As an example the fzf sorter can be configured to be case +sensitive or insensitive. A user can setup a default behavior and then alter +this behavior with the `opts` table. + +After the picker is defined you need to call `find()` to actually start the +picker. + +### Replacing Actions + +Now calling `colors()` will result in the opening of telescope with the values. +`red`, `green` and `blue`. The default theme isn't optimal for this picker so we +want to change it and thanks to the acceptance of `opts` we can. We will replace +the last line with the following to open the picker with the `dropdown` theme. + +```lua +colors(require("telescope.themes").get_dropdown{}) +``` + +Now lets address the issue that selecting a color opens a new buffer. For that +we need to replace the default select action. The benefit of replace rather than +mapping a new function to `<CR>` is that it will respect user configuration. So +if a user has remapped `select_default` to another key then this decision will +be respected and it works as expected for the user. + +To make this work we need more includes at the top of the file. + +```lua +local actions = require "telescope.actions" +local action_state = require "telescope.actions.state" +``` + +- `actions` holds all actions that can be mapped by a user and we need it to + access the default action so we can replace it. Also see `:help + telescope.actions` + +- `action_state` gives us a couple of util function we can use to get the + current picker, current selection or current line. Also see `:help + telescope.actions.state` + +So lets replace the default action. For that we need to define a new key value +pair in our table that we pass into `pickers.new`, for example after `sorter`. + +```lua + attach_mappings = function(prompt_bufnr, map) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + -- print(vim.inspect(selection)) + vim.api.nvim_put({ selection[1] }, "", false, true) + end) + return true + end, +``` + +So we do this by setting the `attach_mappings` key to a function. This function +needs to return either `true` or `false`. If it returns false it means that only +the actions defined in the function should be attached. So no +`move_selection_{next,previous}`, so most of the cases you want that this +function returns `true`. If the function does not return anything a error is +thrown. The `attach_mappings` function will get to parameters passed in +`prompt_bufnr` the buffer number of the prompt buffer, which we can use to get +the pickers object, and `map` a function we can use to map actions or functions +to arbitrary key sequences. + +Now we are replacing `select_default` the default action that happens on `<CR>` +(if not remapped). To do so we need to call `actions.select_default:replace` and +pass in a new function. In this new function we first close the picker with +`actions.close` and then get the `selection` with `action_state`. Its important +to notice that you can still get the selection and current prompt input +(`action_state.get_current_line()`) with `action_state` even tho the picker is +already closed. You can look at the selection with +`print(vim.inspect(selection))` and you will see that it differs from our input +(string), this is because we will internally pack it in a table with different +keys. You can specify this behavior and we will talk about that in the next +section. Now all that is left is to do anything with the selection we have. In +this case we just put the text in the current buffer. + +### Entry Maker + +Entry maker is a function that is used to transform a item from the finder to a +internal entry table, which has a couple of required keys. It allows to have a +different display and match something completly different. It also allows to set +a absolute path (so the file will always be found) and a relative file path as +display and for sorting. This allows that the relative file path doesn't even +have to be valid in the context of the current working directory. + +We will now try to define a our entry maker for our example by providing a +`entry_maker` to `finders.new_table` and changing our table to be a little bit +more interesting. We will end up following new input for `finders.new_table`: + +```lua + finder = finders.new_table { + results = { + { "red", "#ff0000" }, + { "green", "#00ff00" }, + { "blue", "#0000ff" }, + }, + entry_maker = function(entry) + return { + value = entry, + display = entry[1], + ordinal = entry[1], + } + end + }, +``` + +With the new snippet we now no longer have a array of strings but a array of +tables. Each table has a color name and the hex value. + +`entry_maker` is a function that will receive each table and then we can set the +values we want to set. Its best practice to have a `value` reference to the +original entry, that way you can access the whole table in your action later. + +The first required key is `display` and is either a string or a `function(tbl)`, +where `tbl` the table that is returned by `entry_maker`. For a lot of values its +suggested to have display as function especially if you are modifying it because +then the function will only be executed for the entries that are being +displayed. For examples of entry maker take a look at +`lua/telescope/make_entry.lua`. A good way to make your `display` more like a +table is to use `displayer` which can be found in +`lua/telescope/entry_display.lua`. A more simple example of `displayer` is the +function `gen_from_git_commits` in `make_entry.lua`. + +The second required key is `ordinal`, which is used for sorting. So you can have +different display and sorting values. This allows `display` to be more fancier +with icons and special indicators and a separate sorting key. + +There are more important keys which can be set but do not make sense in the +current context: +- `path`: to set the absolute path of the file to make sure its always found +- `lnum`: to specify a line number in the file. This will allow the + `conf.grep_previewer` to show that line and the default action to jump to + that line. + +### Previewer + +We will not write a previewer for this picker because it makes less sense and is +a more advanced topic. Its already documented pretty good under `:help +telescope.previewers` so you should read this section if you want to write your +own `previewer`. If you want a file previewer with or without col you should +default to `conf.file_previewer` or `conf.grep_previewer`. + +### Oneshot Job + +The `oneshot_job` finder can be used to have a async external process which will +produce results and call `entry_maker` on each new line. Example usage would be +`find`. + +```lua +finder = finders.new_oneshot_job { "find", opts }, +``` + +### More examples + +A good way to find more examples is to look into the `lua/telescope/builtin/` +directory which contains all builtin pickers. Another way to find more examples +is to take a look at the [extension wiki page](https://github.com/nvim-telescope/telescope.nvim/wiki/Extensions) +and then at a extension some wrote. + +If you still have questions after reading this guide feel free to ask us for +more information on [gitter](https://gitter.im/nvim-telescope/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +and we happily answer your questions and potentially even improve this guide. Of +course you can also improve this guide by sending a PRs. + +## Technical + +### Picker + +This section is an overview of how custom pickers can be created and configured. + +```lua +-- lua/telescope/pickers.lua +Picker:new{ + prompt_title = "", + finder = FUNCTION, -- see lua/telescope/finder.lua + sorter = FUNCTION, -- see lua/telescope/sorter.lua + previewer = FUNCTION, -- see lua/telescope/previewer.lua + selection_strategy = "reset", -- follow, reset, row + border = {}, + borderchars = {"─", "│", "─", "│", "┌", "┐", "┘", "└"}, + default_selection_index = 1, -- Change the index of the initial selection row +} +``` + +### Finders +<!-- TODO what is finders --> +```lua +-- lua/telescope/finders.lua +Finder:new{ + entry_maker = function(line) end, + fn_command = function() { command = "", args = { "ls-files" } } end, + static = false, + maximum_results = false +} +``` + +### Actions + +#### Overriding actions/action_set How to override what different functions / keys do. TODO: Talk about what actions vs actions sets are -### Relevant Files +##### Relevant Files - `lua/telescope/actions/init.lua` - - The most "user-facing" of the files, which has the actions we provide builtin + - The most "user-facing" of the files, which has the builtin actions that we provide - `lua/telescope/actions/set.lua` - The second most "user-facing" of the files. This provides actions that are consumed by several builtin actions, which allows for only overriding ONE item, instead of copying the same configuration / function several times. - `lua/telescope/actions/state.lua` @@ -18,7 +314,7 @@ TODO: Talk about what actions vs actions sets are - `lua/telescope/actions/mt.lua` - You probably don't need to look at this, but it defines the behavior of actions. -### `:replace(function)` +##### `:replace(function)` Directly override an action with a new function @@ -27,7 +323,7 @@ local actions = require('telescope.actions') actions.select_default:replace(git_checkout_function) ``` -### `:replace_if(conditional, function)` +##### `:replace_if(conditional, function)` Override an action only when `conditional` returns true. @@ -44,7 +340,7 @@ action_set.select:replace_if( ) ``` -### `:replace_map(configuration)` +##### `:replace_map(configuration)` ```lua local action_set = require('telescope.actions.set') @@ -54,3 +350,7 @@ action_set.select:replace_map { [function(e) return e == 0 end] = function(e) return (e + 10) end, } ``` + +### Previewers + +See `:help telescope.previewers` |
