diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index dd871c36..0704fd5b 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -393,7 +393,7 @@ function! ale#engine#FixLocList(buffer, linter_name, loclist) abort \ 'text': l:old_item.text, \ 'lnum': str2nr(l:old_item.lnum), \ 'col': str2nr(get(l:old_item, 'col', 0)), - \ 'vcol': get(l:old_item, 'vcol', 0), + \ 'vcol': 0, \ 'type': get(l:old_item, 'type', 'E'), \ 'nr': get(l:old_item, 'nr', -1), \ 'linter_name': a:linter_name, @@ -453,6 +453,20 @@ function! ale#engine#FixLocList(buffer, linter_name, loclist) abort " When errors go beyond the end of the file, put them at the end. " This is only done for the current buffer. let l:item.lnum = l:last_line_number + elseif get(l:old_item, 'vcol', 0) + " Convert virtual column positions to byte positions. + " The positions will be off if the buffer has changed recently. + let l:line = getbufline(a:buffer, l:item.lnum)[0] + + let l:item.col = ale#util#Col(l:line, l:item.col) + + if has_key(l:item, 'end_col') + let l:end_line = get(l:item, 'end_lnum', l:line) != l:line + \ ? getbufline(a:buffer, l:item.end_lnum)[0] + \ : l:line + + let l:item.end_col = ale#util#Col(l:end_line, l:item.end_col) + endif endif call add(l:new_loclist, l:item) diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim index b94a11b7..e0b31e2c 100644 --- a/autoload/ale/util.vim +++ b/autoload/ale/util.vim @@ -311,3 +311,13 @@ function! ale#util#StopPartialTimer(timer_id) abort call remove(s:partial_timers, a:timer_id) endif endfunction + +" Given a possibly multi-byte string and a 1-based character position on a +" line, return the 1-based byte position on that line. +function! ale#util#Col(str, chr) abort + if a:chr < 2 + return a:chr + endif + + return strlen(join(split(a:str, '\zs')[0:a:chr - 2], '')) + 1 +endfunction diff --git a/doc/ale.txt b/doc/ale.txt index 2e5c5e47..97f1b594 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -2072,6 +2072,13 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()* key is also set with a valid number for some other buffer. `vcol` - Defaults to `0`. + + If set to `1`, ALE will convert virtual column + positions for `col` and `end_col` to byte column + positions. If the buffer is changed in-between + checking it and displaying the results, the + calculated byte column positions will probably be + wrong. `type` - Defaults to `'E'`. `nr` - Defaults to `-1`. diff --git a/test/test_loclist_corrections.vader b/test/test_loclist_corrections.vader index 46c7e272..48aa1f78 100644 --- a/test/test_loclist_corrections.vader +++ b/test/test_loclist_corrections.vader @@ -52,7 +52,7 @@ Execute(FixLocList should use the values we supply): \ 'lnum': 3, \ 'col': 4, \ 'bufnr': 10000, - \ 'vcol': 1, + \ 'vcol': 0, \ 'type': 'W', \ 'nr': 42, \ 'linter_name': 'foobar', @@ -348,3 +348,33 @@ Execute(The error code should be passed on): \ 'foobar', \ [{'text': 'a', 'lnum': 11, 'code': 'some-code'}], \ ) + +Given(A file with Japanese multi-byte text): + はじめまして! + -私はワープです。 +Execute(character positions should be converted to byte positions): + AssertEqual + \ [ + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 0, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 1, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 4, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 7, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 7, 'end_col': 13, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 7, 'end_col': 13, 'end_lnum': 1, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 7, 'end_col': 17, 'end_lnum': 2, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 2, 'bufnr': bufnr(''), 'col': 17, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \], + \ ale#engine#FixLocList( + \ bufnr('%'), + \ 'foobar', + \ [ + \ {'text': 'a', 'lnum': 1, 'col': 0, 'vcol': 1}, + \ {'text': 'a', 'lnum': 1, 'col': 1, 'vcol': 1}, + \ {'text': 'a', 'lnum': 1, 'col': 2, 'vcol': 1}, + \ {'text': 'a', 'lnum': 1, 'col': 3, 'vcol': 1}, + \ {'text': 'a', 'lnum': 1, 'col': 3, 'end_col': 5, 'vcol': 1}, + \ {'text': 'a', 'lnum': 1, 'col': 3, 'end_col': 5, 'end_lnum': 1, 'vcol': 1}, + \ {'text': 'a', 'lnum': 1, 'col': 3, 'end_col': 7, 'end_lnum': 2, 'vcol': 1}, + \ {'text': 'a', 'lnum': 2, 'col': 7, 'vcol': 1}, + \ ], + \ )