]> git.madduck.net Git - etc/vim.git/blobdiff - .vim/bundle/vim-lsp/autoload/lsp/ui/vim/code_action.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Merge commit 'a39f715c13be3352193ffd9c5b7536b8786eff64' as '.vim/bundle/vim-lsp'
[etc/vim.git] / .vim / bundle / vim-lsp / autoload / lsp / ui / vim / code_action.vim
diff --git a/.vim/bundle/vim-lsp/autoload/lsp/ui/vim/code_action.vim b/.vim/bundle/vim-lsp/autoload/lsp/ui/vim/code_action.vim
new file mode 100644 (file)
index 0000000..16073da
--- /dev/null
@@ -0,0 +1,207 @@
+" vint: -ProhibitUnusedVariable
+
+function! lsp#ui#vim#code_action#complete(input, command, len) abort
+    let l:server_names = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_code_action_provider(v:val)')
+    let l:kinds = []
+    for l:server_name in l:server_names
+        let l:kinds += lsp#capabilities#get_code_action_kinds(l:server_name)
+    endfor
+    return filter(copy(l:kinds), { _, kind -> kind =~ '^' . a:input })
+endfunction
+
+"
+" @param option = {
+"   selection: v:true | v:false = Provide by CommandLine like `:'<,'>LspCodeAction`
+"   sync: v:true | v:false      = Specify enable synchronous request. Example use case is `BufWritePre`
+"   query: string               = Specify code action kind query. If query provided and then filtered code action is only one, invoke code action immediately.
+"   ui: 'float' | 'preview'
+" }
+"
+function! lsp#ui#vim#code_action#do(option) abort
+    let l:selection = get(a:option, 'selection', v:false)
+    let l:sync = get(a:option, 'sync', v:false)
+    let l:query = get(a:option, 'query', '')
+    let l:ui = get(a:option, 'ui', g:lsp_code_action_ui)
+    if empty(l:ui)
+        let l:ui = lsp#utils#_has_popup_menu() ? 'float' : 'preview'
+    endif
+
+    let l:server_names = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_code_action_provider(v:val)')
+    if len(l:server_names) == 0
+        return lsp#utils#error('Code action not supported for ' . &filetype)
+    endif
+
+    if l:selection
+        let l:range = lsp#utils#range#_get_recent_visual_range()
+    else
+        let l:range = lsp#utils#range#_get_current_line_range()
+    endif
+
+    let l:ctx = {
+    \ 'count': len(l:server_names),
+    \ 'results': [],
+    \}
+    let l:bufnr = bufnr('%')
+    let l:command_id = lsp#_new_command()
+    for l:server_name in l:server_names
+        let l:diagnostic = lsp#internal#diagnostics#under_cursor#get_diagnostic({'server': l:server_name})
+        call lsp#send_request(l:server_name, {
+                    \ 'method': 'textDocument/codeAction',
+                    \ 'params': {
+                    \   'textDocument': lsp#get_text_document_identifier(),
+                    \   'range': empty(l:diagnostic) || l:selection ? l:range : l:diagnostic['range'],
+                    \   'context': {
+                    \       'diagnostics' : empty(l:diagnostic) ? [] : [l:diagnostic],
+                    \       'only': ['', 'quickfix', 'refactor', 'refactor.extract', 'refactor.inline', 'refactor.rewrite', 'source', 'source.organizeImports'],
+                    \   },
+                    \ },
+                    \ 'sync': l:sync,
+                    \ 'on_notification': function('s:handle_code_action', [l:ui, l:ctx, l:server_name, l:command_id, l:sync, l:query, l:bufnr]),
+                    \ })
+    endfor
+    echo 'Retrieving code actions ...'
+endfunction
+
+function! s:handle_code_action(ui, ctx, server_name, command_id, sync, query, bufnr, data) abort
+    " Ignore old request.
+    if a:command_id != lsp#_last_command()
+        return
+    endif
+
+    call add(a:ctx['results'], {
+    \    'server_name': a:server_name,
+    \    'data': a:data,
+    \})
+    let a:ctx['count'] -= 1
+    if a:ctx['count'] ># 0
+        return
+    endif
+
+    let l:total_code_actions = []
+    for l:result in a:ctx['results']
+        let l:server_name = l:result['server_name']
+        let l:data = l:result['data']
+        " Check response error.
+        if lsp#client#is_error(l:data['response'])
+            call lsp#utils#error('Failed to CodeAction for ' . l:server_name . ': ' . lsp#client#error_message(l:data['response']))
+            continue
+        endif
+
+        " Check code actions.
+        let l:code_actions = l:data['response']['result']
+
+        " Filter code actions.
+        if !empty(a:query)
+            let l:code_actions = filter(l:code_actions, { _, action -> get(action, 'kind', '') =~# '^' . a:query })
+        endif
+        if empty(l:code_actions)
+            continue
+        endif
+
+        for l:code_action in l:code_actions
+            let l:item = {
+            \   'server_name': l:server_name,
+            \   'code_action': l:code_action,
+            \ }
+            if get(l:code_action, 'isPreferred', v:false)
+                let l:total_code_actions = [l:item] + l:total_code_actions
+            else
+                call add(l:total_code_actions, l:item)
+            endif
+        endfor
+    endfor
+
+    if len(l:total_code_actions) == 0
+        echo 'No code actions found'
+        return
+    endif
+    call lsp#log('s:handle_code_action', l:total_code_actions)
+
+    if len(l:total_code_actions) == 1 && !empty(a:query)
+        let l:action = l:total_code_actions[0]
+        if s:handle_disabled_action(l:action) | return | endif
+        " Clear 'Retrieving code actions ...' message
+        echo ''
+        call s:handle_one_code_action(l:action['server_name'], a:sync, a:bufnr, l:action['code_action'])
+        return
+    endif
+
+    " Prompt to choose code actions when empty query provided.
+    let l:items = []
+    for l:action in l:total_code_actions
+        let l:title = printf('[%s] %s', l:action['server_name'], l:action['code_action']['title'])
+        if has_key(l:action['code_action'], 'kind') && l:action['code_action']['kind'] !=# ''
+            let l:title .= ' (' . l:action['code_action']['kind'] . ')'
+        endif
+        call add(l:items, { 'title': l:title, 'item': l:action })
+    endfor
+
+    if lsp#utils#_has_popup_menu() && a:ui ==? 'float'
+        call lsp#internal#ui#popupmenu#open({
+            \   'title': 'Code actions',
+            \   'items': mapnew(l:items, { idx, item -> item.title}),
+            \   'pos': 'topleft',
+            \   'line': 'cursor+1',
+            \   'col': 'cursor',
+            \   'callback': funcref('s:popup_accept_code_action', [a:sync, a:bufnr, l:items]),
+            \ })
+    else
+        call lsp#internal#ui#quickpick#open({
+            \ 'items': l:items,
+            \ 'key': 'title',
+            \ 'on_accept': funcref('s:quickpick_accept_code_action', [a:sync, a:bufnr]),
+            \ })
+    endif
+endfunction
+
+function! s:popup_accept_code_action(sync, bufnr, items, id, selected, ...) abort
+    if a:selected <= 0 | return | endif
+    let l:item = a:items[a:selected - 1]['item']
+    if s:handle_disabled_action(l:item) | return | endif
+    call s:handle_one_code_action(l:item['server_name'], a:sync, a:bufnr, l:item['code_action'])
+    execute('doautocmd <nomodeline> User lsp_float_closed')
+endfunction
+
+function! s:quickpick_accept_code_action(sync, bufnr, data, ...) abort
+    call lsp#internal#ui#quickpick#close()
+    if empty(a:data['items']) | return | endif
+    let l:selected = a:data['items'][0]['item']
+    if s:handle_disabled_action(l:selected) | return | endif
+    call s:handle_one_code_action(l:selected['server_name'], a:sync, a:bufnr, l:selected['code_action'])
+endfunction
+
+function! s:handle_disabled_action(code_action) abort
+    if has_key(a:code_action, 'disabled')
+        echo 'This action is disabled: ' . a:code_action['disabled']['reason']
+        return v:true
+    endif
+    return v:false
+endfunction
+
+function! s:handle_one_code_action(server_name, sync, bufnr, command_or_code_action) abort
+    " has WorkspaceEdit.
+    if has_key(a:command_or_code_action, 'edit')
+        call lsp#utils#workspace_edit#apply_workspace_edit(a:command_or_code_action['edit'])
+    endif
+
+    " Command.
+    if has_key(a:command_or_code_action, 'command') && type(a:command_or_code_action['command']) == type('')
+        call lsp#ui#vim#execute_command#_execute({
+        \   'server_name': a:server_name,
+        \   'command_name': get(a:command_or_code_action, 'command', ''),
+        \   'command_args': get(a:command_or_code_action, 'arguments', v:null),
+        \   'sync': a:sync,
+        \   'bufnr': a:bufnr,
+        \ })
+
+    " has Command.
+    elseif has_key(a:command_or_code_action, 'command') && type(a:command_or_code_action['command']) == type({})
+        call lsp#ui#vim#execute_command#_execute({
+        \   'server_name': a:server_name,
+        \   'command_name': get(a:command_or_code_action['command'], 'command', ''),
+        \   'command_args': get(a:command_or_code_action['command'], 'arguments', v:null),
+        \   'sync': a:sync,
+        \   'bufnr': a:bufnr,
+        \ })
+    endif
+endfunction