diff --git a/autoload/ale/completion.vim b/autoload/ale/completion.vim index 1c9191a1..bb664e03 100644 --- a/autoload/ale/completion.vim +++ b/autoload/ale/completion.vim @@ -776,7 +776,8 @@ function! s:OnReady(linter, lsp_details) abort if a:linter.lsp is# 'tsserver' if get(g:, 'ale_completion_tsserver_autoimport') is 1 - execute 'echom `g:ale_completion_tsserver_autoimport` is deprecated. Use `g:ale_completion_autoimport` instead.''' + " no-custom-checks + echom '`g:ale_completion_tsserver_autoimport` is deprecated. Use `g:ale_completion_autoimport` instead.' endif let l:message = ale#lsp#tsserver_message#Completions( diff --git a/autoload/ale/cursor.vim b/autoload/ale/cursor.vim index ac6b48ba..3479603e 100644 --- a/autoload/ale/cursor.vim +++ b/autoload/ale/cursor.vim @@ -10,6 +10,12 @@ let g:ale_echo_msg_format = get(g:, 'ale_echo_msg_format', '%code: %%s') let s:cursor_timer = -1 +" A wrapper for echon so we can test messages we echo in Vader tests. +function! ale#cursor#Echon(message) abort + " no-custom-checks + echon a:message +endfunction + function! ale#cursor#TruncatedEcho(original_message) abort let l:message = a:original_message " Change tabs to spaces. @@ -37,7 +43,7 @@ function! ale#cursor#TruncatedEcho(original_message) abort let l:message = l:message[:&columns - 5] . '...' endif - echon l:message + call ale#cursor#Echon(l:message) catch /^Vim\%((\a\+)\)\=:E523/ " Fallback into manual truncate (#1987) let l:winwidth = winwidth(0) @@ -97,7 +103,9 @@ function! ale#cursor#EchoCursorWarning(...) abort elseif get(l:info, 'echoed') " We'll only clear the echoed message when moving off errors once, " so we don't continually clear the echo line. - execute 'echo' + " + " no-custom-checks + echo let l:info.echoed = 0 endif endif @@ -160,7 +168,8 @@ function! s:ShowCursorDetailForItem(loc, options) abort " Clear the echo message if we manually displayed details. if !l:stay_here - execute 'echo' + " no-custom-checks + echo endif endif endfunction diff --git a/autoload/ale/debugging.vim b/autoload/ale/debugging.vim index efd52776..31f3078c 100644 --- a/autoload/ale/debugging.vim +++ b/autoload/ale/debugging.vim @@ -62,7 +62,8 @@ let s:global_variable_list = [ \] function! s:Echo(message) abort - execute 'echo a:message' + " no-custom-checks + echo a:message endfunction function! s:GetLinterVariables(filetype, exclude_linter_names) abort diff --git a/autoload/ale/fix.vim b/autoload/ale/fix.vim index 8ebba9fe..d9820847 100644 --- a/autoload/ale/fix.vim +++ b/autoload/ale/fix.vim @@ -77,7 +77,8 @@ function! ale#fix#ApplyFixes(buffer, output) abort call remove(g:ale_fix_buffer_data, a:buffer) if !l:data.ignore_file_changed_errors - execute 'echoerr ''The file was changed before fixing finished''' + " no-custom-checks + echoerr 'The file was changed before fixing finished' endif return @@ -358,7 +359,8 @@ function! ale#fix#Fix(buffer, fixing_flag, ...) abort \ 'There is no fixer named `%s`. Check :ALEFixSuggest', \ l:function_name, \) - execute 'echom l:echo_message' + " no-custom-checks + echom l:echo_message endif return 0 @@ -366,7 +368,8 @@ function! ale#fix#Fix(buffer, fixing_flag, ...) abort if empty(l:callback_list) if a:fixing_flag is# '' - execute 'echom ''No fixers have been defined. Try :ALEFixSuggest''' + " no-custom-checks + echom 'No fixers have been defined. Try :ALEFixSuggest' endif return 0 diff --git a/autoload/ale/floating_preview.vim b/autoload/ale/floating_preview.vim index f0bc8f80..e953c363 100644 --- a/autoload/ale/floating_preview.vim +++ b/autoload/ale/floating_preview.vim @@ -7,7 +7,8 @@ function! ale#floating_preview#Show(lines, ...) abort if !exists('*nvim_open_win') && !has('popupwin') - execute 'echom ''Floating windows not supported in this vim instance.''' + " no-custom-checks + echom 'Floating windows not supported in this vim instance.' return endif diff --git a/autoload/ale/toggle.vim b/autoload/ale/toggle.vim index 1311e527..122d6cc4 100644 --- a/autoload/ale/toggle.vim +++ b/autoload/ale/toggle.vim @@ -64,7 +64,8 @@ function! ale#toggle#ToggleBuffer(buffer) abort " Disabling ALE globally removes autocmd events, so we cannot enable " linting locally when linting is disabled globally if l:enabled && !g:ale_enabled - execute 'echom ''ALE cannot be enabled locally when disabled globally''' + " no-custom-checks + echom 'ALE cannot be enabled locally when disabled globally' return endif diff --git a/autoload/ale/uri/jdt.vim b/autoload/ale/uri/jdt.vim index 8cc88ad1..46cea268 100644 --- a/autoload/ale/uri/jdt.vim +++ b/autoload/ale/uri/jdt.vim @@ -3,7 +3,8 @@ function! s:OpenJDTLink(root, uri, line, column, options, result) abort if has_key(a:result, 'error') - execute 'echoerr a:result.error.message' + " no-custom-checks + echoerr a:result.error.message return endif @@ -11,7 +12,8 @@ function! s:OpenJDTLink(root, uri, line, column, options, result) abort let l:contents = a:result['result'] if type(l:contents) is# type(v:null) - execute 'echoerr ''File content not found''' + " no-custom-checks + echoerr 'File content not found' endif " disable autocmd when opening buffer @@ -59,7 +61,8 @@ endfunction function! s:ReadClassFileContents(uri, result) abort if has_key(a:result, 'error') - execute 'echoerr a:result.error.message' + " no-custom-checks + echoerr a:result.error.message return endif @@ -67,7 +70,8 @@ function! s:ReadClassFileContents(uri, result) abort let l:contents = a:result['result'] if type(l:contents) is# type(v:null) - execute 'echoerr ''File content not found''' + " no-custom-checks + echoerr 'File content not found' endif call setline(1, split(l:contents, '\n')) diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim index c783f220..c884076a 100644 --- a/autoload/ale/util.vim +++ b/autoload/ale/util.vim @@ -25,7 +25,8 @@ function! ale#util#ShowMessage(string, ...) abort " We have to assume the user is using a monospace font. if has('nvim') || (a:string !~? "\n" && len(a:string) < &columns) - execute 'echo a:string' + " no-custom-checks + echo a:string else call ale#preview#Show(split(a:string, "\n"), extend( \ { diff --git a/doc/ale-development.txt b/doc/ale-development.txt index 19a95954..5a58e86f 100644 --- a/doc/ale-development.txt +++ b/doc/ale-development.txt @@ -98,8 +98,8 @@ should also follow some additional rules designed to prevent mistakes. Some of these are reported with ALE's `custom-linting-rules` script. See |ale-development-tests|. -* Don't leave stray `:echo` lines in code. Use `execute 'echo' ...` if you must - echo something. +* Don't leave stray `:echo` lines in code. Write `" no-custom-checks` above + the line if you must echo something. * For strings use |is#| instead of |==#|, `is?` instead of `==?`, `isnot#` instead of `!=#`, and `isnot?` instead of `!=?`. This is because `'x' ==# 0` returns 1, while `'x' is# 0` returns 0, so you will experience fewer issues diff --git a/plugin/ale.vim b/plugin/ale.vim index 2b3886aa..fb016651 100644 --- a/plugin/ale.vim +++ b/plugin/ale.vim @@ -24,8 +24,10 @@ endif if !s:has_features " Only output a warning if editing some special files. if index(['', 'gitcommit'], &filetype) == -1 - execute 'echoerr ''ALE requires NeoVim >= 0.2.0 or Vim 8 with +timers +job +channel''' - execute 'echoerr ''Please update your editor appropriately.''' + " no-custom-checks + echoerr 'ALE requires NeoVim >= 0.2.0 or Vim 8 with +timers +job +channel' + " no-custom-checks + echoerr 'Please update your editor appropriately.' endif " Stop here, as it won't work. diff --git a/test/script/custom-linting-rules b/test/script/custom-linting-rules index d3f5e3f3..486a0db7 100755 --- a/test/script/custom-linting-rules +++ b/test/script/custom-linting-rules @@ -73,6 +73,17 @@ check_errors() { for directory in "${directories[@]}"; do # shellcheck disable=SC2086 while read -r; do + line=$(cut -d ":" -f2 <<< "$REPLY") + + if ((line > 1)); then + line=$((line - 1)) + file=$(cut -d ":" -f1 <<< "$REPLY") + + if sed -n "${line},${line}p" $file | grep -q '^ *" *no-custom-checks$'; then + continue + fi + fi + RETURN_CODE=1 echo "$REPLY $message" done < <(grep -H -n "$regex" $include_arg $exclude_arg "$directory"/**/*.vim \ @@ -125,7 +136,7 @@ check_errors '==#' "Use 'is#' instead of '==#'. 0 ==# 'foobar' is true" check_errors '==?' "Use 'is?' instead of '==?'. 0 ==? 'foobar' is true" check_errors '!=#' "Use 'isnot#' instead of '!=#'. 0 !=# 'foobar' is false" check_errors '!=?' "Use 'isnot?' instead of '!=?'. 0 !=? 'foobar' is false" -check_errors '^ *:\?echo\>' "Stray echo line. Use \`execute echo\` if you want to echo something" +check_errors '^ *:\?echo' "Stray echo line. Ignore with \" no-custom-checks if needed" check_errors '^ *:\?redir' 'User execute() instead of redir' # Exclusions for grandfathered-in exceptions exclusions="clojure/clj_kondo.vim elixir/elixir_ls.vim go/golangci_lint.vim swift/swiftformat.vim" diff --git a/test/test_cursor_warnings.vader b/test/test_cursor_warnings.vader index ef385061..f1f1781c 100644 --- a/test/test_cursor_warnings.vader +++ b/test/test_cursor_warnings.vader @@ -85,14 +85,12 @@ Before: let g:ale_set_highlights = 0 let g:ale_echo_cursor = 1 - function GetLastMessage() - redir => l:output - silent mess - redir END + runtime autoload/ale/cursor.vim - let l:lines = split(l:output, "\n") + let g:last_message = '' - return empty(l:lines) ? '' : l:lines[-1] + function! ale#cursor#Echon(message) abort + let g:last_message = a:message endfunction call ale#linter#Reset() @@ -101,6 +99,10 @@ Before: After: Restore + unlet! g:last_message + + runtime autoload/ale/cursor.vim + call cursor(1, 1) let g:ale_set_loclist = 1 @@ -112,8 +114,6 @@ After: unlet! g:output unlet! b:ale_loclist_msg_format - delfunction GetLastMessage - " Clearing the messages breaks tests on NeoVim for some reason, but all " we need to do for these tests is just make it so the last message isn't " carried over between test cases. @@ -135,19 +135,19 @@ Execute(Messages should be shown for the correct lines): call cursor(1, 1) call ale#cursor#EchoCursorWarning() - AssertEqual 'semi: Missing semicolon.', GetLastMessage() + AssertEqual 'semi: Missing semicolon.', g:last_message Execute(Messages should be shown for earlier columns): call cursor(2, 1) call ale#cursor#EchoCursorWarning() - AssertEqual 'space-infix-ops: Infix operators must be spaced.', GetLastMessage() + AssertEqual 'space-infix-ops: Infix operators must be spaced.', g:last_message Execute(Messages should be shown for later columns): call cursor(2, 16) call ale#cursor#EchoCursorWarning() - AssertEqual 'radix: Missing radix parameter', GetLastMessage() + AssertEqual 'radix: Missing radix parameter', g:last_message Execute(The message at the cursor should be shown when linting ends): call cursor(1, 1) @@ -156,13 +156,13 @@ Execute(The message at the cursor should be shown when linting ends): \ g:ale_buffer_info[bufnr('%')].loclist, \) - AssertEqual 'semi: Missing semicolon.', GetLastMessage() + AssertEqual 'semi: Missing semicolon.', g:last_message Execute(The message at the cursor should be shown on InsertLeave): call cursor(2, 9) doautocmd InsertLeave - AssertEqual 'space-infix-ops: Infix operators must be spaced.', GetLastMessage() + AssertEqual 'space-infix-ops: Infix operators must be spaced.', g:last_message Execute(ALEDetail should print 'detail' attributes): call cursor(1, 1) @@ -187,7 +187,7 @@ Execute(ALEDetail should not capitlise cursor messages): call cursor(3, 1) call ale#cursor#EchoCursorWarning() - AssertEqual 'lowercase error', GetLastMessage() + AssertEqual 'lowercase error', g:last_message Execute(The linter name should be formatted into the message correctly): let g:ale_echo_msg_format = '%linter%: %s' @@ -197,7 +197,7 @@ Execute(The linter name should be formatted into the message correctly): AssertEqual \ 'bettercode: Infix operators must be spaced.', - \ GetLastMessage() + \ g:last_message Execute(The severity should be formatted into the message correctly): let g:ale_echo_msg_format = '%severity%: %s' @@ -207,17 +207,17 @@ Execute(The severity should be formatted into the message correctly): AssertEqual \ 'Warning: Infix operators must be spaced.', - \ GetLastMessage() + \ g:last_message call cursor(1, 10) call ale#cursor#EchoCursorWarning() - AssertEqual 'Error: Missing semicolon.', GetLastMessage() + AssertEqual 'Error: Missing semicolon.', g:last_message call cursor(1, 14) call ale#cursor#EchoCursorWarning() - AssertEqual 'Info: Some information', GetLastMessage() + AssertEqual 'Info: Some information', g:last_message Execute(The %code% and %ifcode% should show the code and some text): let g:ale_echo_msg_format = '%(code) %%s' @@ -227,7 +227,7 @@ Execute(The %code% and %ifcode% should show the code and some text): AssertEqual \ '(space-infix-ops) Infix operators must be spaced.', - \ GetLastMessage() + \ g:last_message Execute(The %code% and %ifcode% should be removed when there's no code): let g:ale_echo_msg_format = '%(code) %%s' @@ -235,7 +235,7 @@ Execute(The %code% and %ifcode% should be removed when there's no code): call cursor(1, 14) call ale#cursor#EchoCursorWarning() - AssertEqual 'Some information', GetLastMessage() + AssertEqual 'Some information', g:last_message Execute(The buffer message format option should take precedence): let g:ale_echo_msg_format = '%(code) %%s' @@ -244,13 +244,13 @@ Execute(The buffer message format option should take precedence): call cursor(1, 14) call ale#cursor#EchoCursorWarning() - AssertEqual 'FOO Some information', GetLastMessage() + AssertEqual 'FOO Some information', g:last_message Execute(The cursor message shouldn't be echoed if the option is off): let g:ale_echo_cursor = 0 - echom 'foo' + let g:last_message = 'foo' call cursor(1, 1) call ale#cursor#EchoCursorWarning() - AssertEqual 'foo', GetLastMessage() + AssertEqual 'foo', g:last_message