diff --git a/docs/config.md b/docs/config.md new file mode 100644 index 0000000..ba77eba --- /dev/null +++ b/docs/config.md @@ -0,0 +1,134 @@ +--- +title: Source +description: Type description of care.nvim config +author: + - max397574 +categories: + - docs, + - types +--- + +# General + +The config of care is used to configure the ui and care itself. + +There are two main parts to the config. The first one is the `ui` field and the second on is the +rest of the configuration which is for configuring care itself. + +## UI + +In the ui field the completion menu, the docs view and the format of the entries are configured. +There is also a field for configuring type icons. + +## Snippet expansion + +Here a function for expanding snippets is defined. By default this is the builtin +`vim.snippet.expand()`. You can also use a plugin like luasnip for this like this: + +```lua +snippet_expansion = function(body) + require("luasnip").lsp_expand(body) +end +``` + +## Selection behavior + +With the selection behavior the user can determine what happens when selecting an entry. This can +either be `"select"` or `"insert"`. Selecting will just select the entry and do nothing else. Insert +will actually insert the text of the entry (this is not necessarily the whole text). + +## Keyword pattern + +Pattern used to determine keywords, used to determine what to use for filtering and what to +remove if insert text is used. + +## Completion events + +The `completion_events` table is used to set events for completion. By default it just contains +`"TextChangedI"`. You can set it to an empty table (`{}`) to disable autocompletion. + +## Sources + +TODO + +## Preselect + +Whether items should be preselected or not + +## Enabled + +This function can be used to disable care in certain contexts. By default this disables +care in prompts. + +# UI + +The ui configuration is used to configure the whole ui of care. One of the main goals of +this is to be as extensible as possible. This is especially important for the completion entries. +Read more about that under [Configuraton of item display](./design.md#configuraton-of-item-display). + +The most important part for many users will be the `menu` field. It's used to configure the +completion menu. + +You can also configure the documentation view just like the main menu. + +Lastly the users can also configure the icons which will be used for the different items. + +## Ghost text + +with this option the user can determine if ghost text should be displayed. Ghost text is just +virtual text which shows a preview of the entry. + +You can use the `enabled` field to determine whether the ghost text should be enabled or not. +The `position` can either be `"inline"` or `"overlay"`. Inline will add the text inline right +where the cursor is. With the overlay position the text will overlap with existing text after the +cursor. + +## Menu + +This configuration should allow you to completely adapt the completion menu to your likings. + +It includes some basic window properties like the border and the maximum height of the window. It +also has a field to define the character used for the scrollbar. +Set `scrollbar` to `nil` value to disable the scrollbar. + +## Position + +If the menu should be displayed on top, bottom or automatically + +Another field is `format_entry`. This is a function which recieves an entry of the completion +menu and determines how it's formatted. For that a table with text-highlight chunks like +`:h nvim_buf_set_extmarks()` is used. You can create sections which are represented by tables +and can have a different alignment each. This is specified with another field which takes a table +with the alignment of each section. + +For example you want to have the label of an entry in a red highlight and an icon in a entry-kind +specific color left aligned first and then the source of the entry right aligned in blue. +You could do that like this: + +```lua +format_entry = function(entry) + return { + -- The first section with the two chunks for the label and the icon + { { entry.label .. " ", "MyRedHlGroup" }, { entry.kind, "HighlightKind" .. entry.kind } } + -- The second section for the source + { { entry.source, "MyBlueHlGroup" } } + } +end, +alignment = { "left", "right" } +``` + +Notice that there are multiple differences between having one table containing the chunks for the +label and kind and having them separately. The latter would require another entry in the `alignment` +table. It would also change the style of the menu because the left sides of the icons would be +aligned at the same column and not be next to the labels. In the example there also was some +spacing added in between the two. + +## Documentation view + +This configuration allows you to configure the documentation view. +It consists of some basic window properties like the border and the maximum height of the window. +It also has a field to define the character used for the scrollbar. + +## Type Icons + +This is a table which defines the different icons. diff --git a/docs/context.md b/docs/context.md new file mode 100644 index 0000000..804eb1c --- /dev/null +++ b/docs/context.md @@ -0,0 +1,52 @@ +--- +title: Index +description: Type description of context +author: + - max397574 +categories: + - docs, + - types +--- + +This is a class representing the current state. It includes buffer number and cursor position. It +is passed to completion sources to get completions. + +# Methods + +## Changed + +Whether the context changed in comparison to the previous one. This is used to check whether to +get new completions or not. + +## New + +Create a new context. This takes the previous one as argument. This one is stored to determine if +the context changed or not when completing. +The previous context of the previous one is deleted so this data structure doesn't grow really +large. + +# Fields + +## Previous + +The previous context which is used to determine whether the context changed or not. + +## Cursor + +The cursor positon. + +## Bufnr + +Number of the buffer. + +## Reason + +Reason for triggering completion. + +## Current line + +The current line. + +## Line before cursor + +Part of the current line which is before the cursor. diff --git a/docs/core.md b/docs/core.md new file mode 100644 index 0000000..bc74668 --- /dev/null +++ b/docs/core.md @@ -0,0 +1,63 @@ +--- +title: Core +description: Type description of care.nvim source +author: + - max397574 +categories: + - docs, + - types +--- + +# General + +This module is for the core of care. There all comes together with the menu being opened +and the completion triggered. + +## New + +Use this function to create a new instance. + +# Methods + +## Complete + +This function starts the completion. It goes through all the sources, triggers them (completion +or sorting) and opens the menu with the result. + +## On Change + +This function is invoked on every text change. It updates the context field and triggers +completion if it changed. + +## Block + +The `block` method can be used to temporarily disable care. It returns a function which is +used to unblock it again. +This is used for the `insert` selection behavior where you don't want to get new completions when +changing the text. + +## Setup + +The setup function is used to setup care so it will actually provide autocompletion when +typing by setting up an autocommand. + +# Fields + +## Context + +This is used to store the current context. There is always a new one created in `on_change` and +compared to see if it changed. + +## Menu + +In this field a menu instance which is used in core is stored. + +## Blocked + +This field is used by the [Block](#block) method. It just completely disables autocompletion when set +to true. + +## Last opened at + +This variable is used to determine where a new completion window was opened for the last time. +This is used to determine when to reopen the completion window. diff --git a/docs/design.md b/docs/design.md new file mode 100644 index 0000000..3069358 --- /dev/null +++ b/docs/design.md @@ -0,0 +1,210 @@ +--- +title: Design +description: Design of care.nvim +author: + - max397574 +categories: + - docs +--- + +# General + +There is the [care.nvim](https://github.com/max397574/care.nvim) plugin. This is +the main module of the whole completion architecture. Then there are also sources, which is where +the core gets it's completions from. + +## Care.nvim + +This is the core of the autocompletion. From here the sources are used to get completions which +are then displayed in the [Completion Menu](#completion-menu) + +### Completion Menu + +The completion menu displays the current completions. +Features that it should have: + +- Completely customizable display for every entry (with **text-highlight chunks** like extmark-api) +- Customizable scrollbar +- Customizable window properties + - Border + - Max height +- Docview + - Customizable + - Try to get nicely concealed like in core or noice.nvim + - Allow to send to e.g. quickfix or copy + +# Terms + +## Offset + +Offset always describes the distance between e.g. the start of an entry from the beginning of the +line. + +# Architecture + +TODO: fancy ascii diagramms + +autocompletion: + +1. `TextChangedI` or `CursorMovedI` +2. get the context (line before, cursor position etc) +3. Check if context changed +4. Check if character was a trigger character or completion was triggered manually +5. Depending on ^^ decide what to do _for every source_: + - Get new completions + 1. get completions from source based on context + - sort completions + 1. Use characters found with `keyword_pattern` to fuzzy match and sort completions +6. Collect all the completions +7. Open menu to display thing + 1. if there is a selected one: + - highlight selected one + - show preview of selected completion + - show docs + +When completing (e.g. ``): + +1. check if menu is open +2. check if anything is selected (or autoselect option) +3. complete + 1. insert text + 2. additional text edits (check core functions) + 3. snippet expansion (core or luasnip) +4. close menu + +# Motivation + +## Nvim-cmp + +These days nvim-cmp is the most popular completion-engine for neovim. There are some mayor issues +me and also other people in the community have with cmp. + +### Bad code/Documentation + +The code of nvim-cmp is often quite unreadable. Sometimes this might be due to optimizations +and surely some of it has just grown historically. Also there are nearly no docs on how the +whole completion engine works. The api for new sources is quite unclear and far from optimal. +While this doesn't really matter to a user it definitely does to a potential contributor and +developers of sources. + +### Legacy code/features + +There are a lot of things which grew just historically. The author of nvim-cmp is +(understandable to a certain degree) afraid of making breaking changes and fixing them or just +doesn't think changes are necessary. + +#### Configuration of item display + +One such example is the configuration of how items are displayed in the menu. This works with +a function `formatting` which takes a completion item and is allowed to return an item where +the three fields `menu`, `kind` and `abbr` and three more fields for highlights for those can +be set. So apart from the background and border color of the menu you're limited to have three +different fields and colors in your menu E.g. source name, kind name, kind icon and text isn't +possible. It's also not possible to have round or half blocks around icons because you don't +have enough colors. An example of an issue can be found [here](https://github.com/hrsh7th/nvim-cmp/issues/1599). +You also can't add padding wherever you want and you can't align the fields as you want. + +#### Legacy code + +There is e.g. the whole "native menu" thing laying around in the codebase. Nowadays this isn't +really needed anymore. Everything of it can be accomplished with the "custom menu". There is a +lot of duplicate code because of that. + +### Mapping system + +The mapping system is quite confusing. It's a table in the config with keys to be mapped as keys +and a call to `cmp.mapping()` with a callback to the actual functionality as value. +Users should able to just use normal mappings or functions with `vim.keymap.set`. + +### Custom solutions for builtin functionality + +An example for this is the [Mapping system](#mapping-system). Another example would be the `cmp.event.on` +which could just be done with User autocmds. + +### Why not contribute? + +The maintainer is in general quite conservative. There were pull-requests for many features open +which were liked by the community (seen by reactions and comments). But they were abandoned +because the maintainer saw no reason to add it. There was for example a pull-request to fix the +issue with the limited fields in the configuration [here](https://github.com/hrsh7th/nvim-cmp/pull/1238). +This pull request was closed because _No specific use cases have emerged at this stage._ +according to the author. Even though there was clearly a problem described and what the pr would +allow (this pr allowed custom fields which still isn't nice but fixed the obvious problems). +There were also some features (in particular the custom scrollbars) removed because there were +some issues with it which apparently weren't worth fixing for the feature. +So it's not really motivating to try to contribute new things. It's also quite hard because of +the messy code with lots of legacy code. + +# Goals + +## Use nvim-cmp sources + +We should be able to use nvim-cmp sources. This should be possible by adding a `package.loaders` +where we can redirect calls to `cmp.register_source` (which happens in most sources auto- +matically) to our own plugin. We **don't want to adapt to cmp's apis** for this though. We won't +extend our own formats e.g. for entries or sources to match cmps. Even when it's complicated we +will just convert between the different formats. + +## Native things + +Use as many native things as possible. This includes setting mappings with `vim.keymap.set` or +add events as user autocmd events. + +# Non-Goals + +## Different views + +Nvim-cmp has different views. At the moment wild-menu, native menu and custom menu. There is a +lot of code duplication because of this. We'd like to avoid having multiple views. The native +one isn't needed anyway (it likely is just in cmp for historical reasons). +In the future we'd like to allow injecting custom views via config where you just get the +entries and do things with them yourself. This is mostly to avoid code duplication in core. + +## Commandline completion + +At the moment no command line completion is planned. This is because the author thinks it's not +really needed because builtin completion is already quite good and there is little value added +by adding commandline completion. Also it doesn't really make sense in my opinion to combine +commandline completion and autocompletion for buffer contents in the same plugin. Especially if +you try to share things in between like nvim-cmp does. + +# Types used + +The types should minimally be the lsp things (for the context passed to source, for response and +for entries). Everything additionally is mostly optional. + +# Code style + +## Object-Orientation + +Most of the modules are written object oriented. This decision was made because it's way easier +to create new instances of the things and associate data with them. + +## Functions + +You should always write functions in the form of `[local] function ()` as +opposed to `[local = function()`. The first notation provides the advantage +that you can directly jump to it's definition and you won't get multiple results (the name and +the anonymous function). + +## Comments and annotations + +Add annotations to **every** public function of a module (e.g. with neogen) and add comments +explaining what the code does. We'd like to have code which would be understandable for outsiders. +Also try to add annotations and descriptions to local functions but this isn't as important as +public ones + +### Format + +For The annotations we use [LuaCATS](https://luals.github.io/wiki/annotations/) style. For types +don't use a space after the `---` marker. For comments you should. Check the annotations in +`lua/care/types/` for examples. + +## Types + +We have files for types which are tangled from a norg file (this one?) using lua-ls annotations. +They are prefixed with `care.`. +As often as possible we should try to use the `lsp.*` types which are in neovim core. + +The types are documented in the `docs/` folder and are tangled to lua type files with [neorg](https://github.com/nvim-neorg/neorg). +So if you want to change a type annotation you should change the `.norg` file and tangle it again. diff --git a/docs/entry.md b/docs/entry.md new file mode 100644 index 0000000..23a98fd --- /dev/null +++ b/docs/entry.md @@ -0,0 +1,58 @@ +--- +title: Entry +description: Type description of care.nvim entry +author: + - max397574 +categories: + - docs, + - types +--- + +# General + +Entries are the basic items in the completion menu. Arguably the most important field is the +completion item for which the lsp type is used. + +# Methods + +## New + +The new function is the constructor for a new completion entry. + +## Get insert text + +This function is used to get the text that will be inserted for the entry. This is important for +the ghost text. + +## Get insert word + +This function is used to get part of the text that will be inserted for the entry. It just uses +a pattern to match the insert text and get the beginning of it which matches a vim `word`. This +is often e.g. the method name but without the parentheses and parameter names. That function is +used for the `insert` selection behavior. + +# Fields + +## Source + +This is the source from which the entry came. This is important for using the right keyword +pattern and getting the right offset. + +## Context + +This is the context in which the entry was completed. This is important to now what context text- +edits of the entry target. + +## Matches + +Position of matches which were found during filtering. This is just used to highlight them in the +completion menu with `@care.match`. + +## Score + +This is the score obtained from filtering. It is used to sort which happens in the +`care.sorter` module. + +## Get Offset + +Essentially where entry insertion should happen (column) diff --git a/docs/internal_source.md b/docs/internal_source.md new file mode 100644 index 0000000..cefef0a --- /dev/null +++ b/docs/internal_source.md @@ -0,0 +1,52 @@ +--- +title: Internal source +description: Type description of internal neovim source +author: + - max397574 +categories: + - docs, + - types +--- + +# General + +The internal sources are used on top of [completion sources](#sourcemd) to store additional +metadata about which the source author doesn't have to care and sometimes can't know. + +## Source + +This field is used to store the source written by the source author. + +## Entries + +In the entries field entries gotten from the source are stored. This is used to be able to sort +and filter the entries when not getting new ones. + +## New + +This function creates a new instance. + +## Incomplete + +Here a boolean is set which shows whether the source already completed all it's entries or not. +This is mostly used by sources for performance reasons. + +## Get keyword pattern + +This function is used to get the keyword pattern for the source. It uses the string field, the +method to get it and as fallback the one from the config. + +## Get trigger characters + +This function is used to get the trigger characters for the source. At the moment it just checks +if the method exists on the source and otherwise just returns an empty table. + +## Get offset + +With this function the offset of the source is determined. The offset describes at which point +the completions for this source start. This is required to be able to remove that text if needed +and to determine the characters used for filtering and sorting. + +## Is enabled + +This function checks whether the function is enabled or not based on it's config. diff --git a/docs/menu.md b/docs/menu.md new file mode 100644 index 0000000..c9daa58 --- /dev/null +++ b/docs/menu.md @@ -0,0 +1,126 @@ +--- +title: Menu +description: Type description of care.nvim menu +author: + - max397574 +categories: + - docs, + - types +--- + +# General + +This is the main class of the care completion menu. The menu is used to display completion +entries and also contains the logic for selecting and inserting the completions. + +# Internals + +## Index + +The index is used to determine the selected entry. It is used to get this entry when confirming +the completion. +The function to select the next and previous entries simply change this index. + +# Methods + +## New + +Creates a new instance of the completion menu. + +## Draw + +Draws the menu. This includes formatting the entries with the function from the config and +setting the virtual text used to display the labels. It also adds the highlights for the selected +entry and for the matched chars. + +## Is open + +This is a function which can be used to determine whether the completion menu is open or not. +This is especially useful for mappings which have a fallback action when the menu isn't visible. + +## Select next + +This function can be used to select the next entry. It accepts a count to skip over some entries. +It automatically wraps at the bottom and jumps up again. + +## Select prev + +This function is used to select the previous entry analogous to [Select next](#select-next) + +## Open + +The `open` function is used to open the completion menu with a specified set of entries. This +includes opening the window and displaying the text. + +## Close + +This function closes the menu and resets some internal things. + +## Get active entry + +With this function you can get the currently selected entry. This can be used for the docs view +or some other api functions. It is also used when the selection is confirmed. + +## Confirm + +This is the function to trigger the completion with a selected entry. It gets the selected entry +closes the menu and completes. + +## Complete + +This function completes with a given entry. That means it removes text used for filtering +(if necessary), expands snippet with the configured function, applies text edits and lsp +commands. + +## Readjust window + +This function readjusts the size of the completion window without reopening it. + +## Docs Visible + +Checks whether docs are visible or not + +## Scroll docs + +Scroll up or down in the docs window by `delta` lines. + +# Fields + +## Menu Window + +## Docs Window + +## Ghost text + +The ghost text instance used to draw the ghost text. + +## Entries + +This field is used to store all the entries of the completion menu. + +## Namespace + +The namespace is used to draw the extmarks and add the additional highlights. + +## Config + +In this field the user config is stored for easier access. + +## Buffer + +This is the buffer used for the menu. It's just created once when initially creating a new +instance. + +## Window + +Window number of the window used to display the menu. This is always newly created when the menu +gets opened and is only set if the menu is open. + +## Index + +The index is used to get and track the currently selected item. It gets modified by the functions +to select next and previous entry. + +## Scrollbar Buffer + +This field is used to store the buffer for drawing the scrollbar. diff --git a/docs/misc.md b/docs/misc.md new file mode 100644 index 0000000..a667a9b --- /dev/null +++ b/docs/misc.md @@ -0,0 +1,21 @@ +--- +title: Misc +description: Misc types +author: + - max397574 +categories: + - docs, + - types +--- + +# Completion context + +The completion context describes the current context. It's used so not every source has again to +determine e.g. where the cursor is in the file and what text was typed. The completion context +required by the lsp is part of this context. + +# Reason + +This type is used in the core to determine why completion was triggered. This is important because +if completion was triggered automatically it will only fetch new completions if there aren't any +or if a trigger character was typed. Otherwise it will just sort existing ones. diff --git a/docs/source.md b/docs/source.md new file mode 100644 index 0000000..acec492 --- /dev/null +++ b/docs/source.md @@ -0,0 +1,73 @@ +--- +title: Source +description: Type description of care.nvim source +author: + - max397574 +categories: + - docs, + - types +--- + +# General + +The sources are used to get get completions for care.nvim. + +# Fields + +## Name + +There are two fields for the name of a source. They are both strings. The `name` field is used for +configuring the source. It should just contain characters, `_`, and `-`. There is also the +`display_name` field. This name is displayed in sources overview. It can be any string. + +The display name is optional and falls back to the normal name. + +# Methods + +## `is_available()` + +Each source can have a function to show whether it's available or not. If your source should +for example be enabled for a certain filetype you can just do it like this: + +```lua +function my_source.is_available() + return vim.bo.ft == "lua" +end +``` + +This function will be called quite often so developers should try to keep it more or less +performant. This won't be an issue in the vast majority of cases though. + +## Resolve + +This is a function used to get additional details for completion items. This is especially +important for the lsp source which needs to send the `completionItem/resolve` request. +Resolving completion items is used for performance reasons so e.g. the documentation for an item +doesn't always have to be sent. + +## `get_trigger_characters()` + +This function should return characters which trigger completion for the source. If one of those +characters is types the completion will be retriggered. Otherwise newly entered characters are +used for sorting and filtering. +An example for this could be `.`, `\\` and `/` when working with paths. + +```lua +function my_source.get_trigger_characters() + return { ".", "\\", "/" } +end +``` + +## Keyword pattern + +The keyword pattern is used to overwrite the keyword pattern from the config per source. It +should basically represent the format of entries the source will provide as regex. +It can either be provided as a string with `keyword_pattern` or dynamically with +`get_keyword_pattern`. +The `get_keyword_pattern` function has higher priority and will overwrite the string if provided. + +## Complete + +This is arguably the most important function of each source. This function returns completions. +The function takes in a [completion context](./index.md#completion-context) and should return a +list of [entries](#entrymd).