summaryrefslogtreecommitdiff
path: root/developers.md
diff options
context:
space:
mode:
authorSimon Hauser <Simon-Hauser@outlook.de>2021-09-13 22:03:41 +0200
committerSimon Hauser <Simon-Hauser@outlook.de>2021-09-16 11:12:12 +0200
commit5131df7df17d640191201ddb462e863022d7a61b (patch)
treeb5eeb8435cf1d5e76e36808bfe2ef7887342191b /developers.md
parentaaffa84ebb0d411eafe2347e2ee0424af1199219 (diff)
docs: rewrite readme and add missing config values + builtin opts
Diffstat (limited to 'developers.md')
-rw-r--r--developers.md312
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`