]> git.madduck.net Git - etc/vim.git/blob - ale_linters/java/javac.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] / ale_linters / java / javac.vim
1 " Author: farenjihn <farenjihn@gmail.com>, w0rp <devw0rp@gmail.com>
2 " Description: Lints java files using javac
3
4 let s:classpath_sep = has('unix') ? ':' : ';'
5
6 call ale#Set('java_javac_executable', 'javac')
7 call ale#Set('java_javac_options', '')
8 call ale#Set('java_javac_classpath', '')
9 call ale#Set('java_javac_sourcepath', '')
10
11 function! ale_linters#java#javac#RunWithImportPaths(buffer) abort
12     let [l:cwd, l:command] = ale#maven#BuildClasspathCommand(a:buffer)
13
14     " Try to use Gradle if Maven isn't available.
15     if empty(l:command)
16         let [l:cwd, l:command] = ale#gradle#BuildClasspathCommand(a:buffer)
17     endif
18
19     " Try to use Ant if Gradle and Maven aren't available
20     if empty(l:command)
21         let [l:cwd, l:command] = ale#ant#BuildClasspathCommand(a:buffer)
22     endif
23
24     if empty(l:command)
25         return ale_linters#java#javac#GetCommand(a:buffer, [], {})
26     endif
27
28     return ale#command#Run(
29     \   a:buffer,
30     \   l:command,
31     \   function('ale_linters#java#javac#GetCommand'),
32     \   {'cwd': l:cwd},
33     \)
34 endfunction
35
36 function! s:BuildClassPathOption(buffer, import_paths) abort
37     " Filter out lines like [INFO], etc.
38     let l:class_paths = filter(a:import_paths[:], 'v:val !~# ''[''')
39     let l:cls_path = ale#Var(a:buffer, 'java_javac_classpath')
40
41     if !empty(l:cls_path) && type(l:cls_path) is v:t_string
42         call extend(l:class_paths, split(l:cls_path, s:classpath_sep))
43     endif
44
45     if !empty(l:cls_path) && type(l:cls_path) is v:t_list
46         call extend(l:class_paths, l:cls_path)
47     endif
48
49     return !empty(l:class_paths)
50     \   ? '-cp ' . ale#Escape(join(l:class_paths, s:classpath_sep))
51     \   : ''
52 endfunction
53
54 function! ale_linters#java#javac#GetCommand(buffer, import_paths, meta) abort
55     let l:cp_option = s:BuildClassPathOption(a:buffer, a:import_paths)
56     let l:sp_option = ''
57
58     " Find the src directory, for files in this project.
59     let l:src_dir = ale#path#FindNearestDirectory(a:buffer, 'src/main/java')
60     let l:sp_dirs = []
61
62     if !empty(l:src_dir)
63         call add(l:sp_dirs, l:src_dir)
64
65         " Automatically include the jaxb directory too, if it's there.
66         let l:jaxb_dir = fnamemodify(l:src_dir, ':h:h')
67         \   . (has('win32') ? '\jaxb\' : '/jaxb/')
68
69         if isdirectory(l:jaxb_dir)
70             call add(l:sp_dirs, l:jaxb_dir)
71         endif
72     endif
73
74     " Automatically include the test directory, but only for test code.
75     if expand('#' . a:buffer . ':p') =~? '\vsrc[/\\]test[/\\]java'
76         let l:test_dir = ale#path#FindNearestDirectory(a:buffer, 'src/test/java')
77
78         if isdirectory(l:test_dir)
79             call add(l:sp_dirs, l:test_dir)
80         endif
81     endif
82
83     let l:source_paths = []
84     let l:source_path = ale#Var(a:buffer, 'java_javac_sourcepath')
85
86     if !empty(l:source_path) && type(l:source_path) is v:t_string
87         let l:source_paths = split(l:source_path, s:classpath_sep)
88     endif
89
90     if !empty(l:source_path) && type(l:source_path) is v:t_list
91         let l:source_paths = l:source_path
92     endif
93
94     if !empty(l:source_paths)
95         for l:path in l:source_paths
96             let l:sp_path = ale#path#FindNearestDirectory(a:buffer, l:path)
97
98             if !empty(l:sp_path)
99                 call add(l:sp_dirs, l:sp_path)
100             endif
101         endfor
102     endif
103
104     if !empty(l:sp_dirs)
105         let l:sp_option = '-sourcepath '
106         \   . ale#Escape(join(l:sp_dirs, s:classpath_sep))
107     endif
108
109     " Create .class files in a temporary directory, which we will delete later.
110     let l:class_file_directory = ale#command#CreateDirectory(a:buffer)
111
112     " Always run javac from the directory the file is in, so we can resolve
113     " relative paths correctly.
114     return '%e -Xlint'
115     \ . ale#Pad(l:cp_option)
116     \ . ale#Pad(l:sp_option)
117     \ . ' -d ' . ale#Escape(l:class_file_directory)
118     \ . ale#Pad(ale#Var(a:buffer, 'java_javac_options'))
119     \ . ' %t'
120 endfunction
121
122 function! ale_linters#java#javac#Handle(buffer, lines) abort
123     " Look for lines like the following.
124     "
125     " Main.java:13: warning: [deprecation] donaught() in Testclass has been deprecated
126     " Main.java:16: error: ';' expected
127     let l:directory = expand('#' . a:buffer . ':p:h')
128     let l:pattern = '\v^(.*):(\d+): (.{-1,}):(.+)$'
129     let l:col_pattern = '\v^(\s*\^)$'
130     let l:symbol_pattern = '\v^ +symbol: *(class|method) +([^ ]+)'
131     let l:output = []
132
133     for l:match in ale#util#GetMatches(a:lines, [l:pattern, l:col_pattern, l:symbol_pattern])
134         if empty(l:match[2]) && empty(l:match[3])
135             if !empty(l:match[1]) && !empty(l:output)
136                 let l:output[-1].col = len(l:match[1])
137             endif
138         elseif empty(l:match[3])
139             " Add symbols to 'cannot find symbol' errors.
140             if l:output[-1].text is# 'error: cannot find symbol'
141                 let l:output[-1].text .= ': ' . l:match[2]
142             endif
143         else
144             call add(l:output, {
145             \   'filename': ale#path#GetAbsPath(l:directory, l:match[1]),
146             \   'lnum': l:match[2] + 0,
147             \   'text': l:match[3] . ':' . l:match[4],
148             \   'type': l:match[3] is# 'error' ? 'E' : 'W',
149             \})
150         endif
151     endfor
152
153     return l:output
154 endfunction
155
156 call ale#linter#Define('java', {
157 \   'name': 'javac',
158 \   'executable': {b -> ale#Var(b, 'java_javac_executable')},
159 \   'cwd': '%s:h',
160 \   'command': function('ale_linters#java#javac#RunWithImportPaths'),
161 \   'output_stream': 'stderr',
162 \   'callback': 'ale_linters#java#javac#Handle',
163 \})