├── README ├── autoload └── unite │ └── sources │ └── tag.vim └── doc └── unite-tag.txt /README: -------------------------------------------------------------------------------- 1 | please see doc/unite-tag.txt 2 | -------------------------------------------------------------------------------- /autoload/unite/sources/tag.vim: -------------------------------------------------------------------------------- 1 | " tag source for unite.vim 2 | " Version: 0.2.0 3 | " Author: tsukkee 4 | " thinca 5 | " Shougo 6 | " Licence: The MIT License {{{ 7 | " Permission is hereby granted, free of charge, to any person obtaining a copy 8 | " of this software and associated documentation files (the "Software"), to deal 9 | " in the Software without restriction, including without limitation the rights 10 | " to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | " copies of the Software, and to permit persons to whom the Software is 12 | " furnished to do so, subject to the following conditions: 13 | " 14 | " The above copyright notice and this permission notice shall be included in 15 | " all copies or substantial portions of the Software. 16 | " 17 | " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | " IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | " FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | " AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | " LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | " OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | " THE SOFTWARE. 24 | " }}} 25 | 26 | " define source 27 | function! unite#sources#tag#define() abort 28 | return [s:source, s:source_files, s:source_include] 29 | endfunction 30 | 31 | let g:unite_source_tag_max_name_length = 32 | \ get(g:, 'unite_source_tag_max_name_length', 25) 33 | let g:unite_source_tag_max_kind_length = 34 | \ get(g:, 'unite_source_tag_max_kind_length', 8) 35 | let g:unite_source_tag_max_fname_length = 36 | \ get(g:, 'unite_source_tag_max_fname_length', 20) 37 | 38 | let g:unite_source_tag_name_footer_length = 39 | \ get(g:, 'unite_source_tag_name_footer_length', 10) 40 | let g:unite_source_tag_fname_footer_length = 41 | \ get(g:, 'unite_source_tag_fname_footer_length', 15) 42 | 43 | " When enabled, use multi-byte aware string truncate method 44 | let g:unite_source_tag_strict_truncate_string = 45 | \ get(g:, 'unite_source_tag_strict_truncate_string', 1) 46 | 47 | let g:unite_source_tag_show_fname = 48 | \ get(g:, 'unite_source_tag_show_fname', 1) 49 | 50 | let g:unite_source_tag_show_kind = 51 | \ get(g:, 'unite_source_tag_show_kind', 1) 52 | 53 | let g:unite_source_tag_relative_fname = 54 | \ get(g:, 'unite_source_tag_relative_fname', 1) 55 | 56 | let g:unite_source_tag_show_location = 57 | \ get(g:, 'unite_source_tag_show_location', 1) 58 | 59 | " cache 60 | let s:tagfile_cache = {} 61 | let s:input_cache = {} 62 | 63 | " cache directory 64 | let s:cache_dir = unite#get_data_directory() . '/tag' 65 | if !isdirectory(s:cache_dir) 66 | call mkdir(s:cache_dir, 'p') 67 | endif 68 | 69 | " use vital 70 | let s:C = unite#util#get_vital_cache() 71 | 72 | " source 73 | let s:source = { 74 | \ 'name': 'tag', 75 | \ 'description': 'candidates from tag file', 76 | \ 'max_candidates': 200, 77 | \ 'action_table': {}, 78 | \ 'hooks': {}, 79 | \ 'syntax': 'uniteSource__Tag', 80 | \} 81 | 82 | function! s:source.hooks.on_syntax(args, context) abort 83 | syntax match uniteSource__Tag_File / @.\{-} /ms=s+2,me=e-2 84 | \ containedin=uniteSource__Tag contained 85 | \ nextgroup=uniteSource__Tag_Kind, 86 | \uniteSource__Tag_Pat,uniteSource__Tag_Line skipwhite 87 | syntax match uniteSource__Tag_Kind /k:\h\w*\s\+/ contained 88 | \ nextgroup=uniteSource__Tag_Pat,uniteSource__Tag_Line 89 | syntax match uniteSource__Tag_Pat /pat:.\{-}\ze\s*$/ contained 90 | syntax match uniteSource__Tag_Line /line:.\{-}\ze\s*$/ contained 91 | highlight default link uniteSource__Tag_File Constant 92 | highlight default link uniteSource__Tag_Kind Type 93 | highlight default link uniteSource__Tag_Pat Comment 94 | highlight default link uniteSource__Tag_Line LineNr 95 | if has('conceal') 96 | syntax match uniteSource__Tag_Ignore /pat:/ 97 | \ containedin=uniteSource__Tag_Pat conceal 98 | else 99 | syntax match uniteSource__Tag_Ignore /pat:/ 100 | \ containedin=uniteSource__Tag_Pat 101 | highlight default link uniteSource__Tag_Ignore Ignore 102 | endif 103 | endfunction 104 | 105 | function! s:source.hooks.on_init(args, context) abort 106 | let a:context.source__tagfiles = tagfiles() 107 | let a:context.source__name = 'tag' 108 | endfunction 109 | 110 | function! s:source.gather_candidates(args, context) abort 111 | let a:context.source__continuation = [] 112 | if a:context.input != '' 113 | return s:taglist_filter(a:context.input, self.name) 114 | endif 115 | 116 | let result = [] 117 | for tagfile in a:context.source__tagfiles 118 | let tagdata = s:get_tagdata(tagfile, a:context) 119 | if empty(tagdata) 120 | continue 121 | endif 122 | let result += tagdata.tags 123 | if has_key(tagdata, 'cont') 124 | let a:context.is_async = 1 125 | call add(a:context.source__continuation, tagdata) 126 | endif 127 | endfor 128 | 129 | let a:context.source__cont_number = 1 130 | let a:context.source__cont_max = len(a:context.source__continuation) 131 | 132 | return s:pre_filter(result, a:args) 133 | endfunction 134 | 135 | function! s:source.async_gather_candidates(args, context) abort 136 | " caching has done 137 | if empty(a:context.source__continuation) 138 | let a:context.is_async = 0 139 | call unite#print_message( 140 | \ printf('[%s] Caching Done!', a:context.source__name)) 141 | return [] 142 | endif 143 | 144 | let result = [] 145 | let tagdata = a:context.source__continuation[0] 146 | if !has_key(tagdata, 'cont') 147 | return [] 148 | endif 149 | 150 | let is_file = self.name ==# 'tag/file' 151 | " gather all candidates if 'immediately' flag is set 152 | if a:context.immediately 153 | while !empty(tagdata.cont.lines) 154 | let result += s:next(tagdata, remove(tagdata.cont.lines, 0), self.name) 155 | endwhile 156 | " gather candidates per 0.05s if 'reltime' and 'float' are enable 157 | elseif has('reltime') && has('float') 158 | let time = reltime() 159 | while str2float(reltimestr(reltime(time))) < 1.0 160 | \ && !empty(tagdata.cont.lines) 161 | let result += s:next(tagdata, remove(tagdata.cont.lines, 0), self.name) 162 | endwhile 163 | " otherwise, gather candidates per 100 items 164 | else 165 | let i = 1000 166 | while 0 < i && !empty(tagdata.cont.lines) 167 | let result += s:next(tagdata, remove(tagdata.cont.lines, 0), self.name) 168 | let i -= 1 169 | endwhile 170 | endif 171 | 172 | " show progress 173 | call unite#clear_message() 174 | let len = tagdata.cont.lnum 175 | let progress = (len - len(tagdata.cont.lines)) * 100 / len 176 | call unite#print_message( 177 | \ printf('[%s] [%2d/%2d] Caching of "%s"...%d%%', 178 | \ a:context.source__name, 179 | \ a:context.source__cont_number, a:context.source__cont_max, 180 | \ tagdata.cont.tagfile, progress)) 181 | 182 | " when caching has done 183 | if empty(tagdata.cont.lines) 184 | let tagfile = tagdata.cont.tagfile 185 | 186 | call remove(tagdata, 'cont') 187 | call remove(a:context.source__continuation, 0) 188 | let a:context.source__cont_number += 1 189 | 190 | " output parse results to file 191 | call s:write_cache(tagfile) 192 | endif 193 | 194 | return s:pre_filter(result, a:args) 195 | endfunction 196 | 197 | 198 | " source tag/file 199 | let s:source_files = { 200 | \ 'name': 'tag/file', 201 | \ 'description': 'candidates from files contained in tag file', 202 | \ 'action_table': {}, 203 | \ 'hooks': {'on_init': s:source.hooks.on_init}, 204 | \ 'async_gather_candidates': s:source.async_gather_candidates, 205 | \} 206 | 207 | function! s:source_files.gather_candidates(args, context) abort 208 | let a:context.source__continuation = [] 209 | let files = {} 210 | for tagfile in a:context.source__tagfiles 211 | let tagdata = s:get_tagdata(tagfile, a:context) 212 | if empty(tagdata) 213 | continue 214 | endif 215 | call extend(files, tagdata.files) 216 | if has_key(tagdata, 'cont') 217 | let a:context.is_async = 1 218 | call add(a:context.source__continuation, tagdata) 219 | endif 220 | endfor 221 | 222 | let a:context.source__cont_number = 1 223 | let a:context.source__cont_max = len(a:context.source__continuation) 224 | 225 | return map(sort(keys(files)), 'files[v:val]') 226 | endfunction 227 | 228 | 229 | " source tag/include 230 | let s:source_include = deepcopy(s:source) 231 | let s:source_include.name = 'tag/include' 232 | let s:source_include.description = 233 | \ 'candidates from files contained in include tag file' 234 | let s:source_include.max_candidates = 0 235 | 236 | function! s:source_include.hooks.on_init(args, context) abort 237 | if get(g:, 'loaded_neoinclude', 0) 238 | if empty(neoinclude#include#get_tag_files()) 239 | NeoIncludeMakeCache 240 | endif 241 | let a:context.source__tagfiles = neoinclude#include#get_tag_files() 242 | else 243 | let a:context.source__tagfiles = [] 244 | endif 245 | let a:context.source__name = 'tag/include' 246 | endfunction 247 | 248 | function! s:source_include.gather_candidates(args, context) abort 249 | if empty(a:context.source__tagfiles) 250 | call unite#print_message( 251 | \ printf('[%s] Nothing include files.', a:context.source__name)) 252 | endif 253 | 254 | let a:context.source__continuation = [] 255 | let result = [] 256 | for tagfile in a:context.source__tagfiles 257 | let tagdata = s:get_tagdata(tagfile, a:context) 258 | if empty(tagdata) 259 | continue 260 | endif 261 | let result += tagdata.tags 262 | if has_key(tagdata, 'cont') 263 | let a:context.is_async = 1 264 | call add(a:context.source__continuation, tagdata) 265 | endif 266 | endfor 267 | 268 | let a:context.source__cont_number = 1 269 | let a:context.source__cont_max = len(a:context.source__continuation) 270 | 271 | return s:pre_filter(result, a:args) 272 | endfunction 273 | 274 | " filter defined by unite's parameter (e.g. Unite tag:filter) 275 | function! s:pre_filter(result, args) abort 276 | if empty(a:args) 277 | return unite#util#uniq_by(a:result, 'v:val.abbr') 278 | endif 279 | 280 | for arg in a:args 281 | if arg ==# '' 282 | continue 283 | endif 284 | if arg ==# '%' 285 | " Current buffer tags 286 | let bufname = (&ft==#'unite' ? 287 | \ bufname(b:unite.prev_bufnr) : expand('%:p')) 288 | call filter(a:result, 'v:val.action__path ==# bufname') 289 | elseif arg =~# '/' 290 | " Pattern matching name 291 | let pat = arg[1 : ] 292 | call filter(a:result, 'v:val.word =~? pat') 293 | else 294 | " Normal matching name 295 | call filter(a:result, 'v:val.word ==# arg') 296 | endif 297 | endfor 298 | return unite#util#uniq_by(a:result, 'v:val.abbr') 299 | endfunction 300 | 301 | function! s:get_tagdata(tagfile, context) abort 302 | let tagfile = fnamemodify(a:tagfile, ':p') 303 | if !filereadable(tagfile) 304 | return {} 305 | endif 306 | 307 | " try to read date from cache file 308 | call s:read_cache(tagfile) 309 | 310 | " set cache structure when: 311 | " - cache file is not available 312 | " - cache data is expired 313 | if !has_key(s:tagfile_cache, tagfile) 314 | \ || s:tagfile_cache[tagfile].time != getftime(tagfile) 315 | \ || a:context.is_redraw 316 | let lines = readfile(tagfile) 317 | let s:tagfile_cache[tagfile] = { 318 | \ 'time': getftime(tagfile), 319 | \ 'tags': [], 320 | \ 'files': {}, 321 | \ 'cont': { 322 | \ 'lines': lines, 323 | \ 'lnum': len(lines), 324 | \ 'basedir': fnamemodify(tagfile, ':p:h'), 325 | \ 'encoding': '', 326 | \ 'tagfile': tagfile, 327 | \ }, 328 | \} 329 | endif 330 | return s:tagfile_cache[tagfile] 331 | endfunction 332 | 333 | function! s:taglist_filter(input, name) abort 334 | let key = string(tagfiles()).a:input 335 | if has_key(s:input_cache, key) 336 | return s:input_cache[key] 337 | endif 338 | 339 | let taglist = map(taglist(a:input), "{ 340 | \ 'word': v:val.name, 341 | \ 'abbr': printf('%s%s%s%s', 342 | \ s:truncate(v:val.name, 343 | \ g:unite_source_tag_max_name_length, 344 | \ g:unite_source_tag_name_footer_length, '..'), 345 | \ (!g:unite_source_tag_show_fname ? '' : 346 | \ ' ' . s:truncate('@'.fnamemodify( 347 | \ v:val.filename, (a:name ==# 'tag/include' 348 | \ || !g:unite_source_tag_relative_fname ? 349 | \ ':t' : ':~:.')), 350 | \ g:unite_source_tag_max_fname_length, 351 | \ g:unite_source_tag_fname_footer_length, '..')), 352 | \ (!g:unite_source_tag_show_kind ? '' : 353 | \ ' k:' . s:truncate(v:val.kind, 354 | \ g:unite_source_tag_max_kind_length, 2, '..')), 355 | \ (!g:unite_source_tag_show_location ? '' : 356 | \ ' pat:' . matchstr(v:val.cmd, 357 | \ '^[?/]\\^\\?\\zs.\\{-1,}\\ze\\$\\?[?/]$')) 358 | \ ), 359 | \ 'kind': 'jump_list', 360 | \ 'action__path': unite#util#substitute_path_separator( 361 | \ fnamemodify(v:val.filename, ':p')), 362 | \ 'action__tagname': v:val.name, 363 | \ 'source__cmd': v:val.cmd, 364 | \}") 365 | 366 | " Uniq 367 | let taglist = s:pre_filter(taglist, {}) 368 | 369 | " Set search pattern. 370 | for tag in taglist 371 | let cmd = tag.source__cmd 372 | 373 | if cmd =~ '^\d\+$' 374 | let linenr = cmd - 0 375 | let tag.action__line = linenr 376 | else 377 | " remove / or ? at the head and the end 378 | let pattern = matchstr(cmd, '^\([/?]\)\?\zs.*\ze\1$') 379 | " unescape / 380 | let pattern = substitute(pattern, '\\\/', '/', 'g') 381 | " use 'nomagic' 382 | let pattern = '\M' . pattern 383 | 384 | let tag.action__pattern = pattern 385 | endif 386 | endfor 387 | 388 | let s:input_cache[key] = taglist 389 | return taglist 390 | endfunction 391 | 392 | function! s:truncate(str, max, footer_width, sep) abort 393 | if g:unite_source_tag_strict_truncate_string 394 | return unite#util#truncate_smart(a:str, a:max, a:footer_width, a:sep) 395 | else 396 | let l = len(a:str) 397 | if l <= a:max 398 | return a:str . repeat(' ', a:max - l) 399 | else 400 | return a:str[0 : (l - a:footer_width-len(a:sep))] 401 | \ .a:sep.a:str[-a:footer_width : -1] 402 | endif 403 | endif 404 | endfunction 405 | 406 | function! s:next(tagdata, line, name) abort 407 | let is_file = a:name ==# 'tag/file' 408 | let cont = a:tagdata.cont 409 | " parsing tag files is faster than using taglist() 410 | let line = cont.encoding != '' ? iconv(a:line, cont.encoding, &encoding) 411 | \ : a:line 412 | let [name, filename, cmd] = s:parse_tag_line(line) 413 | 414 | " check comment line 415 | if empty(name) 416 | if filename != '' 417 | let cont.encoding = filename 418 | endif 419 | return [] 420 | endif 421 | 422 | " when cmd shows line number 423 | let linenr = 0 424 | if cmd =~ '^\d\+$' 425 | let linenr = cmd - 0 426 | else 427 | " remove / or ? at the head and the end 428 | if cmd =~ '^[/?]' 429 | let pattern = cmd[1:-2] 430 | else 431 | let pattern = cmd 432 | endif 433 | " unescape / 434 | let pattern = substitute(pattern, '\\\/', '/', 'g') 435 | " use 'nomagic' 436 | let pattern = '\M' . pattern 437 | endif 438 | 439 | let path = filename =~ '^\%(/\|\a\+:[/\\]\)' ? 440 | \ filename : 441 | \ unite#util#substitute_path_separator( 442 | \ fnamemodify(cont.basedir . '/' . filename, ':p:.')) 443 | 444 | let option = s:parse_option(line) 445 | 446 | let abbr = s:truncate(name, g:unite_source_tag_max_name_length, 447 | \ g:unite_source_tag_name_footer_length, '..') 448 | if g:unite_source_tag_show_fname 449 | let abbr .= ' ' 450 | let abbr .= s:truncate('@'. 451 | \ fnamemodify(path, ( 452 | \ (a:name ==# 'tag/include' 453 | \ || !g:unite_source_tag_relative_fname) ? 454 | \ ':t' : ':~:.')), 455 | \ g:unite_source_tag_max_fname_length, 456 | \ g:unite_source_tag_fname_footer_length, '..') 457 | endif 458 | if g:unite_source_tag_show_kind && option.kind != '' 459 | let abbr .= ' k:' . s:truncate(option.kind, 460 | \ g:unite_source_tag_max_kind_length, 2, '..') 461 | endif 462 | if g:unite_source_tag_show_location 463 | let abbr .= linenr ? ' line:' . linenr 464 | \ : ' pat:' . 465 | \ matchstr(cmd, '^[?/]\^\?\zs.\{-1,}\ze\$\?[?/]$') 466 | endif 467 | 468 | let fullpath = unite#util#substitute_path_separator( 469 | \ fnamemodify(path, ':p')) 470 | let tag = { 471 | \ 'word': name, 472 | \ 'abbr': abbr, 473 | \ 'kind': 'jump_list', 474 | \ 'action__path': fullpath, 475 | \ 'action__tagname': name 476 | \} 477 | if linenr 478 | let tag.action__line = linenr 479 | else 480 | let tag.action__pattern = pattern 481 | endif 482 | call add(a:tagdata.tags, tag) 483 | 484 | let result = is_file ? [] : [tag] 485 | 486 | if !has_key(a:tagdata.files, fullpath) 487 | let file = { 488 | \ 'word': fullpath, 489 | \ 'abbr': fnamemodify(fullpath, ':.'), 490 | \ 'kind': 'jump_list', 491 | \ 'action__path': fullpath, 492 | \ 'action__directory': unite#util#path2directory(fullpath), 493 | \ } 494 | let a:tagdata.files[fullpath] = file 495 | if is_file 496 | let result = [file] 497 | endif 498 | endif 499 | 500 | return result 501 | endfunction 502 | 503 | 504 | " Tag file format 505 | " tag_namefile_nameex_cmd 506 | " tag_namefile_nameex_cmd;"extension_fields 507 | " Parse 508 | " 0. a line starting with ! is comment line 509 | " 1. split extension_fields and others by separating the string at the last ;" 510 | " 2. parse the former half by spliting it by 511 | " 3. the first part is tag_name, the second part is file_name 512 | " and ex_cmd is taken by joining remain parts with 513 | " 4. parsing extension_fields 514 | function! s:parse_tag_line(line) abort 515 | " 0. 516 | if a:line[0] == '!' 517 | let enc = matchstr(a:line, '\C^!_TAG_FILE_ENCODING\t\zs\S\+\ze\t') 518 | return ['', enc, ''] 519 | endif 520 | 521 | " 1. 522 | let tokens = split(a:line, ';"') 523 | let tokens_len = len(tokens) 524 | if tokens_len > 2 525 | let former = join(tokens[0:-2], ';"') 526 | elseif tokens_len == 2 527 | let former = tokens[0] 528 | else 529 | let former = a:line 530 | endif 531 | 532 | " 2. 533 | let fields = split(former, "\t") 534 | if len(fields) < 3 535 | return ['', '', ''] 536 | endif 537 | 538 | " 3. 539 | let name = fields[0] 540 | let file = fields[1] 541 | let cmd = len(fields) == 3 ? fields[2] : join(fields[2:-1], "\t") 542 | 543 | " 4. TODO 544 | 545 | return [name, file, cmd] 546 | endfunction 547 | " " test case 548 | " let s:test = 'Hoge test.php /^function! Hoge()\/*$\/;" f test:*\/ {$/;" f' 549 | " echomsg string(s:parse_tag_line(s:test)) 550 | " let s:test = 'Hoge Hoge/Fuga.php /^class Hoge$/;" c line:15' 551 | " echomsg string(s:parse_tag_line(s:test)) 552 | 553 | " cache to file 554 | function! s:filename_to_cachename(filename) abort 555 | return s:cache_dir . '/' . substitute(a:filename, '[\/]', '+=', 'g') 556 | endfunction 557 | 558 | function! s:write_cache(filename) abort 559 | call s:C.writefile(s:cache_dir, a:filename, 560 | \ [string(s:tagfile_cache[a:filename])]) 561 | endfunction 562 | 563 | function! s:read_cache(filename) abort 564 | if !s:C.check_old_cache(s:cache_dir, a:filename) 565 | let data = s:C.readfile(s:cache_dir, a:filename) 566 | sandbox let s:tagfile_cache[a:filename] = eval(data[0]) 567 | endif 568 | endfunction 569 | 570 | function! s:parse_option(line) abort 571 | let option = {} 572 | let option.kind = '' 573 | 574 | for opt in split(a:line[len(matchstr(a:line, '.*/;"')):], '\t', 1) 575 | let key = matchstr(opt, '^\h\w*\ze:') 576 | if key == '' 577 | let option.kind = opt 578 | else 579 | let option[key] = matchstr(opt, '^\h\w*:\zs.*') 580 | endif 581 | endfor 582 | 583 | return option 584 | endfunction 585 | 586 | " action 587 | let s:action_table = {} 588 | 589 | let s:action_table.jump = { 590 | \ 'description': 'jump to the selected tag' 591 | \} 592 | function! s:action_table.jump.func(candidate) abort 593 | execute "tjump" a:candidate.action__tagname 594 | endfunction 595 | 596 | let s:action_table.select = { 597 | \ 'description': 'list the tags matching the selected tag pattern' 598 | \} 599 | function! s:action_table.select.func(candidate) abort 600 | execute "tselect" a:candidate.action__tagname 601 | endfunction 602 | 603 | let s:action_table.jsplit = { 604 | \ 'description': 'split window and jump to the selected tag', 605 | \ 'is_selectable': 1 606 | \} 607 | function! s:action_table.jsplit.func(candidates) abort 608 | for c in a:candidates 609 | execute "stjump" c.action__tagname 610 | endfor 611 | endfunction 612 | 613 | let s:source.action_table = s:action_table 614 | let s:source_include.action_table = s:action_table 615 | 616 | " vim:foldmethod=marker:fen:sw=4:sts=4 617 | -------------------------------------------------------------------------------- /doc/unite-tag.txt: -------------------------------------------------------------------------------- 1 | *unite-tag.txt* tags source for unite.vim 2 | 3 | Version: 0.2.0 4 | Author: tsukkee 5 | thinca 6 | Shougo 7 | Licence: The MIT License 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | 27 | ============================================================================== 28 | INTRODUCTION *unite-tag-introduction* 29 | 30 | *unite-tag* is a |unite.vim| plugin for selecting |tags| or selecting files 31 | including |tags|. 32 | 33 | Requirement: 34 | - |unite.vim| (Recommend latest version at https://github.com/Shougo/unite.vim) 35 | Note: Using tag/include source 36 | - |neoinclude| (Recommend latest version at 37 | https://github.com/Shougo/neoinclude.vim) 38 | 39 | Latest version: 40 | https://github.com/tsukkee/unite-tag 41 | 42 | 43 | ============================================================================== 44 | USAGE *unite-tag-usage* 45 | 46 | To select tags, execute |:Unite| with argument of tag 47 | > 48 | :Unite tag 49 | < 50 | To select files including tags, execute |:Unite| with argument of tag/file 51 | > 52 | :Unite tag/file 53 | < 54 | To select include tags generated like |tagbar| or |ctrlp|, execute 55 | |:Unite| with argument of tag/include. 56 | Note: |neoinclude| is needed. 57 | > 58 | :Unite tag/include 59 | < 60 | Also, you can filter result using parameter. 61 | > 62 | :Unite tag:text 63 | < 64 | Other filters: > 65 | 66 | :Unite tag:% " Current-buffer 67 | :Unite tag:/pattern " Filter with pattern 68 | 69 | < 70 | This plugin does not block vim because tags' information is aggregated 71 | asynchronously. 72 | 73 | 74 | 75 | ============================================================================== 76 | CUSTOMIZE *unite-tag-customize* 77 | 78 | If you want to unite-tag instead of ||, try to write below in your vimrc. 79 | This allows you to use unite-tag only in normal buffers. But, if the tag 80 | files are too large, this mapping blocks vim for a while, because unite-tag 81 | aggregates tags' information synchronously when -immediately is set. 82 | > 83 | autocmd BufEnter * 84 | \ if empty(&buftype) 85 | \| nnoremap :UniteWithCursorWord -immediately tag 86 | \| endif 87 | < 88 | ------------------------------------------------------------------------------ 89 | VARIABLES *unite-tag-variables* 90 | 91 | g:unite_source_tag_max_name_length *g:unite_source_tag_max_name_length* 92 | Max length of tag name field in candidate. 93 | The default value is 25. 94 | 95 | 96 | g:unite_source_tag_max_kind_length *g:unite_source_tag_max_kind_length* 97 | Max length of tag kind field in candidate. 98 | The default value is 8. 99 | 100 | 101 | g:unite_source_tag_max_fname_length *g:unite_source_tag_max_fname_length* 102 | Max length of file name field in candidate. 103 | The default value is 20. 104 | 105 | 106 | g:unite_source_tag_name_footer_length *g:unite_source_tag_name_footer_length* 107 | Leave this many characters from the end of the tag's name. 108 | The default value is 10. 109 | 110 | 111 | g:unite_source_tag_fname_footer_length *g:unite_source_tag_fname_footer_length* 112 | Leave this many characters from the end of the tag's file name. 113 | The default value is 15. 114 | 115 | 116 | *g:unite_source_tag_strict_truncate_string* 117 | g:unite_source_tag_strict_truncate_string 118 | Use multi-byte aware string truncate method(precise, but slower). 119 | The default value is 1. 120 | 121 | 122 | g:unite_source_tag_show_fname *g:unite_source_tag_show_fname* 123 | Show file name field. 124 | The default value is 1. 125 | 126 | 127 | g:unite_source_tag_show_kind *g:unite_source_tag_show_kind* 128 | Show kind field. 129 | The default value is 1. 130 | 131 | 132 | g:unite_source_tag_show_location *g:unite_source_tag_show_location* 133 | Show source location field. 134 | The default value is 1. 135 | 136 | 137 | g:unite_source_tag_relative_fname *g:unite_source_tag_relative_fname* 138 | Use relative file name in the file name field. 139 | The default value is 1. 140 | 141 | 142 | ============================================================================== 143 | FAQ *unite-tag-faq* 144 | 145 | Q: I want to open files without generating tags files like ctrlp.vim or 146 | tagbar plugin. 147 | 148 | A: You can use "tag/include" source. But it needs |neoinclude| plugin. It uses 149 | automatically generated tag files. 150 | 151 | ============================================================================== 152 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 153 | --------------------------------------------------------------------------------