-
Notifications
You must be signed in to change notification settings - Fork 297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UltiSnips integration #306
UltiSnips integration #306
Conversation
Concerning the failing CI build: the issue is this snippet: execute 'let l:user_data = ' . a:item['user_data']
let s:trigger = l:user_data[0]
let s:snippet = l:user_data[1] which produces This snippet is used to convert a string back to an array, which was needed because |
Because none of the vim snippets actually support lsp I'm a bit hesitant to support this out of the box. Similar to how autocomplete works with asyncomplete.vim and deplolete, we can easily make this work with an external plugin.
This allows to have external plugins such as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add suggestions and comments.
autoload/lsp/omni.vim
Outdated
@@ -201,7 +207,35 @@ function! lsp#omni#get_vim_completion_item(item, ...) abort | |||
endif | |||
endif | |||
|
|||
if exists('l:snippet') | |||
let l:completion['user_data'] = string([l:trigger, l:snippet]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
user_data
is only available in certain version of vim. We need to check if vim has that patch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In plugin/lsp.vim
, I already check if Vim has('patch-8.0.1493')
. Would you prefer I set g:lsp_ultisnips_integration
back to 0
there and/or add an additional has('patch-8.0.1493')
to if exists('l:snippet')
?
autoload/lsp/omni.vim
Outdated
let s:trigger = l:user_data[0] | ||
let s:snippet = l:user_data[1] | ||
|
||
call timer_start(0, function('s:expand_snippet')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious why do we need a timer here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, perhaps it would be a better idea to separate the snippet plugin dependent logic in a separate plugin, and allow that plugin to change the behaviour of |
My thought was to make it simple as this. let g:lsp_get_vim_completion_item = get(g:, 'myplugin#utilsnips#get_vim_completion_item', 'lsp#omni#get_vim_completion_item') We might want to rename existing |
So if I understand correctly, you're proposing the following: In
In
If so, would it not be better to just set |
That is true. It is possible but there is quite a logic that could be reused by others from |
Instead of |
Some snippet managers, like You can see an example of this approach and some discussion here: natebosch/vim-lsc#142 |
@natebosch Thanks for the info! The way I'm rewriting it now is to allow external plugins to provide their own implementation of |
I would still prefer func instead of setting |
@prabirshrestha I'm not entirely sure what you mean exactly. I don't change |
@prabirshrestha Any update on this? |
@thomasfaingnaert Seems to be conflicting a bit with this PR to enable textEdits since both use user data and seems to be conflicting. #318 I do want both the PRs to be merged and enable both use case. Looking at both PRs we might have to merge the text edit PR first since it doesn't expose dependencies to others. //cc @mikoto2000 |
Now that TextEdit for omnicomplete is supported can you try this against the latest master. #318 |
This way, we don't need to start them with a capital letter.
@thomasfaingnaert Do you have a minimal vimrc as well as a langserver that I can try. |
@prabirshrestha I've mainly been using clangd, which you can install from http://releases.llvm.org/download.html or from your package manager if you're on *NIX ( Minimal vimrccall plug#begin()
Plug 'SirVer/ultisnips'
Plug 'prabirshrestha/async.vim'
Plug 'thomasfaingnaert/vim-lsp', {'branch': 'ultisnips-integration'}
Plug 'thomasfaingnaert/vim-lsp-ultisnips'
call plug#end()
let g:UltiSnipsExpandTrigger="<tab>"
let g:UltiSnipsJumpForwardTrigger="<tab>"
let g:UltiSnipsJumpBackwardTrigger="<s-tab>"
if executable('clangd')
augroup vim_lsp_cpp
autocmd!
autocmd User lsp_setup call lsp#register_server({
\ 'name': 'clangd',
\ 'cmd': {server_info->['clangd']},
\ 'whitelist': ['c', 'cpp', 'objc', 'objcpp', 'cc'],
\ })
autocmd FileType c,cpp,objc,objcpp,cc setlocal omnifunc=lsp#complete
augroup end
endif
set completeopt+=menuone Example test.cpp#include <iostream>
#include <vector>
int main(int argc, char **argv)
{
// type: std::co<C-x><C-o>
// to get: std::cout
// type: std::vec<C-x><C-o><C-y>int<Tab> v;
// to get: std::vector<int> v;
// type: vect.pu<C-x><C-o><C-y>30<Tab>;
// to get: vect.push_back(30);
std::vector<int> vect;
// type: for<C-x><C-o><C-y>int i = 0<Tab>i<10<Tab>i++<Tab>// ...
// to get: for(int i = 0;i<10;i++){
// //...
// }
} |
Thanks for the instructions. I will be out on vacation for 2 weeks, will give it a try when I come back. |
What do you think adding snippet plugin integration support API? For example: Difficulty 2 points of snippet integration1. can not call snippet function after
|
augroup lsp_completion_item_text_edit | |
autocmd! | |
autocmd CompleteDone * call <SID>apply_text_edit() | |
augroup END |
e.g.
:augroup
of vim-lsp and vim-lsp-ultisnips.2. v:completed_item
is empty, after call lsp#utils#text_edit#apply_text_edits
.
v:completed_item
is empty after lsp#utils#text_edit#apply_text_edits
, so after called CompleteDone function can not reference v:completed_item
.
v:completed_item
is needed for move cursor to tabstop or placeholder.
call lsp#log(v:completed_item) " {"word": "...(snip)} (not empty)
" apply textEdits
if !empty(l:all_text_edits)
call lsp#utils#text_edit#apply_text_edits(lsp#utils#get_buffer_uri(), l:all_text_edits)
endif
call lsp#log(v:completed_item) " {} (empty)
@mikoto2000 For the second issue: I did some research, and I think the problem is https://github.com/vim/vim/blob/8055d17388736421d875dd4933c4c93d49a2ab58/src/insexpand.c#L1512, which is called in Because the apply_text_edit function uses From my limited testing, that indeed retains the value of |
1fbdfb7
to
eb203d3
Compare
@thomasfaingnaert
That makes sense. |
@prabirshrestha
call plug#begin()
Plug 'SirVer/ultisnips'
Plug 'prabirshrestha/async.vim'
Plug 'thomasfaingnaert/vim-lsp', {'branch': 'ultisnips-integration'}
Plug 'thomasfaingnaert/vim-lsp-snippets'
Plug 'thomasfaingnaert/vim-lsp-ultisnips'
call plug#end()
let g:UltiSnipsExpandTrigger="<tab>"
let g:UltiSnipsJumpForwardTrigger="<tab>"
let g:UltiSnipsJumpBackwardTrigger="<s-tab>"
if executable('clangd')
augroup vim_lsp_cpp
autocmd!
autocmd User lsp_setup call lsp#register_server({
\ 'name': 'clangd',
\ 'cmd': {server_info->['clangd']},
\ 'whitelist': ['c', 'cpp', 'objc', 'objcpp', 'cc'],
\ })
autocmd FileType c,cpp,objc,objcpp,cc setlocal omnifunc=lsp#complete
augroup end
endif
set completeopt+=menuone
#include <iostream>
#include <vector>
int main(int argc, char **argv)
{
// type: std::co<C-x><C-o>
// to get: std::cout
// type: std::vec<C-x><C-o><C-y>int<Tab> v;
// to get: std::vector<int> v;
// type: vect.pu<C-x><C-o><C-y>30<Tab>;
// to get: vect.push_back(30);
std::vector<int> vect;
// type: for<C-x><C-o><C-y>int i = 0<Tab>i<10<Tab>i++<Tab>// ...
// to get: for(int i = 0;i<10;i++){
// //...
// }
} I have also tested this with a language server that uses text edits (I've been using #318 (comment)), and this works as well, provided #389 is merged. |
@prabirshrestha Minimal vimrccall plug#begin()
Plug 'SirVer/ultisnips'
Plug 'prabirshrestha/async.vim'
Plug 'thomasfaingnaert/vim-lsp', {'branch': 'ultisnips-integration'}
Plug 'thomasfaingnaert/vim-lsp-snippets'
Plug 'thomasfaingnaert/vim-lsp-ultisnips'
call plug#end()
let g:UltiSnipsExpandTrigger="<tab>"
let g:UltiSnipsJumpForwardTrigger="<tab>"
let g:UltiSnipsJumpBackwardTrigger="<s-tab>"
autocmd User lsp_setup call lsp#register_server({
\ 'name': 'lsp4xml',
\ 'cmd': {server_info->[
\ 'java',
\ '-noverify',
\ '-Xmx1G',
\ '-XX:+UseStringDeduplication',
\ '-Dfile.encoding=UTF-8',
\ '-jar',
\ '/path/to/lsp4xml/org.eclipse.lsp4xml/target/org.eclipse.lsp4xml-uber.jar'
\ ]},
\ 'whitelist': ['xml', 'arxml'],
\ })
autocmd FileType xml setlocal omnifunc=lsp#complete
set completeopt+=menuone And using the files from #318 (comment): test.xsd<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="books">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="book">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="title" type="xsd:string" />
<xsd:element name="price" type="xsd:decimal" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema> test.xml<?xml version="1.0" encoding="UTF-8"?>
<books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="./test.xsd">
<!-- type <C-x> <C-o> and select book, <C-y> -->
</books> |
Merged. Thanks to all for the PR feedback as well as other fixes. |
I added a new variable
g:lsp_ultisnips_integration
which, when set to1
, uses UltiSnips to provide LSP snippet functionality.If
g:lsp_ultisnips_integration = 0
(the default), vim-lsp should continue to function in exactly the same way as it does now, so this PR should not break anything.This requires UltiSnips to be installed, and Vim 8.0 patch 1493 or higher (for
user_data
).A couple notes:
preview
from'completeopt'
. Alternatively, you can try Fix snippets breaking when opening preview window SirVer/ultisnips#1055.menuone
to'completeopt'
. This is because in that case, theCompleteDone
autocommand is called withv:completed_item = {}
instead of the completed item. If anyone knows another fix for this, please let me know.CompleteDone
, I believe this should also work with asyncomplete.vim.Demo with C++ in clangd:
Minimal vimrc to reproduce: