From eb45d2730af750f617534b21fd181c5eee63e2a3 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 14 Sep 2019 12:48:15 +0200 Subject: [PATCH 1/6] add design document for API --- doc/tooltip-api.txt | 171 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 doc/tooltip-api.txt diff --git a/doc/tooltip-api.txt b/doc/tooltip-api.txt new file mode 100644 index 000000000..a0c1fb585 --- /dev/null +++ b/doc/tooltip-api.txt @@ -0,0 +1,171 @@ +*tooltip-api.txt* generic API for handling tooltips + +Vim-lsp offers a generic API that allows overlaying information on the main +buffer, e.g., for `hover` or `PeekDefinition`, here referred to as "tooltip" to +distinguish from vim's popups or neovim's floating windows (which this API is +meant to abstract). + +The API is separated into +1. a `top-level API` for opening and updating tooltips to be called from +functions handling language server responses, +2. an `intermediate-level API` that is implemented separately for each backend +using the specific backend's low-level API. + +Calling the intermediate-level API should be avoided since it is subject to +change in order to adapt to changes in low-level API or to add new backends. + +============================================================================== +TOP-LEVEL API *top-level-api* + +The top-level API offers generic functions for creating and updating tooltip +windows. It distinguishes two types of windows that behave differently: + +1. `cursor tooltips` open near or relative to the cursor (e.g., for `hover`) +and are typically closed quickly, +2. `pum tooltips` open near or relative to the popup menu (e.g., for showing +documentation) and are typically updated rather than closed. + +All the following functions take the same initial arguments: + + - {lines}: A |list| of |String|s that represents the plain-text content of + the popup. + - {filetype}: The |'filetype'| of the popup buffer. This determines the + syntax highlighting of the entire buffer, which ftplugin is used, and so + on. + - {syn-ranges}: A |list| of |dict|s, each representing a highlight group + to be applied to the popup. + + Example of an entry: > + { + 'range': { + 'start': { + 'line': 5, + 'character': 10 + }, + 'end': { + 'line': 5, + 'character': 15 + } + }, + 'group': 'markdownBold' + } +< + Pass an empty |list| `[]` for no additional highlighting (apart from + the syntax highlighting applied for the {filetype}). + - {options}: A |dict| controlling the behavior of the tooltip that can + contain the following keys: + - 'close': conditions when the tooltip should be closed. Possible + values: 'move', 'insert'. + - 'maxwidth': maximal width of the tooltip + - 'border': draw border around tooltip; default: |v:false| + - 'focus': focus tooltip; default: |v:false| + - 'firstline': ??? + - 'cursor': {'align': , 'pos': } ??? + + TODO: add more options, bike-shed names, decide on defaults + + Options not relevant to a function or a backend are ignored. + +show_cursor_tooltip({lines}, {filetype}, {syn-ranges}, {options}) + + Shows a tooltip at the current cursor position, either above or below, + depending on where there is enough space. + + The preview's content is set depending on {lines}, {syn-ranges} and + {filetype}, see above. + + Returns the window ID of the created popup. + +show_pum_tooltip({lines}, {syn-ranges}, {filetype}, {options}) + + Shows a tooltip associated with the currently selected item in the popup + menu. It can be either to the left/right of the item, depending on where + there is enough space. Settings from |'completepopup'| is taken into + account. + + The preview's content is set depending on {lines}, {syn-ranges} and + {filetype}, see above. + + Returns the window ID of the created popup. + +updaggte_pum_tooltip({winid}, {lines}, {syn-ranges}, {filetype}, {options}) + + Changes the content of the tooltip associated with the currently selected + item in the popup menu. {winid} must be the value returned by + `show_pum_tooltip`. + + +In addition, there are utility functions useful for interacting with floats: + +parse_lsp_response({data}) + + Parses a LSP response (be it a String, MarkedString, Markdown segment, + MarkupContent, ...; from hereon just {data}) to: + + - A |list| of |String|s that represent the "stripped" content. E.g. + markdown `*bold*` strings will be converted to just `bold`, code + blocks will have the markers removed, etc. It's the "plain-text, no + colour" version of the {data}. + + - A |list| of |Dicts| that add colour to the plaintext. Each entry + essentially says: highlight this character range using this Vim + syntax group. Can be used for displaying stripped `*bold*` in a bold + font, or to apply syntax highlighting to a region. + + +TODO: move to `util.vim`? + + +============================================================================== +INTERMEDIATE-LEVEL API *intermediate-level-api* + +These functions abstract the low-level backend-specific API for interacting +with tooltip-type windows. They have a common signature but are implemented +separately for each backend. + +Currently, the following backends are implemented: + +1. `popup` windows for vim 8.1.1517+ +2. `floating windows` for neovim 0.4.0+ +3. TODO `preview` buffers as a fallback D*Todo + +create_tooltip() + + Creates a hidden floating window, with undefined position, and an empty + buffer associated with it. + + Returns the created window ID. + + +set_tooltip_contents({winid}, {lines}) + + Updates the contents of a given floating window, and unhides it. Also + retriggers size calculation. + + +set_tooltip_position({winid}, {options}) + + Sets the position of the given floating window, be it cursor-relative, + pum-relative, etc. Also retriggers size calculation. + + TODO: Which {options}? width in characters or bytes? 0- or 1-indexed? + + +close_tooltip({winid}) + + Closes the tooltip with the ID {winid}. + + +In addition, there are common utility functions: + +get_size_info({lines}) + + Get width and height needed to show the line-wrapped contents of a list + of strings. + + Returns a tuple of |[lines,width]| + + TODO: in characters or bytes? 0- or 1-indexed? + + +vim:tw=78:ts=4:ft=help:et From b89b2ebab982e2ff03d0bfcfafac2dd81b3b7267 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 14 Sep 2019 12:55:31 +0200 Subject: [PATCH 2/6] stub out proposed layout --- autoload/lsp/ui/vim/tooltip.vim | 0 autoload/lsp/ui/vim/tooltip/float.vim | 0 autoload/lsp/ui/vim/tooltip/popup.vim | 0 autoload/lsp/ui/vim/tooltip/preview.vim | 0 autoload/lsp/ui/vim/tooltip/utils.vim | 0 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 autoload/lsp/ui/vim/tooltip.vim create mode 100644 autoload/lsp/ui/vim/tooltip/float.vim create mode 100644 autoload/lsp/ui/vim/tooltip/popup.vim create mode 100644 autoload/lsp/ui/vim/tooltip/preview.vim create mode 100644 autoload/lsp/ui/vim/tooltip/utils.vim diff --git a/autoload/lsp/ui/vim/tooltip.vim b/autoload/lsp/ui/vim/tooltip.vim new file mode 100644 index 000000000..e69de29bb diff --git a/autoload/lsp/ui/vim/tooltip/float.vim b/autoload/lsp/ui/vim/tooltip/float.vim new file mode 100644 index 000000000..e69de29bb diff --git a/autoload/lsp/ui/vim/tooltip/popup.vim b/autoload/lsp/ui/vim/tooltip/popup.vim new file mode 100644 index 000000000..e69de29bb diff --git a/autoload/lsp/ui/vim/tooltip/preview.vim b/autoload/lsp/ui/vim/tooltip/preview.vim new file mode 100644 index 000000000..e69de29bb diff --git a/autoload/lsp/ui/vim/tooltip/utils.vim b/autoload/lsp/ui/vim/tooltip/utils.vim new file mode 100644 index 000000000..e69de29bb From 722fc37a427ffce995735b6fa166934f6a7b2d57 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 14 Sep 2019 13:17:44 +0200 Subject: [PATCH 3/6] stub out backend dispatch --- autoload/lsp/ui/vim/tooltip.vim | 16 ++++++++++++++++ autoload/lsp/ui/vim/tooltip/float.vim | 5 +++++ doc/tooltip-api.txt | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/autoload/lsp/ui/vim/tooltip.vim b/autoload/lsp/ui/vim/tooltip.vim index e69de29bb..fb003102d 100644 --- a/autoload/lsp/ui/vim/tooltip.vim +++ b/autoload/lsp/ui/vim/tooltip.vim @@ -0,0 +1,16 @@ +" Generic functions for interacting with tooltip-type windows for hover, +" preview etc. + +if !has('nvim') && has('patch-8.1.1517') && g:lsp_preview_float + let s:create_tooltip = function('lsp#ui#vim#tooltip#popup#create_tooltip') +elseif has('nvim') && exists('*nvim_open_win') && g:lsp_preview_float + let s:create_tooltip = function('lsp#ui#vim#tooltip#float#create_tooltip') +else + let s:create_tooltip = function('lsp#ui#vim#tooltip#preview#screate_tooltip') +endif + +function! lsp#ui#vim#tooltip#show_cursor_tooltip(lines, filetype, synranges, options) abort + " ... + let winid = s:create_tooltip() + " ... +endfunction diff --git a/autoload/lsp/ui/vim/tooltip/float.vim b/autoload/lsp/ui/vim/tooltip/float.vim index e69de29bb..b15c695d9 100644 --- a/autoload/lsp/ui/vim/tooltip/float.vim +++ b/autoload/lsp/ui/vim/tooltip/float.vim @@ -0,0 +1,5 @@ +" Implements backend-specific tooltip API using neovim floats (version 0.4.0) + +function! lsp#ui#vim#tooltip#float#create_tooltip() abort + return 0 +endfunction diff --git a/doc/tooltip-api.txt b/doc/tooltip-api.txt index a0c1fb585..d93d2c8ae 100644 --- a/doc/tooltip-api.txt +++ b/doc/tooltip-api.txt @@ -127,7 +127,7 @@ Currently, the following backends are implemented: 1. `popup` windows for vim 8.1.1517+ 2. `floating windows` for neovim 0.4.0+ -3. TODO `preview` buffers as a fallback D*Todo +3. TODO: `preview` buffers as a fallback create_tooltip() From f2ab478c5cca890f096b4163e05fc5d507762a04 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 14 Sep 2019 13:23:54 +0200 Subject: [PATCH 4/6] typo --- doc/tooltip-api.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tooltip-api.txt b/doc/tooltip-api.txt index d93d2c8ae..959ec429c 100644 --- a/doc/tooltip-api.txt +++ b/doc/tooltip-api.txt @@ -88,7 +88,7 @@ show_pum_tooltip({lines}, {syn-ranges}, {filetype}, {options}) Returns the window ID of the created popup. -updaggte_pum_tooltip({winid}, {lines}, {syn-ranges}, {filetype}, {options}) +update_pum_tooltip({winid}, {lines}, {syn-ranges}, {filetype}, {options}) Changes the content of the tooltip associated with the currently selected item in the popup menu. {winid} must be the value returned by From 82f533caaae0ce25817f29aadb6a8b532d139c4d Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 14 Sep 2019 13:35:32 +0200 Subject: [PATCH 5/6] reformulations --- doc/tooltip-api.txt | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/doc/tooltip-api.txt b/doc/tooltip-api.txt index 959ec429c..ec1a9ece5 100644 --- a/doc/tooltip-api.txt +++ b/doc/tooltip-api.txt @@ -35,6 +35,8 @@ All the following functions take the same initial arguments: - {syn-ranges}: A |list| of |dict|s, each representing a highlight group to be applied to the popup. + Can be used for displaying stripped `*bold*` in a bold font, or to apply + syntax highlighting to a region. Example of an entry: > { 'range': { @@ -76,7 +78,7 @@ show_cursor_tooltip({lines}, {filetype}, {syn-ranges}, {options}) Returns the window ID of the created popup. -show_pum_tooltip({lines}, {syn-ranges}, {filetype}, {options}) +show_pum_tooltip({lines}, {filetype}, {syn-ranges}, {options}) Shows a tooltip associated with the currently selected item in the popup menu. It can be either to the left/right of the item, depending on where @@ -88,7 +90,7 @@ show_pum_tooltip({lines}, {syn-ranges}, {filetype}, {options}) Returns the window ID of the created popup. -update_pum_tooltip({winid}, {lines}, {syn-ranges}, {filetype}, {options}) +update_pum_tooltip({winid}, {lines}, {filetype}, {syn-ranges}, {options}) Changes the content of the tooltip associated with the currently selected item in the popup menu. {winid} must be the value returned by @@ -100,18 +102,17 @@ In addition, there are utility functions useful for interacting with floats: parse_lsp_response({data}) Parses a LSP response (be it a String, MarkedString, Markdown segment, - MarkupContent, ...; from hereon just {data}) to: - - - A |list| of |String|s that represent the "stripped" content. E.g. + MarkupContent, ...; from hereon just {data}) to + + - a |list| of |String|s that represent the "stripped" content, e.g. markdown `*bold*` strings will be converted to just `bold`, code blocks will have the markers removed, etc. It's the "plain-text, no - colour" version of the {data}. + colour" version of the {data}; - - A |list| of |Dicts| that add colour to the plaintext. Each entry - essentially says: highlight this character range using this Vim - syntax group. Can be used for displaying stripped `*bold*` in a bold - font, or to apply syntax highlighting to a region. + - a |list| of |Dicts| that specifies the |syn-ranges|, i.e., of + character ranges and Vim syntax groups to apply to them. + Returns a tuple |[lines,syn-ranges]| . TODO: move to `util.vim`? From b5ac47a11af9ea1873c713a70237549c1b5f7e9f Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 14 Sep 2019 14:31:43 +0200 Subject: [PATCH 6/6] indexing only makes sense for pos --- doc/tooltip-api.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/tooltip-api.txt b/doc/tooltip-api.txt index ec1a9ece5..963c67c43 100644 --- a/doc/tooltip-api.txt +++ b/doc/tooltip-api.txt @@ -64,7 +64,8 @@ All the following functions take the same initial arguments: - 'firstline': ??? - 'cursor': {'align': , 'pos': } ??? - TODO: add more options, bike-shed names, decide on defaults + TODO: add more options, bike-shed names, decide on defaults, + TODO: 'pos' in characters or bytes? 0- or 1-indexed? Options not relevant to a function or a backend are ignored. @@ -149,7 +150,7 @@ set_tooltip_position({winid}, {options}) Sets the position of the given floating window, be it cursor-relative, pum-relative, etc. Also retriggers size calculation. - TODO: Which {options}? width in characters or bytes? 0- or 1-indexed? + TODO: Which {options}? close_tooltip({winid}) @@ -166,7 +167,7 @@ get_size_info({lines}) Returns a tuple of |[lines,width]| - TODO: in characters or bytes? 0- or 1-indexed? + TODO: in characters or bytes? vim:tw=78:ts=4:ft=help:et