File plugin/qthelp.vim added (mode: 100644) (index 0000000..302b7f8) |
|
1 |
|
" Name: qthelp |
|
2 |
|
" Author: xaizek (xaizek@gmail.com) |
|
3 |
|
" Version: 1.0 |
|
4 |
|
" |
|
5 |
|
" Description: This plugin would allow you to open Qt help pages in browser |
|
6 |
|
" from your C++ source code. Currently it can show help if the word |
|
7 |
|
" under your cursor is a class name, a variable name or a |
|
8 |
|
" class-member name. |
|
9 |
|
" |
|
10 |
|
" Examples: QStr|ing trackTitle, artistName; |
|
11 |
|
" QString track|Title, artistName("Unknown"); |
|
12 |
|
" track|Title = "Unknown"; |
|
13 |
|
" Running command QHelpOnThis will open help on QString. |
|
14 |
|
" |
|
15 |
|
" trackTitle.ri|ght(10); |
|
16 |
|
" Running command :QHelpOnThis will open help on QString::right. |
|
17 |
|
" |
|
18 |
|
" Running command :QHelp QPixmap::QPixmap will open help on |
|
19 |
|
" QPixmap constructor. |
|
20 |
|
" |
|
21 |
|
" Configuring: g:qthelp_browser - command to run your browser |
|
22 |
|
" default: '' (so an error message will be printed if your try to |
|
23 |
|
" use plugin) |
|
24 |
|
" Note: on Windows use something like |
|
25 |
|
" 'start c:\Program files\Mozilla Firefox\firefox.exe' |
|
26 |
|
" or Vim will be waiting until you close your browser. |
|
27 |
|
" |
|
28 |
|
" Using: 1. Make tags-file for your html-qthelp. |
|
29 |
|
" 2. Add that tags-file into your 'tags' option (WARNING: doing |
|
30 |
|
" this in your .vimrc file can slow down and pollute completion |
|
31 |
|
" list for not Qt-projects). |
|
32 |
|
" 3. Let g:qthelp_browser command to run your browser. |
|
33 |
|
" 4. Map command QHelpOnThis on some hotkey. |
|
34 |
|
" 5. Use QHelp from command-line for faster navigating through |
|
35 |
|
" help (to escape manual searching of needed method). |
|
36 |
|
" |
|
37 |
|
" Limitation: I didn't found a way to determine inheritance hierarchy using |
|
38 |
|
" tags so trying |
|
39 |
|
" QStringList strlst; |
|
40 |
|
" strlst.in|sert("String"); |
|
41 |
|
" will open reference for QString, not for QList::insert. |
|
42 |
|
" |
|
43 |
|
" Warning: In some cases it can take a while for searching definition (for |
|
44 |
|
" example when it doesn't exist) if this happens hit Ctrl-C to |
|
45 |
|
" break searching. |
|
46 |
|
|
|
47 |
|
if exists("g:loaded_qthelp") |
|
48 |
|
finish |
|
49 |
|
endif |
|
50 |
|
|
|
51 |
|
let g:loaded_gthelp = 1 |
|
52 |
|
|
|
53 |
|
if !exists('g:qthelp_browser') |
|
54 |
|
let g:qthelp_browser = '' |
|
55 |
|
endif |
|
56 |
|
|
|
57 |
|
" boolean for switching debug output |
|
58 |
|
let s:debugging = 0 |
|
59 |
|
|
|
60 |
|
" regexps, as you can see |
|
61 |
|
let s:idregex = '\%(\<const\>\)\?'.'[_a-zA-Z][_a-zA-Z0-9]*'.'\%(\<const\>\)\?' |
|
62 |
|
let s:nsregex = '\%('.s:idregex.'::\)*' |
|
63 |
|
let s:numregex = '[0-9]\+' |
|
64 |
|
let s:varpfxregex = '\s*&\?\s*\%(\*\s*\)*' |
|
65 |
|
let s:varsfxregex = '\s*\%('. |
|
66 |
|
\'\%(([^)]*)\)'. |
|
67 |
|
\'\|'. |
|
68 |
|
\'\%(\['.s:numregex.'\]\)'. |
|
69 |
|
\'\)\?' |
|
70 |
|
let s:varregex = s:varpfxregex.s:idregex.s:varsfxregex |
|
71 |
|
let s:varlstregex = '\%('.s:varregex.'\s*\%(,\s*\)\?\)*' |
|
72 |
|
let s:typeregex = '^\s*\%(const\s\+\)\?'.s:nsregex.'\zs'.s:idregex.'\ze' |
|
73 |
|
\.'\%(<.*>\)\?'.s:varpfxregex.'\s\+' |
|
74 |
|
|
|
75 |
|
" buffer variables |
|
76 |
|
" b:membername |
|
77 |
|
" b:foundinfile |
|
78 |
|
" b:foundatline |
|
79 |
|
|
|
80 |
|
" some commands |
|
81 |
|
command! -nargs=0 QHelpOnThis call QHHelp('') |
|
82 |
|
command! -nargs=1 QHelp call QHHelp('<args>') |
|
83 |
|
|
|
84 |
|
" the main function |
|
85 |
|
" cword parameter is what we want to get help on or '' for analyzing word under |
|
86 |
|
" cursor |
|
87 |
|
function! QHHelp(query) |
|
88 |
|
call s:QHDebug('QHDBG: QHHelp(cword="'.a:query.'")') |
|
89 |
|
if a:query != '' |
|
90 |
|
let l:lst = s:QHGetTagsList(a:query) |
|
91 |
|
else |
|
92 |
|
let l:lst = s:QHGetTagsListUC() |
|
93 |
|
endif |
|
94 |
|
|
|
95 |
|
if len(l:lst) == 0 |
|
96 |
|
call s:QHTellUser("Nothing was found") |
|
97 |
|
else |
|
98 |
|
call s:QHDebug('QHDBG: QHHelp, filename="'.l:lst[0]['filename'].'"') |
|
99 |
|
call <SID>QHOpenBrowser(l:lst[0]['filename']) |
|
100 |
|
endif |
|
101 |
|
endfunction |
|
102 |
|
|
|
103 |
|
" determines if a class name, a variable name or a class member name is under |
|
104 |
|
" cursor and returns appropriate taglist |
|
105 |
|
function! s:QHGetTagsListUC() |
|
106 |
|
" wuc is for Word Under Cursor |
|
107 |
|
let l:wuc = expand('<cword>') |
|
108 |
|
let l:lst = taglist('//apple_ref/cpp/cl//'.l:wuc.'$') |
|
109 |
|
if len(l:lst) == 0 " if WUC is var_name |
|
110 |
|
let [l:class, b:membername] = QHGetVUCInfo() |
|
111 |
|
if b:membername == '' |
|
112 |
|
let l:lst = taglist('//apple_ref/cpp/cl//'.l:class.'$') |
|
113 |
|
else |
|
114 |
|
let l:lst = s:QHGetTagsListOnMember(l:class, b:membername) |
|
115 |
|
if len(l:lst) == 0 |
|
116 |
|
let b:membername = '' |
|
117 |
|
let l:lst = taglist('//apple_ref/cpp/cl//'.l:class.'$') |
|
118 |
|
endif |
|
119 |
|
endif |
|
120 |
|
else |
|
121 |
|
let b:membername = '' |
|
122 |
|
endif |
|
123 |
|
return l:lst |
|
124 |
|
endfunction |
|
125 |
|
|
|
126 |
|
" b:membername should be set before calling this function because it should |
|
127 |
|
" modify it last |
|
128 |
|
function! s:QHGetTagsListOnMember(class, member) |
|
129 |
|
let l:lst = taglist('^'.a:member.'-typedef$') |
|
130 |
|
if len(l:lst) != 0 |
|
131 |
|
let b:membername = a:member.'-typedef' |
|
132 |
|
return l:lst |
|
133 |
|
endif |
|
134 |
|
let l:lst = taglist('^'.a:member.'-enum$') |
|
135 |
|
if len(l:lst) != 0 |
|
136 |
|
let b:membername = a:member.'-enum' |
|
137 |
|
return l:lst |
|
138 |
|
endif |
|
139 |
|
|
|
140 |
|
if len(l:lst) == 0 |
|
141 |
|
let l:lst = taglist('//apple_ref/cpp/clm/'.a:class.'/'.a:member.'$') |
|
142 |
|
endif |
|
143 |
|
if len(l:lst) == 0 |
|
144 |
|
let l:lst = taglist('//apple_ref/cpp/instm/'.a:class.'/'.a:member.'$') |
|
145 |
|
endif |
|
146 |
|
if len(l:lst) == 0 |
|
147 |
|
let l:lst = taglist('//apple_ref/cpp/econst/'.a:class.'/'.a:member.'$') |
|
148 |
|
endif |
|
149 |
|
if len(l:lst) == 0 |
|
150 |
|
let l:lst = taglist('//apple_ref/cpp/tag/'.a:class.'/'.a:member.'$') |
|
151 |
|
endif |
|
152 |
|
return l:lst |
|
153 |
|
endfunction |
|
154 |
|
|
|
155 |
|
" analyses query for class name or class name and its member name |
|
156 |
|
function! s:QHGetTagsList(query) |
|
157 |
|
call s:QHDebug('QHDBG: QHGetTagsList(query="'.a:query.'")') |
|
158 |
|
let l:lst = [] |
|
159 |
|
|
|
160 |
|
let l:regex = '\('.s:idregex.'\)::\('.s:idregex.'\)' |
|
161 |
|
if matchstr(a:query, l:regex) != '' |
|
162 |
|
let l:class = substitute(a:query, l:regex, '\1', '') |
|
163 |
|
call s:QHDebug('QHDBG: QHGetTagsList, class="'.l:class.'"') |
|
164 |
|
let l:member = substitute(a:query, l:regex, '\2', '') |
|
165 |
|
call s:QHDebug('QHDBG: QHGetTagsList, member="'.l:member.'"') |
|
166 |
|
let l:lst = taglist('//apple_ref/cpp/clm/'.l:class.'/'.l:member.'$') |
|
167 |
|
if len(l:lst) == 0 |
|
168 |
|
let l:lst = taglist('//apple_ref/cpp/instm/' |
|
169 |
|
\.l:class.'/'.l:member.'$') |
|
170 |
|
endif |
|
171 |
|
if len(l:lst) == 0 |
|
172 |
|
let l:lst = taglist('//apple_ref/cpp/tag/' |
|
173 |
|
\.l:class.'/'.l:member.'$') |
|
174 |
|
endif |
|
175 |
|
let b:membername = l:member |
|
176 |
|
else |
|
177 |
|
let l:lst = taglist('//apple_ref/cpp/cl//'.a:query.'$') |
|
178 |
|
let b:membername = '' |
|
179 |
|
endif |
|
180 |
|
|
|
181 |
|
return l:lst |
|
182 |
|
endfunction |
|
183 |
|
|
|
184 |
|
" opens users browser |
|
185 |
|
function! s:QHOpenBrowser(file) |
|
186 |
|
if s:debugging == 1 |
|
187 |
|
return |
|
188 |
|
endif |
|
189 |
|
let l:browserargs = 'file://'.fnamemodify(a:file, ':p') |
|
190 |
|
if b:membername != '' |
|
191 |
|
let l:browserargs = l:browserargs.'\#'.b:membername |
|
192 |
|
endif |
|
193 |
|
let l:browserargs = shellescape(l:browserargs) |
|
194 |
|
if !has('win32') && !has('win64') |
|
195 |
|
let l:browserargs = l:browserargs.'&' |
|
196 |
|
endif |
|
197 |
|
try |
|
198 |
|
exe ":silent !".shellescape(g:qthelp_browser)." ".l:browserargs |
|
199 |
|
catch 'E484' |
|
200 |
|
call s:QHTellUser('An error occuried while running your browser. ' |
|
201 |
|
\.'Maybe your g:qthelp_browser option is incorrect.') |
|
202 |
|
endtry |
|
203 |
|
endfunction |
|
204 |
|
|
|
205 |
|
" lets tell user about what we have found |
|
206 |
|
function! s:QHInformUser(varname, class, membername) |
|
207 |
|
let l:msg = a:class |
|
208 |
|
if a:membername != '' |
|
209 |
|
let l:msg = l:msg.'::' |
|
210 |
|
endif |
|
211 |
|
if a:varname != '' |
|
212 |
|
let l:msg = a:varname.' ('.l:msg.')' |
|
213 |
|
endif |
|
214 |
|
if b:foundinfile != '' |
|
215 |
|
let l:msg = l:msg.'; was found in '.b:foundinfile |
|
216 |
|
\.' at line '.b:foundatline |
|
217 |
|
endif |
|
218 |
|
call s:QHTellUser(l:msg) |
|
219 |
|
endfunction |
|
220 |
|
|
|
221 |
|
" prints some message to a user to let him know what are we doing |
|
222 |
|
function! s:QHTellUser(msg) |
|
223 |
|
execute 'echomsg("QtHelp: '.escape(a:msg, '"').'")' |
|
224 |
|
endfunction |
|
225 |
|
|
|
226 |
|
" prints debug message |
|
227 |
|
function! s:QHDebug(msg) |
|
228 |
|
if s:debugging == 1 |
|
229 |
|
execute 'echomsg("QtHelp: '.escape(a:msg, '"').'")' |
|
230 |
|
endif |
|
231 |
|
endfunction |
|
232 |
|
|
|
233 |
|
" ------------------------------------------------------------------------------ |
|
234 |
|
" stuff below is for analyzing code -------------------------------------------- |
|
235 |
|
" ------------------------------------------------------------------------------ |
|
236 |
|
|
|
237 |
|
" returns list with information about Variable Under Cursor in form of |
|
238 |
|
" [classname, membername] |
|
239 |
|
function! QHGetVUCInfo() |
|
240 |
|
let l:wuc = expand('<cword>') |
|
241 |
|
let l:wuctype = s:QHGetWUCType(wuc) |
|
242 |
|
if l:wuctype == 0 " we're assuming that this is varname |
|
243 |
|
let l:varname = s:QHGetVarType(l:wuc) |
|
244 |
|
if l:varname == '' |
|
245 |
|
return [l:wuc, ''] |
|
246 |
|
else |
|
247 |
|
return [l:varname, ''] |
|
248 |
|
endif |
|
249 |
|
elseif l:wuctype == 1 |
|
250 |
|
return [s:QHGetNSName(l:wuc), l:wuc] |
|
251 |
|
elseif l:wuctype == 2 |
|
252 |
|
return [s:QHGetVarType(s:QHGetVarName(l:wuc)), l:wuc] |
|
253 |
|
elseif l:wuctype == 3 |
|
254 |
|
return [l:wuc, ''] |
|
255 |
|
endif |
|
256 |
|
endfunction |
|
257 |
|
|
|
258 |
|
" this function searches for variable definition in current file and header |
|
259 |
|
" file if the current one is source |
|
260 |
|
function! s:QHGetVarType(varname) |
|
261 |
|
let b:foundatline = line('.') |
|
262 |
|
|
|
263 |
|
" firstly lets try to find declaration in current file |
|
264 |
|
" simple case |
|
265 |
|
let l:type = s:QHSearchSimpleVarDef(a:varname) |
|
266 |
|
if l:type != '' |
|
267 |
|
call s:QHDebug('QHDBG: Simple definition search succesed') |
|
268 |
|
return l:type |
|
269 |
|
endif |
|
270 |
|
" more complex |
|
271 |
|
let l:type = s:QHSearchComplexVarDef(a:varname) |
|
272 |
|
if l:type != '' |
|
273 |
|
call s:QHDebug('QHDBG: Complex definition search succesed') |
|
274 |
|
return l:type |
|
275 |
|
endif |
|
276 |
|
|
|
277 |
|
" try to find variable in function declaration |
|
278 |
|
let l:type = s:QHSearchVarDefInArgs(a:varname) |
|
279 |
|
if l:type != '' |
|
280 |
|
call s:QHDebug('QHDBG: Arg search succesed') |
|
281 |
|
return l:type |
|
282 |
|
endif |
|
283 |
|
|
|
284 |
|
" and now lets take a look at the header if it exists |
|
285 |
|
if expand('%:e') == 'cpp' |
|
286 |
|
if filereadable(expand('%:r').'.hpp') |
|
287 |
|
return s:QHSearchVarDefInFile(a:varname, expand('%:r').'.hpp') |
|
288 |
|
elseif filereadable(expand('%:r').'.h') |
|
289 |
|
return s:QHSearchVarDefInFile(a:varname, expand('%:r').'.h') |
|
290 |
|
else |
|
291 |
|
call s:QHDebug('QHDBG: QHGetVarType, cant find companion file') |
|
292 |
|
return '' |
|
293 |
|
endif |
|
294 |
|
endif |
|
295 |
|
|
|
296 |
|
return '' |
|
297 |
|
endfunction |
|
298 |
|
|
|
299 |
|
" searches for simple declaration of varname above cursor position |
|
300 |
|
function! s:QHSearchSimpleVarDef(varname) |
|
301 |
|
let l:sdefregex = '\<'.s:nsregex.s:idregex.'\>'.'\%(<.*>\)\?'.'[^,()=]\+' |
|
302 |
|
\.'\<'.a:varname.'\>[^&]' |
|
303 |
|
let l:lnum = search(l:sdefregex, 'bcnW') |
|
304 |
|
if l:lnum > 0 |
|
305 |
|
let l:type = matchstr(matchstr(getline(l:lnum), l:sdefregex) |
|
306 |
|
\, s:typeregex) |
|
307 |
|
if l:type != 'delete' |
|
308 |
|
let b:foundinfile = 'this file' |
|
309 |
|
let b:foundatline = l:lnum |
|
310 |
|
return l:type |
|
311 |
|
endif |
|
312 |
|
endif |
|
313 |
|
endfunction |
|
314 |
|
|
|
315 |
|
" searches for complex declaration of varname above cursor position |
|
316 |
|
function! s:QHSearchComplexVarDef(varname) |
|
317 |
|
let l:defregex = '\s*'.s:nsregex.s:idregex.'\s\+' |
|
318 |
|
\.s:varlstregex.s:varpfxregex.a:varname.s:varsfxregex |
|
319 |
|
\.'\%(<.*>\)\?\s*\%(;\|,\|\%(=\)\)' |
|
320 |
|
let l:lnum = search(l:defregex, 'bcnW') |
|
321 |
|
if l:lnum > 0 |
|
322 |
|
call s:QHDebug('QHDBG: QHGetVarType, lnum="'.l:lnum.'"') |
|
323 |
|
let l:type = matchstr(getline(l:lnum), s:typeregex) |
|
324 |
|
if l:type != 'delete' |
|
325 |
|
let b:foundinfile = 'this file' |
|
326 |
|
let b:foundatline = l:lnum |
|
327 |
|
return l:type |
|
328 |
|
else |
|
329 |
|
" continue the search but without search() to escape moving cursor |
|
330 |
|
for l:l in range(l:lnum - 1, 1, -1) |
|
331 |
|
let l:type = matchstr(getline(l:l), l:defregex) |
|
332 |
|
if l:type != '' && l:type != 'delete' |
|
333 |
|
let b:foundinfile = 'this file' |
|
334 |
|
let b:foundatline = l:l |
|
335 |
|
return l:type |
|
336 |
|
endif |
|
337 |
|
endfor |
|
338 |
|
endif |
|
339 |
|
endif |
|
340 |
|
endfunction |
|
341 |
|
|
|
342 |
|
" searches for declaration of varname in args of current function |
|
343 |
|
function! s:QHSearchVarDefInArgs(varname) |
|
344 |
|
let l:argdefregex = '[(,]\s*\%(const\)\?'.s:nsregex.s:idregex.s:varpfxregex |
|
345 |
|
\.'\s\+'.a:varname.s:varsfxregex.'\s*[,)]\?' |
|
346 |
|
let l:stoplnum = search('^}', 'bcnW') |
|
347 |
|
let l:lnum = search(l:argdefregex, 'bcnW', l:stoplnum + 1) |
|
348 |
|
if l:lnum > 0 |
|
349 |
|
let b:foundinfile = 'this file' |
|
350 |
|
let b:foundatline = l:lnum |
|
351 |
|
return matchstr(getline(l:lnum), l:argdefregex, 'bcnW') |
|
352 |
|
endif |
|
353 |
|
return '' |
|
354 |
|
endfunction |
|
355 |
|
|
|
356 |
|
" searches for declaration of varname in file filename |
|
357 |
|
function! s:QHSearchVarDefInFile(varname, filename) |
|
358 |
|
let l:defregex = '^\s*'.s:nsregex.s:idregex.'\>.*\<'.a:varname.'\>' |
|
359 |
|
let l:headerfile = readfile(a:filename) |
|
360 |
|
let l:lnum = 0 |
|
361 |
|
for l:line in l:headerfile |
|
362 |
|
let l:definition = matchstr(l:line, l:defregex) |
|
363 |
|
if l:definition != '' |
|
364 |
|
let b:foundinfile = a:filename |
|
365 |
|
let b:foundatline = l:lnum |
|
366 |
|
return matchstr(l:line, s:typeregex) |
|
367 |
|
endif |
|
368 |
|
let l:lnum = l:lnum + 1 |
|
369 |
|
endfor |
|
370 |
|
return '' |
|
371 |
|
endfunction |
|
372 |
|
|
|
373 |
|
" returns variable name that goes right before the cursor |
|
374 |
|
function! s:QHGetVarName(funcname) |
|
375 |
|
let [l:line, l:col] = searchpos(expand('<cword>'), 'bcn') |
|
376 |
|
let l:varname = matchstr(getline('.'), |
|
377 |
|
\ s:idregex.'\ze\%(\.\|->\)\%'.l:col.'c'.a:funcname) |
|
378 |
|
return l:varname |
|
379 |
|
endfunction |
|
380 |
|
|
|
381 |
|
" returns namespace name that goes right before the cursor |
|
382 |
|
function! s:QHGetNSName(funcname) |
|
383 |
|
let [l:line, l:col] = searchpos(expand('<cword>'), 'bcn') |
|
384 |
|
let l:varname = matchstr(getline('.'), |
|
385 |
|
\ s:idregex.'\ze::\%'.l:col.'c'.a:funcname) |
|
386 |
|
return l:varname |
|
387 |
|
endfunction |
|
388 |
|
|
|
389 |
|
" analyses what is before the wuc and returns: |
|
390 |
|
" - 0 for class_n|ame or va|r_name |
|
391 |
|
" - 1 for class_name::mem|ber_name |
|
392 |
|
" - 2 for var_name.mem|ber_name or var_name->me|mber_name |
|
393 |
|
" - 3 for class_n|ame |
|
394 |
|
function! s:QHGetWUCType(wuc) |
|
395 |
|
let [l:line, l:col] = searchpos(a:wuc, 'bcn') |
|
396 |
|
let l:pref = matchstr(getline('.'), |
|
397 |
|
\ s:idregex.'\zs\%(::\|\.\|->\)\ze\%'.l:col.'c' |
|
398 |
|
\ .a:wuc) |
|
399 |
|
let l:suf = matchstr(getline('.'), |
|
400 |
|
\ '\%'.l:col.'c' |
|
401 |
|
\ .a:wuc.'\zs\%(::\|\.\|->\)\ze'.s:idregex) |
|
402 |
|
if l:pref == '.' || l:pref == '->' |
|
403 |
|
return 2 |
|
404 |
|
elseif l:pref == '::' |
|
405 |
|
return 1 |
|
406 |
|
elseif l:suf == '::' |
|
407 |
|
return 3 |
|
408 |
|
else |
|
409 |
|
return 0 |
|
410 |
|
endif |
|
411 |
|
endfunction |
|
412 |
|
|
|
413 |
|
" vim: set foldmethod=syntax foldlevel=0 : |