]> git.madduck.net Git - etc/vim.git/blob - .vim/bundle/vim-lsp/autoload/lsp/internal/document_range_formatting.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 / internal / document_range_formatting.vim
1 " options - {
2 "   bufnr: bufnr('%')       " required
3 "   type: ''                " optional: defaults to visualmode(). overridden by opfunc
4 "   server - 'server_name'  " optional
5 "   sync: 0                 " optional, defaults to 0 (async)
6 " }
7 function! lsp#internal#document_range_formatting#format(options) abort
8     if has_key(a:options, 'server')
9         let l:servers = [a:options['server']]
10     else
11         let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_document_range_formatting_provider(v:val)')
12     endif
13
14     if len(l:servers) == 0
15         let l:filetype = getbufvar(a:options['bufnr'], '&filetype')
16         call lsp#utils#error('textDocument/rangeFormatting not supported for ' . l:filetype)
17         return
18     endif
19
20     " TODO: ask user to select server for formatting if there are multiple servers
21     let l:server = l:servers[0]
22
23     redraw | echo 'Formatting Document Range ...'
24
25     call lsp#_new_command()
26
27     let [l:start_lnum, l:start_col, l:end_lnum, l:end_col] = s:get_selection_pos(get(a:options, 'type', visualmode()))
28     let l:start_char = lsp#utils#to_char('%', l:start_lnum, l:start_col)
29     let l:end_char = lsp#utils#to_char('%', l:end_lnum, l:end_col)
30
31     let l:request = {
32         \ 'method': 'textDocument/rangeFormatting',
33         \ 'params': {
34         \   'textDocument': lsp#get_text_document_identifier(a:options['bufnr']),
35         \   'range': {
36         \       'start': { 'line': l:start_lnum - 1, 'character': l:start_char },
37         \       'end': { 'line': l:end_lnum - 1, 'character': l:end_char },
38         \   },
39         \   'options': {
40         \       'tabSize': lsp#utils#buffer#get_indent_size(a:options['bufnr']),
41         \       'insertSpaces': getbufvar(a:options['bufnr'], '&expandtab') ? v:true : v:false,
42         \   }
43         \ },
44         \ 'bufnr': a:options['bufnr'],
45         \ }
46
47     if get(a:options, 'sync', 0) == 1
48         try
49             let l:x = lsp#callbag#pipe(
50                 \ lsp#request(l:server, l:request),
51                 \ lsp#callbag#takeUntil(lsp#callbag#pipe(
52                 \   lsp#stream(),
53                 \   lsp#callbag#filter({x->has_key(x, 'command')}),
54                 \ )),
55                 \ lsp#callbag#toList(),
56                 \ ).wait({ 'sleep': get(a:options, 'sleep', 1), 'timeout': get(a:options, 'timeout', g:lsp_format_sync_timeout) })
57             call s:format_next(l:x[0])
58             call s:format_complete()
59         catch
60             call s:format_error(v:exception . ' ' . v:throwpoint)
61         endtry
62     else
63         return lsp#callbag#pipe(
64             \ lsp#request(l:server, l:request),
65             \ lsp#callbag#takeUntil(lsp#callbag#pipe(
66             \   lsp#stream(),
67             \   lsp#callbag#filter({x->has_key(x, 'command')}),
68             \ )),
69             \ lsp#callbag#subscribe({
70             \   'next':{x->s:format_next(x)},
71             \   'error': {x->s:format_error(e)},
72             \   'complete': {->s:format_complete()},
73             \ }),
74             \ )
75     endif
76 endfunction
77
78 function! s:format_next(x) abort
79     if lsp#client#is_error(a:x['response']) | return | endif
80     call lsp#utils#text_edit#apply_text_edits(a:x['request']['params']['textDocument']['uri'], a:x['response']['result'])
81 endfunction
82
83 function! s:format_error(e) abort
84     call lsp#log('Formatting Document Range Failed', a:e)
85     call lsp#utils#error('Formatting Document Range Failed.' . (type(a:e) == type('') ? a:e : ''))
86 endfunction
87
88 function! s:format_complete() abort
89     redraw | echo 'Formatting Document Range complete'
90 endfunction
91
92 function! s:get_selection_pos(type) abort
93     " TODO: support bufnr
94     if a:type ==? 'v'
95         let l:start_pos = getpos("'<")[1:2]
96         let l:end_pos = getpos("'>")[1:2]
97         " fix end_pos column (see :h getpos() and :h 'selection')
98         let l:end_line = getline(l:end_pos[0])
99         let l:offset = (&selection ==# 'inclusive' ? 1 : 2)
100         let l:end_pos[1] = len(l:end_line[:l:end_pos[1]-l:offset])
101         " edge case: single character selected with selection=exclusive
102         if l:start_pos[0] == l:end_pos[0] && l:start_pos[1] > l:end_pos[1]
103             let l:end_pos[1] = l:start_pos[1]
104         endif
105     elseif a:type ==? 'line'
106         let l:start_pos = [line("'["), 1]
107         let l:end_lnum = line("']")
108         let l:end_pos = [line("']"), len(getline(l:end_lnum))]
109     elseif a:type ==? 'char'
110         let l:start_pos = getpos("'[")[1:2]
111         let l:end_pos = getpos("']")[1:2]
112     else
113         let l:start_pos = [0, 0]
114         let l:end_pos = [0, 0]
115     endif
116
117     return l:start_pos + l:end_pos
118 endfunction
119
120 function! lsp#internal#document_range_formatting#opfunc(type) abort
121     call lsp#internal#document_range_formatting#format({
122                 \ 'type': a:type,
123                 \ 'bufnr': bufnr('%'),
124                 \ })
125 endfunction