Before: function! GenerateResults(buffer, output) return [ \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'E', \ 'text': 'foo', \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'W', \ 'text': 'bar', \ }, \ { \ 'lnum': 3, \ 'col': 5, \ 'type': 'E', \ 'text': 'wat', \ }, \] endfunction call ale#linter#Define('testft', { \ 'name': 'x', \ 'executable': 'echo', \ 'command': 'echo', \ 'callback': 'GenerateResults', \}) After: delfunction GenerateResults call ale#linter#Reset() let g:ale_buffer_info = {} call clearmatches() Given testft(A Javscript file with warnings/errors): foo bar baz wat line four Execute(Highlights should be set when a linter runs): call ale#Lint() call ale#engine#WaitForJobs(2000) AssertEqual \ [ \ {'group': 'ALEError', 'id': 4, 'priority': 10, 'pos1': [1, 1, 1]}, \ {'group': 'ALEWarning', 'id': 5, 'priority': 10, 'pos1': [2, 1, 1]}, \ {'group': 'ALEError', 'id': 6, 'priority': 10, 'pos1': [3, 5, 1]} \ ], \ getmatches() AssertEqual [4, 5, 6], map(copy(g:ale_buffer_info[bufnr('')].loclist), 'v:val.match_id') Execute(Existing highlights should be kept): call matchaddpos('ALEError', [[1, 2, 1]], 10, 347) call matchaddpos('ALEWarning', [[2, 2, 1]], 10, 348) call ale#highlight#SetHighlights(bufnr('%'), [ \ {'bufnr': bufnr('%'), 'match_id': 347, 'type': 'E', 'lnum': 1, 'col': 2}, \ {'bufnr': bufnr('%'), 'match_id': 348, 'type': 'W', 'lnum': 2, 'col': 2}, \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 3, 'col': 2}, \ {'bufnr': bufnr('%'), 'type': 'W', 'lnum': 4, 'col': 1}, \]) AssertEqual \ [ \ {'group': 'ALEError', 'id': 347, 'priority': 10, 'pos1': [1, 2, 1]}, \ {'group': 'ALEWarning', 'id': 348, 'priority': 10, 'pos1': [2, 2, 1]}, \ {'group': 'ALEError', 'id': 7, 'priority': 10, 'pos1': [3, 2, 1]}, \ {'group': 'ALEWarning', 'id': 8, 'priority': 10, 'pos1': [4, 1, 1]}, \ ], \ getmatches()