~gpanders/dotfiles

ref: c8e63bac959db19c138dcc3198a56514f0b444ff dotfiles/.vim/after/plugin/projectionist/compile_commands.vim -rw-r--r-- 2.6 KiB
c8e63bacGreg Anders Manage dotfiles directly in home directory 1 year, 3 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
" Projections for projects with compile_commands.json
" Author: Greg Anders <greg@gpanders.com>
" Date: 2019-03-20

if !get(g:, 'loaded_projectionist', 0)
  finish
endif

let g:projectionist_heuristics = get(g:, 'projectionist_heuristics', {})

call extend(g:projectionist_heuristics, {
      \ 'compile_commands.json': {
      \   'src/*.cpp': {
      \     'type': 'src',
      \     'alternate': ['src/{}.h', 'include/{}.h'],
      \   },
      \   'src/*.cc': {
      \     'type': 'src',
      \     'alternate': ['src/{}.h', 'include/{}.h'],
      \   },
      \   'src/*.h': {
      \     'type': 'include',
      \     'alternate': ['src/{}.cpp', 'src/{}.cc'],
      \   },
      \   'include/*.h': {
      \     'type': 'include',
      \     'alternate': ['src/{}.cpp', 'src/{}.cc'],
      \   }
      \ }})

let s:paths = {}

let s:async = (has('nvim') || has('job')) && executable('jq')

function! s:parse_compile_commands(root)
  if s:async
    call async#run([
          \ 'jq',
          \ '-c',
          \ '[[.[].command?, .[].arguments[]?] | join(" ") | match("-(?:I|isystem )(\\S+)"; "g") | .captures[0].string] | unique',
          \ a:root . '/compile_commands.json'
          \ ], {paths -> s:set_path(a:root, eval(get(paths, 0, '[]')))})
  else
    let compile_commands = projectionist#json_parse(readfile(a:root . '/compile_commands.json'))
    let cmds = []
    for item in compile_commands
      if has_key(item, 'arguments')
        let cmd = join(item.arguments)
      elseif has_key(item, 'command')
        let cmd = item.command
      else
        continue
      endif
      let cmds += [cmd]
    endfor
    " Add every match of -I<dir> or -isystem <dir> to paths
    let paths = []
    call substitute(join(cmds),
          \ '\C\-\%(I\|isystem \)\(\f\+\)', '\=add(paths, submatch(1))', 'g')

    let paths = uniq(sort(paths))
    call s:set_path(a:root, paths)
  endif
endfunction

function! s:set_path(root, ...)
  if a:0
    let paths = a:1
    let s:paths[a:root] = filter(map(paths, "fnamemodify(v:val, ':p')"), 'isdirectory(v:val)')
  endif
  for dir in s:paths[a:root]
    if stridx(',' . &l:path . ',', ',' . escape(dir, ', ') . ',') < 0
      let &l:path = escape(dir, ', ') . ',' . &path
    endif
  endfor
endfunction

function! s:activate() abort
  let root = projectionist#path()
  if ProjectionistHas('compile_commands.json', root)
    if !has_key(s:paths, root)
      call s:parse_compile_commands(root)
    else
      call s:set_path(root)
    endif
  endif
endfunction

autocmd User ProjectionistActivate
      \ if &ft ==# 'c' || &ft ==# 'cpp' |
      \   call s:activate() |
      \ endif