]> git.madduck.net Git - etc/vim.git/blob - autoload/ale/handlers/haskell.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 / handlers / haskell.vim
1 " Author: w0rp <devw0rp@gmail.com>
2 " Description: Error handling for the format GHC outputs.
3 "
4 function! ale#handlers#haskell#GetStackExecutable(bufnr) abort
5     if ale#path#FindNearestFile(a:bufnr, 'stack.yaml') isnot# ''
6         return 'stack'
7     endif
8
9     " if there is no stack.yaml file, we don't use stack even if it exists,
10     " so we return '', because executable('') apparently always fails
11     return ''
12 endfunction
13
14 " Remember the directory used for temporary files for Vim.
15 let s:temp_dir = fnamemodify(ale#util#Tempname(), ':h')
16 " Build part of a regular expression for matching ALE temporary filenames.
17 let s:temp_regex_prefix =
18 \   '\M'
19 \   . substitute(s:temp_dir, '\\', '\\\\', 'g')
20 \   . '\.\{-}'
21
22 function! s:PanicOutput(lines) abort
23     return [{
24     \   'lnum': 1,
25     \   'col': 1,
26     \   'text': 'ghc panic!',
27     \   'type': 'E',
28     \   'detail' : join(a:lines, "\n"),
29     \}]
30 endfunction
31
32 function! ale#handlers#haskell#HandleGHCFormat(buffer, lines) abort
33     " Look for lines like the following.
34     "
35     "Appoint/Lib.hs:8:1: warning:
36     "Appoint/Lib.hs:8:1:
37     let l:basename = expand('#' . a:buffer . ':t')
38     " Build a complete regular expression for replacing temporary filenames
39     " in Haskell error messages with the basename for this file.
40     let l:temp_filename_regex = s:temp_regex_prefix . l:basename
41
42     let l:pattern = '\v^\s*([a-zA-Z]?:?[^:]+):(\d+):(\d+):(.*)?$'
43     let l:output = []
44
45     let l:corrected_lines = []
46
47     " If ghc panic error, put the whole message in details and exit.
48     let l:panic_position = match(a:lines,'ghc: panic!')
49     let l:panic_end = match(a:lines,'Please report this as a GHC bug:')
50
51     if l:panic_position >= 0
52         return s:PanicOutput(a:lines[l:panic_position : l:panic_end])
53     endif
54
55     " Group the lines into smaller lists.
56     for l:line in a:lines
57         if len(matchlist(l:line, l:pattern)) > 0
58             call add(l:corrected_lines, [l:line])
59         elseif l:line is# ''
60             call add(l:corrected_lines, [l:line])
61         elseif len(l:corrected_lines) > 0
62             call add(l:corrected_lines[-1], l:line)
63         endif
64     endfor
65
66     for l:line_list in l:corrected_lines
67         " Join the smaller lists into one large line to parse.
68         let l:line = l:line_list[0]
69
70         for l:extra_line in l:line_list[1:]
71             let l:line .= substitute(l:extra_line, '\v^\s+', ' ', '')
72         endfor
73
74         let l:match = matchlist(l:line, l:pattern)
75
76         if len(l:match) == 0
77             continue
78         endif
79
80         if !ale#path#IsBufferPath(a:buffer, l:match[1])
81             continue
82         endif
83
84         let l:errors = matchlist(l:match[4], '\v([wW]arning|[eE]rror): ?(.*)')
85
86         if len(l:errors) > 0
87             let l:ghc_type = l:errors[1]
88             let l:text = l:errors[2]
89         else
90             let l:ghc_type = ''
91             let l:text = l:match[4][:0] is# ' ' ? l:match[4][1:] : l:match[4]
92         endif
93
94         if l:ghc_type is? 'Warning'
95             let l:type = 'W'
96         else
97             let l:type = 'E'
98         endif
99
100         " Replace temporary filenames in problem messages with the basename
101         let l:text = substitute(l:text, l:temp_filename_regex, l:basename, 'g')
102
103         let l:item = {
104         \   'lnum': l:match[2] + 0,
105         \   'col': l:match[3] + 0,
106         \   'text': l:text,
107         \   'type': l:type,
108         \}
109
110         " Include extra lines as details if they are there.
111         if len(l:line_list) > 1
112             let l:item.detail = join(l:line_list[1:], "\n")
113         endif
114
115         call add(l:output, l:item)
116     endfor
117
118     return l:output
119 endfunction