Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
* upstream/master:
  Cover the SaveEvent function with a test
  dense-analysis#734 - Use the buffer number from the events for entering buffers and saving buffers for checking buffers
  dense-analysis#734 - Do not clear file linter results when no buffers are run
  Add stylelint fixer
  Cover special LSP initialize response handling with Vader tests
  dense-analysis#517 - Get the Rust language server working in a basic way
  When servers never send an initialize response, but instead just publish diagnostics straight away, handle that as an initialize response
  Add some error message handling for LSP, for test purposes
  Fix some bugs so the PHP language server will show errors at least once
  • Loading branch information
rsrchboy committed Aug 2, 2017
2 parents 5d0358f + 35913d9 commit 82156b4
Show file tree
Hide file tree
Showing 19 changed files with 369 additions and 74 deletions.
2 changes: 1 addition & 1 deletion ale_linters/php/langserver.vim
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ endfunction
function! ale_linters#php#langserver#GetProjectRoot(buffer) abort
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')

return !empty(l:git_path) ? fnamemodify(l:git_path, ':h') : ''
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
endfunction

call ale#linter#Define('php', {
Expand Down
33 changes: 33 additions & 0 deletions ale_linters/rust/langserver.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: A language server for Rust

call ale#Set('rust_langserver_executable', 'rls')

function! ale_linters#rust#langserver#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'rust_langserver_executable')
endfunction

function! ale_linters#rust#langserver#GetCommand(buffer) abort
let l:executable = ale_linters#rust#langserver#GetExecutable(a:buffer)

return ale#Escape(l:executable) . ' +nightly'
endfunction

function! ale_linters#rust#langserver#GetLanguage(buffer) abort
return 'rust'
endfunction

function! ale_linters#rust#langserver#GetProjectRoot(buffer) abort
let l:cargo_file = ale#path#FindNearestFile(a:buffer, 'Cargo.toml')

return !empty(l:cargo_file) ? fnamemodify(l:cargo_file, ':h') : ''
endfunction

call ale#linter#Define('rust', {
\ 'name': 'langserver',
\ 'lsp': 'stdio',
\ 'executable_callback': 'ale_linters#rust#langserver#GetExecutable',
\ 'command_callback': 'ale_linters#rust#langserver#GetCommand',
\ 'language_callback': 'ale_linters#rust#langserver#GetLanguage',
\ 'project_root_callback': 'ale_linters#rust#langserver#GetProjectRoot',
\})
38 changes: 24 additions & 14 deletions autoload/ale.vim
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ endfunction

" A function for checking various conditions whereby ALE just shouldn't
" attempt to do anything, say if particular buffer types are open in Vim.
function! ale#ShouldDoNothing() abort
function! ale#ShouldDoNothing(buffer) abort
" Do nothing for blacklisted files
" OR if ALE is running in the sandbox
return index(g:ale_filetype_blacklist, &filetype) >= 0
\ || (exists('*getcmdwintype') && !empty(getcmdwintype()))
\ || ale#util#InSandbox()
\ || !ale#Var(bufnr(''), 'enabled')
\ || !ale#Var(a:buffer, 'enabled')
\ || ale#FileTooLarge()
endfunction

" (delay, [linting_flag])
" (delay, [linting_flag, buffer_number])
function! ale#Queue(delay, ...) abort
if len(a:0) > 1
if a:0 > 2
throw 'too many arguments!'
endif

Expand All @@ -38,7 +38,13 @@ function! ale#Queue(delay, ...) abort
throw "linting_flag must be either '' or 'lint_file'"
endif

if ale#ShouldDoNothing()
let l:buffer = get(a:000, 1, bufnr(''))

if type(l:buffer) != type(0)
throw 'buffer_number must be a Number'
endif

if ale#ShouldDoNothing(l:buffer)
return
endif

Expand All @@ -53,7 +59,6 @@ function! ale#Queue(delay, ...) abort
let s:lint_timer = -1
endif

let l:buffer = bufnr('')
let l:linters = ale#linter#Get(getbufvar(l:buffer, '&filetype'))

" Don't set up buffer data and so on if there are no linters to run.
Expand All @@ -68,21 +73,26 @@ function! ale#Queue(delay, ...) abort
endif

if a:delay > 0
let s:queued_buffer_number = bufnr('%')
let s:queued_buffer_number = l:buffer
let s:lint_timer = timer_start(a:delay, function('ale#Lint'))
else
call ale#Lint()
call ale#Lint(-1, l:buffer)
endif
endfunction

function! ale#Lint(...) abort
" Get the buffer number linting was queued for.
" or else take the current one.
let l:buffer = len(a:0) > 1 && a:1 == s:lint_timer
\ ? s:queued_buffer_number
\ : bufnr('%')
if a:0 > 1
" Use the buffer number given as the optional second argument.
let l:buffer = a:2
elseif a:0 > 0 && a:1 == s:lint_timer
" Use the buffer number for the buffer linting was queued for.
let l:buffer = s:queued_buffer_number
else
" Use the current buffer number.
let l:buffer = bufnr('')
endif

if ale#ShouldDoNothing()
if ale#ShouldDoNothing(l:buffer)
return
endif

Expand Down
6 changes: 3 additions & 3 deletions autoload/ale/cursor.vim
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function! s:StopCursorTimer() abort
endfunction

function! ale#cursor#EchoCursorWarning(...) abort
if ale#ShouldDoNothing()
if ale#ShouldDoNothing(bufnr(''))
return
endif

Expand All @@ -93,7 +93,7 @@ let s:cursor_timer = -1
let s:last_pos = [0, 0, 0]

function! ale#cursor#EchoCursorWarningWithDelay() abort
if ale#ShouldDoNothing()
if ale#ShouldDoNothing(bufnr(''))
return
endif

Expand All @@ -112,7 +112,7 @@ function! ale#cursor#EchoCursorWarningWithDelay() abort
endfunction

function! ale#cursor#ShowCursorDetail() abort
if ale#ShouldDoNothing()
if ale#ShouldDoNothing(bufnr(''))
return
endif

Expand Down
44 changes: 28 additions & 16 deletions autoload/ale/engine.vim
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ function! s:HandleLoclist(linter_name, buffer, loclist) abort
" for efficient lookup of the messages in the cursor handler.
call sort(g:ale_buffer_info[a:buffer].loclist, 'ale#util#LocItemCompare')

if ale#ShouldDoNothing()
if ale#ShouldDoNothing(a:buffer)
return
endif

Expand Down Expand Up @@ -225,10 +225,21 @@ function! s:HandleTSServerDiagnostics(response, error_type) abort
call s:HandleLoclist('tsserver', l:buffer, l:loclist)
endfunction

function! s:HandleLSPErrorMessage(error_message) abort
echoerr 'Error from LSP:'

for l:line in split(a:error_message, "\n")
echoerr l:line
endfor
endfunction

function! ale#engine#HandleLSPResponse(response) abort
let l:method = get(a:response, 'method', '')

if l:method ==# 'textDocument/publishDiagnostics'
if get(a:response, 'jsonrpc', '') ==# '2.0' && has_key(a:response, 'error')
" Uncomment this line to print LSP error messages.
" call s:HandleLSPErrorMessage(a:response.error.message)
elseif l:method ==# 'textDocument/publishDiagnostics'
call s:HandleLSPDiagnostics(a:response)
elseif get(a:response, 'type', '') ==# 'event'
\&& get(a:response, 'event', '') ==# 'semanticDiag'
Expand Down Expand Up @@ -672,25 +683,26 @@ function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
call s:StopCurrentJobs(a:buffer, a:should_lint_file)
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)

let l:any_linter_ran = 0
" We can only clear the results if we aren't checking the buffer.
let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer)

for l:linter in a:linters
" Skip linters for checking files if we shouldn't check the file.
if l:linter.lint_file && !a:should_lint_file
continue
endif

if s:RunLinter(a:buffer, l:linter)
let l:any_linter_ran = 1
" Only run lint_file linters if we should.
if !l:linter.lint_file || a:should_lint_file
if s:RunLinter(a:buffer, l:linter)
" If a single linter ran, we shouldn't clear everything.
let l:can_clear_results = 0
endif
else
" If we skipped running a lint_file linter still in the list,
" we shouldn't clear everything.
let l:can_clear_results = 0
endif
endfor

" If we didn't manage to start checking the buffer with anything,
" and there's nothing running currently for the buffer, then clear the
" results.
"
" We need to use both checks, as we run some tests synchronously.
if !l:any_linter_ran && !ale#engine#IsCheckingBuffer(a:buffer)
" Clear the results if we can. This needs to be done when linters are
" disabled, or ALE itself is disabled.
if l:can_clear_results
call ale#engine#SetResults(a:buffer, [])
endif
endfunction
Expand Down
20 changes: 11 additions & 9 deletions autoload/ale/events.vim
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
" Author: w0rp <devw0rp@gmail.com>

function! ale#events#SaveEvent() abort
let l:should_lint = g:ale_enabled && g:ale_lint_on_save
function! ale#events#SaveEvent(buffer) abort
let l:should_lint = ale#Var(a:buffer, 'enabled') && g:ale_lint_on_save

if g:ale_fix_on_save
let l:will_fix = ale#fix#Fix('save_file')
let l:should_lint = l:should_lint && !l:will_fix
endif

if l:should_lint
call ale#Queue(0, 'lint_file')
call ale#Queue(0, 'lint_file', a:buffer)
endif
endfunction

function! s:LintOnEnter() abort
if g:ale_enabled && g:ale_lint_on_enter && has_key(b:, 'ale_file_changed')
function! s:LintOnEnter(buffer) abort
if ale#Var(a:buffer, 'enabled')
\&& g:ale_lint_on_enter
\&& has_key(b:, 'ale_file_changed')
call remove(b:, 'ale_file_changed')
call ale#Queue(0, 'lint_file')
call ale#Queue(0, 'lint_file', a:buffer)
endif
endfunction

function! ale#events#EnterEvent() abort
call s:LintOnEnter()
function! ale#events#EnterEvent(buffer) abort
call s:LintOnEnter(a:buffer)
endfunction

function! ale#events#FileChangedEvent(buffer) abort
call setbufvar(a:buffer, 'ale_file_changed', 1)

if bufnr('') == a:buffer
call s:LintOnEnter()
call s:LintOnEnter(a:buffer)
endif
endfunction
5 changes: 5 additions & 0 deletions autoload/ale/fix/registry.vim
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['javascript'],
\ 'description': 'Fix JavaScript files using standard --fix',
\ },
\ 'stylelint': {
\ 'function': 'ale#fixers#stylelint#Fix',
\ 'suggested_filetypes': ['css', 'sass', 'scss', 'stylus'],
\ 'description': 'Fix stylesheet files using stylelint --fix.',
\ },
\}

" Reset the function registry to the default entries.
Expand Down
31 changes: 31 additions & 0 deletions autoload/ale/fixers/stylelint.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
" Author: Mahmoud Mostafa <mah@moud.info>
" Description: Fixing files with stylelint.

call ale#Set('stylelint_executable', 'stylelint')
call ale#Set('stylelint_use_global', 0)

function! ale#fixers#stylelint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'stylelint', [
\ 'node_modules/stylelint/bin/stylelint.js',
\ 'node_modules/.bin/stylelint',
\])
endfunction


function! ale#fixers#stylelint#Fix(buffer) abort
let l:executable = ale#fixers#stylelint#GetExecutable(a:buffer)

if ale#Has('win32') && l:executable =~? 'stylelint\.js$'
" For Windows, if we detect an stylelint.js script, we need to execute
" it with node, or the file can be opened with a text editor.
let l:head = 'node ' . ale#Escape(l:executable)
else
let l:head = ale#Escape(l:executable)
endif

return {
\ 'command': l:head
\ . ' --fix %t',
\ 'read_temporary_file': 1,
\}
endfunction
6 changes: 6 additions & 0 deletions autoload/ale/linter.vim
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,12 @@ function! ale#linter#StartLSP(buffer, linter, callback) abort
let l:address = ''
let l:root = ale#util#GetFunction(a:linter.project_root_callback)(a:buffer)

if empty(l:root) && a:linter.lsp !=# 'tsserver'
" If there's no project root, then we can't check files with LSP,
" unless we are using tsserver, which doesn't use project roots.
return {}
endif

if a:linter.lsp ==# 'socket'
let l:address = ale#linter#GetAddress(a:buffer, a:linter)
let l:conn_id = ale#lsp#ConnectToAddress(
Expand Down
Loading

0 comments on commit 82156b4

Please sign in to comment.