]> git.madduck.net Git - etc/vim.git/blob - autoload/ale/floating_preview.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:

Squashed '.vim/bundle/ale/' content from commit 22185c4c
[etc/vim.git] / autoload / ale / floating_preview.vim
1 " Author: Jan-Grimo Sobez <jan-grimo.sobez@phys.chem.ethz.ch>
2 " Author: Kevin Clark <kevin.clark@gmail.com>
3 " Author: D. Ben Knoble <ben.knoble+github@gmail.com>
4 " Author: Shaun Duncan <shaun.duncan@gmail.com>
5 " Description: Floating preview window for showing whatever information in.
6
7 " Precondition: exists('*nvim_open_win') || has('popupwin')
8
9 function! ale#floating_preview#Show(lines, ...) abort
10     if !exists('*nvim_open_win') && !has('popupwin')
11         " no-custom-checks
12         echom 'Floating windows not supported in this vim instance.'
13
14         return
15     endif
16
17     let l:options = get(a:000, 0, {})
18
19     if has('nvim')
20         call s:NvimShow(a:lines, l:options)
21     else
22         call s:VimShow(a:lines, l:options)
23     endif
24
25     return w:preview.id
26 endfunction
27
28 function! s:NvimShow(lines, options) abort
29     " Remove the close autocmd so it doesn't happen mid update
30     augroup ale_floating_preview_window
31         autocmd!
32     augroup END
33
34     " Only create a new window if we need it
35     if !exists('w:preview') || index(nvim_list_wins(), w:preview['id']) is# -1
36         call s:NvimCreate(a:options)
37     else
38         call nvim_buf_set_option(w:preview['buffer'], 'modifiable', v:true)
39     endif
40
41     " Execute commands in window context
42     if exists('*win_execute')
43         for l:command in get(a:options, 'commands', [])
44             call win_execute(w:preview['id'], l:command)
45         endfor
46     else
47         let l:parent_window = nvim_get_current_win()
48
49         call nvim_set_current_win(w:preview['id'])
50
51         for l:command in get(a:options, 'commands', [])
52             call execute(l:command)
53         endfor
54
55         call nvim_set_current_win(l:parent_window)
56     endif
57
58     " Return to parent context on move
59     augroup ale_floating_preview_window
60         autocmd!
61
62         if g:ale_close_preview_on_insert
63             autocmd CursorMoved,TabLeave,WinLeave,BufWinLeave,WinScrolled,InsertEnter <buffer> ++once call s:NvimClose()
64         else
65             autocmd CursorMoved,TabLeave,WinLeave,BufWinLeave,WinScrolled <buffer> ++once call s:NvimClose()
66         endif
67     augroup END
68
69     let [l:lines, l:width, l:height] = s:NvimPrepareWindowContent(a:lines)
70
71     call nvim_win_set_width(w:preview['id'], l:width)
72     call nvim_win_set_height(w:preview['id'], l:height)
73     call nvim_buf_set_lines(w:preview['buffer'], 0, -1, v:false, l:lines)
74     call nvim_buf_set_option(w:preview['buffer'], 'modified', v:false)
75     call nvim_buf_set_option(w:preview['buffer'], 'modifiable', v:false)
76 endfunction
77
78 function! s:VimShow(lines, options) abort
79     if g:ale_close_preview_on_insert
80         " Remove the close autocmd so it doesn't happen mid update
81         silent! autocmd! ale_floating_preview_window
82     endif
83
84     " Only create a new window if we need it
85     if !exists('w:preview') || index(popup_list(), w:preview['id']) is# -1
86         call s:VimCreate(a:options)
87     endif
88
89     " Execute commands in window context
90     for l:command in get(a:options, 'commands', [])
91         call win_execute(w:preview['id'], l:command)
92     endfor
93
94     call popup_settext(w:preview['id'], a:lines)
95
96     if g:ale_close_preview_on_insert
97         augroup ale_floating_preview_window
98             autocmd!
99             autocmd InsertEnter * ++once call s:VimClose()
100         augroup END
101     endif
102 endfunction
103
104 function! s:NvimPrepareWindowContent(lines) abort
105     let l:max_height = 10
106
107     let l:width = max(map(copy(a:lines), 'strdisplaywidth(v:val)'))
108     let l:height = min([len(a:lines), l:max_height])
109
110     return [a:lines[0:l:height-1], l:width, l:height]
111 endfunction
112
113 function! s:NvimCreate(options) abort
114     let l:left = get(g:ale_floating_window_border, 0, '|')
115     let l:top = get(g:ale_floating_window_border, 1, '-')
116
117     let l:popup_opts = extend({
118     \    'relative': 'cursor',
119     \    'row': 1,
120     \    'col': 0,
121     \    'width': 42,
122     \    'height': 4,
123     \    'style': 'minimal',
124     \    'border': empty(g:ale_floating_window_border) ? 'none' : [
125     \        get(g:ale_floating_window_border, 2, '+'),
126     \        l:top,
127     \        get(g:ale_floating_window_border, 3, '+'),
128     \        get(g:ale_floating_window_border, 6, l:left),
129     \        get(g:ale_floating_window_border, 4, '+'),
130     \        get(g:ale_floating_window_border, 7, l:top),
131     \        get(g:ale_floating_window_border, 5, '+'),
132     \        l:left,
133     \    ],
134     \ }, s:GetPopupOpts())
135
136     let l:buffer = nvim_create_buf(v:false, v:false)
137     let l:winid = nvim_open_win(l:buffer, v:false, l:popup_opts)
138
139     call nvim_buf_set_option(l:buffer, 'buftype', 'acwrite')
140     call nvim_buf_set_option(l:buffer, 'bufhidden', 'delete')
141     call nvim_buf_set_option(l:buffer, 'swapfile', v:false)
142     call nvim_buf_set_option(l:buffer, 'filetype', get(a:options, 'filetype', 'ale-preview'))
143
144     let w:preview = {'id': l:winid, 'buffer': l:buffer}
145 endfunction
146
147 function! s:VimCreate(options) abort
148     " default options
149     let l:popup_opts = extend({
150     \    'line': 'cursor+1',
151     \    'col': 'cursor',
152     \    'drag': v:true,
153     \    'resize': v:true,
154     \    'close': 'button',
155     \    'padding': [0, 1, 0, 1],
156     \    'border': [],
157     \    'borderchars': empty(g:ale_floating_window_border) ? [' '] : [
158     \        get(g:ale_floating_window_border, 1, '-'),
159     \        get(g:ale_floating_window_border, 6, '|'),
160     \        get(g:ale_floating_window_border, 7, '-'),
161     \        get(g:ale_floating_window_border, 0, '|'),
162     \        get(g:ale_floating_window_border, 2, '+'),
163     \        get(g:ale_floating_window_border, 3, '+'),
164     \        get(g:ale_floating_window_border, 4, '+'),
165     \        get(g:ale_floating_window_border, 5, '+'),
166     \    ],
167     \    'moved': 'any',
168     \ }, s:GetPopupOpts())
169
170     let l:popup_id = popup_create([], l:popup_opts)
171     call setbufvar(winbufnr(l:popup_id), '&filetype', get(a:options, 'filetype', 'ale-preview'))
172     let w:preview = {'id': l:popup_id}
173 endfunction
174
175 function! s:NvimClose() abort
176     let l:mode = mode()
177     let l:restore_visual = l:mode is# 'v' || l:mode is# 'V' || l:mode is# "\<C-V>"
178
179     if !exists('w:preview')
180         return
181     endif
182
183     call setbufvar(w:preview['buffer'], '&modified', 0)
184
185     if win_id2win(w:preview['id']) > 0
186         execute win_id2win(w:preview['id']).'wincmd c'
187     endif
188
189     unlet w:preview
190
191     if l:restore_visual
192         normal! gv
193     endif
194 endfunction
195
196 function! s:VimClose() abort
197     if !exists('w:preview')
198         return
199     endif
200
201     call popup_close(w:preview['id'])
202     unlet w:preview
203 endfunction
204
205 " get either the results of a function callback or dictionary for popup overrides
206 function! s:GetPopupOpts() abort
207     if exists('g:ale_floating_preview_popup_opts')
208         let l:ref = g:ale_floating_preview_popup_opts
209
210         if type(l:ref) is# v:t_dict
211             return l:ref
212         elseif type(l:ref) is# v:t_string
213             try
214                 return function(l:ref)()
215             catch /E700/
216             endtry
217         endif
218     endif
219
220     return {}
221 endfunction