mirror of
				https://github.com/amix/vimrc
				synced 2025-10-31 06:33:35 +08:00 
			
		
		
		
	Removed syntastic and replaced it with ale
Read more here: https://github.com/w0rp/ale
This commit is contained in:
		
							
								
								
									
										287
									
								
								sources_non_forked/ale/autoload/ale.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								sources_non_forked/ale/autoload/ale.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,287 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com>, David Alexander <opensource@thelonelyghost.com> | ||||
| " Description: Primary code path for the plugin | ||||
| "   Manages execution of linters when requested by autocommands | ||||
|  | ||||
| let s:lint_timer = -1 | ||||
| let s:queued_buffer_number = -1 | ||||
| let s:should_lint_file_for_buffer = {} | ||||
| let s:error_delay_ms = 1000 * 60 * 2 | ||||
|  | ||||
| let s:timestamp_map = {} | ||||
|  | ||||
| " Given a key for a script variable for tracking the time to wait until | ||||
| " a given function should be called, a funcref for a function to call, and | ||||
| " a List of arguments, call the function and return whatever value it returns. | ||||
| " | ||||
| " If the function throws an exception, then the function will not be called | ||||
| " for a while, and 0 will be returned instead. | ||||
| function! ale#CallWithCooldown(timestamp_key, func, arglist) abort | ||||
|     let l:now = ale#util#ClockMilliseconds() | ||||
|  | ||||
|     if l:now < get(s:timestamp_map, a:timestamp_key, -1) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let s:timestamp_map[a:timestamp_key] = l:now + s:error_delay_ms | ||||
|  | ||||
|     let l:return_value = call(a:func, a:arglist) | ||||
|  | ||||
|     let s:timestamp_map[a:timestamp_key] = -1 | ||||
|  | ||||
|     return l:return_value | ||||
| endfunction | ||||
|  | ||||
| " Return 1 if a file is too large for ALE to handle. | ||||
| function! ale#FileTooLarge() abort | ||||
|     let l:max = ale#Var(bufnr(''), 'maximum_file_size') | ||||
|  | ||||
|     return l:max > 0 ? (line2byte(line('$') + 1) > l:max) : 0 | ||||
| endfunction | ||||
|  | ||||
| let s:getcmdwintype_exists = exists('*getcmdwintype') | ||||
|  | ||||
| " 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(buffer) abort | ||||
|     " The checks are split into separate if statements to make it possible to | ||||
|     " profile each check individually with Vim's profiling tools. | ||||
|  | ||||
|     " Don't perform any checks when newer NeoVim versions are exiting. | ||||
|     if get(v:, 'exiting', v:null) isnot v:null | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     " Do nothing for blacklisted files | ||||
|     if index(g:ale_filetype_blacklist, getbufvar(a:buffer, '&filetype')) >= 0 | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     " Do nothing if running from command mode | ||||
|     if s:getcmdwintype_exists && !empty(getcmdwintype()) | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     let l:filename = fnamemodify(bufname(a:buffer), ':t') | ||||
|  | ||||
|     if l:filename is# '.' | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     " Do nothing if running in the sandbox | ||||
|     if ale#util#InSandbox() | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     " Do nothing if ALE is disabled. | ||||
|     if !ale#Var(a:buffer, 'enabled') | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     " Do nothing if the file is too large. | ||||
|     if ale#FileTooLarge() | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     " Do nothing from CtrlP buffers with CtrlP-funky. | ||||
|     if exists(':CtrlPFunky') is 2 | ||||
|     \&& getbufvar(a:buffer, '&l:statusline') =~# 'CtrlPMode.*funky' | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     return 0 | ||||
| endfunction | ||||
|  | ||||
| " (delay, [linting_flag, buffer_number]) | ||||
| function! ale#Queue(delay, ...) abort | ||||
|     if a:0 > 2 | ||||
|         throw 'too many arguments!' | ||||
|     endif | ||||
|  | ||||
|     " Default linting_flag to '' | ||||
|     let l:linting_flag = get(a:000, 0, '') | ||||
|     let l:buffer = get(a:000, 1, bufnr('')) | ||||
|  | ||||
|     return ale#CallWithCooldown( | ||||
|     \   'dont_queue_until', | ||||
|     \   function('s:ALEQueueImpl'), | ||||
|     \   [a:delay, l:linting_flag, l:buffer], | ||||
|     \) | ||||
| endfunction | ||||
|  | ||||
| function! s:ALEQueueImpl(delay, linting_flag, buffer) abort | ||||
|     if a:linting_flag isnot# '' && a:linting_flag isnot# 'lint_file' | ||||
|         throw "linting_flag must be either '' or 'lint_file'" | ||||
|     endif | ||||
|  | ||||
|     if type(a:buffer) != type(0) | ||||
|         throw 'buffer_number must be a Number' | ||||
|     endif | ||||
|  | ||||
|     if ale#ShouldDoNothing(a:buffer) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " Remember that we want to check files for this buffer. | ||||
|     " We will remember this until we finally run the linters, via any event. | ||||
|     if a:linting_flag is# 'lint_file' | ||||
|         let s:should_lint_file_for_buffer[a:buffer] = 1 | ||||
|     endif | ||||
|  | ||||
|     if s:lint_timer != -1 | ||||
|         call timer_stop(s:lint_timer) | ||||
|         let s:lint_timer = -1 | ||||
|     endif | ||||
|  | ||||
|     let l:linters = ale#linter#Get(getbufvar(a:buffer, '&filetype')) | ||||
|  | ||||
|     " Don't set up buffer data and so on if there are no linters to run. | ||||
|     if empty(l:linters) | ||||
|         " If we have some previous buffer data, then stop any jobs currently | ||||
|         " running and clear everything. | ||||
|         if has_key(g:ale_buffer_info, a:buffer) | ||||
|             call ale#engine#RunLinters(a:buffer, [], 1) | ||||
|         endif | ||||
|  | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     if a:delay > 0 | ||||
|         let s:queued_buffer_number = a:buffer | ||||
|         let s:lint_timer = timer_start(a:delay, function('ale#Lint')) | ||||
|     else | ||||
|         call ale#Lint(-1, a:buffer) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#Lint(...) abort | ||||
|     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 | ||||
|  | ||||
|     return ale#CallWithCooldown( | ||||
|     \   'dont_lint_until', | ||||
|     \   function('s:ALELintImpl'), | ||||
|     \   [l:buffer], | ||||
|     \) | ||||
| endfunction | ||||
|  | ||||
| function! s:ALELintImpl(buffer) abort | ||||
|     if ale#ShouldDoNothing(a:buffer) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " Use the filetype from the buffer | ||||
|     let l:linters = ale#linter#Get(getbufvar(a:buffer, '&filetype')) | ||||
|     let l:should_lint_file = 0 | ||||
|  | ||||
|     " Check if we previously requested checking the file. | ||||
|     if has_key(s:should_lint_file_for_buffer, a:buffer) | ||||
|         unlet s:should_lint_file_for_buffer[a:buffer] | ||||
|         " Lint files if they exist. | ||||
|         let l:should_lint_file = filereadable(expand('#' . a:buffer . ':p')) | ||||
|     endif | ||||
|  | ||||
|     call ale#engine#RunLinters(a:buffer, l:linters, l:should_lint_file) | ||||
| endfunction | ||||
|  | ||||
| " Reset flags indicating that files should be checked for all buffers. | ||||
| function! ale#ResetLintFileMarkers() abort | ||||
|     let s:should_lint_file_for_buffer = {} | ||||
| endfunction | ||||
|  | ||||
| function! ale#ResetErrorDelays() abort | ||||
|     let s:timestamp_map = {} | ||||
| endfunction | ||||
|  | ||||
| let g:ale_has_override = get(g:, 'ale_has_override', {}) | ||||
|  | ||||
| " Call has(), but check a global Dictionary so we can force flags on or off | ||||
| " for testing purposes. | ||||
| function! ale#Has(feature) abort | ||||
|     return get(g:ale_has_override, a:feature, has(a:feature)) | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer number and a variable name, look for that variable in the | ||||
| " buffer scope, then in global scope. If the name does not exist in the global | ||||
| " scope, an exception will be thrown. | ||||
| " | ||||
| " Every variable name will be prefixed with 'ale_'. | ||||
| function! ale#Var(buffer, variable_name) abort | ||||
|     let l:nr = str2nr(a:buffer) | ||||
|     let l:full_name = 'ale_' . a:variable_name | ||||
|  | ||||
|     if bufexists(l:nr) | ||||
|         let l:vars = getbufvar(l:nr, '') | ||||
|     elseif has_key(g:, 'ale_fix_buffer_data') | ||||
|         let l:vars = get(g:ale_fix_buffer_data, l:nr, {'vars': {}}).vars | ||||
|     else | ||||
|         let l:vars = {} | ||||
|     endif | ||||
|  | ||||
|     return get(l:vars, l:full_name, g:[l:full_name]) | ||||
| endfunction | ||||
|  | ||||
| " Initialize a variable with a default value, if it isn't already set. | ||||
| " | ||||
| " Every variable name will be prefixed with 'ale_'. | ||||
| function! ale#Set(variable_name, default) abort | ||||
|     let l:full_name = 'ale_' . a:variable_name | ||||
|     let l:value = get(g:, l:full_name, a:default) | ||||
|     let g:[l:full_name] = l:value | ||||
|  | ||||
|     return l:value | ||||
| endfunction | ||||
|  | ||||
| " Escape a string suitably for each platform. | ||||
| " shellescape does not work on Windows. | ||||
| function! ale#Escape(str) abort | ||||
|     if fnamemodify(&shell, ':t') is? 'cmd.exe' | ||||
|         " If the string contains spaces, it will be surrounded by quotes. | ||||
|         " Otherwise, special characters will be escaped with carets (^). | ||||
|         return substitute( | ||||
|         \   a:str =~# ' ' | ||||
|         \       ?  '"' .  substitute(a:str, '"', '""', 'g') . '"' | ||||
|         \       : substitute(a:str, '\v([&|<>^])', '^\1', 'g'), | ||||
|         \   '%', | ||||
|         \   '%%', | ||||
|         \   'g', | ||||
|         \) | ||||
|     endif | ||||
|  | ||||
|     return shellescape (a:str) | ||||
| endfunction | ||||
|  | ||||
| " Get the loclist item message according to a given format string. | ||||
| " | ||||
| " See `:help g:ale_loclist_msg_format` and `:help g:ale_echo_msg_format` | ||||
| function! ale#GetLocItemMessage(item, format_string) abort | ||||
|     let l:msg = a:format_string | ||||
|     let l:severity = g:ale_echo_msg_warning_str | ||||
|     let l:code = get(a:item, 'code', '') | ||||
|     let l:type = get(a:item, 'type', 'E') | ||||
|     let l:linter_name = get(a:item, 'linter_name', '') | ||||
|     let l:code_repl = !empty(l:code) ? '\=submatch(1) . l:code . submatch(2)' : '' | ||||
|  | ||||
|     if l:type is# 'E' | ||||
|         let l:severity = g:ale_echo_msg_error_str | ||||
|     elseif l:type is# 'I' | ||||
|         let l:severity = g:ale_echo_msg_info_str | ||||
|     endif | ||||
|  | ||||
|     " Replace special markers with certain information. | ||||
|     " \=l:variable is used to avoid escaping issues. | ||||
|     let l:msg = substitute(l:msg, '\V%severity%', '\=l:severity', 'g') | ||||
|     let l:msg = substitute(l:msg, '\V%linter%', '\=l:linter_name', 'g') | ||||
|     let l:msg = substitute(l:msg, '\v\%([^\%]*)code([^\%]*)\%', l:code_repl, 'g') | ||||
|     " Replace %s with the text. | ||||
|     let l:msg = substitute(l:msg, '\V%s', '\=a:item.text', 'g') | ||||
|  | ||||
|     return l:msg | ||||
| endfunction | ||||
							
								
								
									
										28
									
								
								sources_non_forked/ale/autoload/ale/balloon.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								sources_non_forked/ale/autoload/ale/balloon.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: balloonexpr support for ALE. | ||||
|  | ||||
| function! ale#balloon#MessageForPos(bufnr, lnum, col) abort | ||||
|     " Don't show balloons if they are disabled, or linting is disabled. | ||||
|     if !ale#Var(a:bufnr, 'set_balloons') | ||||
|     \|| !g:ale_enabled | ||||
|     \|| !getbufvar(a:bufnr, 'ale_enabled', 1) | ||||
|         return '' | ||||
|     endif | ||||
|  | ||||
|     let l:loclist = get(g:ale_buffer_info, a:bufnr, {'loclist': []}).loclist | ||||
|     let l:index = ale#util#BinarySearch(l:loclist, a:bufnr, a:lnum, a:col) | ||||
|  | ||||
|     return l:index >= 0 ? l:loclist[l:index].text : '' | ||||
| endfunction | ||||
|  | ||||
| function! ale#balloon#Expr() abort | ||||
|     return ale#balloon#MessageForPos(v:beval_bufnr, v:beval_lnum, v:beval_col) | ||||
| endfunction | ||||
|  | ||||
| function! ale#balloon#Disable() abort | ||||
|     set noballooneval balloonexpr= | ||||
| endfunction | ||||
|  | ||||
| function! ale#balloon#Enable() abort | ||||
|     set ballooneval balloonexpr=ale#balloon#Expr() | ||||
| endfunction | ||||
							
								
								
									
										176
									
								
								sources_non_forked/ale/autoload/ale/c.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								sources_non_forked/ale/autoload/ale/c.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,176 @@ | ||||
| " Author: gagbo <gagbobada@gmail.com>, w0rp <devw0rp@gmail.com>, roel0 <postelmansroel@gmail.com> | ||||
| " Description: Functions for integrating with C-family linters. | ||||
|  | ||||
| call ale#Set('c_parse_makefile', 0) | ||||
| let s:sep = has('win32') ? '\' : '/' | ||||
|  | ||||
| function! ale#c#FindProjectRoot(buffer) abort | ||||
|     for l:project_filename in ['.git/HEAD', 'configure', 'Makefile', 'CMakeLists.txt'] | ||||
|         let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename) | ||||
|  | ||||
|         if !empty(l:full_path) | ||||
|             let l:path = fnamemodify(l:full_path, ':h') | ||||
|  | ||||
|             " Correct .git path detection. | ||||
|             if fnamemodify(l:path, ':t') is# '.git' | ||||
|                 let l:path = fnamemodify(l:path, ':h') | ||||
|             endif | ||||
|  | ||||
|             return l:path | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
|  | ||||
| function! ale#c#ParseCFlagsToList(path_prefix, cflags) abort | ||||
|     let l:cflags_list = [] | ||||
|     let l:previous_options = [] | ||||
|  | ||||
|     for l:option in a:cflags | ||||
|         call add(l:previous_options, l:option) | ||||
|         " Check if cflag contained a '-' and should not have been splitted | ||||
|         let l:option_list = split(l:option, '\zs') | ||||
|         if l:option_list[-1] isnot# ' ' | ||||
|             continue | ||||
|         endif | ||||
|  | ||||
|         let l:option = join(l:previous_options, '-') | ||||
|         let l:previous_options = [] | ||||
|  | ||||
|         let l:option = '-' . substitute(l:option, '^\s*\(.\{-}\)\s*$', '\1', '') | ||||
|  | ||||
|         " Fix relative paths if needed | ||||
|         if stridx(l:option, '-I') >= 0 && | ||||
|            \ stridx(l:option, '-I' . s:sep) < 0 | ||||
|             let l:rel_path = join(split(l:option, '\zs')[2:], '') | ||||
|             let l:rel_path = substitute(l:rel_path, '"', '', 'g') | ||||
|             let l:rel_path = substitute(l:rel_path, '''', '', 'g') | ||||
|             let l:option = ale#Escape('-I' . a:path_prefix . | ||||
|                                       \ s:sep . l:rel_path) | ||||
|         endif | ||||
|  | ||||
|         " Parse the cflag | ||||
|         if stridx(l:option, '-I') >= 0 || | ||||
|            \ stridx(l:option, '-D') >= 0 | ||||
|             if index(l:cflags_list, l:option) < 0 | ||||
|                 call add(l:cflags_list, l:option) | ||||
|             endif | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return l:cflags_list | ||||
| endfunction | ||||
|  | ||||
| function! ale#c#ParseCFlags(buffer, stdout_make) abort | ||||
|     if !g:ale_c_parse_makefile | ||||
|         return [] | ||||
|     endif | ||||
|  | ||||
|     let l:buffer_filename = expand('#' . a:buffer . ':t') | ||||
|     let l:cflags = [] | ||||
|     for l:lines in split(a:stdout_make, '\\n') | ||||
|         if stridx(l:lines, l:buffer_filename) >= 0 | ||||
|             let l:cflags = split(l:lines, '-') | ||||
|             break | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile') | ||||
|     return ale#c#ParseCFlagsToList(fnamemodify(l:makefile_path, ':p:h'), l:cflags) | ||||
| endfunction | ||||
|  | ||||
| function! ale#c#GetCFlags(buffer, output) abort | ||||
|     let l:cflags = ' ' | ||||
|  | ||||
|     if g:ale_c_parse_makefile && !empty(a:output) | ||||
|         let l:cflags = join(ale#c#ParseCFlags(a:buffer, join(a:output, '\n')), ' ') . ' ' | ||||
|     endif | ||||
|  | ||||
|     if l:cflags is# ' ' | ||||
|         let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)) | ||||
|     endif | ||||
|  | ||||
|     return l:cflags | ||||
| endfunction | ||||
|  | ||||
| function! ale#c#GetMakeCommand(buffer) abort | ||||
|     if g:ale_c_parse_makefile | ||||
|         let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile') | ||||
|         if !empty(l:makefile_path) | ||||
|             return 'cd '. fnamemodify(l:makefile_path, ':p:h') . ' && make -n' | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer number, search for a project root, and output a List | ||||
| " of directories to include based on some heuristics. | ||||
| " | ||||
| " For projects with headers in the project root, the project root will | ||||
| " be returned. | ||||
| " | ||||
| " For projects with an 'include' directory, that directory will be returned. | ||||
| function! ale#c#FindLocalHeaderPaths(buffer) abort | ||||
|     let l:project_root = ale#c#FindProjectRoot(a:buffer) | ||||
|  | ||||
|     if empty(l:project_root) | ||||
|         return [] | ||||
|     endif | ||||
|  | ||||
|     " See if we can find .h files directory in the project root. | ||||
|     " If we can, that's our include directory. | ||||
|     if !empty(globpath(l:project_root, '*.h', 0)) | ||||
|         return [l:project_root] | ||||
|     endif | ||||
|  | ||||
|     " Look for .hpp files too. | ||||
|     if !empty(globpath(l:project_root, '*.hpp', 0)) | ||||
|         return [l:project_root] | ||||
|     endif | ||||
|  | ||||
|     " If we find an 'include' directory in the project root, then use that. | ||||
|     if isdirectory(l:project_root . '/include') | ||||
|         return [ale#path#Simplify(l:project_root . s:sep . 'include')] | ||||
|     endif | ||||
|  | ||||
|     return [] | ||||
| endfunction | ||||
|  | ||||
| " Given a List of include paths, create a string containing the -I include | ||||
| " options for those paths, with the paths escaped for use in the shell. | ||||
| function! ale#c#IncludeOptions(include_paths) abort | ||||
|     let l:option_list = [] | ||||
|  | ||||
|     for l:path in a:include_paths | ||||
|         call add(l:option_list, '-I' . ale#Escape(l:path)) | ||||
|     endfor | ||||
|  | ||||
|     if empty(l:option_list) | ||||
|         return '' | ||||
|     endif | ||||
|  | ||||
|     return ' ' . join(l:option_list) . ' ' | ||||
| endfunction | ||||
|  | ||||
| let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [ | ||||
| \   'build', | ||||
| \   'bin', | ||||
| \]) | ||||
|  | ||||
| " Given a buffer number, find the build subdirectory with compile commands | ||||
| " The subdirectory is returned without the trailing / | ||||
| function! ale#c#FindCompileCommands(buffer) abort | ||||
|     for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) | ||||
|         for l:dirname in ale#Var(a:buffer, 'c_build_dir_names') | ||||
|             let l:c_build_dir = l:path . s:sep . l:dirname | ||||
|  | ||||
|             if filereadable(l:c_build_dir . '/compile_commands.json') | ||||
|                 return l:c_build_dir | ||||
|             endif | ||||
|         endfor | ||||
|     endfor | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
							
								
								
									
										57
									
								
								sources_non_forked/ale/autoload/ale/command.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								sources_non_forked/ale/autoload/ale/command.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Special command formatting for creating temporary files and | ||||
| " passing buffer filenames easily. | ||||
|  | ||||
| function! s:TemporaryFilename(buffer) abort | ||||
|     let l:filename = fnamemodify(bufname(a:buffer), ':t') | ||||
|  | ||||
|     if empty(l:filename) | ||||
|         " If the buffer's filename is empty, create a dummy filename. | ||||
|         let l:ft = getbufvar(a:buffer, '&filetype') | ||||
|         let l:filename = 'file' . ale#filetypes#GuessExtension(l:ft) | ||||
|     endif | ||||
|  | ||||
|     " Create a temporary filename, <temp_dir>/<original_basename> | ||||
|     " The file itself will not be created by this function. | ||||
|     return tempname() . (has('win32') ? '\' : '/') . l:filename | ||||
| endfunction | ||||
|  | ||||
| " Given a command string, replace every... | ||||
| " %s -> with the current filename | ||||
| " %t -> with the name of an unused file in a temporary directory | ||||
| " %% -> with a literal % | ||||
| function! ale#command#FormatCommand(buffer, command, pipe_file_if_needed) abort | ||||
|     let l:temporary_file = '' | ||||
|     let l:command = a:command | ||||
|  | ||||
|     " First replace all uses of %%, used for literal percent characters, | ||||
|     " with an ugly string. | ||||
|     let l:command = substitute(l:command, '%%', '<<PERCENTS>>', 'g') | ||||
|  | ||||
|     " Replace all %s occurrences in the string with the name of the current | ||||
|     " file. | ||||
|     if l:command =~# '%s' | ||||
|         let l:filename = fnamemodify(bufname(a:buffer), ':p') | ||||
|         let l:command = substitute(l:command, '%s', '\=ale#Escape(l:filename)', 'g') | ||||
|     endif | ||||
|  | ||||
|     if l:command =~# '%t' | ||||
|         " Create a temporary filename, <temp_dir>/<original_basename> | ||||
|         " The file itself will not be created by this function. | ||||
|         let l:temporary_file = s:TemporaryFilename(a:buffer) | ||||
|         let l:command = substitute(l:command, '%t', '\=ale#Escape(l:temporary_file)', 'g') | ||||
|     endif | ||||
|  | ||||
|     " Finish formatting so %% becomes %. | ||||
|     let l:command = substitute(l:command, '<<PERCENTS>>', '%', 'g') | ||||
|  | ||||
|     if a:pipe_file_if_needed && empty(l:temporary_file) | ||||
|         " If we are to send the Vim buffer to a command, we'll do it | ||||
|         " in the shell. We'll write out the file to a temporary file, | ||||
|         " and then read it back in, in the shell. | ||||
|         let l:temporary_file = s:TemporaryFilename(a:buffer) | ||||
|         let l:command = l:command . ' < ' . ale#Escape(l:temporary_file) | ||||
|     endif | ||||
|  | ||||
|     return [l:temporary_file, l:command] | ||||
| endfunction | ||||
							
								
								
									
										477
									
								
								sources_non_forked/ale/autoload/ale/completion.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										477
									
								
								sources_non_forked/ale/autoload/ale/completion.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,477 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Completion support for LSP linters | ||||
|  | ||||
| let s:timer_id = -1 | ||||
| let s:last_done_pos = [] | ||||
|  | ||||
| " CompletionItemKind values from the LSP protocol. | ||||
| let s:LSP_COMPLETION_TEXT_KIND = 1 | ||||
| let s:LSP_COMPLETION_METHOD_KIND = 2 | ||||
| let s:LSP_COMPLETION_FUNCTION_KIND = 3 | ||||
| let s:LSP_COMPLETION_CONSTRUCTOR_KIND = 4 | ||||
| let s:LSP_COMPLETION_FIELD_KIND = 5 | ||||
| let s:LSP_COMPLETION_VARIABLE_KIND = 6 | ||||
| let s:LSP_COMPLETION_CLASS_KIND = 7 | ||||
| let s:LSP_COMPLETION_INTERFACE_KIND = 8 | ||||
| let s:LSP_COMPLETION_MODULE_KIND = 9 | ||||
| let s:LSP_COMPLETION_PROPERTY_KIND = 10 | ||||
| let s:LSP_COMPLETION_UNIT_KIND = 11 | ||||
| let s:LSP_COMPLETION_VALUE_KIND = 12 | ||||
| let s:LSP_COMPLETION_ENUM_KIND = 13 | ||||
| let s:LSP_COMPLETION_KEYWORD_KIND = 14 | ||||
| let s:LSP_COMPLETION_SNIPPET_KIND = 15 | ||||
| let s:LSP_COMPLETION_COLOR_KIND = 16 | ||||
| let s:LSP_COMPLETION_FILE_KIND = 17 | ||||
| let s:LSP_COMPLETION_REFERENCE_KIND = 18 | ||||
|  | ||||
| " Regular expressions for checking the characters in the line before where | ||||
| " the insert cursor is. If one of these matches, we'll check for completions. | ||||
| let s:should_complete_map = { | ||||
| \   '<default>': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$', | ||||
| \} | ||||
|  | ||||
| " Regular expressions for finding the start column to replace with completion. | ||||
| let s:omni_start_map = { | ||||
| \   '<default>': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$', | ||||
| \} | ||||
|  | ||||
| " A map of exact characters for triggering LSP completions. | ||||
| let s:trigger_character_map = { | ||||
| \   '<default>': ['.'], | ||||
| \} | ||||
|  | ||||
| function! s:GetFiletypeValue(map, filetype) abort | ||||
|     for l:part in reverse(split(a:filetype, '\.')) | ||||
|         let l:regex = get(a:map, l:part, []) | ||||
|  | ||||
|         if !empty(l:regex) | ||||
|             return l:regex | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     " Use the default regex for other files. | ||||
|     return a:map['<default>'] | ||||
| endfunction | ||||
|  | ||||
| " Check if we should look for completions for a language. | ||||
| function! ale#completion#GetPrefix(filetype, line, column) abort | ||||
|     let l:regex = s:GetFiletypeValue(s:should_complete_map, a:filetype) | ||||
|     " The column we're using completions for is where we are inserting text, | ||||
|     " like so: | ||||
|     "   abc | ||||
|     "      ^ | ||||
|     " So we need check the text in the column before that position. | ||||
|     return matchstr(getline(a:line)[: a:column - 2], l:regex) | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#GetTriggerCharacter(filetype, prefix) abort | ||||
|     let l:char_list = s:GetFiletypeValue(s:trigger_character_map, a:filetype) | ||||
|  | ||||
|     if index(l:char_list, a:prefix) >= 0 | ||||
|         return a:prefix | ||||
|     endif | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#Filter(suggestions, prefix) abort | ||||
|     " For completing... | ||||
|     "   foo. | ||||
|     "       ^ | ||||
|     " We need to include all of the given suggestions. | ||||
|     if a:prefix is# '.' | ||||
|         return a:suggestions | ||||
|     endif | ||||
|  | ||||
|     let l:filtered_suggestions = [] | ||||
|  | ||||
|     " Filter suggestions down to those starting with the prefix we used for | ||||
|     " finding suggestions in the first place. | ||||
|     " | ||||
|     " Some completion tools will include suggestions which don't even start | ||||
|     " with the characters we have already typed. | ||||
|     for l:item in a:suggestions | ||||
|         " A List of String values or a List of completion item Dictionaries | ||||
|         " is accepted here. | ||||
|         let l:word = type(l:item) == type('') ? l:item : l:item.word | ||||
|  | ||||
|         " Add suggestions if the suggestion starts with a case-insensitive | ||||
|         " match for the prefix. | ||||
|         if l:word[: len(a:prefix) - 1] is? a:prefix | ||||
|             call add(l:filtered_suggestions, l:item) | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return l:filtered_suggestions | ||||
| endfunction | ||||
|  | ||||
| function! s:ReplaceCompleteopt() abort | ||||
|     if !exists('b:ale_old_completopt') | ||||
|         let b:ale_old_completopt = &l:completeopt | ||||
|     endif | ||||
|  | ||||
|     let &l:completeopt = 'menu,menuone,preview,noselect,noinsert' | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#OmniFunc(findstart, base) abort | ||||
|     if a:findstart | ||||
|         let l:line = b:ale_completion_info.line | ||||
|         let l:column = b:ale_completion_info.column | ||||
|         let l:regex = s:GetFiletypeValue(s:omni_start_map, &filetype) | ||||
|         let l:up_to_column = getline(l:line)[: l:column - 2] | ||||
|         let l:match = matchstr(l:up_to_column, l:regex) | ||||
|  | ||||
|         return l:column - len(l:match) - 1 | ||||
|     else | ||||
|         " Parse a new response if there is one. | ||||
|         if exists('b:ale_completion_response') | ||||
|         \&& exists('b:ale_completion_parser') | ||||
|             let l:response = b:ale_completion_response | ||||
|             let l:parser = b:ale_completion_parser | ||||
|  | ||||
|             unlet b:ale_completion_response | ||||
|             unlet b:ale_completion_parser | ||||
|  | ||||
|             let b:ale_completion_result = function(l:parser)(l:response) | ||||
|         endif | ||||
|  | ||||
|         call s:ReplaceCompleteopt() | ||||
|  | ||||
|         return get(b:, 'ale_completion_result', []) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#Show(response, completion_parser) abort | ||||
|     " Remember the old omnifunc value, if there is one. | ||||
|     " If we don't store an old one, we'll just never reset the option. | ||||
|     " This will stop some random exceptions from appearing. | ||||
|     if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc) | ||||
|         let b:ale_old_omnifunc = &l:omnifunc | ||||
|     endif | ||||
|  | ||||
|     " Set the list in the buffer, temporarily replace omnifunc with our | ||||
|     " function, and then start omni-completion. | ||||
|     let b:ale_completion_response = a:response | ||||
|     let b:ale_completion_parser = a:completion_parser | ||||
|     let &l:omnifunc = 'ale#completion#OmniFunc' | ||||
|     call s:ReplaceCompleteopt() | ||||
|     call ale#util#FeedKeys("\<C-x>\<C-o>", 'n') | ||||
| endfunction | ||||
|  | ||||
| function! s:CompletionStillValid(request_id) abort | ||||
|     let [l:line, l:column] = getcurpos()[1:2] | ||||
|  | ||||
|     return has_key(b:, 'ale_completion_info') | ||||
|     \&& b:ale_completion_info.request_id == a:request_id | ||||
|     \&& b:ale_completion_info.line == l:line | ||||
|     \&& b:ale_completion_info.column == l:column | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#ParseTSServerCompletions(response) abort | ||||
|     let l:names = [] | ||||
|  | ||||
|     for l:suggestion in a:response.body | ||||
|         call add(l:names, l:suggestion.name) | ||||
|     endfor | ||||
|  | ||||
|     return l:names | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort | ||||
|     let l:results = [] | ||||
|  | ||||
|     for l:suggestion in a:response.body | ||||
|         let l:displayParts = [] | ||||
|  | ||||
|         for l:part in l:suggestion.displayParts | ||||
|             call add(l:displayParts, l:part.text) | ||||
|         endfor | ||||
|  | ||||
|         " Each one of these parts has 'kind' properties | ||||
|         let l:documentationParts = [] | ||||
|  | ||||
|         for l:part in get(l:suggestion, 'documentation', []) | ||||
|             call add(l:documentationParts, l:part.text) | ||||
|         endfor | ||||
|  | ||||
|         if l:suggestion.kind is# 'clasName' | ||||
|             let l:kind = 'f' | ||||
|         elseif l:suggestion.kind is# 'parameterName' | ||||
|             let l:kind = 'f' | ||||
|         else | ||||
|             let l:kind = 'v' | ||||
|         endif | ||||
|  | ||||
|         " See :help complete-items | ||||
|         call add(l:results, { | ||||
|         \   'word': l:suggestion.name, | ||||
|         \   'kind': l:kind, | ||||
|         \   'icase': 1, | ||||
|         \   'menu': join(l:displayParts, ''), | ||||
|         \   'info': join(l:documentationParts, ''), | ||||
|         \}) | ||||
|     endfor | ||||
|  | ||||
|     return l:results | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#ParseLSPCompletions(response) abort | ||||
|     let l:item_list = [] | ||||
|  | ||||
|     if type(get(a:response, 'result')) is type([]) | ||||
|         let l:item_list = a:response.result | ||||
|     elseif type(get(a:response, 'result')) is type({}) | ||||
|     \&& type(get(a:response.result, 'items')) is type([]) | ||||
|         let l:item_list = a:response.result.items | ||||
|     endif | ||||
|  | ||||
|     let l:results = [] | ||||
|  | ||||
|     for l:item in l:item_list | ||||
|         " See :help complete-items for Vim completion kinds | ||||
|         if l:item.kind is s:LSP_COMPLETION_METHOD_KIND | ||||
|             let l:kind = 'm' | ||||
|         elseif l:item.kind is s:LSP_COMPLETION_CONSTRUCTOR_KIND | ||||
|             let l:kind = 'm' | ||||
|         elseif l:item.kind is s:LSP_COMPLETION_FUNCTION_KIND | ||||
|             let l:kind = 'f' | ||||
|         elseif l:item.kind is s:LSP_COMPLETION_CLASS_KIND | ||||
|             let l:kind = 'f' | ||||
|         elseif l:item.kind is s:LSP_COMPLETION_INTERFACE_KIND | ||||
|             let l:kind = 'f' | ||||
|         else | ||||
|             let l:kind = 'v' | ||||
|         endif | ||||
|  | ||||
|         call add(l:results, { | ||||
|         \   'word': l:item.label, | ||||
|         \   'kind': l:kind, | ||||
|         \   'icase': 1, | ||||
|         \   'menu': l:item.detail, | ||||
|         \   'info': l:item.documentation, | ||||
|         \}) | ||||
|     endfor | ||||
|  | ||||
|     return l:results | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#HandleTSServerResponse(conn_id, response) abort | ||||
|     if !s:CompletionStillValid(get(a:response, 'request_seq')) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     if !has_key(a:response, 'body') | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let l:command = get(a:response, 'command', '') | ||||
|  | ||||
|     if l:command is# 'completions' | ||||
|         let l:names = ale#completion#Filter( | ||||
|         \   ale#completion#ParseTSServerCompletions(a:response), | ||||
|         \   b:ale_completion_info.prefix, | ||||
|         \)[: g:ale_completion_max_suggestions - 1] | ||||
|  | ||||
|         if !empty(l:names) | ||||
|             let b:ale_completion_info.request_id = ale#lsp#Send( | ||||
|             \   b:ale_completion_info.conn_id, | ||||
|             \   ale#lsp#tsserver_message#CompletionEntryDetails( | ||||
|             \       bufnr(''), | ||||
|             \       b:ale_completion_info.line, | ||||
|             \       b:ale_completion_info.column, | ||||
|             \       l:names, | ||||
|             \   ), | ||||
|             \) | ||||
|         endif | ||||
|     elseif l:command is# 'completionEntryDetails' | ||||
|         call ale#completion#Show( | ||||
|         \   a:response, | ||||
|         \   'ale#completion#ParseTSServerCompletionEntryDetails', | ||||
|         \) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| function! ale#completion#HandleLSPResponse(conn_id, response) abort | ||||
|     if !s:CompletionStillValid(get(a:response, 'id')) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     call ale#completion#Show( | ||||
|     \   a:response, | ||||
|     \   'ale#completion#ParseLSPCompletions', | ||||
|     \) | ||||
| endfunction | ||||
|  | ||||
| function! s:GetLSPCompletions(linter) abort | ||||
|     let l:buffer = bufnr('') | ||||
|     let l:Callback = a:linter.lsp is# 'tsserver' | ||||
|     \   ? function('ale#completion#HandleTSServerResponse') | ||||
|     \   : function('ale#completion#HandleLSPResponse') | ||||
|  | ||||
|     let l:lsp_details = ale#linter#StartLSP(l:buffer, a:linter, l:Callback) | ||||
|  | ||||
|     if empty(l:lsp_details) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:id = l:lsp_details.connection_id | ||||
|     let l:root = l:lsp_details.project_root | ||||
|  | ||||
|     if a:linter.lsp is# 'tsserver' | ||||
|         let l:message = ale#lsp#tsserver_message#Completions( | ||||
|         \   l:buffer, | ||||
|         \   b:ale_completion_info.line, | ||||
|         \   b:ale_completion_info.column, | ||||
|         \   b:ale_completion_info.prefix, | ||||
|         \) | ||||
|     else | ||||
|         " Send a message saying the buffer has changed first, otherwise | ||||
|         " completions won't know what text is nearby. | ||||
|         call ale#lsp#Send(l:id, ale#lsp#message#DidChange(l:buffer), l:root) | ||||
|  | ||||
|         " For LSP completions, we need to clamp the column to the length of | ||||
|         " the line. python-language-server and perhaps others do not implement | ||||
|         " this correctly. | ||||
|         let l:message = ale#lsp#message#Completion( | ||||
|         \   l:buffer, | ||||
|         \   b:ale_completion_info.line, | ||||
|         \   min([ | ||||
|         \       b:ale_completion_info.line_length, | ||||
|         \       b:ale_completion_info.column, | ||||
|         \   ]), | ||||
|         \   ale#completion#GetTriggerCharacter(&filetype, b:ale_completion_info.prefix), | ||||
|         \) | ||||
|     endif | ||||
|  | ||||
|     let l:request_id = ale#lsp#Send(l:id, l:message, l:root) | ||||
|  | ||||
|     if l:request_id | ||||
|         let b:ale_completion_info.conn_id = l:id | ||||
|         let b:ale_completion_info.request_id = l:request_id | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#GetCompletions() abort | ||||
|     if !g:ale_completion_enabled | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let [l:line, l:column] = getcurpos()[1:2] | ||||
|  | ||||
|     let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column) | ||||
|  | ||||
|     if empty(l:prefix) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let l:line_length = len(getline('.')) | ||||
|  | ||||
|     let b:ale_completion_info = { | ||||
|     \   'line': l:line, | ||||
|     \   'line_length': l:line_length, | ||||
|     \   'column': l:column, | ||||
|     \   'prefix': l:prefix, | ||||
|     \   'conn_id': 0, | ||||
|     \   'request_id': 0, | ||||
|     \} | ||||
|  | ||||
|     for l:linter in ale#linter#Get(&filetype) | ||||
|         if !empty(l:linter.lsp) | ||||
|             if l:linter.lsp is# 'tsserver' | ||||
|             \|| get(g:, 'ale_completion_experimental_lsp_support', 0) | ||||
|                 call s:GetLSPCompletions(l:linter) | ||||
|             endif | ||||
|         endif | ||||
|     endfor | ||||
| endfunction | ||||
|  | ||||
| function! s:TimerHandler(...) abort | ||||
|     let s:timer_id = -1 | ||||
|  | ||||
|     let [l:line, l:column] = getcurpos()[1:2] | ||||
|  | ||||
|     " When running the timer callback, we have to be sure that the cursor | ||||
|     " hasn't moved from where it was when we requested completions by typing. | ||||
|     if s:timer_pos == [l:line, l:column] | ||||
|         call ale#completion#GetCompletions() | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| " Stop any completion timer that is queued. This is useful for tests. | ||||
| function! ale#completion#StopTimer() abort | ||||
|     if s:timer_id != -1 | ||||
|         call timer_stop(s:timer_id) | ||||
|     endif | ||||
|  | ||||
|     let s:timer_id = -1 | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#Queue() abort | ||||
|     if !g:ale_completion_enabled | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let s:timer_pos = getcurpos()[1:2] | ||||
|  | ||||
|     if s:timer_pos == s:last_done_pos | ||||
|         " Do not ask for completions if the cursor rests on the position we | ||||
|         " last completed on. | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " If we changed the text again while we're still waiting for a response, | ||||
|     " then invalidate the requests before the timer ticks again. | ||||
|     if exists('b:ale_completion_info') | ||||
|         let b:ale_completion_info.request_id = 0 | ||||
|     endif | ||||
|  | ||||
|     call ale#completion#StopTimer() | ||||
|  | ||||
|     let s:timer_id = timer_start(g:ale_completion_delay, function('s:TimerHandler')) | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#Done() abort | ||||
|     silent! pclose | ||||
|  | ||||
|     " Reset settings when completion is done. | ||||
|     if exists('b:ale_old_omnifunc') | ||||
|         if b:ale_old_omnifunc isnot# 'pythoncomplete#Complete' | ||||
|             let &l:omnifunc = b:ale_old_omnifunc | ||||
|         endif | ||||
|  | ||||
|         unlet b:ale_old_omnifunc | ||||
|     endif | ||||
|  | ||||
|     if exists('b:ale_old_completopt') | ||||
|         let &l:completeopt = b:ale_old_completopt | ||||
|         unlet b:ale_old_completopt | ||||
|     endif | ||||
|  | ||||
|     let s:last_done_pos = getcurpos()[1:2] | ||||
| endfunction | ||||
|  | ||||
| function! s:Setup(enabled) abort | ||||
|     augroup ALECompletionGroup | ||||
|         autocmd! | ||||
|  | ||||
|         if a:enabled | ||||
|             autocmd TextChangedI * call ale#completion#Queue() | ||||
|             autocmd CompleteDone * call ale#completion#Done() | ||||
|         endif | ||||
|     augroup END | ||||
|  | ||||
|     if !a:enabled | ||||
|         augroup! ALECompletionGroup | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#Enable() abort | ||||
|     let g:ale_completion_enabled = 1 | ||||
|     call s:Setup(1) | ||||
| endfunction | ||||
|  | ||||
| function! ale#completion#Disable() abort | ||||
|     let g:ale_completion_enabled = 0 | ||||
|     call s:Setup(0) | ||||
| endfunction | ||||
							
								
								
									
										136
									
								
								sources_non_forked/ale/autoload/ale/cursor.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								sources_non_forked/ale/autoload/ale/cursor.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,136 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Echoes lint message for the current line, if any | ||||
|  | ||||
| let s:cursor_timer = -1 | ||||
| let s:last_pos = [0, 0, 0] | ||||
|  | ||||
| function! ale#cursor#TruncatedEcho(original_message) abort | ||||
|     let l:message = a:original_message | ||||
|     " Change tabs to spaces. | ||||
|     let l:message = substitute(l:message, "\t", ' ', 'g') | ||||
|     " Remove any newlines in the message. | ||||
|     let l:message = substitute(l:message, "\n", '', 'g') | ||||
|  | ||||
|     " We need to remember the setting for shortmess and reset it again. | ||||
|     let l:shortmess_options = &l:shortmess | ||||
|  | ||||
|     try | ||||
|         let l:cursor_position = getcurpos() | ||||
|  | ||||
|         " The message is truncated and saved to the history. | ||||
|         setlocal shortmess+=T | ||||
|         exec "norm! :echomsg l:message\n" | ||||
|  | ||||
|         " Reset the cursor position if we moved off the end of the line. | ||||
|         " Using :norm and :echomsg can move the cursor off the end of the | ||||
|         " line. | ||||
|         if l:cursor_position != getcurpos() | ||||
|             call setpos('.', l:cursor_position) | ||||
|         endif | ||||
|     finally | ||||
|         let &l:shortmess = l:shortmess_options | ||||
|     endtry | ||||
| endfunction | ||||
|  | ||||
| function! s:FindItemAtCursor() abort | ||||
|     let l:buf = bufnr('') | ||||
|     let l:info = get(g:ale_buffer_info, l:buf, {}) | ||||
|     let l:loclist = get(l:info, 'loclist', []) | ||||
|     let l:pos = getcurpos() | ||||
|     let l:index = ale#util#BinarySearch(l:loclist, l:buf, l:pos[1], l:pos[2]) | ||||
|     let l:loc = l:index >= 0 ? l:loclist[l:index] : {} | ||||
|  | ||||
|     return [l:info, l:loc] | ||||
| endfunction | ||||
|  | ||||
| function! s:StopCursorTimer() abort | ||||
|     if s:cursor_timer != -1 | ||||
|         call timer_stop(s:cursor_timer) | ||||
|         let s:cursor_timer = -1 | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#cursor#EchoCursorWarning(...) abort | ||||
|     return ale#CallWithCooldown('dont_echo_until', function('s:EchoImpl'), []) | ||||
| endfunction | ||||
|  | ||||
| function! s:EchoImpl() abort | ||||
|     if !g:ale_echo_cursor | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " Only echo the warnings in normal mode, otherwise we will get problems. | ||||
|     if mode() isnot# 'n' | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     if ale#ShouldDoNothing(bufnr('')) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let l:buffer = bufnr('') | ||||
|     let [l:info, l:loc] = s:FindItemAtCursor() | ||||
|  | ||||
|     if !empty(l:loc) | ||||
|         let l:format = ale#Var(l:buffer, 'echo_msg_format') | ||||
|         let l:msg = ale#GetLocItemMessage(l:loc, l:format) | ||||
|         call ale#cursor#TruncatedEcho(l:msg) | ||||
|         let l:info.echoed = 1 | ||||
|     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' | ||||
|         let l:info.echoed = 0 | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#cursor#EchoCursorWarningWithDelay() abort | ||||
|     if !g:ale_echo_cursor | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " Only echo the warnings in normal mode, otherwise we will get problems. | ||||
|     if mode() isnot# 'n' | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     call s:StopCursorTimer() | ||||
|  | ||||
|     let l:pos = getcurpos()[0:2] | ||||
|  | ||||
|     " Check the current buffer, line, and column number against the last | ||||
|     " recorded position. If the position has actually changed, *then* | ||||
|     " we should echo something. Otherwise we can end up doing processing | ||||
|     " the echo message far too frequently. | ||||
|     if l:pos != s:last_pos | ||||
|         let l:delay = ale#Var(bufnr(''), 'echo_delay') | ||||
|  | ||||
|         let s:last_pos = l:pos | ||||
|         let s:cursor_timer = timer_start( | ||||
|         \   l:delay, | ||||
|         \   function('ale#cursor#EchoCursorWarning') | ||||
|         \) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#cursor#ShowCursorDetail() abort | ||||
|     " Only echo the warnings in normal mode, otherwise we will get problems. | ||||
|     if mode() isnot# 'n' | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     if ale#ShouldDoNothing(bufnr('')) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     call s:StopCursorTimer() | ||||
|  | ||||
|     let [l:info, l:loc] = s:FindItemAtCursor() | ||||
|  | ||||
|     if !empty(l:loc) | ||||
|         let l:message = get(l:loc, 'detail', l:loc.text) | ||||
|  | ||||
|         call ale#preview#Show(split(l:message, "\n")) | ||||
|         execute 'echo' | ||||
|     endif | ||||
| endfunction | ||||
							
								
								
									
										213
									
								
								sources_non_forked/ale/autoload/ale/debugging.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								sources_non_forked/ale/autoload/ale/debugging.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,213 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: This file implements debugging information for ALE | ||||
|  | ||||
| let s:global_variable_list = [ | ||||
| \    'ale_cache_executable_check_failures', | ||||
| \    'ale_change_sign_column_color', | ||||
| \    'ale_command_wrapper', | ||||
| \    'ale_completion_delay', | ||||
| \    'ale_completion_enabled', | ||||
| \    'ale_completion_max_suggestions', | ||||
| \    'ale_echo_cursor', | ||||
| \    'ale_echo_msg_error_str', | ||||
| \    'ale_echo_msg_format', | ||||
| \    'ale_echo_msg_info_str', | ||||
| \    'ale_echo_msg_warning_str', | ||||
| \    'ale_enabled', | ||||
| \    'ale_fix_on_save', | ||||
| \    'ale_fixers', | ||||
| \    'ale_history_enabled', | ||||
| \    'ale_history_log_output', | ||||
| \    'ale_keep_list_window_open', | ||||
| \    'ale_lint_delay', | ||||
| \    'ale_lint_on_enter', | ||||
| \    'ale_lint_on_filetype_changed', | ||||
| \    'ale_lint_on_save', | ||||
| \    'ale_lint_on_text_changed', | ||||
| \    'ale_lint_on_insert_leave', | ||||
| \    'ale_linter_aliases', | ||||
| \    'ale_linters', | ||||
| \    'ale_linters_explicit', | ||||
| \    'ale_list_window_size', | ||||
| \    'ale_list_vertical', | ||||
| \    'ale_loclist_msg_format', | ||||
| \    'ale_max_buffer_history_size', | ||||
| \    'ale_max_signs', | ||||
| \    'ale_maximum_file_size', | ||||
| \    'ale_open_list', | ||||
| \    'ale_pattern_options', | ||||
| \    'ale_pattern_options_enabled', | ||||
| \    'ale_set_balloons', | ||||
| \    'ale_set_highlights', | ||||
| \    'ale_set_loclist', | ||||
| \    'ale_set_quickfix', | ||||
| \    'ale_set_signs', | ||||
| \    'ale_sign_column_always', | ||||
| \    'ale_sign_error', | ||||
| \    'ale_sign_info', | ||||
| \    'ale_sign_offset', | ||||
| \    'ale_sign_style_error', | ||||
| \    'ale_sign_style_warning', | ||||
| \    'ale_sign_warning', | ||||
| \    'ale_statusline_format', | ||||
| \    'ale_type_map', | ||||
| \    'ale_warn_about_trailing_blank_lines', | ||||
| \    'ale_warn_about_trailing_whitespace', | ||||
| \] | ||||
|  | ||||
| function! s:Echo(message) abort | ||||
|     execute 'echo a:message' | ||||
| endfunction | ||||
|  | ||||
| function! s:GetLinterVariables(filetype, linter_names) abort | ||||
|     let l:variable_list = [] | ||||
|     let l:filetype_parts = split(a:filetype, '\.') | ||||
|  | ||||
|     for l:key in keys(g:) | ||||
|         " Extract variable names like: 'ale_python_flake8_executable' | ||||
|         let l:match = matchlist(l:key, '\v^ale_([^_]+)_([^_]+)_.+$') | ||||
|  | ||||
|         " Include matching variables. | ||||
|         if !empty(l:match) | ||||
|         \&& index(l:filetype_parts, l:match[1]) >= 0 | ||||
|         \&& index(a:linter_names, l:match[2]) >= 0 | ||||
|             call add(l:variable_list, l:key) | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     call sort(l:variable_list) | ||||
|  | ||||
|     return l:variable_list | ||||
| endfunction | ||||
|  | ||||
| function! s:EchoLinterVariables(variable_list) abort | ||||
|     for l:key in a:variable_list | ||||
|         call s:Echo('let g:' . l:key . ' = ' . string(g:[l:key])) | ||||
|  | ||||
|         if has_key(b:, l:key) | ||||
|             call s:Echo('let b:' . l:key . ' = ' . string(b:[l:key])) | ||||
|         endif | ||||
|     endfor | ||||
| endfunction | ||||
|  | ||||
| function! s:EchoGlobalVariables() abort | ||||
|     for l:key in s:global_variable_list | ||||
|         call s:Echo('let g:' . l:key . ' = ' . string(get(g:, l:key, v:null))) | ||||
|  | ||||
|         if has_key(b:, l:key) | ||||
|             call s:Echo('let b:' . l:key . ' = ' . string(b:[l:key])) | ||||
|         endif | ||||
|     endfor | ||||
| endfunction | ||||
|  | ||||
| " Echo a command that was run. | ||||
| function! s:EchoCommand(item) abort | ||||
|     let l:status_message = a:item.status | ||||
|  | ||||
|     " Include the exit code in output if we have it. | ||||
|     if a:item.status is# 'finished' | ||||
|         let l:status_message .= ' - exit code ' . a:item.exit_code | ||||
|     endif | ||||
|  | ||||
|     call s:Echo('(' . l:status_message . ') ' . string(a:item.command)) | ||||
|  | ||||
|     if g:ale_history_log_output && has_key(a:item, 'output') | ||||
|         if empty(a:item.output) | ||||
|             call s:Echo('') | ||||
|             call s:Echo('<<<NO OUTPUT RETURNED>>>') | ||||
|             call s:Echo('') | ||||
|         else | ||||
|             call s:Echo('') | ||||
|             call s:Echo('<<<OUTPUT STARTS>>>') | ||||
|  | ||||
|             for l:line in a:item.output | ||||
|                 call s:Echo(l:line) | ||||
|             endfor | ||||
|  | ||||
|             call s:Echo('<<<OUTPUT ENDS>>>') | ||||
|             call s:Echo('') | ||||
|         endif | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| " Echo the results of an executable check. | ||||
| function! s:EchoExecutable(item) abort | ||||
|     call s:Echo(printf( | ||||
|     \   '(executable check - %s) %s', | ||||
|     \   a:item.status ? 'success' : 'failure', | ||||
|     \   a:item.command, | ||||
|     \)) | ||||
| endfunction | ||||
|  | ||||
| function! s:EchoCommandHistory() abort | ||||
|     let l:buffer = bufnr('%') | ||||
|  | ||||
|     for l:item in ale#history#Get(l:buffer) | ||||
|         if l:item.job_id is# 'executable' | ||||
|             call s:EchoExecutable(l:item) | ||||
|         else | ||||
|             call s:EchoCommand(l:item) | ||||
|         endif | ||||
|     endfor | ||||
| endfunction | ||||
|  | ||||
| function! s:EchoLinterAliases(all_linters) abort | ||||
|     let l:first = 1 | ||||
|  | ||||
|     for l:linter in a:all_linters | ||||
|         if !empty(l:linter.aliases) | ||||
|             if l:first | ||||
|                 call s:Echo('   Linter Aliases:') | ||||
|             endif | ||||
|  | ||||
|             let l:first = 0 | ||||
|  | ||||
|             call s:Echo(string(l:linter.name) . ' -> ' . string(l:linter.aliases)) | ||||
|         endif | ||||
|     endfor | ||||
| endfunction | ||||
|  | ||||
| function! ale#debugging#Info() abort | ||||
|     let l:filetype = &filetype | ||||
|  | ||||
|     " We get the list of enabled linters for free by the above function. | ||||
|     let l:enabled_linters = deepcopy(ale#linter#Get(l:filetype)) | ||||
|  | ||||
|     " But have to build the list of available linters ourselves. | ||||
|     let l:all_linters = [] | ||||
|     let l:linter_variable_list = [] | ||||
|  | ||||
|     for l:part in split(l:filetype, '\.') | ||||
|         let l:aliased_filetype = ale#linter#ResolveFiletype(l:part) | ||||
|         call extend(l:all_linters, ale#linter#GetAll(l:aliased_filetype)) | ||||
|     endfor | ||||
|  | ||||
|     let l:all_names = map(copy(l:all_linters), 'v:val[''name'']') | ||||
|     let l:enabled_names = map(copy(l:enabled_linters), 'v:val[''name'']') | ||||
|  | ||||
|     " Load linter variables to display | ||||
|     " This must be done after linters are loaded. | ||||
|     let l:variable_list = s:GetLinterVariables(l:filetype, l:enabled_names) | ||||
|  | ||||
|     call s:Echo(' Current Filetype: ' . l:filetype) | ||||
|     call s:Echo('Available Linters: ' . string(l:all_names)) | ||||
|     call s:EchoLinterAliases(l:all_linters) | ||||
|     call s:Echo('  Enabled Linters: ' . string(l:enabled_names)) | ||||
|     call s:Echo(' Linter Variables:') | ||||
|     call s:Echo('') | ||||
|     call s:EchoLinterVariables(l:variable_list) | ||||
|     call s:Echo(' Global Variables:') | ||||
|     call s:Echo('') | ||||
|     call s:EchoGlobalVariables() | ||||
|     call s:Echo('  Command History:') | ||||
|     call s:Echo('') | ||||
|     call s:EchoCommandHistory() | ||||
| endfunction | ||||
|  | ||||
| function! ale#debugging#InfoToClipboard() abort | ||||
|     redir @+> | ||||
|         silent call ale#debugging#Info() | ||||
|     redir END | ||||
|  | ||||
|     call s:Echo('ALEInfo copied to your clipboard') | ||||
| endfunction | ||||
							
								
								
									
										125
									
								
								sources_non_forked/ale/autoload/ale/definition.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								sources_non_forked/ale/autoload/ale/definition.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,125 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Go to definition support for LSP linters. | ||||
|  | ||||
| let s:go_to_definition_map = {} | ||||
|  | ||||
| " Used to get the definition map in tests. | ||||
| function! ale#definition#GetMap() abort | ||||
|     return deepcopy(s:go_to_definition_map) | ||||
| endfunction | ||||
|  | ||||
| " Used to set the definition map in tests. | ||||
| function! ale#definition#SetMap(map) abort | ||||
|     let s:go_to_definition_map = a:map | ||||
| endfunction | ||||
|  | ||||
| " This function is used so we can check the execution of commands without | ||||
| " running them. | ||||
| function! ale#definition#Execute(expr) abort | ||||
|     execute a:expr | ||||
| endfunction | ||||
|  | ||||
| function! ale#definition#ClearLSPData() abort | ||||
|     let s:go_to_definition_map = {} | ||||
| endfunction | ||||
|  | ||||
| function! ale#definition#Open(options, filename, line, column) abort | ||||
|     if a:options.open_in_tab | ||||
|         call ale#definition#Execute('tabedit ' . fnameescape(a:filename)) | ||||
|     else | ||||
|         call ale#definition#Execute('edit ' . fnameescape(a:filename)) | ||||
|     endif | ||||
|  | ||||
|     call cursor(a:line, a:column) | ||||
| endfunction | ||||
|  | ||||
| function! ale#definition#HandleTSServerResponse(conn_id, response) abort | ||||
|     if get(a:response, 'command', '') is# 'definition' | ||||
|     \&& has_key(s:go_to_definition_map, a:response.request_seq) | ||||
|         let l:options = remove(s:go_to_definition_map, a:response.request_seq) | ||||
|  | ||||
|         if get(a:response, 'success', v:false) is v:true | ||||
|             let l:filename = a:response.body[0].file | ||||
|             let l:line = a:response.body[0].start.line | ||||
|             let l:column = a:response.body[0].start.offset | ||||
|  | ||||
|             call ale#definition#Open(l:options, l:filename, l:line, l:column) | ||||
|         endif | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#definition#HandleLSPResponse(conn_id, response) abort | ||||
|     if has_key(a:response, 'id') | ||||
|     \&& has_key(s:go_to_definition_map, a:response.id) | ||||
|         let l:options = remove(s:go_to_definition_map, a:response.id) | ||||
|  | ||||
|         " The result can be a Dictionary item, a List of the same, or null. | ||||
|         let l:result = get(a:response, 'result', v:null) | ||||
|  | ||||
|         if type(l:result) is type({}) | ||||
|             let l:result = [l:result] | ||||
|         elseif type(l:result) isnot type([]) | ||||
|             let l:result = [] | ||||
|         endif | ||||
|  | ||||
|         for l:item in l:result | ||||
|             let l:filename = ale#path#FromURI(l:item.uri) | ||||
|             let l:line = l:item.range.start.line + 1 | ||||
|             let l:column = l:item.range.start.character | ||||
|  | ||||
|             call ale#definition#Open(l:options, l:filename, l:line, l:column) | ||||
|             break | ||||
|         endfor | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! s:GoToLSPDefinition(linter, options) abort | ||||
|     let l:buffer = bufnr('') | ||||
|     let [l:line, l:column] = getcurpos()[1:2] | ||||
|  | ||||
|     let l:Callback = a:linter.lsp is# 'tsserver' | ||||
|     \   ? function('ale#definition#HandleTSServerResponse') | ||||
|     \   : function('ale#definition#HandleLSPResponse') | ||||
|  | ||||
|     let l:lsp_details = ale#linter#StartLSP(l:buffer, a:linter, l:Callback) | ||||
|  | ||||
|     if empty(l:lsp_details) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:id = l:lsp_details.connection_id | ||||
|     let l:root = l:lsp_details.project_root | ||||
|  | ||||
|     if a:linter.lsp is# 'tsserver' | ||||
|         let l:message = ale#lsp#tsserver_message#Definition( | ||||
|         \   l:buffer, | ||||
|         \   l:line, | ||||
|         \   l:column | ||||
|         \) | ||||
|     else | ||||
|         " Send a message saying the buffer has changed first, or the | ||||
|         " definition position probably won't make sense. | ||||
|         call ale#lsp#Send(l:id, ale#lsp#message#DidChange(l:buffer), l:root) | ||||
|  | ||||
|         let l:column = min([l:column, len(getline(l:line))]) | ||||
|  | ||||
|         " For LSP completions, we need to clamp the column to the length of | ||||
|         " the line. python-language-server and perhaps others do not implement | ||||
|         " this correctly. | ||||
|         let l:message = ale#lsp#message#Definition(l:buffer, l:line, l:column) | ||||
|     endif | ||||
|  | ||||
|     let l:request_id = ale#lsp#Send(l:id, l:message, l:root) | ||||
|  | ||||
|     let s:go_to_definition_map[l:request_id] = { | ||||
|     \   'open_in_tab': get(a:options, 'open_in_tab', 0), | ||||
|     \} | ||||
| endfunction | ||||
|  | ||||
| function! ale#definition#GoTo(options) abort | ||||
|     for l:linter in ale#linter#Get(&filetype) | ||||
|         if !empty(l:linter.lsp) | ||||
|             call s:GoToLSPDefinition(l:linter, a:options) | ||||
|         endif | ||||
|     endfor | ||||
| endfunction | ||||
							
								
								
									
										950
									
								
								sources_non_forked/ale/autoload/ale/engine.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										950
									
								
								sources_non_forked/ale/autoload/ale/engine.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,950 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Backend execution and job management | ||||
| "   Executes linters in the background, using NeoVim or Vim 8 jobs | ||||
|  | ||||
| " Stores information for each job including: | ||||
| " | ||||
| " linter: The linter dictionary for the job. | ||||
| " buffer: The buffer number for the job. | ||||
| " output: The array of lines for the output of the job. | ||||
| if !has_key(s:, 'job_info_map') | ||||
|     let s:job_info_map = {} | ||||
| endif | ||||
|  | ||||
| " Associates LSP connection IDs with linter names. | ||||
| if !has_key(s:, 'lsp_linter_map') | ||||
|     let s:lsp_linter_map = {} | ||||
| endif | ||||
|  | ||||
| if !has_key(s:, 'executable_cache_map') | ||||
|     let s:executable_cache_map = {} | ||||
| endif | ||||
|  | ||||
| function! ale#engine#ResetExecutableCache() abort | ||||
|     let s:executable_cache_map = {} | ||||
| endfunction | ||||
|  | ||||
| " Check if files are executable, and if they are, remember that they are | ||||
| " for subsequent calls. We'll keep checking until programs can be executed. | ||||
| function! ale#engine#IsExecutable(buffer, executable) abort | ||||
|     if empty(a:executable) | ||||
|         " Don't log the executable check if the executable string is empty. | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     " Check for a cached executable() check. | ||||
|     let l:result = get(s:executable_cache_map, a:executable, v:null) | ||||
|  | ||||
|     if l:result isnot v:null | ||||
|         return l:result | ||||
|     endif | ||||
|  | ||||
|     " Check if the file is executable, and convert -1 to 1. | ||||
|     let l:result = executable(a:executable) isnot 0 | ||||
|  | ||||
|     " Cache the executable check if we found it, or if the option to cache | ||||
|     " failing checks is on. | ||||
|     if l:result || g:ale_cache_executable_check_failures | ||||
|         let s:executable_cache_map[a:executable] = l:result | ||||
|     endif | ||||
|  | ||||
|     if g:ale_history_enabled | ||||
|         call ale#history#Add(a:buffer, l:result, 'executable', a:executable) | ||||
|     endif | ||||
|  | ||||
|     return l:result | ||||
| endfunction | ||||
|  | ||||
| function! ale#engine#InitBufferInfo(buffer) abort | ||||
|     if !has_key(g:ale_buffer_info, a:buffer) | ||||
|         " job_list will hold the list of job IDs | ||||
|         " active_linter_list will hold the list of active linter names | ||||
|         " loclist holds the loclist items after all jobs have completed. | ||||
|         " temporary_file_list holds temporary files to be cleaned up | ||||
|         " temporary_directory_list holds temporary directories to be cleaned up | ||||
|         let g:ale_buffer_info[a:buffer] = { | ||||
|         \   'job_list': [], | ||||
|         \   'active_linter_list': [], | ||||
|         \   'loclist': [], | ||||
|         \   'temporary_file_list': [], | ||||
|         \   'temporary_directory_list': [], | ||||
|         \} | ||||
|  | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     return 0 | ||||
| endfunction | ||||
|  | ||||
| " Clear LSP linter data for the linting engine. | ||||
| function! ale#engine#ClearLSPData() abort | ||||
|     let s:lsp_linter_map = {} | ||||
| endfunction | ||||
|  | ||||
| " This function is documented and part of the public API. | ||||
| " | ||||
| " Return 1 if ALE is busy checking a given buffer | ||||
| function! ale#engine#IsCheckingBuffer(buffer) abort | ||||
|     let l:info = get(g:ale_buffer_info, a:buffer, {}) | ||||
|  | ||||
|     return !empty(get(l:info, 'active_linter_list', [])) | ||||
| endfunction | ||||
|  | ||||
| " Register a temporary file to be managed with the ALE engine for | ||||
| " a current job run. | ||||
| function! ale#engine#ManageFile(buffer, filename) abort | ||||
|     call add(g:ale_buffer_info[a:buffer].temporary_file_list, a:filename) | ||||
| endfunction | ||||
|  | ||||
| " Same as the above, but manage an entire directory. | ||||
| function! ale#engine#ManageDirectory(buffer, directory) abort | ||||
|     call add(g:ale_buffer_info[a:buffer].temporary_directory_list, a:directory) | ||||
| endfunction | ||||
|  | ||||
| " Create a new temporary directory and manage it in one go. | ||||
| function! ale#engine#CreateDirectory(buffer) abort | ||||
|     let l:temporary_directory = tempname() | ||||
|     " Create the temporary directory for the file, unreadable by 'other' | ||||
|     " users. | ||||
|     call mkdir(l:temporary_directory, '', 0750) | ||||
|     call ale#engine#ManageDirectory(a:buffer, l:temporary_directory) | ||||
|  | ||||
|     return l:temporary_directory | ||||
| endfunction | ||||
|  | ||||
| function! ale#engine#RemoveManagedFiles(buffer) abort | ||||
|     let l:info = get(g:ale_buffer_info, a:buffer, {}) | ||||
|  | ||||
|     " We can't delete anything in a sandbox, so wait until we escape from | ||||
|     " it to delete temporary files and directories. | ||||
|     if ale#util#InSandbox() | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " Delete files with a call akin to a plan `rm` command. | ||||
|     if has_key(l:info, 'temporary_file_list') | ||||
|         for l:filename in l:info.temporary_file_list | ||||
|             call delete(l:filename) | ||||
|         endfor | ||||
|  | ||||
|         let l:info.temporary_file_list = [] | ||||
|     endif | ||||
|  | ||||
|     " Delete directories like `rm -rf`. | ||||
|     " Directories are handled differently from files, so paths that are | ||||
|     " intended to be single files can be set up for automatic deletion without | ||||
|     " accidentally deleting entire directories. | ||||
|     if has_key(l:info, 'temporary_directory_list') | ||||
|         for l:directory in l:info.temporary_directory_list | ||||
|             call delete(l:directory, 'rf') | ||||
|         endfor | ||||
|  | ||||
|         let l:info.temporary_directory_list = [] | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! s:GatherOutput(job_id, line) abort | ||||
|     if has_key(s:job_info_map, a:job_id) | ||||
|         call add(s:job_info_map[a:job_id].output, a:line) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#engine#HandleLoclist(linter_name, buffer, loclist) abort | ||||
|     let l:info = get(g:ale_buffer_info, a:buffer, {}) | ||||
|  | ||||
|     if empty(l:info) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " Remove this linter from the list of active linters. | ||||
|     " This may have already been done when the job exits. | ||||
|     call filter(l:info.active_linter_list, 'v:val isnot# a:linter_name') | ||||
|  | ||||
|     " Make some adjustments to the loclists to fix common problems, and also | ||||
|     " to set default values for loclist items. | ||||
|     let l:linter_loclist = ale#engine#FixLocList(a:buffer, a:linter_name, a:loclist) | ||||
|  | ||||
|     " Remove previous items for this linter. | ||||
|     call filter(l:info.loclist, 'v:val.linter_name isnot# a:linter_name') | ||||
|  | ||||
|     " We don't need to add items or sort the list when this list is empty. | ||||
|     if !empty(l:linter_loclist) | ||||
|         " Add the new items. | ||||
|         call extend(l:info.loclist, l:linter_loclist) | ||||
|  | ||||
|         " Sort the loclist again. | ||||
|         " We need a sorted list so we can run a binary search against it | ||||
|         " for efficient lookup of the messages in the cursor handler. | ||||
|         call sort(l:info.loclist, 'ale#util#LocItemCompare') | ||||
|     endif | ||||
|  | ||||
|     if ale#ShouldDoNothing(a:buffer) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     call ale#engine#SetResults(a:buffer, l:info.loclist) | ||||
| endfunction | ||||
|  | ||||
| function! s:HandleExit(job_id, exit_code) abort | ||||
|     if !has_key(s:job_info_map, a:job_id) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let l:job_info = s:job_info_map[a:job_id] | ||||
|     let l:linter = l:job_info.linter | ||||
|     let l:output = l:job_info.output | ||||
|     let l:buffer = l:job_info.buffer | ||||
|     let l:next_chain_index = l:job_info.next_chain_index | ||||
|  | ||||
|     if g:ale_history_enabled | ||||
|         call ale#history#SetExitCode(l:buffer, a:job_id, a:exit_code) | ||||
|     endif | ||||
|  | ||||
|     " Remove this job from the list. | ||||
|     call ale#job#Stop(a:job_id) | ||||
|     call remove(s:job_info_map, a:job_id) | ||||
|     call filter(g:ale_buffer_info[l:buffer].job_list, 'v:val isnot# a:job_id') | ||||
|     call filter(g:ale_buffer_info[l:buffer].active_linter_list, 'v:val isnot# l:linter.name') | ||||
|  | ||||
|     " Stop here if we land in the handle for a job completing if we're in | ||||
|     " a sandbox. | ||||
|     if ale#util#InSandbox() | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     if has('nvim') && !empty(l:output) && empty(l:output[-1]) | ||||
|         call remove(l:output, -1) | ||||
|     endif | ||||
|  | ||||
|     if l:next_chain_index < len(get(l:linter, 'command_chain', [])) | ||||
|         call s:InvokeChain(l:buffer, l:linter, l:next_chain_index, l:output) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " Log the output of the command for ALEInfo if we should. | ||||
|     if g:ale_history_enabled && g:ale_history_log_output | ||||
|         call ale#history#RememberOutput(l:buffer, a:job_id, l:output[:]) | ||||
|     endif | ||||
|  | ||||
|     let l:loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output) | ||||
|  | ||||
|     call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist) | ||||
| endfunction | ||||
|  | ||||
| function! s:HandleLSPDiagnostics(conn_id, response) abort | ||||
|     let l:linter_name = s:lsp_linter_map[a:conn_id] | ||||
|     let l:filename = ale#path#FromURI(a:response.params.uri) | ||||
|     let l:buffer = bufnr(l:filename) | ||||
|  | ||||
|     if l:buffer <= 0 | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let l:loclist = ale#lsp#response#ReadDiagnostics(a:response) | ||||
|  | ||||
|     call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist) | ||||
| endfunction | ||||
|  | ||||
| function! s:HandleTSServerDiagnostics(response, error_type) abort | ||||
|     let l:buffer = bufnr(a:response.body.file) | ||||
|     let l:info = get(g:ale_buffer_info, l:buffer, {}) | ||||
|  | ||||
|     if empty(l:info) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let l:thislist = ale#lsp#response#ReadTSServerDiagnostics(a:response) | ||||
|  | ||||
|     " tsserver sends syntax and semantic errors in separate messages, so we | ||||
|     " have to collect the messages separately for each buffer and join them | ||||
|     " back together again. | ||||
|     if a:error_type is# 'syntax' | ||||
|         let l:info.syntax_loclist = l:thislist | ||||
|     else | ||||
|         let l:info.semantic_loclist = l:thislist | ||||
|     endif | ||||
|  | ||||
|     let l:loclist = get(l:info, 'semantic_loclist', []) | ||||
|     \   + get(l:info, 'syntax_loclist', []) | ||||
|  | ||||
|     call ale#engine#HandleLoclist('tsserver', l:buffer, l:loclist) | ||||
| endfunction | ||||
|  | ||||
| function! s:HandleLSPErrorMessage(error_message) abort | ||||
|     execute 'echoerr ''Error from LSP:''' | ||||
|  | ||||
|     for l:line in split(a:error_message, "\n") | ||||
|         execute 'echoerr l:line' | ||||
|     endfor | ||||
| endfunction | ||||
|  | ||||
| function! ale#engine#HandleLSPResponse(conn_id, response) abort | ||||
|     let l:method = get(a:response, 'method', '') | ||||
|  | ||||
|     if get(a:response, 'jsonrpc', '') is# '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 is# 'textDocument/publishDiagnostics' | ||||
|         call s:HandleLSPDiagnostics(a:conn_id, a:response) | ||||
|     elseif get(a:response, 'type', '') is# 'event' | ||||
|     \&& get(a:response, 'event', '') is# 'semanticDiag' | ||||
|         call s:HandleTSServerDiagnostics(a:response, 'semantic') | ||||
|     elseif get(a:response, 'type', '') is# 'event' | ||||
|     \&& get(a:response, 'event', '') is# 'syntaxDiag' | ||||
|         call s:HandleTSServerDiagnostics(a:response, 'syntax') | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#engine#SetResults(buffer, loclist) abort | ||||
|     let l:linting_is_done = !ale#engine#IsCheckingBuffer(a:buffer) | ||||
|  | ||||
|     " Set signs first. This could potentially fix some line numbers. | ||||
|     " The List could be sorted again here by SetSigns. | ||||
|     if g:ale_set_signs | ||||
|         call ale#sign#SetSigns(a:buffer, a:loclist) | ||||
|     endif | ||||
|  | ||||
|     if g:ale_set_quickfix || g:ale_set_loclist | ||||
|         call ale#list#SetLists(a:buffer, a:loclist) | ||||
|     endif | ||||
|  | ||||
|     if exists('*ale#statusline#Update') | ||||
|         " Don't load/run if not already loaded. | ||||
|         call ale#statusline#Update(a:buffer, a:loclist) | ||||
|     endif | ||||
|  | ||||
|     if g:ale_set_highlights | ||||
|         call ale#highlight#SetHighlights(a:buffer, a:loclist) | ||||
|     endif | ||||
|  | ||||
|     if l:linting_is_done | ||||
|         if g:ale_echo_cursor | ||||
|             " Try and echo the warning now. | ||||
|             " This will only do something meaningful if we're in normal mode. | ||||
|             call ale#cursor#EchoCursorWarning() | ||||
|         endif | ||||
|  | ||||
|         " Reset the save event marker, used for opening windows, etc. | ||||
|         call setbufvar(a:buffer, 'ale_save_event_fired', 0) | ||||
|         " Set a marker showing how many times a buffer has been checked. | ||||
|         call setbufvar( | ||||
|         \   a:buffer, | ||||
|         \   'ale_linted', | ||||
|         \   getbufvar(a:buffer, 'ale_linted', 0) + 1 | ||||
|         \) | ||||
|  | ||||
|         " Automatically remove all managed temporary files and directories | ||||
|         " now that all jobs have completed. | ||||
|         call ale#engine#RemoveManagedFiles(a:buffer) | ||||
|  | ||||
|         " Call user autocommands. This allows users to hook into ALE's lint cycle. | ||||
|         silent doautocmd <nomodeline> User ALELintPost | ||||
|         " Old DEPRECATED name; call it for backwards compatibility. | ||||
|         silent doautocmd <nomodeline> User ALELint | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! s:RemapItemTypes(type_map, loclist) abort | ||||
|     for l:item in a:loclist | ||||
|         let l:key = l:item.type | ||||
|         \   . (get(l:item, 'sub_type', '') is# 'style' ? 'S' : '') | ||||
|         let l:new_key = get(a:type_map, l:key, '') | ||||
|  | ||||
|         if l:new_key is# 'E' | ||||
|         \|| l:new_key is# 'ES' | ||||
|         \|| l:new_key is# 'W' | ||||
|         \|| l:new_key is# 'WS' | ||||
|         \|| l:new_key is# 'I' | ||||
|             let l:item.type = l:new_key[0] | ||||
|  | ||||
|             if l:new_key is# 'ES' || l:new_key is# 'WS' | ||||
|                 let l:item.sub_type = 'style' | ||||
|             elseif has_key(l:item, 'sub_type') | ||||
|                 call remove(l:item, 'sub_type') | ||||
|             endif | ||||
|         endif | ||||
|     endfor | ||||
| endfunction | ||||
|  | ||||
| function! ale#engine#FixLocList(buffer, linter_name, loclist) abort | ||||
|     let l:bufnr_map = {} | ||||
|     let l:new_loclist = [] | ||||
|  | ||||
|     " Some errors have line numbers beyond the end of the file, | ||||
|     " so we need to adjust them so they set the error at the last line | ||||
|     " of the file instead. | ||||
|     let l:last_line_number = ale#util#GetLineCount(a:buffer) | ||||
|  | ||||
|     for l:old_item in a:loclist | ||||
|         " Copy the loclist item with some default values and corrections. | ||||
|         " | ||||
|         " line and column numbers will be converted to numbers. | ||||
|         " The buffer will default to the buffer being checked. | ||||
|         " The vcol setting will default to 0, a byte index. | ||||
|         " The error type will default to 'E' for errors. | ||||
|         " The error number will default to -1. | ||||
|         " | ||||
|         " The line number and text are the only required keys. | ||||
|         " | ||||
|         " The linter_name will be set on the errors so it can be used in | ||||
|         " output, filtering, etc.. | ||||
|         let l:item = { | ||||
|         \   'bufnr': a:buffer, | ||||
|         \   '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), | ||||
|         \   'type': get(l:old_item, 'type', 'E'), | ||||
|         \   'nr': get(l:old_item, 'nr', -1), | ||||
|         \   'linter_name': a:linter_name, | ||||
|         \} | ||||
|  | ||||
|         if has_key(l:old_item, 'code') | ||||
|             let l:item.code = l:old_item.code | ||||
|         endif | ||||
|  | ||||
|         if has_key(l:old_item, 'filename') | ||||
|         \&& !ale#path#IsTempName(l:old_item.filename) | ||||
|             " Use the filename given. | ||||
|             " Temporary files are assumed to be for this buffer, | ||||
|             " and the filename is not included then, because it looks bad | ||||
|             " in the loclist window. | ||||
|             let l:filename = l:old_item.filename | ||||
|             let l:item.filename = l:filename | ||||
|  | ||||
|             if has_key(l:old_item, 'bufnr') | ||||
|                 " If a buffer number is also given, include that too. | ||||
|                 " If Vim detects that he buffer number is valid, it will | ||||
|                 " be used instead of the filename. | ||||
|                 let l:item.bufnr = l:old_item.bufnr | ||||
|             elseif has_key(l:bufnr_map, l:filename) | ||||
|                 " Get the buffer number from the map, which can be faster. | ||||
|                 let l:item.bufnr = l:bufnr_map[l:filename] | ||||
|             else | ||||
|                 " Look up the buffer number. | ||||
|                 let l:item.bufnr = bufnr(l:filename) | ||||
|                 let l:bufnr_map[l:filename] = l:item.bufnr | ||||
|             endif | ||||
|         elseif has_key(l:old_item, 'bufnr') | ||||
|             let l:item.bufnr = l:old_item.bufnr | ||||
|         endif | ||||
|  | ||||
|         if has_key(l:old_item, 'detail') | ||||
|             let l:item.detail = l:old_item.detail | ||||
|         endif | ||||
|  | ||||
|         " Pass on a end_col key if set, used for highlights. | ||||
|         if has_key(l:old_item, 'end_col') | ||||
|             let l:item.end_col = str2nr(l:old_item.end_col) | ||||
|         endif | ||||
|  | ||||
|         if has_key(l:old_item, 'end_lnum') | ||||
|             let l:item.end_lnum = str2nr(l:old_item.end_lnum) | ||||
|         endif | ||||
|  | ||||
|         if has_key(l:old_item, 'sub_type') | ||||
|             let l:item.sub_type = l:old_item.sub_type | ||||
|         endif | ||||
|  | ||||
|         if l:item.lnum < 1 | ||||
|             " When errors appear before line 1, put them at line 1. | ||||
|             let l:item.lnum = 1 | ||||
|         elseif l:item.bufnr == a:buffer && l:item.lnum > l:last_line_number | ||||
|             " 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 | ||||
|         endif | ||||
|  | ||||
|         call add(l:new_loclist, l:item) | ||||
|     endfor | ||||
|  | ||||
|     let l:type_map = get(ale#Var(a:buffer, 'type_map'), a:linter_name, {}) | ||||
|  | ||||
|     if !empty(l:type_map) | ||||
|         call s:RemapItemTypes(l:type_map, l:new_loclist) | ||||
|     endif | ||||
|  | ||||
|     return l:new_loclist | ||||
| endfunction | ||||
|  | ||||
| " Given part of a command, replace any % with %%, so that no characters in | ||||
| " the string will be replaced with filenames, etc. | ||||
| function! ale#engine#EscapeCommandPart(command_part) abort | ||||
|     return substitute(a:command_part, '%', '%%', 'g') | ||||
| endfunction | ||||
|  | ||||
| function! s:CreateTemporaryFileForJob(buffer, temporary_file) abort | ||||
|     if empty(a:temporary_file) | ||||
|         " There is no file, so we didn't create anything. | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:temporary_directory = fnamemodify(a:temporary_file, ':h') | ||||
|     " Create the temporary directory for the file, unreadable by 'other' | ||||
|     " users. | ||||
|     call mkdir(l:temporary_directory, '', 0750) | ||||
|     " Automatically delete the directory later. | ||||
|     call ale#engine#ManageDirectory(a:buffer, l:temporary_directory) | ||||
|     " Write the buffer out to a file. | ||||
|     let l:lines = getbufline(a:buffer, 1, '$') | ||||
|     call ale#util#Writefile(a:buffer, l:lines, a:temporary_file) | ||||
|  | ||||
|     return 1 | ||||
| endfunction | ||||
|  | ||||
| " Run a job. | ||||
| " | ||||
| " Returns 1 when the job was started successfully. | ||||
| function! s:RunJob(options) abort | ||||
|     let l:command = a:options.command | ||||
|     let l:buffer = a:options.buffer | ||||
|     let l:linter = a:options.linter | ||||
|     let l:output_stream = a:options.output_stream | ||||
|     let l:next_chain_index = a:options.next_chain_index | ||||
|     let l:read_buffer = a:options.read_buffer | ||||
|     let l:info = g:ale_buffer_info[l:buffer] | ||||
|  | ||||
|     if empty(l:command) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let [l:temporary_file, l:command] = ale#command#FormatCommand(l:buffer, l:command, l:read_buffer) | ||||
|  | ||||
|     if s:CreateTemporaryFileForJob(l:buffer, l:temporary_file) | ||||
|         " If a temporary filename has been formatted in to the command, then | ||||
|         " we do not need to send the Vim buffer to the command. | ||||
|         let l:read_buffer = 0 | ||||
|     endif | ||||
|  | ||||
|     " Add a newline to commands which need it. | ||||
|     " This is only used for Flow for now, and is not documented. | ||||
|     if l:linter.add_newline | ||||
|         if has('win32') | ||||
|             let l:command = l:command . '; echo.' | ||||
|         else | ||||
|             let l:command = l:command . '; echo' | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     let l:command = ale#job#PrepareCommand(l:buffer, l:command) | ||||
|     let l:job_options = { | ||||
|     \   'mode': 'nl', | ||||
|     \   'exit_cb': function('s:HandleExit'), | ||||
|     \} | ||||
|  | ||||
|     if l:output_stream is# 'stderr' | ||||
|         let l:job_options.err_cb = function('s:GatherOutput') | ||||
|     elseif l:output_stream is# 'both' | ||||
|         let l:job_options.out_cb = function('s:GatherOutput') | ||||
|         let l:job_options.err_cb = function('s:GatherOutput') | ||||
|     else | ||||
|         let l:job_options.out_cb = function('s:GatherOutput') | ||||
|     endif | ||||
|  | ||||
|     if get(g:, 'ale_run_synchronously') == 1 | ||||
|         " Find a unique Job value to use, which will be the same as the ID for | ||||
|         " running commands synchronously. This is only for test code. | ||||
|         let l:job_id = len(s:job_info_map) + 1 | ||||
|  | ||||
|         while has_key(s:job_info_map, l:job_id) | ||||
|             let l:job_id += 1 | ||||
|         endwhile | ||||
|     else | ||||
|         let l:job_id = ale#job#Start(l:command, l:job_options) | ||||
|     endif | ||||
|  | ||||
|     let l:status = 'failed' | ||||
|  | ||||
|     " Only proceed if the job is being run. | ||||
|     if l:job_id | ||||
|         " Add the job to the list of jobs, so we can track them. | ||||
|         call add(l:info.job_list, l:job_id) | ||||
|  | ||||
|         if index(l:info.active_linter_list, l:linter.name) < 0 | ||||
|             call add(l:info.active_linter_list, l:linter.name) | ||||
|         endif | ||||
|  | ||||
|         let l:status = 'started' | ||||
|         " Store the ID for the job in the map to read back again. | ||||
|         let s:job_info_map[l:job_id] = { | ||||
|         \   'linter': l:linter, | ||||
|         \   'buffer': l:buffer, | ||||
|         \   'output': [], | ||||
|         \   'next_chain_index': l:next_chain_index, | ||||
|         \} | ||||
|     endif | ||||
|  | ||||
|     if g:ale_history_enabled | ||||
|         call ale#history#Add(l:buffer, l:status, l:job_id, l:command) | ||||
|     endif | ||||
|  | ||||
|     if get(g:, 'ale_run_synchronously') == 1 | ||||
|         " Run a command synchronously if this test option is set. | ||||
|         let s:job_info_map[l:job_id].output = systemlist( | ||||
|         \   type(l:command) == type([]) | ||||
|         \   ?  join(l:command[0:1]) . ' ' . ale#Escape(l:command[2]) | ||||
|         \   : l:command | ||||
|         \) | ||||
|  | ||||
|         call l:job_options.exit_cb(l:job_id, v:shell_error) | ||||
|     endif | ||||
|  | ||||
|     return l:job_id != 0 | ||||
| endfunction | ||||
|  | ||||
| " Determine which commands to run for a link in a command chain, or | ||||
| " just a regular command. | ||||
| function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort | ||||
|     let l:output_stream = get(a:linter, 'output_stream', 'stdout') | ||||
|     let l:read_buffer = a:linter.read_buffer | ||||
|     let l:chain_index = a:chain_index | ||||
|     let l:input = a:input | ||||
|  | ||||
|     if has_key(a:linter, 'command_chain') | ||||
|         while l:chain_index < len(a:linter.command_chain) | ||||
|             " Run a chain of commands, one asynchronous command after the other, | ||||
|             " so that many programs can be run in a sequence. | ||||
|             let l:chain_item = a:linter.command_chain[l:chain_index] | ||||
|  | ||||
|             if l:chain_index == 0 | ||||
|                 " The first callback in the chain takes only a buffer number. | ||||
|                 let l:command = ale#util#GetFunction(l:chain_item.callback)( | ||||
|                 \   a:buffer | ||||
|                 \) | ||||
|             else | ||||
|                 " The second callback in the chain takes some input too. | ||||
|                 let l:command = ale#util#GetFunction(l:chain_item.callback)( | ||||
|                 \   a:buffer, | ||||
|                 \   l:input | ||||
|                 \) | ||||
|             endif | ||||
|  | ||||
|             if !empty(l:command) | ||||
|                 " We hit a command to run, so we'll execute that | ||||
|  | ||||
|                 " The chain item can override the output_stream option. | ||||
|                 if has_key(l:chain_item, 'output_stream') | ||||
|                     let l:output_stream = l:chain_item.output_stream | ||||
|                 endif | ||||
|  | ||||
|                 " The chain item can override the read_buffer option. | ||||
|                 if has_key(l:chain_item, 'read_buffer') | ||||
|                     let l:read_buffer = l:chain_item.read_buffer | ||||
|                 elseif l:chain_index != len(a:linter.command_chain) - 1 | ||||
|                     " Don't read the buffer for commands besides the last one | ||||
|                     " in the chain by default. | ||||
|                     let l:read_buffer = 0 | ||||
|                 endif | ||||
|  | ||||
|                 break | ||||
|             endif | ||||
|  | ||||
|             " Command chain items can return an empty string to indicate that | ||||
|             " a command should be skipped, so we should try the next item | ||||
|             " with no input. | ||||
|             let l:input = [] | ||||
|             let l:chain_index += 1 | ||||
|         endwhile | ||||
|     else | ||||
|         let l:command = ale#linter#GetCommand(a:buffer, a:linter) | ||||
|     endif | ||||
|  | ||||
|     return { | ||||
|     \   'command': l:command, | ||||
|     \   'buffer': a:buffer, | ||||
|     \   'linter': a:linter, | ||||
|     \   'output_stream': l:output_stream, | ||||
|     \   'next_chain_index': l:chain_index + 1, | ||||
|     \   'read_buffer': l:read_buffer, | ||||
|     \} | ||||
| endfunction | ||||
|  | ||||
| function! s:InvokeChain(buffer, linter, chain_index, input) abort | ||||
|     let l:options = ale#engine#ProcessChain(a:buffer, a:linter, a:chain_index, a:input) | ||||
|  | ||||
|     return s:RunJob(l:options) | ||||
| endfunction | ||||
|  | ||||
| function! s:StopCurrentJobs(buffer, include_lint_file_jobs) abort | ||||
|     let l:info = get(g:ale_buffer_info, a:buffer, {}) | ||||
|     let l:new_job_list = [] | ||||
|     let l:new_active_linter_list = [] | ||||
|  | ||||
|     for l:job_id in get(l:info, 'job_list', []) | ||||
|         let l:job_info = get(s:job_info_map, l:job_id, {}) | ||||
|  | ||||
|         if !empty(l:job_info) | ||||
|             if a:include_lint_file_jobs || !l:job_info.linter.lint_file | ||||
|                 call ale#job#Stop(l:job_id) | ||||
|                 call remove(s:job_info_map, l:job_id) | ||||
|             else | ||||
|                 call add(l:new_job_list, l:job_id) | ||||
|                 " Linters with jobs still running are still active. | ||||
|                 call add(l:new_active_linter_list, l:job_info.linter.name) | ||||
|             endif | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     " Remove duplicates from the active linter list. | ||||
|     call uniq(sort(l:new_active_linter_list)) | ||||
|  | ||||
|     " Update the List, so it includes only the jobs we still need. | ||||
|     let l:info.job_list = l:new_job_list | ||||
|     " Update the active linter list, clearing out anything not running. | ||||
|     let l:info.active_linter_list = l:new_active_linter_list | ||||
| endfunction | ||||
|  | ||||
| function! s:CheckWithLSP(buffer, linter) abort | ||||
|     let l:info = g:ale_buffer_info[a:buffer] | ||||
|     let l:lsp_details = ale#linter#StartLSP( | ||||
|     \   a:buffer, | ||||
|     \   a:linter, | ||||
|     \   function('ale#engine#HandleLSPResponse'), | ||||
|     \) | ||||
|  | ||||
|     if empty(l:lsp_details) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:id = l:lsp_details.connection_id | ||||
|     let l:root = l:lsp_details.project_root | ||||
|  | ||||
|     " Remember the linter this connection is for. | ||||
|     let s:lsp_linter_map[l:id] = a:linter.name | ||||
|  | ||||
|     let l:change_message = a:linter.lsp is# 'tsserver' | ||||
|     \   ? ale#lsp#tsserver_message#Geterr(a:buffer) | ||||
|     \   : ale#lsp#message#DidChange(a:buffer) | ||||
|     let l:request_id = ale#lsp#Send(l:id, l:change_message, l:root) | ||||
|  | ||||
|     " If this was a file save event, also notify the server of that. | ||||
|     if a:linter.lsp isnot# 'tsserver' | ||||
|     \&& getbufvar(a:buffer, 'ale_save_event_fired', 0) | ||||
|       let l:save_message = ale#lsp#message#DidSave(a:buffer) | ||||
|       let l:request_id = ale#lsp#Send(l:id, l:save_message, l:root) | ||||
|     endif | ||||
|  | ||||
|     if l:request_id != 0 | ||||
|         if index(l:info.active_linter_list, a:linter.name) < 0 | ||||
|             call add(l:info.active_linter_list, a:linter.name) | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     return l:request_id != 0 | ||||
| endfunction | ||||
|  | ||||
| function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort | ||||
|     " Figure out which linters are still enabled, and remove | ||||
|     " problems for linters which are no longer enabled. | ||||
|     let l:name_map = {} | ||||
|  | ||||
|     for l:linter in a:linters | ||||
|         let l:name_map[l:linter.name] = 1 | ||||
|     endfor | ||||
|  | ||||
|     call filter( | ||||
|     \   get(g:ale_buffer_info[a:buffer], 'loclist', []), | ||||
|     \   'get(l:name_map, get(v:val, ''linter_name''))', | ||||
|     \) | ||||
| endfunction | ||||
|  | ||||
| function! s:AddProblemsFromOtherBuffers(buffer, linters) abort | ||||
|     let l:filename = expand('#' . a:buffer . ':p') | ||||
|     let l:loclist = [] | ||||
|     let l:name_map = {} | ||||
|  | ||||
|     " Build a map of the active linters. | ||||
|     for l:linter in a:linters | ||||
|         let l:name_map[l:linter.name] = 1 | ||||
|     endfor | ||||
|  | ||||
|     " Find the items from other buffers, for the linters that are enabled. | ||||
|     for l:info in values(g:ale_buffer_info) | ||||
|         for l:item in l:info.loclist | ||||
|             if has_key(l:item, 'filename') | ||||
|             \&& l:item.filename is# l:filename | ||||
|             \&& has_key(l:name_map, l:item.linter_name) | ||||
|                 " Copy the items and set the buffer numbers to this one. | ||||
|                 let l:new_item = copy(l:item) | ||||
|                 let l:new_item.bufnr = a:buffer | ||||
|                 call add(l:loclist, l:new_item) | ||||
|             endif | ||||
|         endfor | ||||
|     endfor | ||||
|  | ||||
|     if !empty(l:loclist) | ||||
|         call sort(l:loclist, function('ale#util#LocItemCompareWithText')) | ||||
|         call uniq(l:loclist, function('ale#util#LocItemCompareWithText')) | ||||
|  | ||||
|         " Set the loclist variable, used by some parts of ALE. | ||||
|         let g:ale_buffer_info[a:buffer].loclist = l:loclist | ||||
|         call ale#engine#SetResults(a:buffer, l:loclist) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| " Run a linter for a buffer. | ||||
| " | ||||
| " Returns 1 if the linter was successfully run. | ||||
| function! s:RunLinter(buffer, linter) abort | ||||
|     if !empty(a:linter.lsp) | ||||
|         return s:CheckWithLSP(a:buffer, a:linter) | ||||
|     else | ||||
|         let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) | ||||
|  | ||||
|         if ale#engine#IsExecutable(a:buffer, l:executable) | ||||
|             return s:InvokeChain(a:buffer, a:linter, 0, []) | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     return 0 | ||||
| endfunction | ||||
|  | ||||
| function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort | ||||
|     " Initialise the buffer information if needed. | ||||
|     let l:new_buffer = ale#engine#InitBufferInfo(a:buffer) | ||||
|     call s:StopCurrentJobs(a:buffer, a:should_lint_file) | ||||
|     call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters) | ||||
|  | ||||
|     " We can only clear the results if we aren't checking the buffer. | ||||
|     let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer) | ||||
|  | ||||
|     silent doautocmd <nomodeline> User ALELintPre | ||||
|  | ||||
|     for l:linter in a:linters | ||||
|         " 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 | ||||
|  | ||||
|     " 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, []) | ||||
|     elseif l:new_buffer | ||||
|         call s:AddProblemsFromOtherBuffers(a:buffer, a:linters) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| " Clean up a buffer. | ||||
| " | ||||
| " This function will stop all current jobs for the buffer, | ||||
| " clear the state of everything, and remove the Dictionary for managing | ||||
| " the buffer. | ||||
| function! ale#engine#Cleanup(buffer) abort | ||||
|     " Don't bother with cleanup code when newer NeoVim versions are exiting. | ||||
|     if get(v:, 'exiting', v:null) isnot v:null | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     if !has_key(g:ale_buffer_info, a:buffer) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     call ale#engine#RunLinters(a:buffer, [], 1) | ||||
|  | ||||
|     call remove(g:ale_buffer_info, a:buffer) | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer number, return the warnings and errors for a given buffer. | ||||
| function! ale#engine#GetLoclist(buffer) abort | ||||
|     if !has_key(g:ale_buffer_info, a:buffer) | ||||
|         return [] | ||||
|     endif | ||||
|  | ||||
|     return g:ale_buffer_info[a:buffer].loclist | ||||
| endfunction | ||||
|  | ||||
| " This function can be called with a timeout to wait for all jobs to finish. | ||||
| " If the jobs to not finish in the given number of milliseconds, | ||||
| " an exception will be thrown. | ||||
| " | ||||
| " The time taken will be a very rough approximation, and more time may be | ||||
| " permitted than is specified. | ||||
| function! ale#engine#WaitForJobs(deadline) abort | ||||
|     let l:start_time = ale#util#ClockMilliseconds() | ||||
|  | ||||
|     if l:start_time == 0 | ||||
|         throw 'Failed to read milliseconds from the clock!' | ||||
|     endif | ||||
|  | ||||
|     let l:job_list = [] | ||||
|  | ||||
|     " Gather all of the jobs from every buffer. | ||||
|     for l:info in values(g:ale_buffer_info) | ||||
|         call extend(l:job_list, get(l:info, 'job_list', [])) | ||||
|     endfor | ||||
|  | ||||
|     " NeoVim has a built-in API for this, so use that. | ||||
|     if has('nvim') | ||||
|         let l:nvim_code_list = jobwait(l:job_list, a:deadline) | ||||
|  | ||||
|         if index(l:nvim_code_list, -1) >= 0 | ||||
|             throw 'Jobs did not complete on time!' | ||||
|         endif | ||||
|  | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let l:should_wait_more = 1 | ||||
|  | ||||
|     while l:should_wait_more | ||||
|         let l:should_wait_more = 0 | ||||
|  | ||||
|         for l:job_id in l:job_list | ||||
|             if ale#job#IsRunning(l:job_id) | ||||
|                 let l:now = ale#util#ClockMilliseconds() | ||||
|  | ||||
|                 if l:now - l:start_time > a:deadline | ||||
|                     " Stop waiting after a timeout, so we don't wait forever. | ||||
|                     throw 'Jobs did not complete on time!' | ||||
|                 endif | ||||
|  | ||||
|                 " Wait another 10 milliseconds | ||||
|                 let l:should_wait_more = 1 | ||||
|                 sleep 10ms | ||||
|                 break | ||||
|             endif | ||||
|         endfor | ||||
|     endwhile | ||||
|  | ||||
|     " Sleep for a small amount of time after all jobs finish. | ||||
|     " This seems to be enough to let handlers after jobs end run, and | ||||
|     " prevents the occasional failure where this function exits after jobs | ||||
|     " end, but before handlers are run. | ||||
|     sleep 10ms | ||||
|  | ||||
|     " We must check the buffer data again to see if new jobs started | ||||
|     " for command_chain linters. | ||||
|     let l:has_new_jobs = 0 | ||||
|  | ||||
|     " Check again to see if any jobs are running. | ||||
|     for l:info in values(g:ale_buffer_info) | ||||
|         for l:job_id in get(l:info, 'job_list', []) | ||||
|             if ale#job#IsRunning(l:job_id) | ||||
|                 let l:has_new_jobs = 1 | ||||
|                 break | ||||
|             endif | ||||
|         endfor | ||||
|     endfor | ||||
|  | ||||
|     if l:has_new_jobs | ||||
|         " We have to wait more. Offset the timeout by the time taken so far. | ||||
|         let l:now = ale#util#ClockMilliseconds() | ||||
|         let l:new_deadline = a:deadline - (l:now - l:start_time) | ||||
|  | ||||
|         if l:new_deadline <= 0 | ||||
|             " Enough time passed already, so stop immediately. | ||||
|             throw 'Jobs did not complete on time!' | ||||
|         endif | ||||
|  | ||||
|         call ale#engine#WaitForJobs(l:new_deadline) | ||||
|     endif | ||||
| endfunction | ||||
							
								
								
									
										69
									
								
								sources_non_forked/ale/autoload/ale/events.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								sources_non_forked/ale/autoload/ale/events.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
|  | ||||
| function! ale#events#QuitEvent(buffer) abort | ||||
|     " Remember when ALE is quitting for BufWrite, etc. | ||||
|     call setbufvar(a:buffer, 'ale_quitting', ale#util#ClockMilliseconds()) | ||||
| endfunction | ||||
|  | ||||
| function! ale#events#QuitRecently(buffer) abort | ||||
|     let l:time = getbufvar(a:buffer, 'ale_quitting', 0) | ||||
|  | ||||
|     return l:time && ale#util#ClockMilliseconds() - l:time < 1000 | ||||
| endfunction | ||||
|  | ||||
| function! ale#events#SaveEvent(buffer) abort | ||||
|     let l:should_lint = ale#Var(a:buffer, 'enabled') && g:ale_lint_on_save | ||||
|  | ||||
|     if l:should_lint | ||||
|         call setbufvar(a:buffer, 'ale_save_event_fired', 1) | ||||
|     endif | ||||
|  | ||||
|     if ale#Var(a:buffer, '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 && !ale#events#QuitRecently(a:buffer) | ||||
|         call ale#Queue(0, 'lint_file', a:buffer) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| 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', a:buffer) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#events#EnterEvent(buffer) abort | ||||
|     " When entering a buffer, we are no longer quitting it. | ||||
|     call setbufvar(a:buffer, 'ale_quitting', 0) | ||||
|     let l:filetype = getbufvar(a:buffer, '&filetype') | ||||
|     call setbufvar(a:buffer, 'ale_original_filetype', l:filetype) | ||||
|  | ||||
|     call s:LintOnEnter(a:buffer) | ||||
| endfunction | ||||
|  | ||||
| function! ale#events#FileTypeEvent(buffer, new_filetype) abort | ||||
|     let l:filetype = getbufvar(a:buffer, 'ale_original_filetype', '') | ||||
|  | ||||
|     " If we're setting the filetype for the first time after it was blank, | ||||
|     " and the option for linting on enter is off, then we should set this | ||||
|     " filetype as the original filetype. Otherwise ALE will still appear to | ||||
|     " lint files because of the BufEnter event, etc. | ||||
|     if empty(l:filetype) && !ale#Var(a:buffer, 'lint_on_enter') | ||||
|         call setbufvar(a:buffer, 'ale_original_filetype', a:new_filetype) | ||||
|     elseif a:new_filetype isnot# l:filetype | ||||
|         call ale#Queue(300, 'lint_file', a:buffer) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#events#FileChangedEvent(buffer) abort | ||||
|     call setbufvar(a:buffer, 'ale_file_changed', 1) | ||||
|  | ||||
|     if bufnr('') == a:buffer | ||||
|         call s:LintOnEnter(a:buffer) | ||||
|     endif | ||||
| endfunction | ||||
							
								
								
									
										60
									
								
								sources_non_forked/ale/autoload/ale/filetypes.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								sources_non_forked/ale/autoload/ale/filetypes.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: This file handles guessing file extensions for filetypes, etc. | ||||
|  | ||||
| function! ale#filetypes#LoadExtensionMap() abort | ||||
|     " Output includes: | ||||
|     "    '*.erl setf erlang' | ||||
|     redir => l:output | ||||
|        silent exec 'autocmd' | ||||
|     redir end | ||||
|  | ||||
|     let l:map = {} | ||||
|  | ||||
|     for l:line in split(l:output, "\n") | ||||
|         " Parse filetypes, like so: | ||||
|         " | ||||
|         "    *.erl setf erlang | ||||
|         " *.md      set filetype=markdown | ||||
|         " *.snippet setlocal filetype=snippets | ||||
|         let l:match = matchlist(l:line, '\v^ *\*(\.[^ ]+).*set(f *| *filetype=|local *filetype=)([^ ]+)') | ||||
|  | ||||
|         if !empty(l:match) | ||||
|             let l:map[substitute(l:match[3], '^=', '', '')] = l:match[1] | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return l:map | ||||
| endfunction | ||||
|  | ||||
| let s:cached_map = {} | ||||
|  | ||||
| function! s:GetCachedExtensionMap() abort | ||||
|     if empty(s:cached_map) | ||||
|         let s:cached_map = ale#filetypes#LoadExtensionMap() | ||||
|     endif | ||||
|  | ||||
|     return s:cached_map | ||||
| endfunction | ||||
|  | ||||
| function! ale#filetypes#GuessExtension(filetype) abort | ||||
|     let l:map = s:GetCachedExtensionMap() | ||||
|     let l:ext = get(l:map, a:filetype, '') | ||||
|  | ||||
|     " If we have an exact match, like something for javascript.jsx, use that. | ||||
|     if !empty(l:ext) | ||||
|         return l:ext | ||||
|     endif | ||||
|  | ||||
|     " If we don't have an exact match, use the first filetype in the compound | ||||
|     " filetype. | ||||
|     for l:part in split(a:filetype, '\.') | ||||
|         let l:ext = get(l:map, l:part, '') | ||||
|  | ||||
|         if !empty(l:ext) | ||||
|             return l:ext | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     " Return an empty string if we don't find anything. | ||||
|     return '' | ||||
| endfunction | ||||
							
								
								
									
										484
									
								
								sources_non_forked/ale/autoload/ale/fix.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										484
									
								
								sources_non_forked/ale/autoload/ale/fix.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,484 @@ | ||||
| " This global Dictionary tracks the ALE fix data for jobs, etc. | ||||
| " This Dictionary should not be accessed outside of the plugin. It is only | ||||
| " global so it can be modified in Vader tests. | ||||
| if !has_key(g:, 'ale_fix_buffer_data') | ||||
|     let g:ale_fix_buffer_data = {} | ||||
| endif | ||||
|  | ||||
| if !has_key(s:, 'job_info_map') | ||||
|     let s:job_info_map = {} | ||||
| endif | ||||
|  | ||||
| function! s:GatherOutput(job_id, line) abort | ||||
|     if has_key(s:job_info_map, a:job_id) | ||||
|         call add(s:job_info_map[a:job_id].output, a:line) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| " Apply fixes queued up for buffers which may be hidden. | ||||
| " Vim doesn't let you modify hidden buffers. | ||||
| function! ale#fix#ApplyQueuedFixes() abort | ||||
|     let l:buffer = bufnr('') | ||||
|     let l:data = get(g:ale_fix_buffer_data, l:buffer, {'done': 0}) | ||||
|  | ||||
|     if !l:data.done | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     call remove(g:ale_fix_buffer_data, l:buffer) | ||||
|  | ||||
|     if l:data.changes_made | ||||
|         call setline(1, l:data.output) | ||||
|  | ||||
|         let l:start_line = len(l:data.output) + 1 | ||||
|         let l:end_line = len(l:data.lines_before) | ||||
|  | ||||
|         if l:end_line >= l:start_line | ||||
|             let l:save = winsaveview() | ||||
|             silent execute l:start_line . ',' . l:end_line . 'd_' | ||||
|             call winrestview(l:save) | ||||
|         endif | ||||
|  | ||||
|         if l:data.should_save | ||||
|             if empty(&buftype) | ||||
|                 noautocmd :w! | ||||
|             else | ||||
|                 set nomodified | ||||
|             endif | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     if l:data.should_save | ||||
|         let l:should_lint = g:ale_fix_on_save | ||||
|     else | ||||
|         let l:should_lint = l:data.changes_made | ||||
|     endif | ||||
|  | ||||
|     silent doautocmd <nomodeline> User ALEFixPost | ||||
|  | ||||
|     " If ALE linting is enabled, check for problems with the file again after | ||||
|     " fixing problems. | ||||
|     if g:ale_enabled | ||||
|     \&& l:should_lint | ||||
|     \&& !ale#events#QuitRecently(l:buffer) | ||||
|         call ale#Queue(0, l:data.should_save ? 'lint_file' : '') | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#fix#ApplyFixes(buffer, output) abort | ||||
|     call ale#fix#RemoveManagedFiles(a:buffer) | ||||
|  | ||||
|     let l:data = g:ale_fix_buffer_data[a:buffer] | ||||
|     let l:data.output = a:output | ||||
|     let l:data.changes_made = l:data.lines_before != l:data.output | ||||
|  | ||||
|     if l:data.changes_made && bufexists(a:buffer) | ||||
|         let l:lines = getbufline(a:buffer, 1, '$') | ||||
|  | ||||
|         if l:data.lines_before != l:lines | ||||
|             call remove(g:ale_fix_buffer_data, a:buffer) | ||||
|             execute 'echoerr ''The file was changed before fixing finished''' | ||||
|             return | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     if !bufexists(a:buffer) | ||||
|         " Remove the buffer data when it doesn't exist. | ||||
|         call remove(g:ale_fix_buffer_data, a:buffer) | ||||
|     endif | ||||
|  | ||||
|     let l:data.done = 1 | ||||
|  | ||||
|     " We can only change the lines of a buffer which is currently open, | ||||
|     " so try and apply the fixes to the current buffer. | ||||
|     call ale#fix#ApplyQueuedFixes() | ||||
| endfunction | ||||
|  | ||||
| function! s:HandleExit(job_id, exit_code) abort | ||||
|     if !has_key(s:job_info_map, a:job_id) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let l:job_info = remove(s:job_info_map, a:job_id) | ||||
|     let l:buffer = l:job_info.buffer | ||||
|  | ||||
|     if g:ale_history_enabled | ||||
|         call ale#history#SetExitCode(l:buffer, a:job_id, a:exit_code) | ||||
|     endif | ||||
|  | ||||
|     if has_key(l:job_info, 'file_to_read') | ||||
|         let l:job_info.output = readfile(l:job_info.file_to_read) | ||||
|     endif | ||||
|  | ||||
|     let l:ChainCallback = get(l:job_info, 'chain_with', v:null) | ||||
|     let l:ProcessWith = get(l:job_info, 'process_with', v:null) | ||||
|  | ||||
|     " Post-process the output with a function if we have one. | ||||
|     if l:ProcessWith isnot v:null | ||||
|         let l:job_info.output = call( | ||||
|         \   ale#util#GetFunction(l:ProcessWith), | ||||
|         \   [l:buffer, l:job_info.output] | ||||
|         \) | ||||
|     endif | ||||
|  | ||||
|     " Use the output of the job for changing the file if it isn't empty, | ||||
|     " otherwise skip this job and use the input from before. | ||||
|     " | ||||
|     " We'll use the input from before for chained commands. | ||||
|     if l:ChainCallback is v:null && !empty(split(join(l:job_info.output))) | ||||
|         let l:input = l:job_info.output | ||||
|     else | ||||
|         let l:input = l:job_info.input | ||||
|     endif | ||||
|  | ||||
|     let l:next_index = l:ChainCallback is v:null | ||||
|     \   ? l:job_info.callback_index + 1 | ||||
|     \   : l:job_info.callback_index | ||||
|  | ||||
|     call s:RunFixer({ | ||||
|     \   'buffer': l:buffer, | ||||
|     \   'input': l:input, | ||||
|     \   'output': l:job_info.output, | ||||
|     \   'callback_list': l:job_info.callback_list, | ||||
|     \   'callback_index': l:next_index, | ||||
|     \   'chain_callback': l:ChainCallback, | ||||
|     \}) | ||||
| endfunction | ||||
|  | ||||
| function! ale#fix#ManageDirectory(buffer, directory) abort | ||||
|     call add(g:ale_fix_buffer_data[a:buffer].temporary_directory_list, a:directory) | ||||
| endfunction | ||||
|  | ||||
| function! ale#fix#RemoveManagedFiles(buffer) abort | ||||
|     if !has_key(g:ale_fix_buffer_data, a:buffer) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " We can't delete anything in a sandbox, so wait until we escape from | ||||
|     " it to delete temporary files and directories. | ||||
|     if ale#util#InSandbox() | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " Delete directories like `rm -rf`. | ||||
|     " Directories are handled differently from files, so paths that are | ||||
|     " intended to be single files can be set up for automatic deletion without | ||||
|     " accidentally deleting entire directories. | ||||
|     for l:directory in g:ale_fix_buffer_data[a:buffer].temporary_directory_list | ||||
|         call delete(l:directory, 'rf') | ||||
|     endfor | ||||
|  | ||||
|     let g:ale_fix_buffer_data[a:buffer].temporary_directory_list = [] | ||||
| endfunction | ||||
|  | ||||
| function! s:CreateTemporaryFileForJob(buffer, temporary_file, input) abort | ||||
|     if empty(a:temporary_file) | ||||
|         " There is no file, so we didn't create anything. | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:temporary_directory = fnamemodify(a:temporary_file, ':h') | ||||
|     " Create the temporary directory for the file, unreadable by 'other' | ||||
|     " users. | ||||
|     call mkdir(l:temporary_directory, '', 0750) | ||||
|     " Automatically delete the directory later. | ||||
|     call ale#fix#ManageDirectory(a:buffer, l:temporary_directory) | ||||
|     " Write the buffer out to a file. | ||||
|     call ale#util#Writefile(a:buffer, a:input, a:temporary_file) | ||||
|  | ||||
|     return 1 | ||||
| endfunction | ||||
|  | ||||
| function! s:RunJob(options) abort | ||||
|     let l:buffer = a:options.buffer | ||||
|     let l:command = a:options.command | ||||
|     let l:input = a:options.input | ||||
|     let l:output_stream = a:options.output_stream | ||||
|     let l:read_temporary_file = a:options.read_temporary_file | ||||
|     let l:ChainWith = a:options.chain_with | ||||
|     let l:read_buffer = a:options.read_buffer | ||||
|  | ||||
|     if empty(l:command) | ||||
|         " If there's nothing further to chain the command with, stop here. | ||||
|         if l:ChainWith is v:null | ||||
|             return 0 | ||||
|         endif | ||||
|  | ||||
|         " If there's another chained callback to run, then run that. | ||||
|         call s:RunFixer({ | ||||
|         \   'buffer': l:buffer, | ||||
|         \   'input': l:input, | ||||
|         \   'callback_index': a:options.callback_index, | ||||
|         \   'callback_list': a:options.callback_list, | ||||
|         \   'chain_callback': l:ChainWith, | ||||
|         \   'output': [], | ||||
|         \}) | ||||
|  | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     let [l:temporary_file, l:command] = ale#command#FormatCommand( | ||||
|     \   l:buffer, | ||||
|     \   l:command, | ||||
|     \   l:read_buffer, | ||||
|     \) | ||||
|     call s:CreateTemporaryFileForJob(l:buffer, l:temporary_file, l:input) | ||||
|  | ||||
|     let l:command = ale#job#PrepareCommand(l:buffer, l:command) | ||||
|     let l:job_options = { | ||||
|     \   'mode': 'nl', | ||||
|     \   'exit_cb': function('s:HandleExit'), | ||||
|     \} | ||||
|  | ||||
|     let l:job_info = { | ||||
|     \   'buffer': l:buffer, | ||||
|     \   'input': l:input, | ||||
|     \   'output': [], | ||||
|     \   'chain_with': l:ChainWith, | ||||
|     \   'callback_index': a:options.callback_index, | ||||
|     \   'callback_list': a:options.callback_list, | ||||
|     \   'process_with': a:options.process_with, | ||||
|     \} | ||||
|  | ||||
|     if l:read_temporary_file | ||||
|         " TODO: Check that a temporary file is set here. | ||||
|         let l:job_info.file_to_read = l:temporary_file | ||||
|     elseif l:output_stream is# 'stderr' | ||||
|         let l:job_options.err_cb = function('s:GatherOutput') | ||||
|     elseif l:output_stream is# 'both' | ||||
|         let l:job_options.out_cb = function('s:GatherOutput') | ||||
|         let l:job_options.err_cb = function('s:GatherOutput') | ||||
|     else | ||||
|         let l:job_options.out_cb = function('s:GatherOutput') | ||||
|     endif | ||||
|  | ||||
|     if get(g:, 'ale_emulate_job_failure') == 1 | ||||
|         let l:job_id = 0 | ||||
|     elseif get(g:, 'ale_run_synchronously') == 1 | ||||
|         " Find a unique Job value to use, which will be the same as the ID for | ||||
|         " running commands synchronously. This is only for test code. | ||||
|         let l:job_id = len(s:job_info_map) + 1 | ||||
|  | ||||
|         while has_key(s:job_info_map, l:job_id) | ||||
|             let l:job_id += 1 | ||||
|         endwhile | ||||
|     else | ||||
|         let l:job_id = ale#job#Start(l:command, l:job_options) | ||||
|     endif | ||||
|  | ||||
|     let l:status = l:job_id ? 'started' : 'failed' | ||||
|  | ||||
|     if g:ale_history_enabled | ||||
|         call ale#history#Add(l:buffer, l:status, l:job_id, l:command) | ||||
|     endif | ||||
|  | ||||
|     if l:job_id == 0 | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let s:job_info_map[l:job_id] = l:job_info | ||||
|  | ||||
|     if get(g:, 'ale_run_synchronously') == 1 | ||||
|         " Run a command synchronously if this test option is set. | ||||
|         let l:output = systemlist( | ||||
|         \   type(l:command) == type([]) | ||||
|         \   ?  join(l:command[0:1]) . ' ' . ale#Escape(l:command[2]) | ||||
|         \   : l:command | ||||
|         \) | ||||
|  | ||||
|         if !l:read_temporary_file | ||||
|             let s:job_info_map[l:job_id].output = l:output | ||||
|         endif | ||||
|  | ||||
|         call l:job_options.exit_cb(l:job_id, v:shell_error) | ||||
|     endif | ||||
|  | ||||
|     return 1 | ||||
| endfunction | ||||
|  | ||||
| function! s:RunFixer(options) abort | ||||
|     let l:buffer = a:options.buffer | ||||
|     let l:input = a:options.input | ||||
|     let l:index = a:options.callback_index | ||||
|     let l:ChainCallback = get(a:options, 'chain_callback', v:null) | ||||
|  | ||||
|     while len(a:options.callback_list) > l:index | ||||
|         let l:Function = l:ChainCallback isnot v:null | ||||
|         \   ? ale#util#GetFunction(l:ChainCallback) | ||||
|         \   : a:options.callback_list[l:index] | ||||
|  | ||||
|         if l:ChainCallback isnot v:null | ||||
|             " Chained commands accept (buffer, output, [input]) | ||||
|             let l:result = ale#util#FunctionArgCount(l:Function) == 2 | ||||
|             \   ? call(l:Function, [l:buffer, a:options.output]) | ||||
|             \   : call(l:Function, [l:buffer, a:options.output, copy(l:input)]) | ||||
|         else | ||||
|             " Chained commands accept (buffer, [input]) | ||||
|             let l:result = ale#util#FunctionArgCount(l:Function) == 1 | ||||
|             \   ? call(l:Function, [l:buffer]) | ||||
|             \   : call(l:Function, [l:buffer, copy(l:input)]) | ||||
|         endif | ||||
|  | ||||
|         if type(l:result) == type(0) && l:result == 0 | ||||
|             " When `0` is returned, skip this item. | ||||
|             let l:index += 1 | ||||
|         elseif type(l:result) == type([]) | ||||
|             let l:input = l:result | ||||
|             let l:index += 1 | ||||
|         else | ||||
|             let l:ChainWith = get(l:result, 'chain_with', v:null) | ||||
|             " Default to piping the buffer for the last fixer in the chain. | ||||
|             let l:read_buffer = get(l:result, 'read_buffer', l:ChainWith is v:null) | ||||
|  | ||||
|             let l:job_ran = s:RunJob({ | ||||
|             \   'buffer': l:buffer, | ||||
|             \   'command': l:result.command, | ||||
|             \   'input': l:input, | ||||
|             \   'output_stream': get(l:result, 'output_stream', 'stdout'), | ||||
|             \   'read_temporary_file': get(l:result, 'read_temporary_file', 0), | ||||
|             \   'read_buffer': l:read_buffer, | ||||
|             \   'chain_with': l:ChainWith, | ||||
|             \   'callback_list': a:options.callback_list, | ||||
|             \   'callback_index': l:index, | ||||
|             \   'process_with': get(l:result, 'process_with', v:null), | ||||
|             \}) | ||||
|  | ||||
|             if !l:job_ran | ||||
|                 " The job failed to run, so skip to the next item. | ||||
|                 let l:index += 1 | ||||
|             else | ||||
|                 " Stop here, we will handle exit later on. | ||||
|                 return | ||||
|             endif | ||||
|         endif | ||||
|     endwhile | ||||
|  | ||||
|     call ale#fix#ApplyFixes(l:buffer, l:input) | ||||
| endfunction | ||||
|  | ||||
| function! s:GetCallbacks() abort | ||||
|     if type(get(b:, 'ale_fixers')) is type([]) | ||||
|         " Lists can be used for buffer-local variables only | ||||
|         let l:callback_list = b:ale_fixers | ||||
|     else | ||||
|         " buffer and global options can use dictionaries mapping filetypes to | ||||
|         " callbacks to run. | ||||
|         let l:fixers = ale#Var(bufnr(''), 'fixers') | ||||
|         let l:callback_list = [] | ||||
|  | ||||
|         for l:sub_type in split(&filetype, '\.') | ||||
|             let l:sub_type_callacks = get(l:fixers, l:sub_type, []) | ||||
|  | ||||
|             if type(l:sub_type_callacks) == type('') | ||||
|                 call add(l:callback_list, l:sub_type_callacks) | ||||
|             else | ||||
|                 call extend(l:callback_list, l:sub_type_callacks) | ||||
|             endif | ||||
|         endfor | ||||
|     endif | ||||
|  | ||||
|     if empty(l:callback_list) | ||||
|         return [] | ||||
|     endif | ||||
|  | ||||
|     let l:corrected_list = [] | ||||
|  | ||||
|     " Variables with capital characters are needed, or Vim will complain about | ||||
|     " funcref variables. | ||||
|     for l:Item in l:callback_list | ||||
|         if type(l:Item) == type('') | ||||
|             let l:Func = ale#fix#registry#GetFunc(l:Item) | ||||
|  | ||||
|             if !empty(l:Func) | ||||
|                 let l:Item = l:Func | ||||
|             endif | ||||
|         endif | ||||
|  | ||||
|         try | ||||
|             call add(l:corrected_list, ale#util#GetFunction(l:Item)) | ||||
|         catch /E475/ | ||||
|             " Rethrow exceptions for failing to get a function so we can print | ||||
|             " a friendly message about it. | ||||
|             throw 'BADNAME ' . v:exception | ||||
|         endtry | ||||
|     endfor | ||||
|  | ||||
|     return l:corrected_list | ||||
| endfunction | ||||
|  | ||||
| function! ale#fix#InitBufferData(buffer, fixing_flag) abort | ||||
|     " The 'done' flag tells the function for applying changes when fixing | ||||
|     " is complete. | ||||
|     let g:ale_fix_buffer_data[a:buffer] = { | ||||
|     \   'vars': getbufvar(a:buffer, ''), | ||||
|     \   'lines_before': getbufline(a:buffer, 1, '$'), | ||||
|     \   'filename': expand('#' . a:buffer . ':p'), | ||||
|     \   'done': 0, | ||||
|     \   'should_save': a:fixing_flag is# 'save_file', | ||||
|     \   'temporary_directory_list': [], | ||||
|     \} | ||||
| endfunction | ||||
|  | ||||
| " Accepts an optional argument for what to do when fixing. | ||||
| " | ||||
| " Returns 0 if no fixes can be applied, and 1 if fixing can be done. | ||||
| function! ale#fix#Fix(...) abort | ||||
|     if len(a:0) > 1 | ||||
|         throw 'too many arguments!' | ||||
|     endif | ||||
|  | ||||
|     let l:fixing_flag = get(a:000, 0, '') | ||||
|  | ||||
|     if l:fixing_flag isnot# '' && l:fixing_flag isnot# 'save_file' | ||||
|         throw "fixing_flag must be either '' or 'save_file'" | ||||
|     endif | ||||
|  | ||||
|     try | ||||
|         let l:callback_list = s:GetCallbacks() | ||||
|     catch /E700\|BADNAME/ | ||||
|         let l:function_name = join(split(split(v:exception, ':')[3])) | ||||
|         let l:echo_message = printf( | ||||
|         \   'There is no fixer named `%s`. Check :ALEFixSuggest', | ||||
|         \   l:function_name, | ||||
|         \) | ||||
|         execute 'echom l:echo_message' | ||||
|  | ||||
|         return 0 | ||||
|     endtry | ||||
|  | ||||
|     if empty(l:callback_list) | ||||
|         if l:fixing_flag is# '' | ||||
|             execute 'echom ''No fixers have been defined. Try :ALEFixSuggest''' | ||||
|         endif | ||||
|  | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:buffer = bufnr('') | ||||
|  | ||||
|     for l:job_id in keys(s:job_info_map) | ||||
|         call remove(s:job_info_map, l:job_id) | ||||
|         call ale#job#Stop(l:job_id) | ||||
|     endfor | ||||
|  | ||||
|     " Clean up any files we might have left behind from a previous run. | ||||
|     call ale#fix#RemoveManagedFiles(l:buffer) | ||||
|     call ale#fix#InitBufferData(l:buffer, l:fixing_flag) | ||||
|  | ||||
|     silent doautocmd <nomodeline> User ALEFixPre | ||||
|  | ||||
|     call s:RunFixer({ | ||||
|     \   'buffer': l:buffer, | ||||
|     \   'input': g:ale_fix_buffer_data[l:buffer].lines_before, | ||||
|     \   'callback_index': 0, | ||||
|     \   'callback_list': l:callback_list, | ||||
|     \}) | ||||
|  | ||||
|     return 1 | ||||
| endfunction | ||||
|  | ||||
| " Set up an autocmd command to try and apply buffer fixes when available. | ||||
| augroup ALEBufferFixGroup | ||||
|     autocmd! | ||||
|     autocmd BufEnter * call ale#fix#ApplyQueuedFixes() | ||||
| augroup END | ||||
							
								
								
									
										349
									
								
								sources_non_forked/ale/autoload/ale/fix/registry.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										349
									
								
								sources_non_forked/ale/autoload/ale/fix/registry.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,349 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: A registry of functions for fixing things. | ||||
|  | ||||
| let s:default_registry = { | ||||
| \   'add_blank_lines_for_python_control_statements': { | ||||
| \       'function': 'ale#fixers#generic_python#AddLinesBeforeControlStatements', | ||||
| \       'suggested_filetypes': ['python'], | ||||
| \       'description': 'Add blank lines before control statements.', | ||||
| \   }, | ||||
| \   'align_help_tags': { | ||||
| \       'function': 'ale#fixers#help#AlignTags', | ||||
| \       'suggested_filetypes': ['help'], | ||||
| \       'description': 'Align help tags to the right margin', | ||||
| \   }, | ||||
| \   'autopep8': { | ||||
| \       'function': 'ale#fixers#autopep8#Fix', | ||||
| \       'suggested_filetypes': ['python'], | ||||
| \       'description': 'Fix PEP8 issues with autopep8.', | ||||
| \   }, | ||||
| \   'prettier_standard': { | ||||
| \       'function': 'ale#fixers#prettier_standard#Fix', | ||||
| \       'suggested_filetypes': ['javascript'], | ||||
| \       'description': 'Apply prettier-standard to a file.', | ||||
| \       'aliases': ['prettier-standard'], | ||||
| \   }, | ||||
| \   'elm-format': { | ||||
| \       'function': 'ale#fixers#elm_format#Fix', | ||||
| \       'suggested_filetypes': ['elm'], | ||||
| \       'description': 'Apply elm-format to a file.', | ||||
| \       'aliases': ['format'], | ||||
| \   }, | ||||
| \   'eslint': { | ||||
| \       'function': 'ale#fixers#eslint#Fix', | ||||
| \       'suggested_filetypes': ['javascript', 'typescript'], | ||||
| \       'description': 'Apply eslint --fix to a file.', | ||||
| \   }, | ||||
| \   'mix_format': { | ||||
| \       'function': 'ale#fixers#mix_format#Fix', | ||||
| \       'suggested_filetypes': ['elixir'], | ||||
| \       'description': 'Apply mix format to a file.', | ||||
| \   }, | ||||
| \   'isort': { | ||||
| \       'function': 'ale#fixers#isort#Fix', | ||||
| \       'suggested_filetypes': ['python'], | ||||
| \       'description': 'Sort Python imports with isort.', | ||||
| \   }, | ||||
| \   'prettier': { | ||||
| \       'function': 'ale#fixers#prettier#Fix', | ||||
| \       'suggested_filetypes': ['javascript', 'typescript', 'json', 'css', 'scss', 'less', 'markdown', 'graphql', 'vue'], | ||||
| \       'description': 'Apply prettier to a file.', | ||||
| \   }, | ||||
| \   'prettier_eslint': { | ||||
| \       'function': 'ale#fixers#prettier_eslint#Fix', | ||||
| \       'suggested_filetypes': ['javascript'], | ||||
| \       'description': 'Apply prettier-eslint to a file.', | ||||
| \       'aliases': ['prettier-eslint'], | ||||
| \   }, | ||||
| \   'importjs': { | ||||
| \       'function': 'ale#fixers#importjs#Fix', | ||||
| \       'suggested_filetypes': ['javascript'], | ||||
| \       'description': 'automatic imports for javascript', | ||||
| \   }, | ||||
| \   'puppetlint': { | ||||
| \       'function': 'ale#fixers#puppetlint#Fix', | ||||
| \       'suggested_filetypes': ['puppet'], | ||||
| \       'description': 'Run puppet-lint -f on a file.', | ||||
| \   }, | ||||
| \   'remove_trailing_lines': { | ||||
| \       'function': 'ale#fixers#generic#RemoveTrailingBlankLines', | ||||
| \       'suggested_filetypes': [], | ||||
| \       'description': 'Remove all blank lines at the end of a file.', | ||||
| \   }, | ||||
| \   'trim_whitespace': { | ||||
| \       'function': 'ale#fixers#generic#TrimWhitespace', | ||||
| \       'suggested_filetypes': [], | ||||
| \       'description': 'Remove all trailing whitespace characters at the end of every line.', | ||||
| \   }, | ||||
| \   'yapf': { | ||||
| \       'function': 'ale#fixers#yapf#Fix', | ||||
| \       'suggested_filetypes': ['python'], | ||||
| \       'description': 'Fix Python files with yapf.', | ||||
| \   }, | ||||
| \   'rubocop': { | ||||
| \       'function': 'ale#fixers#rubocop#Fix', | ||||
| \       'suggested_filetypes': ['ruby'], | ||||
| \       'description': 'Fix ruby files with rubocop --auto-correct.', | ||||
| \   }, | ||||
| \   'rufo': { | ||||
| \       'function': 'ale#fixers#rufo#Fix', | ||||
| \       'suggested_filetypes': ['ruby'], | ||||
| \       'description': 'Fix ruby files with rufo', | ||||
| \   }, | ||||
| \   'standard': { | ||||
| \       'function': 'ale#fixers#standard#Fix', | ||||
| \       '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.', | ||||
| \   }, | ||||
| \   'swiftformat': { | ||||
| \       'function': 'ale#fixers#swiftformat#Fix', | ||||
| \       'suggested_filetypes': ['swift'], | ||||
| \       'description': 'Apply SwiftFormat to a file.', | ||||
| \   }, | ||||
| \   'phpcbf': { | ||||
| \       'function': 'ale#fixers#phpcbf#Fix', | ||||
| \       'suggested_filetypes': ['php'], | ||||
| \       'description': 'Fix PHP files with phpcbf.', | ||||
| \   }, | ||||
| \   'php_cs_fixer': { | ||||
| \       'function': 'ale#fixers#php_cs_fixer#Fix', | ||||
| \       'suggested_filetypes': ['php'], | ||||
| \       'description': 'Fix PHP files with php-cs-fixer.', | ||||
| \   }, | ||||
| \   'clang-format': { | ||||
| \       'function': 'ale#fixers#clangformat#Fix', | ||||
| \       'suggested_filetypes': ['c', 'cpp'], | ||||
| \       'description': 'Fix C/C++ files with clang-format.', | ||||
| \   }, | ||||
| \   'gofmt': { | ||||
| \       'function': 'ale#fixers#gofmt#Fix', | ||||
| \       'suggested_filetypes': ['go'], | ||||
| \       'description': 'Fix Go files with go fmt.', | ||||
| \   }, | ||||
| \   'goimports': { | ||||
| \       'function': 'ale#fixers#goimports#Fix', | ||||
| \       'suggested_filetypes': ['go'], | ||||
| \       'description': 'Fix Go files imports with goimports.', | ||||
| \   }, | ||||
| \   'tslint': { | ||||
| \       'function': 'ale#fixers#tslint#Fix', | ||||
| \       'suggested_filetypes': ['typescript'], | ||||
| \       'description': 'Fix typescript files with tslint --fix.', | ||||
| \   }, | ||||
| \   'rustfmt': { | ||||
| \       'function': 'ale#fixers#rustfmt#Fix', | ||||
| \       'suggested_filetypes': ['rust'], | ||||
| \       'description': 'Fix Rust files with Rustfmt.', | ||||
| \   }, | ||||
| \   'hackfmt': { | ||||
| \       'function': 'ale#fixers#hackfmt#Fix', | ||||
| \       'suggested_filetypes': ['php'], | ||||
| \       'description': 'Fix Hack files with hackfmt.', | ||||
| \   }, | ||||
| \   'hfmt': { | ||||
| \       'function': 'ale#fixers#hfmt#Fix', | ||||
| \       'suggested_filetypes': ['haskell'], | ||||
| \       'description': 'Fix Haskell files with hfmt.', | ||||
| \   }, | ||||
| \   'brittany': { | ||||
| \       'function': 'ale#fixers#brittany#Fix', | ||||
| \       'suggested_filetypes': ['haskell'], | ||||
| \       'description': 'Fix Haskell files with brittany.', | ||||
| \   }, | ||||
| \   'refmt': { | ||||
| \       'function': 'ale#fixers#refmt#Fix', | ||||
| \       'suggested_filetypes': ['reason'], | ||||
| \       'description': 'Fix ReasonML files with refmt.', | ||||
| \   }, | ||||
| \   'shfmt': { | ||||
| \       'function': 'ale#fixers#shfmt#Fix', | ||||
| \       'suggested_filetypes': ['sh'], | ||||
| \       'description': 'Fix sh files with shfmt.', | ||||
| \   }, | ||||
| \   'google_java_format': { | ||||
| \       'function': 'ale#fixers#google_java_format#Fix', | ||||
| \       'suggested_filetypes': ['java'], | ||||
| \       'description': 'Fix Java files with google-java-format.', | ||||
| \   }, | ||||
| \   'fixjson': { | ||||
| \       'function': 'ale#fixers#fixjson#Fix', | ||||
| \       'suggested_filetypes': ['json'], | ||||
| \       'description': 'Fix JSON files with fixjson.', | ||||
| \   }, | ||||
| \   'jq': { | ||||
| \       'function': 'ale#fixers#jq#Fix', | ||||
| \       'suggested_filetypes': ['json'], | ||||
| \       'description': 'Fix JSON files with jq.', | ||||
| \   }, | ||||
| \} | ||||
|  | ||||
| " Reset the function registry to the default entries. | ||||
| function! ale#fix#registry#ResetToDefaults() abort | ||||
|     let s:entries = deepcopy(s:default_registry) | ||||
|     let s:aliases = {} | ||||
|  | ||||
|     " Set up aliases for fixers too. | ||||
|     for [l:key, l:entry] in items(s:entries) | ||||
|         for l:alias in get(l:entry, 'aliases', []) | ||||
|             let s:aliases[l:alias] = l:key | ||||
|         endfor | ||||
|     endfor | ||||
| endfunction | ||||
|  | ||||
| " Set up entries now. | ||||
| call ale#fix#registry#ResetToDefaults() | ||||
|  | ||||
| " Remove everything from the registry, useful for tests. | ||||
| function! ale#fix#registry#Clear() abort | ||||
|     let s:entries = {} | ||||
|     let s:aliases = {} | ||||
| endfunction | ||||
|  | ||||
| " Add a function for fixing problems to the registry. | ||||
| " (name, func, filetypes, desc, aliases) | ||||
| function! ale#fix#registry#Add(name, func, filetypes, desc, ...) abort | ||||
|     if type(a:name) != type('') | ||||
|         throw '''name'' must be a String' | ||||
|     endif | ||||
|  | ||||
|     if type(a:func) != type('') | ||||
|         throw '''func'' must be a String' | ||||
|     endif | ||||
|  | ||||
|     if type(a:filetypes) != type([]) | ||||
|         throw '''filetypes'' must be a List' | ||||
|     endif | ||||
|  | ||||
|     for l:type in a:filetypes | ||||
|         if type(l:type) != type('') | ||||
|             throw 'Each entry of ''filetypes'' must be a String' | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     if type(a:desc) != type('') | ||||
|         throw '''desc'' must be a String' | ||||
|     endif | ||||
|  | ||||
|     let l:aliases = get(a:000, 0, []) | ||||
|  | ||||
|     if type(l:aliases) != type([]) | ||||
|     \|| !empty(filter(copy(l:aliases), 'type(v:val) != type('''')')) | ||||
|         throw '''aliases'' must be a List of String values' | ||||
|     endif | ||||
|  | ||||
|     let s:entries[a:name] = { | ||||
|     \   'function': a:func, | ||||
|     \   'suggested_filetypes': a:filetypes, | ||||
|     \   'description': a:desc, | ||||
|     \} | ||||
|  | ||||
|     " Set up aliases for the fixer. | ||||
|     if !empty(l:aliases) | ||||
|         let s:entries[a:name].aliases = l:aliases | ||||
|  | ||||
|         for l:alias in l:aliases | ||||
|             let s:aliases[l:alias] = a:name | ||||
|         endfor | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| " Get a function from the registry by its short name. | ||||
| function! ale#fix#registry#GetFunc(name) abort | ||||
|     " Use the exact name, or an alias. | ||||
|     let l:resolved_name = !has_key(s:entries, a:name) | ||||
|     \   ? get(s:aliases, a:name, a:name) | ||||
|     \   : a:name | ||||
|  | ||||
|     return get(s:entries, l:resolved_name, {'function': ''}).function | ||||
| endfunction | ||||
|  | ||||
| function! s:ShouldSuggestForType(suggested_filetypes, type_list) abort | ||||
|     for l:type in a:type_list | ||||
|         if index(a:suggested_filetypes, l:type) >= 0 | ||||
|             return 1 | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return 0 | ||||
| endfunction | ||||
|  | ||||
| function! s:FormatEntry(key, entry) abort | ||||
|     let l:aliases_str = '' | ||||
|  | ||||
|     " Show aliases in :ALEFixSuggest if they are there. | ||||
|     if !empty(get(a:entry, 'aliases', [])) | ||||
|         let l:aliases_str = ', ' . join( | ||||
|         \   map(copy(a:entry.aliases), 'string(v:val)'), | ||||
|         \   ',' | ||||
|         \) | ||||
|     endif | ||||
|  | ||||
|     return printf( | ||||
|     \   '%s%s - %s', | ||||
|     \   string(a:key), | ||||
|     \   l:aliases_str, | ||||
|     \   a:entry.description, | ||||
|     \) | ||||
| endfunction | ||||
|  | ||||
| " Suggest functions to use from the registry. | ||||
| function! ale#fix#registry#Suggest(filetype) abort | ||||
|     let l:type_list = split(a:filetype, '\.') | ||||
|     let l:filetype_fixer_list = [] | ||||
|  | ||||
|     for l:key in sort(keys(s:entries)) | ||||
|         let l:suggested_filetypes = s:entries[l:key].suggested_filetypes | ||||
|  | ||||
|         if s:ShouldSuggestForType(l:suggested_filetypes, l:type_list) | ||||
|             call add( | ||||
|             \   l:filetype_fixer_list, | ||||
|             \   s:FormatEntry(l:key, s:entries[l:key]), | ||||
|             \) | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     let l:generic_fixer_list = [] | ||||
|  | ||||
|     for l:key in sort(keys(s:entries)) | ||||
|         if empty(s:entries[l:key].suggested_filetypes) | ||||
|             call add( | ||||
|             \   l:generic_fixer_list, | ||||
|             \   s:FormatEntry(l:key, s:entries[l:key]), | ||||
|             \) | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     let l:filetype_fixer_header = !empty(l:filetype_fixer_list) | ||||
|     \   ? ['Try the following fixers appropriate for the filetype:', ''] | ||||
|     \   : [] | ||||
|     let l:generic_fixer_header = !empty(l:generic_fixer_list) | ||||
|     \   ? ['Try the following generic fixers:', ''] | ||||
|     \   : [] | ||||
|  | ||||
|     let l:has_both_lists = !empty(l:filetype_fixer_list) && !empty(l:generic_fixer_list) | ||||
|  | ||||
|     let l:lines = | ||||
|     \   l:filetype_fixer_header | ||||
|     \   + l:filetype_fixer_list | ||||
|     \   + (l:has_both_lists ? [''] : []) | ||||
|     \   + l:generic_fixer_header | ||||
|     \   + l:generic_fixer_list | ||||
|  | ||||
|     if empty(l:lines) | ||||
|         let l:lines = ['There is nothing in the registry to suggest.'] | ||||
|     else | ||||
|         let l:lines += ['', 'See :help ale-fix-configuration'] | ||||
|     endif | ||||
|  | ||||
|     let l:lines += ['', 'Press q to close this window'] | ||||
|  | ||||
|     new +set\ filetype=ale-fix-suggest | ||||
|     call setline(1, l:lines) | ||||
|     setlocal nomodified | ||||
|     setlocal nomodifiable | ||||
| endfunction | ||||
							
								
								
									
										26
									
								
								sources_non_forked/ale/autoload/ale/fixers/autopep8.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								sources_non_forked/ale/autoload/ale/fixers/autopep8.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Fixing files with autopep8. | ||||
|  | ||||
| call ale#Set('python_autopep8_executable', 'autopep8') | ||||
| call ale#Set('python_autopep8_use_global', 0) | ||||
| call ale#Set('python_autopep8_options', '') | ||||
|  | ||||
| function! ale#fixers#autopep8#Fix(buffer) abort | ||||
|     let l:executable = ale#python#FindExecutable( | ||||
|     \   a:buffer, | ||||
|     \   'python_autopep8', | ||||
|     \   ['autopep8'], | ||||
|     \) | ||||
|  | ||||
|     if !executable(l:executable) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:options = ale#Var(a:buffer, 'python_autopep8_options') | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . (!empty(l:options) ? ' ' . l:options : '') | ||||
|     \       . ' -', | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										15
									
								
								sources_non_forked/ale/autoload/ale/fixers/brittany.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								sources_non_forked/ale/autoload/ale/fixers/brittany.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| " Author: eborden <evan@evan-borden.com> | ||||
| " Description: Integration of brittany with ALE. | ||||
|  | ||||
| call ale#Set('haskell_brittany_executable', 'brittany') | ||||
|  | ||||
| function! ale#fixers#brittany#Fix(buffer) abort | ||||
|     let l:executable = ale#Var(a:buffer, 'haskell_brittany_executable') | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . ' %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
|  | ||||
							
								
								
									
										22
									
								
								sources_non_forked/ale/autoload/ale/fixers/clangformat.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								sources_non_forked/ale/autoload/ale/fixers/clangformat.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| scriptencoding utf-8 | ||||
| " Author: Peter Renström <renstrom.peter@gmail.com> | ||||
| " Description: Fixing C/C++ files with clang-format. | ||||
|  | ||||
| call ale#Set('c_clangformat_executable', 'clang-format') | ||||
| call ale#Set('c_clangformat_use_global', 0) | ||||
| call ale#Set('c_clangformat_options', '') | ||||
|  | ||||
| function! ale#fixers#clangformat#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'c_clangformat', [ | ||||
|     \   'clang-format', | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#clangformat#Fix(buffer) abort | ||||
|     let l:options = ale#Var(a:buffer, 'c_clangformat_options') | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(ale#fixers#clangformat#GetExecutable(a:buffer)) | ||||
|     \       . ' ' . l:options, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										23
									
								
								sources_non_forked/ale/autoload/ale/fixers/elm_format.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								sources_non_forked/ale/autoload/ale/fixers/elm_format.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| " Author: soywod <clement.douin@gmail.com> | ||||
| " Description: Integration of elm-format with ALE. | ||||
|  | ||||
| call ale#Set('elm_format_executable', 'elm-format') | ||||
| call ale#Set('elm_format_use_global', 0) | ||||
| call ale#Set('elm_format_options', '--yes') | ||||
|  | ||||
| function! ale#fixers#elm_format#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'elm_format', [ | ||||
|     \   'node_modules/.bin/elm-format', | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#elm_format#Fix(buffer) abort | ||||
|     let l:options = ale#Var(a:buffer, 'elm_format_options') | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(ale#fixers#elm_format#GetExecutable(a:buffer)) | ||||
|     \       . ' %t' | ||||
|     \       . (empty(l:options) ? '' : ' ' . l:options), | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										70
									
								
								sources_non_forked/ale/autoload/ale/fixers/eslint.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								sources_non_forked/ale/autoload/ale/fixers/eslint.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Fixing files with eslint. | ||||
|  | ||||
| function! ale#fixers#eslint#Fix(buffer) abort | ||||
|     let l:executable = ale#handlers#eslint#GetExecutable(a:buffer) | ||||
|  | ||||
|     let l:command = ale#semver#HasVersion(l:executable) | ||||
|     \   ? '' | ||||
|     \   : ale#node#Executable(a:buffer, l:executable) . ' --version' | ||||
|  | ||||
|     return { | ||||
|     \   'command': l:command, | ||||
|     \   'chain_with': 'ale#fixers#eslint#ApplyFixForVersion', | ||||
|     \} | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#eslint#ProcessFixDryRunOutput(buffer, output) abort | ||||
|     for l:item in ale#util#FuzzyJSONDecode(a:output, []) | ||||
|         return split(get(l:item, 'output', ''), "\n") | ||||
|     endfor | ||||
|  | ||||
|     return [] | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#eslint#ProcessEslintDOutput(buffer, output) abort | ||||
|     " If the output is an error message, don't use it. | ||||
|     for l:line in a:output[:10] | ||||
|         if l:line =~# '^Error:' | ||||
|             return [] | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return a:output | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#eslint#ApplyFixForVersion(buffer, version_output) abort | ||||
|     let l:executable = ale#handlers#eslint#GetExecutable(a:buffer) | ||||
|     let l:version = ale#semver#GetVersion(l:executable, a:version_output) | ||||
|  | ||||
|     let l:config = ale#handlers#eslint#FindConfig(a:buffer) | ||||
|  | ||||
|     if empty(l:config) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     " Use --fix-to-stdout with eslint_d | ||||
|     if l:executable =~# 'eslint_d$' && ale#semver#GTE(l:version, [3, 19, 0]) | ||||
|         return { | ||||
|         \   'command': ale#node#Executable(a:buffer, l:executable) | ||||
|         \       . ' --stdin-filename %s --stdin --fix-to-stdout', | ||||
|         \   'process_with': 'ale#fixers#eslint#ProcessEslintDOutput', | ||||
|         \} | ||||
|     endif | ||||
|  | ||||
|     " 4.9.0 is the first version with --fix-dry-run | ||||
|     if ale#semver#GTE(l:version, [4, 9, 0]) | ||||
|         return { | ||||
|         \   'command': ale#node#Executable(a:buffer, l:executable) | ||||
|         \       . ' --stdin-filename %s --stdin --fix-dry-run --format=json', | ||||
|         \   'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', | ||||
|         \} | ||||
|     endif | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#node#Executable(a:buffer, l:executable) | ||||
|     \       . ' -c ' . ale#Escape(l:config) | ||||
|     \       . ' --fix %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										27
									
								
								sources_non_forked/ale/autoload/ale/fixers/fixjson.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								sources_non_forked/ale/autoload/ale/fixers/fixjson.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| " Author: rhysd <https://rhysd.github.io> | ||||
| " Description: Integration of fixjson with ALE. | ||||
|  | ||||
| call ale#Set('json_fixjson_executable', 'fixjson') | ||||
| call ale#Set('json_fixjson_options', '') | ||||
| call ale#Set('json_fixjson_use_global', 0) | ||||
|  | ||||
| function! ale#fixers#fixjson#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'json_fixjson', [ | ||||
|     \   'node_modules/.bin/fixjson', | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#fixjson#Fix(buffer) abort | ||||
|     let l:executable = ale#Escape(ale#fixers#fixjson#GetExecutable(a:buffer)) | ||||
|     let l:filename = ale#Escape(bufname(a:buffer)) | ||||
|     let l:command = l:executable . ' --stdin-filename ' . l:filename | ||||
|  | ||||
|     let l:options = ale#Var(a:buffer, 'json_fixjson_options') | ||||
|     if l:options isnot# '' | ||||
|         let l:command .= ' ' . l:options | ||||
|     endif | ||||
|  | ||||
|     return { | ||||
|     \   'command': l:command | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										25
									
								
								sources_non_forked/ale/autoload/ale/fixers/generic.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								sources_non_forked/ale/autoload/ale/fixers/generic.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Generic functions for fixing files with. | ||||
|  | ||||
| function! ale#fixers#generic#RemoveTrailingBlankLines(buffer, lines) abort | ||||
|     let l:end_index = len(a:lines) - 1 | ||||
|  | ||||
|     while l:end_index > 0 && empty(a:lines[l:end_index]) | ||||
|         let l:end_index -= 1 | ||||
|     endwhile | ||||
|  | ||||
|     return a:lines[:l:end_index] | ||||
| endfunction | ||||
|  | ||||
| " Remove all whitespaces at the end of lines | ||||
| function! ale#fixers#generic#TrimWhitespace(buffer, lines) abort | ||||
|     let l:index = 0 | ||||
|     let l:lines_new = range(len(a:lines)) | ||||
|  | ||||
|     for l:line in a:lines | ||||
|         let l:lines_new[l:index] = substitute(l:line, '\s\+$', '', 'g') | ||||
|         let l:index = l:index + 1 | ||||
|     endfor | ||||
|  | ||||
|     return l:lines_new | ||||
| endfunction | ||||
| @ -0,0 +1,60 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Generic fixer functions for Python. | ||||
|  | ||||
| " Add blank lines before control statements. | ||||
| function! ale#fixers#generic_python#AddLinesBeforeControlStatements(buffer, lines) abort | ||||
|     let l:new_lines = [] | ||||
|     let l:last_indent_size = 0 | ||||
|     let l:last_line_is_blank = 0 | ||||
|  | ||||
|     for l:line in a:lines | ||||
|         let l:indent_size = len(matchstr(l:line, '^ *')) | ||||
|  | ||||
|         if !l:last_line_is_blank | ||||
|         \&& l:indent_size <= l:last_indent_size | ||||
|         \&& match(l:line, '\v^ *(return|if|for|while|break|continue)') >= 0 | ||||
|             call add(l:new_lines, '') | ||||
|         endif | ||||
|  | ||||
|         call add(l:new_lines, l:line) | ||||
|         let l:last_indent_size = l:indent_size | ||||
|         let l:last_line_is_blank = empty(split(l:line)) | ||||
|     endfor | ||||
|  | ||||
|     return l:new_lines | ||||
| endfunction | ||||
|  | ||||
| " This function breaks up long lines so that autopep8 or other tools can | ||||
| " fix the badly-indented code which is produced as a result. | ||||
| function! ale#fixers#generic_python#BreakUpLongLines(buffer, lines) abort | ||||
|     " Default to a maximum line length of 79 | ||||
|     let l:max_line_length = 79 | ||||
|     let l:conf = ale#path#FindNearestFile(a:buffer, 'setup.cfg') | ||||
|  | ||||
|     " Read the maximum line length from setup.cfg | ||||
|     if !empty(l:conf) | ||||
|         for l:match in ale#util#GetMatches( | ||||
|         \   readfile(l:conf), | ||||
|         \   '\v^ *max-line-length *\= *(\d+)', | ||||
|         \) | ||||
|             let l:max_line_length = str2nr(l:match[1]) | ||||
|         endfor | ||||
|     endif | ||||
|  | ||||
|     let l:new_list = [] | ||||
|  | ||||
|     for l:line in a:lines | ||||
|         if len(l:line) > l:max_line_length && l:line !~# '# *noqa' | ||||
|             let l:line = substitute(l:line, '\v([(,])([^)])', '\1\n\2', 'g') | ||||
|             let l:line = substitute(l:line, '\v([^(])([)])', '\1,\n\2', 'g') | ||||
|  | ||||
|             for l:split_line in split(l:line, "\n") | ||||
|                 call add(l:new_list, l:split_line) | ||||
|             endfor | ||||
|         else | ||||
|             call add(l:new_list, l:line) | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return l:new_list | ||||
| endfunction | ||||
							
								
								
									
										18
									
								
								sources_non_forked/ale/autoload/ale/fixers/gofmt.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								sources_non_forked/ale/autoload/ale/fixers/gofmt.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| " Author: aliou <code@aliou.me> | ||||
| " Description: Integration of gofmt with ALE. | ||||
|  | ||||
| call ale#Set('go_gofmt_executable', 'gofmt') | ||||
| call ale#Set('go_gofmt_options', '') | ||||
|  | ||||
| function! ale#fixers#gofmt#Fix(buffer) abort | ||||
|     let l:executable = ale#Var(a:buffer, 'go_gofmt_executable') | ||||
|     let l:options = ale#Var(a:buffer, 'go_gofmt_options') | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . ' -l -w' | ||||
|     \       . (empty(l:options) ? '' : ' ' . l:options) | ||||
|     \       . ' %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										22
									
								
								sources_non_forked/ale/autoload/ale/fixers/goimports.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								sources_non_forked/ale/autoload/ale/fixers/goimports.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| " Author: Jeff Willette <jrwillette88@gmail.com> | ||||
| " Description: Integration of goimports with ALE. | ||||
|  | ||||
| call ale#Set('go_goimports_executable', 'goimports') | ||||
| call ale#Set('go_goimports_options', '') | ||||
|  | ||||
| function! ale#fixers#goimports#Fix(buffer) abort | ||||
|     let l:executable = ale#Var(a:buffer, 'go_goimports_executable') | ||||
|     let l:options = ale#Var(a:buffer, 'go_goimports_options') | ||||
|  | ||||
|     if !executable(l:executable) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . ' -l -w -srcdir %s' | ||||
|     \       . (empty(l:options) ? '' : ' ' . l:options) | ||||
|     \       . ' %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
| @ -0,0 +1,23 @@ | ||||
| " Author: butlerx <butlerx@notthe,cloud> | ||||
| " Description: Integration of Google-java-format with ALE. | ||||
|  | ||||
| call ale#Set('google_java_format_executable', 'google-java-format') | ||||
| call ale#Set('google_java_format_use_global', 0) | ||||
| call ale#Set('google_java_format_options', '') | ||||
|  | ||||
| function! ale#fixers#google_java_format#Fix(buffer) abort | ||||
|     let l:options = ale#Var(a:buffer, 'google_java_format_options') | ||||
|     let l:executable = ale#Var(a:buffer, 'google_java_format_executable') | ||||
|  | ||||
|     if !executable(l:executable) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . ' ' . (empty(l:options) ? '' : ' ' . l:options) | ||||
|     \       . ' --replace' | ||||
|     \       . ' %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										18
									
								
								sources_non_forked/ale/autoload/ale/fixers/hackfmt.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								sources_non_forked/ale/autoload/ale/fixers/hackfmt.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| " Author: Sam Howie <samhowie@gmail.com> | ||||
| " Description: Integration of hackfmt with ALE. | ||||
|  | ||||
| call ale#Set('php_hackfmt_executable', 'hackfmt') | ||||
| call ale#Set('php_hackfmt_options', '') | ||||
|  | ||||
| function! ale#fixers#hackfmt#Fix(buffer) abort | ||||
|     let l:executable = ale#Var(a:buffer, 'php_hackfmt_executable') | ||||
|     let l:options = ale#Var(a:buffer, 'php_hackfmt_options') | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . ' -i' | ||||
|     \       . (empty(l:options) ? '' : ' ' . l:options) | ||||
|     \       . ' %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										24
									
								
								sources_non_forked/ale/autoload/ale/fixers/help.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								sources_non_forked/ale/autoload/ale/fixers/help.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Generic fixer functions for Vim help documents. | ||||
|  | ||||
| function! ale#fixers#help#AlignTags(buffer, lines) abort | ||||
|     let l:new_lines = [] | ||||
|  | ||||
|     for l:line in a:lines | ||||
|         if len(l:line) != 79 | ||||
|             let l:match = matchlist(l:line, '\v +(\*[^*]+\*)$') | ||||
|  | ||||
|             if !empty(l:match) | ||||
|                 let l:start = l:line[:-len(l:match[0]) - 1] | ||||
|                 let l:tag = l:match[1] | ||||
|                 let l:spaces = repeat(' ', 79 - len(l:start) - len(l:tag)) | ||||
|  | ||||
|                 let l:line = l:start . l:spaces . l:tag | ||||
|             endif | ||||
|         endif | ||||
|  | ||||
|         call add(l:new_lines, l:line) | ||||
|     endfor | ||||
|  | ||||
|     return l:new_lines | ||||
| endfunction | ||||
							
								
								
									
										16
									
								
								sources_non_forked/ale/autoload/ale/fixers/hfmt.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								sources_non_forked/ale/autoload/ale/fixers/hfmt.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| " Author: zack <zack@kourouma.me> | ||||
| " Description: Integration of hfmt with ALE. | ||||
|  | ||||
| call ale#Set('haskell_hfmt_executable', 'hfmt') | ||||
|  | ||||
| function! ale#fixers#hfmt#Fix(buffer) abort | ||||
|     let l:executable = ale#Var(a:buffer, 'haskell_hfmt_executable') | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . ' -w' | ||||
|     \       . ' %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
|  | ||||
							
								
								
									
										24
									
								
								sources_non_forked/ale/autoload/ale/fixers/importjs.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								sources_non_forked/ale/autoload/ale/fixers/importjs.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| " Author: Jeff Willette <jrwillette88@gmail.com> | ||||
| " Description: Integration of importjs with ALE. | ||||
|  | ||||
| call ale#Set('js_importjs_executable', 'importjs') | ||||
|  | ||||
| function! ale#fixers#importjs#ProcessOutput(buffer, output) abort | ||||
|     let l:result = ale#util#FuzzyJSONDecode(a:output, []) | ||||
|     return split(get(l:result, 'fileContent', ''), "\n") | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#importjs#Fix(buffer) abort | ||||
|     let l:executable = ale#Var(a:buffer, 'js_importjs_executable') | ||||
|  | ||||
|     if !executable(l:executable) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . ' fix' | ||||
|     \       . ' %s', | ||||
|     \   'process_with': 'ale#fixers#importjs#ProcessOutput', | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										22
									
								
								sources_non_forked/ale/autoload/ale/fixers/isort.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								sources_non_forked/ale/autoload/ale/fixers/isort.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Fixing Python imports with isort. | ||||
|  | ||||
| call ale#Set('python_isort_executable', 'isort') | ||||
| call ale#Set('python_isort_use_global', 0) | ||||
|  | ||||
| function! ale#fixers#isort#Fix(buffer) abort | ||||
|     let l:executable = ale#python#FindExecutable( | ||||
|     \   a:buffer, | ||||
|     \   'python_isort', | ||||
|     \   ['isort'], | ||||
|     \) | ||||
|  | ||||
|     if !executable(l:executable) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#path#BufferCdString(a:buffer) | ||||
|     \   .   ale#Escape(l:executable) . ' -', | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										15
									
								
								sources_non_forked/ale/autoload/ale/fixers/jq.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								sources_non_forked/ale/autoload/ale/fixers/jq.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| call ale#Set('json_jq_executable', 'jq') | ||||
| call ale#Set('json_jq_options', '') | ||||
|  | ||||
| function! ale#fixers#jq#GetExecutable(buffer) abort | ||||
|     return ale#Var(a:buffer, 'json_jq_executable') | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#jq#Fix(buffer) abort | ||||
|      let l:options = ale#Var(a:buffer, 'json_jq_options') | ||||
|  | ||||
|      return { | ||||
|      \  'command': ale#Escape(ale#fixers#jq#GetExecutable(a:buffer)) | ||||
|      \      . ' . ' . l:options, | ||||
|      \} | ||||
| endfunction | ||||
							
								
								
									
										25
									
								
								sources_non_forked/ale/autoload/ale/fixers/mix_format.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								sources_non_forked/ale/autoload/ale/fixers/mix_format.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| " Author: carakan <carakan@gmail.com>, Fernando Mendes <fernando@mendes.codes> | ||||
| " Description: Fixing files with elixir formatter 'mix format'. | ||||
|  | ||||
| call ale#Set('elixir_mix_executable', 'mix') | ||||
| call ale#Set('elixir_mix_format_options', '') | ||||
|  | ||||
| function! ale#fixers#mix_format#GetExecutable(buffer) abort | ||||
|     return ale#Var(a:buffer, 'elixir_mix_executable') | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#mix_format#GetCommand(buffer) abort | ||||
|     let l:executable = ale#Escape(ale#fixers#mix_format#GetExecutable(a:buffer)) | ||||
|     let l:options = ale#Var(a:buffer, 'elixir_mix_format_options') | ||||
|  | ||||
|     return l:executable . ' format' | ||||
|     \   . (!empty(l:options) ? ' ' . l:options : '') | ||||
|     \   . ' %t' | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#mix_format#Fix(buffer) abort | ||||
|     return { | ||||
|     \   'command': ale#fixers#mix_format#GetCommand(a:buffer), | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										23
									
								
								sources_non_forked/ale/autoload/ale/fixers/php_cs_fixer.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								sources_non_forked/ale/autoload/ale/fixers/php_cs_fixer.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| " Author: Julien Deniau <julien.deniau@gmail.com> | ||||
| " Description: Fixing files with php-cs-fixer. | ||||
|  | ||||
| call ale#Set('php_cs_fixer_executable', 'php-cs-fixer') | ||||
| call ale#Set('php_cs_fixer_use_global', 0) | ||||
|  | ||||
| function! ale#fixers#php_cs_fixer#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'php_cs_fixer', [ | ||||
|     \   'vendor/bin/php-cs-fixer', | ||||
|     \   'php-cs-fixer' | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#php_cs_fixer#Fix(buffer) abort | ||||
|     let l:executable = ale#fixers#php_cs_fixer#GetExecutable(a:buffer) | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) . ' fix %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										24
									
								
								sources_non_forked/ale/autoload/ale/fixers/phpcbf.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								sources_non_forked/ale/autoload/ale/fixers/phpcbf.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| " Author: notomo <notomo.motono@gmail.com> | ||||
| " Description: Fixing files with phpcbf. | ||||
|  | ||||
| call ale#Set('php_phpcbf_standard', '') | ||||
| call ale#Set('php_phpcbf_executable', 'phpcbf') | ||||
| call ale#Set('php_phpcbf_use_global', 0) | ||||
|  | ||||
| function! ale#fixers#phpcbf#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'php_phpcbf', [ | ||||
|     \   'vendor/bin/phpcbf', | ||||
|     \   'phpcbf' | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#phpcbf#Fix(buffer) abort | ||||
|     let l:executable = ale#fixers#phpcbf#GetExecutable(a:buffer) | ||||
|     let l:standard = ale#Var(a:buffer, 'php_phpcbf_standard') | ||||
|     let l:standard_option = !empty(l:standard) | ||||
|     \   ? '--standard=' . l:standard | ||||
|     \   : '' | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) . ' --stdin-path=%s ' . l:standard_option . ' -' | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										53
									
								
								sources_non_forked/ale/autoload/ale/fixers/prettier.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								sources_non_forked/ale/autoload/ale/fixers/prettier.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| " Author: tunnckoCore (Charlike Mike Reagent) <mameto2011@gmail.com>, | ||||
| "         w0rp <devw0rp@gmail.com>, morhetz (Pavel Pertsev) <morhetz@gmail.com> | ||||
| " Description: Integration of Prettier with ALE. | ||||
|  | ||||
| call ale#Set('javascript_prettier_executable', 'prettier') | ||||
| call ale#Set('javascript_prettier_use_global', 0) | ||||
| call ale#Set('javascript_prettier_options', '') | ||||
|  | ||||
| function! ale#fixers#prettier#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'javascript_prettier', [ | ||||
|     \   'node_modules/.bin/prettier_d', | ||||
|     \   'node_modules/prettier-cli/index.js', | ||||
|     \   'node_modules/.bin/prettier', | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#prettier#Fix(buffer) abort | ||||
|     let l:executable = ale#fixers#prettier#GetExecutable(a:buffer) | ||||
|  | ||||
|     let l:command = ale#semver#HasVersion(l:executable) | ||||
|     \   ? '' | ||||
|     \   : ale#Escape(l:executable) . ' --version' | ||||
|  | ||||
|     return { | ||||
|     \   'command': l:command, | ||||
|     \   'chain_with': 'ale#fixers#prettier#ApplyFixForVersion', | ||||
|     \} | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#prettier#ApplyFixForVersion(buffer, version_output) abort | ||||
|     let l:executable = ale#fixers#prettier#GetExecutable(a:buffer) | ||||
|     let l:options = ale#Var(a:buffer, 'javascript_prettier_options') | ||||
|  | ||||
|     let l:version = ale#semver#GetVersion(l:executable, a:version_output) | ||||
|  | ||||
|     " 1.4.0 is the first version with --stdin-filepath | ||||
|     if ale#semver#GTE(l:version, [1, 4, 0]) | ||||
|         return { | ||||
|         \   'command': ale#path#BufferCdString(a:buffer) | ||||
|         \       . ale#Escape(l:executable) | ||||
|         \       . (!empty(l:options) ? ' ' . l:options : '') | ||||
|         \       . ' --stdin-filepath %s --stdin', | ||||
|         \} | ||||
|     endif | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . ' %t' | ||||
|     \       . (!empty(l:options) ? ' ' . l:options : '') | ||||
|     \       . ' --write', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
| @ -0,0 +1,66 @@ | ||||
| " Author: tunnckoCore (Charlike Mike Reagent) <mameto2011@gmail.com>, | ||||
| "         w0rp <devw0rp@gmail.com>, morhetz (Pavel Pertsev) <morhetz@gmail.com> | ||||
| " Description: Integration between Prettier and ESLint. | ||||
|  | ||||
| function! ale#fixers#prettier_eslint#SetOptionDefaults() abort | ||||
|     call ale#Set('javascript_prettier_eslint_executable', 'prettier-eslint') | ||||
|     call ale#Set('javascript_prettier_eslint_use_global', 0) | ||||
|     call ale#Set('javascript_prettier_eslint_options', '') | ||||
| endfunction | ||||
|  | ||||
| call ale#fixers#prettier_eslint#SetOptionDefaults() | ||||
|  | ||||
| function! ale#fixers#prettier_eslint#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'javascript_prettier_eslint', [ | ||||
|     \   'node_modules/prettier-eslint-cli/dist/index.js', | ||||
|     \   'node_modules/.bin/prettier-eslint', | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#prettier_eslint#Fix(buffer) abort | ||||
|     let l:executable = ale#fixers#prettier_eslint#GetExecutable(a:buffer) | ||||
|  | ||||
|     let l:command = ale#semver#HasVersion(l:executable) | ||||
|     \   ? '' | ||||
|     \   : ale#Escape(l:executable) . ' --version' | ||||
|  | ||||
|     return { | ||||
|     \   'command': l:command, | ||||
|     \   'chain_with': 'ale#fixers#prettier_eslint#ApplyFixForVersion', | ||||
|     \} | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#prettier_eslint#ApplyFixForVersion(buffer, version_output) abort | ||||
|     let l:options = ale#Var(a:buffer, 'javascript_prettier_eslint_options') | ||||
|     let l:executable = ale#fixers#prettier_eslint#GetExecutable(a:buffer) | ||||
|  | ||||
|     let l:version = ale#semver#GetVersion(l:executable, a:version_output) | ||||
|  | ||||
|     " 4.2.0 is the first version with --eslint-config-path | ||||
|     let l:config = ale#semver#GTE(l:version, [4, 2, 0]) | ||||
|     \   ? ale#handlers#eslint#FindConfig(a:buffer) | ||||
|     \   : '' | ||||
|     let l:eslint_config_option = !empty(l:config) | ||||
|     \   ? ' --eslint-config-path ' . ale#Escape(l:config) | ||||
|     \   : '' | ||||
|  | ||||
|     " 4.4.0 is the first version with --stdin-filepath | ||||
|     if ale#semver#GTE(l:version, [4, 4, 0]) | ||||
|         return { | ||||
|         \   'command': ale#path#BufferCdString(a:buffer) | ||||
|         \       . ale#Escape(l:executable) | ||||
|         \       . l:eslint_config_option | ||||
|         \       . (!empty(l:options) ? ' ' . l:options : '') | ||||
|         \       . ' --stdin-filepath %s --stdin', | ||||
|         \} | ||||
|     endif | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . ' %t' | ||||
|     \       . l:eslint_config_option | ||||
|     \       . (!empty(l:options) ? ' ' . l:options : '') | ||||
|     \       . ' --write', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
| @ -0,0 +1,24 @@ | ||||
| " Author: sheerun (Adam Stankiewicz) <sheerun@sher.pl> | ||||
| " Description: Integration of Prettier Standard with ALE. | ||||
|  | ||||
| call ale#Set('javascript_prettier_standard_executable', 'prettier-standard') | ||||
| call ale#Set('javascript_prettier_standard_use_global', 0) | ||||
| call ale#Set('javascript_prettier_standard_options', '') | ||||
|  | ||||
| function! ale#fixers#prettier_standard#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'javascript_prettier_standard', [ | ||||
|     \   'node_modules/prettier-standard/lib/index.js', | ||||
|     \   'node_modules/.bin/prettier-standard', | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#prettier_standard#Fix(buffer) abort | ||||
|     let l:options = ale#Var(a:buffer, 'javascript_prettier_standard_options') | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(ale#fixers#prettier_standard#GetExecutable(a:buffer)) | ||||
|     \       . ' %t' | ||||
|     \       . ' ' . l:options, | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										21
									
								
								sources_non_forked/ale/autoload/ale/fixers/puppetlint.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								sources_non_forked/ale/autoload/ale/fixers/puppetlint.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| " Author: Alexander Olofsson <alexander.olofsson@liu.se> | ||||
| " Description: puppet-lint fixer | ||||
|  | ||||
| if !exists('g:ale_puppet_puppetlint_executable') | ||||
|     let g:ale_puppet_puppetlint_executable = 'puppet-lint' | ||||
| endif | ||||
| if !exists('g:ale_puppet_puppetlint_options') | ||||
|     let g:ale_puppet_puppetlint_options = '' | ||||
| endif | ||||
|  | ||||
| function! ale#fixers#puppetlint#Fix(buffer) abort | ||||
|     let l:executable = ale#Var(a:buffer, 'puppet_puppetlint_executable') | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . ' ' . ale#Var(a:buffer, 'puppet_puppetlint_options') | ||||
|     \       . ' --fix' | ||||
|     \       . ' %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										18
									
								
								sources_non_forked/ale/autoload/ale/fixers/refmt.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								sources_non_forked/ale/autoload/ale/fixers/refmt.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| " Author: Ahmed El Gabri <@ahmedelgabri> | ||||
| " Description: Integration of refmt with ALE. | ||||
|  | ||||
| call ale#Set('reasonml_refmt_executable', 'refmt') | ||||
| call ale#Set('reasonml_refmt_options', '') | ||||
|  | ||||
| function! ale#fixers#refmt#Fix(buffer) abort | ||||
|     let l:executable = ale#Var(a:buffer, 'reasonml_refmt_executable') | ||||
|     let l:options = ale#Var(a:buffer, 'reasonml_refmt_options') | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . (empty(l:options) ? '' : ' ' . l:options) | ||||
|     \       . ' --in-place' | ||||
|     \       . ' %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										21
									
								
								sources_non_forked/ale/autoload/ale/fixers/rubocop.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								sources_non_forked/ale/autoload/ale/fixers/rubocop.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| function! ale#fixers#rubocop#GetCommand(buffer) abort | ||||
|     let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer) | ||||
|     let l:exec_args = l:executable =~? 'bundle$' | ||||
|     \   ? ' exec rubocop' | ||||
|     \   : '' | ||||
|     let l:config = ale#path#FindNearestFile(a:buffer, '.rubocop.yml') | ||||
|     let l:options = ale#Var(a:buffer, 'ruby_rubocop_options') | ||||
|  | ||||
|     return ale#Escape(l:executable) . l:exec_args | ||||
|     \   . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '') | ||||
|     \   . (!empty(l:options) ? ' ' . l:options : '') | ||||
|     \   . ' --auto-correct %t' | ||||
|  | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#rubocop#Fix(buffer) abort | ||||
|     return { | ||||
|     \   'command': ale#fixers#rubocop#GetCommand(a:buffer), | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										20
									
								
								sources_non_forked/ale/autoload/ale/fixers/rufo.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								sources_non_forked/ale/autoload/ale/fixers/rufo.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| " Author: Fohte (Hayato Kawai) https://github.com/fohte | ||||
| " Description: Integration of Rufo with ALE. | ||||
|  | ||||
| call ale#Set('ruby_rufo_executable', 'rufo') | ||||
|  | ||||
| function! ale#fixers#rufo#GetCommand(buffer) abort | ||||
|     let l:executable = ale#Var(a:buffer, 'ruby_rufo_executable') | ||||
|     let l:exec_args = l:executable =~? 'bundle$' | ||||
|     \   ? ' exec rufo' | ||||
|     \   : '' | ||||
|  | ||||
|     return ale#Escape(l:executable) . l:exec_args . ' %t' | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#rufo#Fix(buffer) abort | ||||
|     return { | ||||
|     \   'command': ale#fixers#rufo#GetCommand(a:buffer), | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										15
									
								
								sources_non_forked/ale/autoload/ale/fixers/rustfmt.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								sources_non_forked/ale/autoload/ale/fixers/rustfmt.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| " Author: Kelly Fox <kelly@bumfuddled.com> | ||||
| " Description: Integration of rustfmt with ALE. | ||||
|  | ||||
| call ale#Set('rust_rustfmt_executable', 'rustfmt') | ||||
| call ale#Set('rust_rustfmt_options', '') | ||||
|  | ||||
| function! ale#fixers#rustfmt#Fix(buffer) abort | ||||
|     let l:executable = ale#Var(a:buffer, 'rust_rustfmt_executable') | ||||
|     let l:options = ale#Var(a:buffer, 'rust_rustfmt_options') | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . (empty(l:options) ? '' : ' ' . l:options), | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										17
									
								
								sources_non_forked/ale/autoload/ale/fixers/shfmt.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								sources_non_forked/ale/autoload/ale/fixers/shfmt.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| scriptencoding utf-8 | ||||
| " Author: Simon Bugert <simon.bugert@gmail.com> | ||||
| " Description: Fix sh files with shfmt. | ||||
|  | ||||
| call ale#Set('sh_shfmt_executable', 'shfmt') | ||||
| call ale#Set('sh_shfmt_options', '') | ||||
|  | ||||
| function! ale#fixers#shfmt#Fix(buffer) abort | ||||
|     let l:executable = ale#Var(a:buffer, 'sh_shfmt_executable') | ||||
|     let l:options = ale#Var(a:buffer, 'sh_shfmt_options') | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) | ||||
|     \       . (empty(l:options) ? '' : ' ' . l:options) | ||||
|     \} | ||||
|  | ||||
| endfunction | ||||
							
								
								
									
										23
									
								
								sources_non_forked/ale/autoload/ale/fixers/standard.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								sources_non_forked/ale/autoload/ale/fixers/standard.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| " Author: Sumner Evans <sumner.evans98@gmail.com> | ||||
| " Description: Fixing files with Standard. | ||||
|  | ||||
| call ale#Set('javascript_standard_executable', 'standard') | ||||
| call ale#Set('javascript_standard_use_global', 0) | ||||
| call ale#Set('javascript_standard_options', '') | ||||
|  | ||||
| function! ale#fixers#standard#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'javascript_standard', [ | ||||
|     \   'node_modules/standard/bin/cmd.js', | ||||
|     \   'node_modules/.bin/standard', | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#standard#Fix(buffer) abort | ||||
|     let l:executable = ale#fixers#standard#GetExecutable(a:buffer) | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#node#Executable(a:buffer, l:executable) | ||||
|     \       . ' --fix %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										23
									
								
								sources_non_forked/ale/autoload/ale/fixers/stylelint.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								sources_non_forked/ale/autoload/ale/fixers/stylelint.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| " 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) | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#node#Executable(a:buffer, l:executable) | ||||
|     \       . ' --fix %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										25
									
								
								sources_non_forked/ale/autoload/ale/fixers/swiftformat.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								sources_non_forked/ale/autoload/ale/fixers/swiftformat.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| " Author: gfontenot (Gordon Fontenot) <gordon@fonten.io> | ||||
| " Description: Integration of SwiftFormat with ALE. | ||||
|  | ||||
| call ale#Set('swift_swiftformat_executable', 'swiftformat') | ||||
| call ale#Set('swift_swiftformat_use_global', 0) | ||||
| call ale#Set('swift_swiftformat_options', '') | ||||
|  | ||||
| function! ale#fixers#swiftformat#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'swift_swiftformat', [ | ||||
|     \   'Pods/SwiftFormat/CommandLineTool/swiftformat', | ||||
|     \   'ios/Pods/SwiftFormat/CommandLineTool/swiftformat', | ||||
|     \   'swiftformat', | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#fixers#swiftformat#Fix(buffer) abort | ||||
|     let l:options = ale#Var(a:buffer, 'swift_swiftformat_options') | ||||
|  | ||||
|     return { | ||||
|     \   'read_temporary_file': 1, | ||||
|     \   'command': ale#Escape(ale#fixers#swiftformat#GetExecutable(a:buffer)) | ||||
|     \       . ' %t' | ||||
|     \       . ' ' . l:options, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										22
									
								
								sources_non_forked/ale/autoload/ale/fixers/tslint.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								sources_non_forked/ale/autoload/ale/fixers/tslint.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| " Author: carakan <carakan@gmail.com> | ||||
| " Description: Fixing files with tslint. | ||||
|  | ||||
| function! ale#fixers#tslint#Fix(buffer) abort | ||||
|     let l:executable = ale_linters#typescript#tslint#GetExecutable(a:buffer) | ||||
|  | ||||
|     let l:tslint_config_path = ale#path#ResolveLocalPath( | ||||
|     \   a:buffer, | ||||
|     \   'tslint.json', | ||||
|     \   ale#Var(a:buffer, 'typescript_tslint_config_path') | ||||
|     \) | ||||
|     let l:tslint_config_option = !empty(l:tslint_config_path) | ||||
|     \   ? ' -c ' . ale#Escape(l:tslint_config_path) | ||||
|     \   : '' | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#node#Executable(a:buffer, l:executable) | ||||
|     \       . l:tslint_config_option | ||||
|     \       . ' --fix %t', | ||||
|     \   'read_temporary_file': 1, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										26
									
								
								sources_non_forked/ale/autoload/ale/fixers/yapf.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								sources_non_forked/ale/autoload/ale/fixers/yapf.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Fixing Python files with yapf. | ||||
|  | ||||
| call ale#Set('python_yapf_executable', 'yapf') | ||||
| call ale#Set('python_yapf_use_global', 0) | ||||
|  | ||||
| function! ale#fixers#yapf#Fix(buffer) abort | ||||
|     let l:executable = ale#python#FindExecutable( | ||||
|     \   a:buffer, | ||||
|     \   'python_yapf', | ||||
|     \   ['yapf'], | ||||
|     \) | ||||
|  | ||||
|     if !executable(l:executable) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:config = ale#path#FindNearestFile(a:buffer, '.style.yapf') | ||||
|     let l:config_options = !empty(l:config) | ||||
|     \   ? ' --no-local-style --style ' . ale#Escape(l:config) | ||||
|     \   : '' | ||||
|  | ||||
|     return { | ||||
|     \   'command': ale#Escape(l:executable) . l:config_options, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										67
									
								
								sources_non_forked/ale/autoload/ale/gradle.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								sources_non_forked/ale/autoload/ale/gradle.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | ||||
| " Author: Michael Pardo <michael@michaelpardo.com> | ||||
| " Description: Functions for working with Gradle projects. | ||||
|  | ||||
| let s:script_path = fnamemodify(resolve(expand('<sfile>:p')), ':h') | ||||
| let s:init_path = has('win32') | ||||
| \   ? s:script_path . '\gradle\init.gradle' | ||||
| \   : s:script_path . '/gradle/init.gradle' | ||||
|  | ||||
| function! ale#gradle#GetInitPath() abort | ||||
|     return s:init_path | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer number, find a Gradle project root. | ||||
| function! ale#gradle#FindProjectRoot(buffer) abort | ||||
|     let l:gradlew_path = ale#path#FindNearestFile(a:buffer, 'gradlew') | ||||
|  | ||||
|     if !empty(l:gradlew_path) | ||||
|         return fnamemodify(l:gradlew_path, ':h') | ||||
|     endif | ||||
|  | ||||
|     let l:settings_path = ale#path#FindNearestFile(a:buffer, 'settings.gradle') | ||||
|  | ||||
|     if !empty(l:settings_path) | ||||
|         return fnamemodify(l:settings_path, ':h') | ||||
|     endif | ||||
|  | ||||
|     let l:build_path = ale#path#FindNearestFile(a:buffer, 'build.gradle') | ||||
|  | ||||
|     if !empty(l:build_path) | ||||
|         return fnamemodify(l:build_path, ':h') | ||||
|     endif | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer number, find the path to the executable. | ||||
| " First search on the path for 'gradlew', if nothing is found, try the global | ||||
| " command. Returns an empty string if cannot find the executable. | ||||
| function! ale#gradle#FindExecutable(buffer) abort | ||||
|     let l:gradlew_path = ale#path#FindNearestFile(a:buffer, 'gradlew') | ||||
|  | ||||
|     if !empty(l:gradlew_path) | ||||
|         return l:gradlew_path | ||||
|     endif | ||||
|  | ||||
|     if executable('gradle') | ||||
|         return 'gradle' | ||||
|     endif | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer number, build a command to print the classpath of the root | ||||
| " project. Returns an empty string if cannot build the command. | ||||
| function! ale#gradle#BuildClasspathCommand(buffer) abort | ||||
|     let l:executable = ale#gradle#FindExecutable(a:buffer) | ||||
|     let l:project_root = ale#gradle#FindProjectRoot(a:buffer) | ||||
|  | ||||
|     if !empty(l:executable) && !empty(l:project_root) | ||||
|         return ale#path#CdString(l:project_root) | ||||
|         \   . ale#Escape(l:executable) | ||||
|         \   . ' -I ' . ale#Escape(s:init_path) | ||||
|         \   . ' -q printClasspath' | ||||
|     endif | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
							
								
								
									
										23
									
								
								sources_non_forked/ale/autoload/ale/gradle/init.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								sources_non_forked/ale/autoload/ale/gradle/init.gradle
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| class ClasspathPlugin implements Plugin<Project> { | ||||
|     void apply(Project project) { | ||||
|         project.task('printClasspath') { | ||||
|             doLast { | ||||
|                 project | ||||
|                     .rootProject | ||||
|                     .allprojects | ||||
|                     .configurations | ||||
|                     .flatten() | ||||
|                     .findAll { it.name.endsWith('Classpath') } | ||||
|                     .collect { it.resolve() } | ||||
|                     .flatten() | ||||
|                     .unique() | ||||
|                     .findAll { it.exists() } | ||||
|                     .each { println it } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| rootProject { | ||||
|     apply plugin: ClasspathPlugin | ||||
| } | ||||
							
								
								
									
										22
									
								
								sources_non_forked/ale/autoload/ale/handlers/alex.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								sources_non_forked/ale/autoload/ale/handlers/alex.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| " Author: Johannes Wienke <languitar@semipol.de> | ||||
| " Description: Error handling for errors in alex output format | ||||
|  | ||||
| function! ale#handlers#alex#Handle(buffer, lines) abort | ||||
|     " Example output: | ||||
|     "       6:256-6:262  warning  Be careful with “killed”, it’s profane in some cases      killed           retext-profanities | ||||
|     let l:pattern = '^ *\(\d\+\):\(\d\+\)-\(\d\+\):\(\d\+\) \+warning \+\(.\{-\}\)  \+\(.\{-\}\)  \+\(.\{-\}\)$' | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, l:pattern) | ||||
|         call add(l:output, { | ||||
|         \   'lnum': l:match[1] + 0, | ||||
|         \   'col': l:match[2] + 0, | ||||
|         \   'end_lnum': l:match[3] + 0, | ||||
|         \   'end_col': l:match[4] - 1, | ||||
|         \   'text': l:match[5] . ' (' . (l:match[7]) . ')', | ||||
|         \   'type': 'W', | ||||
|         \}) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										21
									
								
								sources_non_forked/ale/autoload/ale/handlers/cppcheck.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								sources_non_forked/ale/autoload/ale/handlers/cppcheck.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| " Description: Handle errors for cppcheck. | ||||
|  | ||||
| function! ale#handlers#cppcheck#HandleCppCheckFormat(buffer, lines) abort | ||||
|     " Look for lines like the following. | ||||
|     " | ||||
|     " [test.cpp:5]: (error) Array 'a[10]' accessed at index 10, which is out of bounds | ||||
|     let l:pattern = '\v^\[(.+):(\d+)\]: \(([a-z]+)\) (.+)$' | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, l:pattern) | ||||
|         if ale#path#IsBufferPath(a:buffer, l:match[1]) | ||||
|             call add(l:output, { | ||||
|             \   'lnum': str2nr(l:match[2]), | ||||
|             \   'type': l:match[3] is# 'error' ? 'E' : 'W', | ||||
|             \   'text': l:match[4], | ||||
|             \}) | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										21
									
								
								sources_non_forked/ale/autoload/ale/handlers/cpplint.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								sources_non_forked/ale/autoload/ale/handlers/cpplint.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| " Author: Dawid Kurek https://github.com/dawikur | ||||
| " Description: Handle errors for cpplint. | ||||
|  | ||||
| function! ale#handlers#cpplint#HandleCppLintFormat(buffer, lines) abort | ||||
|     " Look for lines like the following. | ||||
|     " test.cpp:5:  Estra space after ( in function call [whitespace/parents] [4] | ||||
|     let l:pattern = '^.\{-}:\(\d\+\): *\(.\+\) *\[\(.*/.*\)\] ' | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, l:pattern) | ||||
|         call add(l:output, { | ||||
|         \   'lnum': l:match[1] + 0, | ||||
|         \   'col': 0, | ||||
|         \   'text': join(split(l:match[2])), | ||||
|         \   'code': l:match[3], | ||||
|         \   'type': 'W', | ||||
|         \}) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										70
									
								
								sources_non_forked/ale/autoload/ale/handlers/css.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								sources_non_forked/ale/autoload/ale/handlers/css.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| scriptencoding utf-8 | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Error handling for CSS linters. | ||||
|  | ||||
| function! ale#handlers#css#HandleCSSLintFormat(buffer, lines) abort | ||||
|     " Matches patterns line the following: | ||||
|     " | ||||
|     " something.css: line 2, col 1, Error - Expected RBRACE at line 2, col 1. (errors) | ||||
|     " something.css: line 2, col 5, Warning - Expected (inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | grid | inline-grid | run-in | ruby | ruby-base | ruby-text | ruby-base-container | ruby-text-container | contents | none | -moz-box | -moz-inline-block | -moz-inline-box | -moz-inline-grid | -moz-inline-stack | -moz-inline-table | -moz-grid | -moz-grid-group | -moz-grid-line | -moz-groupbox | -moz-deck | -moz-popup | -moz-stack | -moz-marker | -webkit-box | -webkit-inline-box | -ms-flexbox | -ms-inline-flexbox | flex | -webkit-flex | inline-flex | -webkit-inline-flex) but found 'wat'. (known-properties) | ||||
|     " | ||||
|     " These errors can be very massive, so the type will be moved to the front | ||||
|     " so you can actually read the error type. | ||||
|     let l:pattern = '\v^.*: line (\d+), col (\d+), (Error|Warning) - (.+)$' | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, l:pattern) | ||||
|         let l:item = { | ||||
|         \   'lnum': l:match[1] + 0, | ||||
|         \   'col': l:match[2] + 0, | ||||
|         \   'type': l:match[3] is# 'Warning' ? 'W' : 'E', | ||||
|         \   'text': l:match[4], | ||||
|         \} | ||||
|  | ||||
|         let l:code_match = matchlist(l:match[4], '\v(.+) \(([^(]+)\)$') | ||||
|  | ||||
|         " Split up the error code and the text if we find one. | ||||
|         if !empty(l:code_match) | ||||
|             let l:item.text = l:code_match[1] | ||||
|             let l:item.code = l:code_match[2] | ||||
|         endif | ||||
|  | ||||
|         call add(l:output, l:item) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#css#HandleStyleLintFormat(buffer, lines) abort | ||||
|     let l:exception_pattern = '\v^Error:' | ||||
|  | ||||
|     for l:line in a:lines[:10] | ||||
|         if len(matchlist(l:line, l:exception_pattern)) > 0 | ||||
|             return [{ | ||||
|             \   'lnum': 1, | ||||
|             \   'text': 'stylelint exception thrown (type :ALEDetail for more information)', | ||||
|             \   'detail': join(a:lines, "\n"), | ||||
|             \}] | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     " Matches patterns line the following: | ||||
|     " | ||||
|     " src/main.css | ||||
|     "  108:10  ✖  Unexpected leading zero         number-leading-zero | ||||
|     "  116:20  ✖  Expected a trailing semicolon   declaration-block-trailing-semicolon | ||||
|     let l:pattern = '\v^.* (\d+):(\d+) \s+(\S+)\s+ (.*[^ ])\s+([^ ]+)\s*$' | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, l:pattern) | ||||
|         call add(l:output, { | ||||
|         \   'lnum': l:match[1] + 0, | ||||
|         \   'col': l:match[2] + 0, | ||||
|         \   'type': l:match[3] is# '✖' ? 'E' : 'W', | ||||
|         \   'text': l:match[4], | ||||
|         \   'code': l:match[5], | ||||
|         \}) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										153
									
								
								sources_non_forked/ale/autoload/ale/handlers/eslint.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								sources_non_forked/ale/autoload/ale/handlers/eslint.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,153 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Functions for working with eslint, for checking or fixing files. | ||||
|  | ||||
| let s:sep = has('win32') ? '\' : '/' | ||||
|  | ||||
| call ale#Set('javascript_eslint_options', '') | ||||
| call ale#Set('javascript_eslint_executable', 'eslint') | ||||
| call ale#Set('javascript_eslint_use_global', 0) | ||||
| call ale#Set('javascript_eslint_suppress_eslintignore', 0) | ||||
| call ale#Set('javascript_eslint_suppress_missing_config', 0) | ||||
|  | ||||
| function! ale#handlers#eslint#FindConfig(buffer) abort | ||||
|     for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) | ||||
|         for l:basename in [ | ||||
|         \   '.eslintrc.js', | ||||
|         \   '.eslintrc.yaml', | ||||
|         \   '.eslintrc.yml', | ||||
|         \   '.eslintrc.json', | ||||
|         \   '.eslintrc', | ||||
|         \] | ||||
|             let l:config = ale#path#Simplify(join([l:path, l:basename], s:sep)) | ||||
|  | ||||
|             if filereadable(l:config) | ||||
|                 return l:config | ||||
|             endif | ||||
|         endfor | ||||
|     endfor | ||||
|  | ||||
|     return ale#path#FindNearestFile(a:buffer, 'package.json') | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#eslint#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'javascript_eslint', [ | ||||
|     \   'node_modules/.bin/eslint_d', | ||||
|     \   'node_modules/eslint/bin/eslint.js', | ||||
|     \   'node_modules/.bin/eslint', | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#eslint#GetCommand(buffer) abort | ||||
|     let l:executable = ale#handlers#eslint#GetExecutable(a:buffer) | ||||
|  | ||||
|     let l:options = ale#Var(a:buffer, 'javascript_eslint_options') | ||||
|  | ||||
|     return ale#node#Executable(a:buffer, l:executable) | ||||
|     \   . (!empty(l:options) ? ' ' . l:options : '') | ||||
|     \   . ' -f unix --stdin --stdin-filename %s' | ||||
| endfunction | ||||
|  | ||||
| let s:col_end_patterns = [ | ||||
| \   '\vParsing error: Unexpected token (.+) ?', | ||||
| \   '\v''(.+)'' is not defined.', | ||||
| \   '\v%(Unexpected|Redundant use of) [''`](.+)[''`]', | ||||
| \   '\vUnexpected (console) statement', | ||||
| \] | ||||
|  | ||||
| function! s:AddHintsForTypeScriptParsingErrors(output) abort | ||||
|     for l:item in a:output | ||||
|         let l:item.text = substitute( | ||||
|         \   l:item.text, | ||||
|         \   '^\(Parsing error\)', | ||||
|         \   '\1 (You may need configure typescript-eslint-parser)', | ||||
|         \   '', | ||||
|         \) | ||||
|     endfor | ||||
| endfunction | ||||
|  | ||||
| function! s:CheckForBadConfig(buffer, lines) abort | ||||
|     let l:config_error_pattern = '\v^ESLint couldn''t find a configuration file' | ||||
|     \   . '|^Cannot read config file' | ||||
|     \   . '|^.*Configuration for rule .* is invalid' | ||||
|     \   . '|^ImportDeclaration should appear' | ||||
|  | ||||
|     " Look for a message in the first few lines which indicates that | ||||
|     " a configuration file couldn't be found. | ||||
|     for l:line in a:lines[:10] | ||||
|         let l:match = matchlist(l:line, l:config_error_pattern) | ||||
|  | ||||
|         if len(l:match) > 0 | ||||
|             " Don't show the missing config error if we've disabled it. | ||||
|             if ale#Var(a:buffer, 'javascript_eslint_suppress_missing_config') | ||||
|             \&& l:match[0] is# 'ESLint couldn''t find a configuration file' | ||||
|                 return 0 | ||||
|             endif | ||||
|  | ||||
|             return 1 | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return 0 | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#eslint#Handle(buffer, lines) abort | ||||
|     if s:CheckForBadConfig(a:buffer, a:lines) | ||||
|         return [{ | ||||
|         \   'lnum': 1, | ||||
|         \   'text': 'eslint configuration error (type :ALEDetail for more information)', | ||||
|         \   'detail': join(a:lines, "\n"), | ||||
|         \}] | ||||
|     endif | ||||
|  | ||||
|     " Matches patterns line the following: | ||||
|     " | ||||
|     " /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle] | ||||
|     " /path/to/some-filename.js:56:41: Missing semicolon. [Error/semi] | ||||
|     let l:pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\) \[\(.\+\)\]$' | ||||
|     " This second pattern matches lines like the following: | ||||
|     " | ||||
|     " /path/to/some-filename.js:13:3: Parsing error: Unexpected token | ||||
|     let l:parsing_pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\)$' | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, [l:pattern, l:parsing_pattern]) | ||||
|         let l:text = l:match[3] | ||||
|  | ||||
|         if ale#Var(a:buffer, 'javascript_eslint_suppress_eslintignore') | ||||
|             if l:text is# 'File ignored because of a matching ignore pattern. Use "--no-ignore" to override.' | ||||
|                 continue | ||||
|             endif | ||||
|         endif | ||||
|  | ||||
|         let l:obj = { | ||||
|         \   'lnum': l:match[1] + 0, | ||||
|         \   'col': l:match[2] + 0, | ||||
|         \   'text': l:text, | ||||
|         \   'type': 'E', | ||||
|         \} | ||||
|  | ||||
|         " Take the error type from the output if available. | ||||
|         let l:split_code = split(l:match[4], '/') | ||||
|  | ||||
|         if get(l:split_code, 0, '') is# 'Warning' | ||||
|             let l:obj.type = 'W' | ||||
|         endif | ||||
|  | ||||
|         " The code can be something like 'Error/foo/bar', or just 'Error' | ||||
|         if !empty(get(l:split_code, 1)) | ||||
|             let l:obj.code = join(l:split_code[1:], '/') | ||||
|         endif | ||||
|  | ||||
|         for l:col_match in ale#util#GetMatches(l:text, s:col_end_patterns) | ||||
|             let l:obj.end_col = l:obj.col + len(l:col_match[1]) - 1 | ||||
|         endfor | ||||
|  | ||||
|         call add(l:output, l:obj) | ||||
|     endfor | ||||
|  | ||||
|     if expand('#' . a:buffer . ':t') =~? '\.tsx\?$' | ||||
|         call s:AddHintsForTypeScriptParsingErrors(l:output) | ||||
|     endif | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										47
									
								
								sources_non_forked/ale/autoload/ale/handlers/flawfinder.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								sources_non_forked/ale/autoload/ale/handlers/flawfinder.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| " Author: Christian Gibbons <cgibbons@gmu.edu> | ||||
| " Description: This file defines a handler function that should work for the | ||||
| " flawfinder format with the -CDQS flags. | ||||
|  | ||||
| " Swiped this function from the GCC handler. Not sure if needed, but doesn't | ||||
| " hurt to have it. | ||||
| function! s:RemoveUnicodeQuotes(text) abort | ||||
|     let l:text = a:text | ||||
|     let l:text = substitute(l:text, '[`´‘’]', '''', 'g') | ||||
|     let l:text = substitute(l:text, '\v\\u2018([^\\]+)\\u2019', '''\1''', 'g') | ||||
|     let l:text = substitute(l:text, '[“”]', '"', 'g') | ||||
|  | ||||
|     return l:text | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#flawfinder#HandleFlawfinderFormat(buffer, lines) abort | ||||
|     " Look for lines like the following. | ||||
|     " | ||||
|     " <stdin>:12:4:  [2] (buffer) char:Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120).  Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length. | ||||
|     " <stdin>:31:4:  [1] (buffer) strncpy:Easily used incorrectly; doesn't always \0-terminate or check for invalid pointers [MS-banned] (CWE-120). | ||||
|     let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ( \[[0-5]\] [^:]+):(.+)$' | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, l:pattern) | ||||
|         " Use severity level to determine if it should be considered a warning | ||||
|         " or error. | ||||
|         let l:severity = str2nr(matchstr(split(l:match[4])[0], '[0-5]')) | ||||
|  | ||||
|         let l:item = { | ||||
|         \   'lnum': str2nr(l:match[2]), | ||||
|         \   'col': str2nr(l:match[3]), | ||||
|         \   'type': (l:severity < ale#Var(a:buffer, 'c_flawfinder_error_severity')) | ||||
|             \   ? 'W' : 'E', | ||||
|         \   'text': s:RemoveUnicodeQuotes(join(split(l:match[4])[1:]) . ': ' . l:match[5]), | ||||
|         \} | ||||
|  | ||||
|         " If the filename is something like <stdin>, <nofile> or -, then | ||||
|         " this is an error for the file we checked. | ||||
|         if l:match[1] isnot# '-' && l:match[1][0] isnot# '<' | ||||
|             let l:item['filename'] = l:match[1] | ||||
|         endif | ||||
|  | ||||
|         call add(l:output, l:item) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										25
									
								
								sources_non_forked/ale/autoload/ale/handlers/gawk.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								sources_non_forked/ale/autoload/ale/handlers/gawk.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| " Author: Anthony DeDominic <adedomin@gmail.com> | ||||
| " Description: Handle output from gawk's --lint option | ||||
|  | ||||
| function! ale#handlers#gawk#HandleGawkFormat(buffer, lines) abort | ||||
|     " Look for lines like the following: | ||||
|     " gawk: /tmp/v0fddXz/1/something.awk:1: ^ invalid char ''' in expression | ||||
|     let l:pattern = '^.\{-}:\(\d\+\):\s\+\(warning:\|\^\)\s*\(.*\)' | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, l:pattern) | ||||
|         let l:ecode = 'E' | ||||
|         if l:match[2] is? 'warning:' | ||||
|             let l:ecode = 'W' | ||||
|         endif | ||||
|         call add(l:output, { | ||||
|         \   'lnum': l:match[1] + 0, | ||||
|         \   'col': 0, | ||||
|         \   'text': l:match[3], | ||||
|         \   'code': 0, | ||||
|         \   'type': l:ecode, | ||||
|         \}) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										69
									
								
								sources_non_forked/ale/autoload/ale/handlers/gcc.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								sources_non_forked/ale/autoload/ale/handlers/gcc.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| scriptencoding utf-8 | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: This file defines a handler function which ought to work for | ||||
| " any program which outputs errors in the format that GCC uses. | ||||
|  | ||||
| let s:pragma_error = '#pragma once in main file' | ||||
|  | ||||
| function! s:IsHeaderFile(filename) abort | ||||
|     return a:filename =~? '\v\.(h|hpp)$' | ||||
| endfunction | ||||
|  | ||||
| function! s:RemoveUnicodeQuotes(text) abort | ||||
|     let l:text = a:text | ||||
|     let l:text = substitute(l:text, '[`´‘’]', '''', 'g') | ||||
|     let l:text = substitute(l:text, '\v\\u2018([^\\]+)\\u2019', '''\1''', 'g') | ||||
|     let l:text = substitute(l:text, '[“”]', '"', 'g') | ||||
|  | ||||
|     return l:text | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort | ||||
|     " Look for lines like the following. | ||||
|     " | ||||
|     " <stdin>:8:5: warning: conversion lacks type at end of format [-Wformat=] | ||||
|     " <stdin>:10:27: error: invalid operands to binary - (have ‘int’ and ‘char *’) | ||||
|     " -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004] | ||||
|     let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$' | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, l:pattern) | ||||
|         " Filter out the pragma errors | ||||
|         if s:IsHeaderFile(bufname(bufnr(''))) | ||||
|         \&& l:match[5][:len(s:pragma_error) - 1] is# s:pragma_error | ||||
|             continue | ||||
|         endif | ||||
|  | ||||
|         " If the 'error type' is a note, make it detail related to | ||||
|         " the previous error parsed in output | ||||
|         if l:match[4] is# 'note' | ||||
|             if !empty(l:output) | ||||
|                 let l:output[-1]['detail'] = | ||||
|                 \   get(l:output[-1], 'detail', '') | ||||
|                 \   . s:RemoveUnicodeQuotes(l:match[0]) . "\n" | ||||
|             endif | ||||
|  | ||||
|             continue | ||||
|         endif | ||||
|  | ||||
|         let l:item = { | ||||
|         \   'lnum': str2nr(l:match[2]), | ||||
|         \   'type': l:match[4] is# 'error' ? 'E' : 'W', | ||||
|         \   'text': s:RemoveUnicodeQuotes(l:match[5]), | ||||
|         \} | ||||
|  | ||||
|         if !empty(l:match[3]) | ||||
|             let l:item.col = str2nr(l:match[3]) | ||||
|         endif | ||||
|  | ||||
|         " If the filename is something like <stdin>, <nofile> or -, then | ||||
|         " this is an error for the file we checked. | ||||
|         if l:match[1] isnot# '-' && l:match[1][0] isnot# '<' | ||||
|             let l:item['filename'] = l:match[1] | ||||
|         endif | ||||
|  | ||||
|         call add(l:output, l:item) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										25
									
								
								sources_non_forked/ale/autoload/ale/handlers/go.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								sources_non_forked/ale/autoload/ale/handlers/go.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| " Author: neersighted <bjorn@neersighted.com> | ||||
| " Description: go vet for Go files | ||||
| " | ||||
| " Author: John Eikenberry <jae@zhar.net> | ||||
| " Description: updated to work with go1.10 | ||||
| " | ||||
| " Author: Ben Paxton <ben@gn32.uk> | ||||
| " Description: moved to generic Golang file from govet | ||||
|  | ||||
| function! ale#handlers#go#Handler(buffer, lines) abort | ||||
|     let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?:? ?(.+)$' | ||||
|     let l:output = [] | ||||
|     let l:dir = expand('#' . a:buffer . ':p:h') | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, l:pattern) | ||||
|         call add(l:output, { | ||||
|         \   'filename': ale#path#GetAbsPath(l:dir, l:match[1]), | ||||
|         \   'lnum': l:match[2] + 0, | ||||
|         \   'col': l:match[3] + 0, | ||||
|         \   'text': l:match[4], | ||||
|         \   'type': 'E', | ||||
|         \}) | ||||
|     endfor | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										91
									
								
								sources_non_forked/ale/autoload/ale/handlers/haskell.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								sources_non_forked/ale/autoload/ale/handlers/haskell.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Error handling for the format GHC outputs. | ||||
|  | ||||
| " Remember the directory used for temporary files for Vim. | ||||
| let s:temp_dir = fnamemodify(tempname(), ':h') | ||||
| " Build part of a regular expression for matching ALE temporary filenames. | ||||
| let s:temp_regex_prefix = | ||||
| \   '\M' | ||||
| \   . substitute(s:temp_dir, '\\', '\\\\', 'g') | ||||
| \   . '\.\{-}' | ||||
|  | ||||
| function! ale#handlers#haskell#HandleGHCFormat(buffer, lines) abort | ||||
|     " Look for lines like the following. | ||||
|     " | ||||
|     "Appoint/Lib.hs:8:1: warning: | ||||
|     "Appoint/Lib.hs:8:1: | ||||
|     let l:basename = expand('#' . a:buffer . ':t') | ||||
|     " Build a complete regular expression for replacing temporary filenames | ||||
|     " in Haskell error messages with the basename for this file. | ||||
|     let l:temp_filename_regex = s:temp_regex_prefix . l:basename | ||||
|  | ||||
|     let l:pattern = '\v^\s*([a-zA-Z]?:?[^:]+):(\d+):(\d+):(.*)?$' | ||||
|     let l:output = [] | ||||
|  | ||||
|     let l:corrected_lines = [] | ||||
|  | ||||
|     " Group the lines into smaller lists. | ||||
|     for l:line in a:lines | ||||
|         if len(matchlist(l:line, l:pattern)) > 0 | ||||
|             call add(l:corrected_lines, [l:line]) | ||||
|         elseif l:line is# '' | ||||
|             call add(l:corrected_lines, [l:line]) | ||||
|         elseif len(l:corrected_lines) > 0 | ||||
|             call add(l:corrected_lines[-1], l:line) | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     for l:line_list in l:corrected_lines | ||||
|         " Join the smaller lists into one large line to parse. | ||||
|         let l:line = l:line_list[0] | ||||
|  | ||||
|         for l:extra_line in l:line_list[1:] | ||||
|             let l:line .= substitute(l:extra_line, '\v^\s+', ' ', '') | ||||
|         endfor | ||||
|  | ||||
|         let l:match = matchlist(l:line, l:pattern) | ||||
|  | ||||
|         if len(l:match) == 0 | ||||
|             continue | ||||
|         endif | ||||
|  | ||||
|         if !ale#path#IsBufferPath(a:buffer, l:match[1]) | ||||
|             continue | ||||
|         endif | ||||
|  | ||||
|         let l:errors = matchlist(l:match[4], '\v([wW]arning|[eE]rror): ?(.*)') | ||||
|  | ||||
|         if len(l:errors) > 0 | ||||
|           let l:ghc_type = l:errors[1] | ||||
|           let l:text = l:errors[2] | ||||
|         else | ||||
|           let l:ghc_type = '' | ||||
|           let l:text = l:match[4][:0] is# ' ' ? l:match[4][1:] : l:match[4] | ||||
|         endif | ||||
|  | ||||
|         if l:ghc_type is? 'Warning' | ||||
|             let l:type = 'W' | ||||
|         else | ||||
|             let l:type = 'E' | ||||
|         endif | ||||
|  | ||||
|         " Replace temporary filenames in problem messages with the basename | ||||
|         let l:text = substitute(l:text, l:temp_filename_regex, l:basename, 'g') | ||||
|  | ||||
|         let l:item = { | ||||
|         \   'lnum': l:match[2] + 0, | ||||
|         \   'col': l:match[3] + 0, | ||||
|         \   'text': l:text, | ||||
|         \   'type': l:type, | ||||
|         \} | ||||
|  | ||||
|         " Include extra lines as details if they are there. | ||||
|         if len(l:line_list) > 1 | ||||
|             let l:item.detail = join(l:line_list[1:], "\n") | ||||
|         endif | ||||
|  | ||||
|         call add(l:output, l:item) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
| @ -0,0 +1,17 @@ | ||||
| " Author: Ty-Lucas Kelley <tylucaskelley@gmail.com> | ||||
| " Description: Adds support for markdownlint | ||||
|  | ||||
| function! ale#handlers#markdownlint#Handle(buffer, lines) abort | ||||
|     let l:pattern=': \(\d*\): \(MD\d\{3}\)\(\/\)\([A-Za-z0-9-]\+\)\(.*\)$' | ||||
|     let l:output=[] | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, l:pattern) | ||||
|         call add(l:output, { | ||||
|             \ 'lnum': l:match[1] + 0, | ||||
|             \ 'text': '(' . l:match[2] . l:match[3] . l:match[4] . ')' . l:match[5], | ||||
|             \ 'type': 'W', | ||||
|         \ }) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										25
									
								
								sources_non_forked/ale/autoload/ale/handlers/ols.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								sources_non_forked/ale/autoload/ale/handlers/ols.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| " Author: Michael Jungo <michaeljungo92@gmail.com> | ||||
| " Description: Handlers for the OCaml language server | ||||
|  | ||||
| function! ale#handlers#ols#GetExecutable(buffer) abort | ||||
|     let l:ols_setting = ale#handlers#ols#GetLanguage(a:buffer) . '_ols' | ||||
|     return ale#node#FindExecutable(a:buffer, l:ols_setting, [ | ||||
|     \   'node_modules/.bin/ocaml-language-server', | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#ols#GetCommand(buffer) abort | ||||
|     let l:executable = ale#handlers#ols#GetExecutable(a:buffer) | ||||
|  | ||||
|     return ale#node#Executable(a:buffer, l:executable) . ' --stdio' | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#ols#GetLanguage(buffer) abort | ||||
|     return getbufvar(a:buffer, '&filetype') | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#ols#GetProjectRoot(buffer) abort | ||||
|     let l:merlin_file = ale#path#FindNearestFile(a:buffer, '.merlin') | ||||
|  | ||||
|     return !empty(l:merlin_file) ? fnamemodify(l:merlin_file, ':h') : '' | ||||
| endfunction | ||||
							
								
								
									
										34
									
								
								sources_non_forked/ale/autoload/ale/handlers/pony.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								sources_non_forked/ale/autoload/ale/handlers/pony.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| scriptencoding utf-8 | ||||
| " Description: This file defines a handler function which ought to work for | ||||
| " any program which outputs errors in the format that ponyc uses. | ||||
|  | ||||
| function! s:RemoveUnicodeQuotes(text) abort | ||||
|     let l:text = a:text | ||||
|     let l:text = substitute(l:text, '[`´‘’]', '''', 'g') | ||||
|     let l:text = substitute(l:text, '\v\\u2018([^\\]+)\\u2019', '''\1''', 'g') | ||||
|     let l:text = substitute(l:text, '[“”]', '"', 'g') | ||||
|  | ||||
|     return l:text | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#pony#HandlePonycFormat(buffer, lines) abort | ||||
|     " Look for lines like the following. | ||||
|     " /home/code/pony/classes/Wombat.pony:22:30: can't lookup private fields from outside the type | ||||
|  | ||||
|     let l:pattern = '\v^([^:]+):(\d+):(\d+)?:? (.+)$' | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, l:pattern) | ||||
|         let l:item = { | ||||
|         \   'filename': l:match[1], | ||||
|         \   'lnum': str2nr(l:match[2]), | ||||
|         \   'col': str2nr(l:match[3]), | ||||
|         \   'type': 'E', | ||||
|         \   'text': s:RemoveUnicodeQuotes(l:match[4]), | ||||
|         \} | ||||
|  | ||||
|         call add(l:output, l:item) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
| @ -0,0 +1,6 @@ | ||||
| call ale#Set('ruby_rails_best_practices_options', '') | ||||
| call ale#Set('ruby_rails_best_practices_executable', 'rails_best_practices') | ||||
|  | ||||
| function! ale#handlers#rails_best_practices#GetExecutable(buffer) abort | ||||
|     return ale#Var(a:buffer, 'ruby_rails_best_practices_executable') | ||||
| endfunction | ||||
							
								
								
									
										56
									
								
								sources_non_forked/ale/autoload/ale/handlers/redpen.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								sources_non_forked/ale/autoload/ale/handlers/redpen.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| " Author: rhysd https://rhysd.github.io | ||||
| " Description: Redpen, a proofreading tool (http://redpen.cc) | ||||
|  | ||||
| function! ale#handlers#redpen#HandleRedpenOutput(buffer, lines) abort | ||||
|     " Only one file was passed to redpen. So response array has only one | ||||
|     " element. | ||||
|     let l:res = json_decode(join(a:lines))[0] | ||||
|     let l:output = [] | ||||
|     for l:err in l:res.errors | ||||
|         let l:item = { | ||||
|         \   'text': l:err.message, | ||||
|         \   'type': 'W', | ||||
|         \   'code': l:err.validator, | ||||
|         \} | ||||
|         if has_key(l:err, 'startPosition') | ||||
|             let l:item.lnum = l:err.startPosition.lineNum | ||||
|             let l:item.col = l:err.startPosition.offset + 1 | ||||
|             if has_key(l:err, 'endPosition') | ||||
|                 let l:item.end_lnum = l:err.endPosition.lineNum | ||||
|                 let l:item.end_col = l:err.endPosition.offset | ||||
|             endif | ||||
|         else | ||||
|             " Fallback to a whole sentence region when a region is not | ||||
|             " specified by the error. | ||||
|             let l:item.lnum = l:err.lineNum | ||||
|             let l:item.col = l:err.sentenceStartColumnNum + 1 | ||||
|         endif | ||||
|  | ||||
|         " Adjust column number for multibyte string | ||||
|         let l:line = getline(l:item.lnum) | ||||
|         if l:line is# '' | ||||
|             let l:line = l:err.sentence | ||||
|         endif | ||||
|         let l:line = split(l:line, '\zs') | ||||
|  | ||||
|         if l:item.col >= 2 | ||||
|             let l:col = 0 | ||||
|             for l:strlen in map(l:line[0:(l:item.col - 2)], 'strlen(v:val)') | ||||
|                 let l:col = l:col + l:strlen | ||||
|             endfor | ||||
|             let l:item.col = l:col + 1 | ||||
|         endif | ||||
|  | ||||
|         if has_key(l:item, 'end_col') | ||||
|             let l:col = 0 | ||||
|             for l:strlen in map(l:line[0:(l:item.end_col - 1)], 'strlen(v:val)') | ||||
|                 let l:col = l:col + l:strlen | ||||
|             endfor | ||||
|             let l:item.end_col = l:col | ||||
|         endif | ||||
|  | ||||
|         call add(l:output, l:item) | ||||
|     endfor | ||||
|     return l:output | ||||
| endfunction | ||||
|  | ||||
							
								
								
									
										6
									
								
								sources_non_forked/ale/autoload/ale/handlers/rubocop.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								sources_non_forked/ale/autoload/ale/handlers/rubocop.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| call ale#Set('ruby_rubocop_options', '') | ||||
| call ale#Set('ruby_rubocop_executable', 'rubocop') | ||||
|  | ||||
| function! ale#handlers#rubocop#GetExecutable(buffer) abort | ||||
|     return ale#Var(a:buffer, 'ruby_rubocop_executable') | ||||
| endfunction | ||||
							
								
								
									
										37
									
								
								sources_non_forked/ale/autoload/ale/handlers/ruby.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								sources_non_forked/ale/autoload/ale/handlers/ruby.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| " Author: Brandon Roehl - https://github.com/BrandonRoehl, Matthias Guenther https://wikimatze.de | ||||
| " | ||||
| " Description: This file implements handlers specific to Ruby. | ||||
|  | ||||
| function! s:HandleSyntaxError(buffer, lines) abort | ||||
|     " Matches patterns line the following: | ||||
|     " | ||||
|     " test.rb:3: warning: parentheses after method name is interpreted as an argument list, not a decomposed argument | ||||
|     " test.rb:8: syntax error, unexpected keyword_end, expecting end-of-input | ||||
|     let l:pattern = '\v^.+:(\d+): (warning: )?(.+)$' | ||||
|     let l:column = '\v^(\s+)\^$' | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:line in a:lines | ||||
|         let l:match = matchlist(l:line, l:pattern) | ||||
|         if len(l:match) == 0 | ||||
|             let l:match = matchlist(l:line, l:column) | ||||
|             if len(l:match) != 0 | ||||
|                 let l:output[len(l:output) - 1]['col'] = len(l:match[1]) | ||||
|             endif | ||||
|         else | ||||
|             call add(l:output, { | ||||
|             \   'lnum': l:match[1] + 0, | ||||
|             \   'col': 0, | ||||
|             \   'text': l:match[2] . l:match[3], | ||||
|             \   'type': empty(l:match[2]) ? 'E' : 'W', | ||||
|             \}) | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#ruby#HandleSyntaxErrors(buffer, lines) abort | ||||
|     return s:HandleSyntaxError(a:buffer, a:lines) | ||||
| endfunction | ||||
|  | ||||
							
								
								
									
										64
									
								
								sources_non_forked/ale/autoload/ale/handlers/rust.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								sources_non_forked/ale/autoload/ale/handlers/rust.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| " Author: Daniel Schemala <istjanichtzufassen@gmail.com>, | ||||
| "   w0rp <devw0rp@gmail.com> | ||||
| " | ||||
| " Description: This file implements handlers specific to Rust. | ||||
|  | ||||
| if !exists('g:ale_rust_ignore_error_codes') | ||||
|     let g:ale_rust_ignore_error_codes = [] | ||||
| endif | ||||
|  | ||||
| function! s:FindSpan(buffer, span) abort | ||||
|     if ale#path#IsBufferPath(a:buffer, a:span.file_name) || a:span.file_name is# '<anon>' | ||||
|         return a:span | ||||
|     endif | ||||
|  | ||||
|     " Search inside the expansion of an error, as the problem for this buffer | ||||
|     " could lie inside a nested object. | ||||
|     if !empty(get(a:span, 'expansion', v:null)) | ||||
|         return s:FindSpan(a:buffer, a:span.expansion.span) | ||||
|     endif | ||||
|  | ||||
|     return {} | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#rust#HandleRustErrors(buffer, lines) abort | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:errorline in a:lines | ||||
|         " ignore everything that is not JSON | ||||
|         if l:errorline !~# '^{' | ||||
|             continue | ||||
|         endif | ||||
|  | ||||
|         let l:error = json_decode(l:errorline) | ||||
|  | ||||
|         if has_key(l:error, 'message') && type(l:error.message) == type({}) | ||||
|             let l:error = l:error.message | ||||
|         endif | ||||
|  | ||||
|         if !has_key(l:error, 'code') | ||||
|             continue | ||||
|         endif | ||||
|  | ||||
|         if !empty(l:error.code) && index(g:ale_rust_ignore_error_codes, l:error.code.code) > -1 | ||||
|             continue | ||||
|         endif | ||||
|  | ||||
|         for l:root_span in l:error.spans | ||||
|             let l:span = s:FindSpan(a:buffer, l:root_span) | ||||
|  | ||||
|             if !empty(l:span) | ||||
|                 call add(l:output, { | ||||
|                 \   'lnum': l:span.line_start, | ||||
|                 \   'end_lnum': l:span.line_end, | ||||
|                 \   'col': l:span.column_start, | ||||
|                 \   'end_col': l:span.column_end, | ||||
|                 \   'text': empty(l:span.label) ? l:error.message : printf('%s: %s', l:error.message, l:span.label), | ||||
|                 \   'type': toupper(l:error.level[0]), | ||||
|                 \}) | ||||
|             endif | ||||
|         endfor | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										20
									
								
								sources_non_forked/ale/autoload/ale/handlers/sh.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								sources_non_forked/ale/autoload/ale/handlers/sh.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
|  | ||||
| " Get the shell type for a buffer, based on the hashbang line. | ||||
| function! ale#handlers#sh#GetShellType(buffer) abort | ||||
|     let l:bang_line = get(getbufline(a:buffer, 1), 0, '') | ||||
|  | ||||
|     " Take the shell executable from the hashbang, if we can. | ||||
|     if l:bang_line[:1] is# '#!' | ||||
|         " Remove options like -e, etc. | ||||
|         let l:command = substitute(l:bang_line, ' --\?[a-zA-Z0-9]\+', '', 'g') | ||||
|  | ||||
|         for l:possible_shell in ['bash', 'dash', 'ash', 'tcsh', 'csh', 'zsh', 'sh'] | ||||
|             if l:command =~# l:possible_shell . '\s*$' | ||||
|                 return l:possible_shell | ||||
|             endif | ||||
|         endfor | ||||
|     endif | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
							
								
								
									
										92
									
								
								sources_non_forked/ale/autoload/ale/handlers/sml.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								sources_non_forked/ale/autoload/ale/handlers/sml.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | ||||
| " Author: Jake Zimmerman <jake@zimmerman.io> | ||||
| " Description: Shared functions for SML linters | ||||
|  | ||||
| " The glob to use for finding the .cm file. | ||||
| " | ||||
| " See :help ale-sml-smlnj for more information. | ||||
| call ale#Set('sml_smlnj_cm_file', '*.cm') | ||||
|  | ||||
| function! ale#handlers#sml#GetCmFile(buffer) abort | ||||
|     let l:pattern = ale#Var(a:buffer, 'sml_smlnj_cm_file') | ||||
|     let l:as_list = 1 | ||||
|  | ||||
|     let l:cmfile = '' | ||||
|     for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) | ||||
|         let l:results = glob(l:path . '/' . l:pattern, 0, l:as_list) | ||||
|         if len(l:results) > 0 | ||||
|             " If there is more than one CM file, we take the first one | ||||
|             " See :help ale-sml-smlnj for how to configure this. | ||||
|             let l:cmfile = l:results[0] | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return l:cmfile | ||||
| endfunction | ||||
|  | ||||
| " Only one of smlnj or smlnj-cm can be enabled at a time. | ||||
| " executable_callback is called before *every* lint attempt | ||||
| function! s:GetExecutable(buffer, source) abort | ||||
|     if ale#handlers#sml#GetCmFile(a:buffer) is# '' | ||||
|         " No CM file found; only allow single-file mode to be enabled | ||||
|         if a:source is# 'smlnj-file' | ||||
|             return 'sml' | ||||
|         elseif a:source is# 'smlnj-cm' | ||||
|             return '' | ||||
|         endif | ||||
|     else | ||||
|         " Found a CM file; only allow cm-file mode to be enabled | ||||
|         if a:source is# 'smlnj-file' | ||||
|             return '' | ||||
|         elseif a:source is# 'smlnj-cm' | ||||
|             return 'sml' | ||||
|         endif | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#sml#GetExecutableSmlnjCm(buffer) abort | ||||
|     return s:GetExecutable(a:buffer, 'smlnj-cm') | ||||
| endfunction | ||||
| function! ale#handlers#sml#GetExecutableSmlnjFile(buffer) abort | ||||
|     return s:GetExecutable(a:buffer, 'smlnj-file') | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#sml#Handle(buffer, lines) abort | ||||
|     " Try to match basic sml errors | ||||
|     " TODO(jez) We can get better errorfmt strings from Syntastic | ||||
|  | ||||
|     let l:out = [] | ||||
|     let l:pattern = '^.*\:\([0-9\.]\+\)\ \(\w\+\)\:\ \(.*\)' | ||||
|     let l:pattern2 = '^.*\:\([0-9]\+\)\.\?\([0-9]\+\).* \(\(Warning\|Error\): .*\)' | ||||
|  | ||||
|     for l:line in a:lines | ||||
|         let l:match2 = matchlist(l:line, l:pattern2) | ||||
|  | ||||
|         if len(l:match2) != 0 | ||||
|           call add(l:out, { | ||||
|           \   'bufnr': a:buffer, | ||||
|           \   'lnum': l:match2[1] + 0, | ||||
|           \   'col' : l:match2[2] - 1, | ||||
|           \   'text': l:match2[3], | ||||
|           \   'type': l:match2[3] =~# '^Warning' ? 'W' : 'E', | ||||
|           \}) | ||||
|           continue | ||||
|         endif | ||||
|  | ||||
|         let l:match = matchlist(l:line, l:pattern) | ||||
|  | ||||
|         if len(l:match) != 0 | ||||
|           call add(l:out, { | ||||
|           \   'bufnr': a:buffer, | ||||
|           \   'lnum': l:match[1] + 0, | ||||
|           \   'text': l:match[2] . ': ' . l:match[3], | ||||
|           \   'type': l:match[2] is# 'error' ? 'E' : 'W', | ||||
|           \}) | ||||
|           continue | ||||
|         endif | ||||
|  | ||||
|     endfor | ||||
|  | ||||
|     return l:out | ||||
| endfunction | ||||
|  | ||||
| " vim:ts=4:sts=4:sw=4 | ||||
							
								
								
									
										39
									
								
								sources_non_forked/ale/autoload/ale/handlers/textlint.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								sources_non_forked/ale/autoload/ale/handlers/textlint.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| " Author: tokida https://rouger.info, Yasuhiro Kiyota <yasuhiroki.duck@gmail.com> | ||||
| " Description: textlint, a proofreading tool (https://textlint.github.io/) | ||||
|  | ||||
| call ale#Set('textlint_executable', 'textlint') | ||||
| call ale#Set('textlint_use_global', 0) | ||||
| call ale#Set('textlint_options', '') | ||||
|  | ||||
| function! ale#handlers#textlint#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'textlint', [ | ||||
|     \   'node_modules/.bin/textlint', | ||||
|     \   'node_modules/textlint/bin/textlint.js', | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#textlint#GetCommand(buffer) abort | ||||
|     let l:executable = ale#handlers#textlint#GetExecutable(a:buffer) | ||||
|     let l:options = ale#Var(a:buffer, 'textlint_options') | ||||
|  | ||||
|     return ale#node#Executable(a:buffer, l:executable) | ||||
|     \    . (!empty(l:options) ? ' ' . l:options : '') | ||||
|     \    . ' -f json --stdin --stdin-filename %s' | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#textlint#HandleTextlintOutput(buffer, lines) abort | ||||
|     let l:res = get(ale#util#FuzzyJSONDecode(a:lines, []), 0, {'messages': []}) | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:err in l:res.messages | ||||
|         call add(l:output, { | ||||
|         \   'text': l:err.message, | ||||
|         \   'type': 'W', | ||||
|         \   'code': l:err.ruleId, | ||||
|         \   'lnum': l:err.line, | ||||
|         \   'col' : l:err.column | ||||
|         \}) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										26
									
								
								sources_non_forked/ale/autoload/ale/handlers/unix.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								sources_non_forked/ale/autoload/ale/handlers/unix.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Error handling for errors in a Unix format. | ||||
|  | ||||
| function! s:HandleUnixFormat(buffer, lines, type) abort | ||||
|     let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):?(\d+)?:? ?(.+)$' | ||||
|     let l:output = [] | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, l:pattern) | ||||
|         call add(l:output, { | ||||
|         \   'lnum': l:match[1] + 0, | ||||
|         \   'col': l:match[2] + 0, | ||||
|         \   'text': l:match[3], | ||||
|         \   'type': a:type, | ||||
|         \}) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#unix#HandleAsError(buffer, lines) abort | ||||
|     return s:HandleUnixFormat(a:buffer, a:lines, 'E') | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#unix#HandleAsWarning(buffer, lines) abort | ||||
|     return s:HandleUnixFormat(a:buffer, a:lines, 'W') | ||||
| endfunction | ||||
							
								
								
									
										38
									
								
								sources_non_forked/ale/autoload/ale/handlers/vale.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								sources_non_forked/ale/autoload/ale/handlers/vale.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| " Author: Johannes Wienke <languitar@semipol.de> | ||||
| " Description: output handler for the vale JSON format | ||||
|  | ||||
| function! ale#handlers#vale#GetType(severity) abort | ||||
|     if a:severity is? 'warning' | ||||
|         return 'W' | ||||
|     elseif a:severity is? 'suggestion' | ||||
|         return 'I' | ||||
|     endif | ||||
|  | ||||
|     return 'E' | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#vale#Handle(buffer, lines) abort | ||||
|     try | ||||
|         let l:errors = json_decode(join(a:lines, '')) | ||||
|     catch | ||||
|         return [] | ||||
|     endtry | ||||
|  | ||||
|     if empty(l:errors) | ||||
|         return [] | ||||
|     endif | ||||
|  | ||||
|     let l:output = [] | ||||
|     for l:error in l:errors[keys(l:errors)[0]] | ||||
|         call add(l:output, { | ||||
|         \   'lnum': l:error['Line'], | ||||
|         \   'col': l:error['Span'][0], | ||||
|         \   'end_col': l:error['Span'][1], | ||||
|         \   'code': l:error['Check'], | ||||
|         \   'text': l:error['Message'], | ||||
|         \   'type': ale#handlers#vale#GetType(l:error['Severity']), | ||||
|         \}) | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										61
									
								
								sources_non_forked/ale/autoload/ale/handlers/writegood.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								sources_non_forked/ale/autoload/ale/handlers/writegood.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| " Author: Sumner Evans <sumner.evans98@gmail.com> | ||||
| " Description: Error handling for errors in the write-good format. | ||||
|  | ||||
| function! ale#handlers#writegood#ResetOptions() abort | ||||
|     call ale#Set('writegood_options', '') | ||||
|     call ale#Set('writegood_executable', 'write-good') | ||||
|     call ale#Set('writegood_use_global', 0) | ||||
| endfunction | ||||
|  | ||||
| " Reset the options so the tests can test how they are set. | ||||
| call ale#handlers#writegood#ResetOptions() | ||||
|  | ||||
| function! ale#handlers#writegood#GetExecutable(buffer) abort | ||||
|     return ale#node#FindExecutable(a:buffer, 'writegood', [ | ||||
|     \   'node_modules/.bin/write-good', | ||||
|     \   'node_modules/write-good/bin/write-good.js', | ||||
|     \]) | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#writegood#GetCommand(buffer) abort | ||||
|     let l:executable = ale#handlers#writegood#GetExecutable(a:buffer) | ||||
|     let l:options = ale#Var(a:buffer, 'writegood_options') | ||||
|  | ||||
|     return ale#node#Executable(a:buffer, l:executable) | ||||
|     \   . (!empty(l:options) ? ' ' . l:options : '') | ||||
|     \   . ' %t' | ||||
| endfunction | ||||
|  | ||||
| function! ale#handlers#writegood#Handle(buffer, lines) abort | ||||
|     " Look for lines like the following. | ||||
|     " | ||||
|     " "it is" is wordy or unneeded on line 20 at column 53 | ||||
|     " "easily" can weaken meaning on line 154 at column 29 | ||||
|     let l:marks_pattern = '\v^ *(\^+) *$' | ||||
|     let l:pattern = '\v^(".*"\s.*)\son\sline\s(\d+)\sat\scolumn\s(\d+)$' | ||||
|     let l:output = [] | ||||
|     let l:last_len = 0 | ||||
|  | ||||
|     for l:match in ale#util#GetMatches(a:lines, [l:marks_pattern, l:pattern]) | ||||
|         if empty(l:match[2]) | ||||
|             let l:last_len = len(l:match[1]) | ||||
|         else | ||||
|             let l:col = l:match[3] + 1 | ||||
|  | ||||
|             " Add the linter error. Note that we need to add 1 to the col because | ||||
|             " write-good reports the column corresponding to the space before the | ||||
|             " offending word or phrase. | ||||
|             call add(l:output, { | ||||
|             \   'text': l:match[1], | ||||
|             \   'lnum': l:match[2] + 0, | ||||
|             \   'col': l:col, | ||||
|             \   'end_col': l:last_len ? (l:col + l:last_len - 1) : l:col, | ||||
|             \   'type': 'W', | ||||
|             \}) | ||||
|  | ||||
|             let l:last_len = 0 | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return l:output | ||||
| endfunction | ||||
							
								
								
									
										143
									
								
								sources_non_forked/ale/autoload/ale/highlight.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								sources_non_forked/ale/autoload/ale/highlight.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,143 @@ | ||||
| scriptencoding utf8 | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: This module implements error/warning highlighting. | ||||
|  | ||||
| if !hlexists('ALEError') | ||||
|     highlight link ALEError SpellBad | ||||
| endif | ||||
|  | ||||
| if !hlexists('ALEStyleError') | ||||
|     highlight link ALEStyleError ALEError | ||||
| endif | ||||
|  | ||||
| if !hlexists('ALEWarning') | ||||
|     highlight link ALEWarning SpellCap | ||||
| endif | ||||
|  | ||||
| if !hlexists('ALEStyleWarning') | ||||
|     highlight link ALEStyleWarning ALEWarning | ||||
| endif | ||||
|  | ||||
| if !hlexists('ALEInfo') | ||||
|     highlight link ALEInfo ALEWarning | ||||
| endif | ||||
|  | ||||
| " The maximum number of items for the second argument of matchaddpos() | ||||
| let s:MAX_POS_VALUES = 8 | ||||
| let s:MAX_COL_SIZE = 1073741824 " pow(2, 30) | ||||
|  | ||||
| function! ale#highlight#CreatePositions(line, col, end_line, end_col) abort | ||||
|     if a:line >= a:end_line | ||||
|         " For single lines, just return the one position. | ||||
|         return [[[a:line, a:col, a:end_col - a:col + 1]]] | ||||
|     endif | ||||
|  | ||||
|     " Get positions from the first line at the first column, up to a large | ||||
|     " integer for highlighting up to the end of the line, followed by | ||||
|     " the lines in-between, for highlighting entire lines, and | ||||
|     " a highlight for the last line, up to the end column. | ||||
|     let l:all_positions = | ||||
|     \   [[a:line, a:col, s:MAX_COL_SIZE]] | ||||
|     \   + range(a:line + 1, a:end_line - 1) | ||||
|     \   + [[a:end_line, 1, a:end_col]] | ||||
|  | ||||
|     return map( | ||||
|     \   range(0, len(l:all_positions) - 1, s:MAX_POS_VALUES), | ||||
|     \   'l:all_positions[v:val : v:val + s:MAX_POS_VALUES - 1]', | ||||
|     \) | ||||
| endfunction | ||||
|  | ||||
| " Given a loclist for current items to highlight, remove all highlights | ||||
| " except these which have matching loclist item entries. | ||||
| function! ale#highlight#RemoveHighlights() abort | ||||
|     for l:match in getmatches() | ||||
|         if l:match.group =~# '^ALE' | ||||
|             call matchdelete(l:match.id) | ||||
|         endif | ||||
|     endfor | ||||
| endfunction | ||||
|  | ||||
| function! ale#highlight#UpdateHighlights() abort | ||||
|     let l:item_list = get(b:, 'ale_enabled', 1) && g:ale_enabled | ||||
|     \   ? get(b:, 'ale_highlight_items', []) | ||||
|     \   : [] | ||||
|  | ||||
|     call ale#highlight#RemoveHighlights() | ||||
|  | ||||
|     for l:item in l:item_list | ||||
|         if l:item.type is# 'W' | ||||
|             if get(l:item, 'sub_type', '') is# 'style' | ||||
|                 let l:group = 'ALEStyleWarning' | ||||
|             else | ||||
|                 let l:group = 'ALEWarning' | ||||
|             endif | ||||
|         elseif l:item.type is# 'I' | ||||
|             let l:group = 'ALEInfo' | ||||
|         elseif get(l:item, 'sub_type', '') is# 'style' | ||||
|             let l:group = 'ALEStyleError' | ||||
|         else | ||||
|             let l:group = 'ALEError' | ||||
|         endif | ||||
|  | ||||
|         let l:line = l:item.lnum | ||||
|         let l:col = l:item.col | ||||
|         let l:end_line = get(l:item, 'end_lnum', l:line) | ||||
|         let l:end_col = get(l:item, 'end_col', l:col) | ||||
|  | ||||
|         " Set all of the positions, which are chunked into Lists which | ||||
|         " are as large as will be accepted by matchaddpos. | ||||
|         call map( | ||||
|         \   ale#highlight#CreatePositions(l:line, l:col, l:end_line, l:end_col), | ||||
|         \   'matchaddpos(l:group, v:val)' | ||||
|         \) | ||||
|     endfor | ||||
|  | ||||
|     " If highlights are enabled and signs are not enabled, we should still | ||||
|     " offer line highlights by adding a separate set of highlights. | ||||
|     if !g:ale_set_signs | ||||
|         let l:available_groups = { | ||||
|         \   'ALEWarningLine': hlexists('ALEWarningLine'), | ||||
|         \   'ALEInfoLine': hlexists('ALEInfoLine'), | ||||
|         \   'ALEErrorLine': hlexists('ALEErrorLine'), | ||||
|         \} | ||||
|  | ||||
|         for l:item in l:item_list | ||||
|             if l:item.type is# 'W' | ||||
|                 let l:group = 'ALEWarningLine' | ||||
|             elseif l:item.type is# 'I' | ||||
|                 let l:group = 'ALEInfoLine' | ||||
|             else | ||||
|                 let l:group = 'ALEErrorLine' | ||||
|             endif | ||||
|  | ||||
|             if l:available_groups[l:group] | ||||
|                 call matchaddpos(l:group, [l:item.lnum]) | ||||
|             endif | ||||
|         endfor | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#highlight#BufferHidden(buffer) abort | ||||
|     " Remove highlights right away when buffers are hidden. | ||||
|     " They will be restored later when buffers are entered. | ||||
|     call ale#highlight#RemoveHighlights() | ||||
| endfunction | ||||
|  | ||||
| augroup ALEHighlightBufferGroup | ||||
|     autocmd! | ||||
|     autocmd BufEnter * call ale#highlight#UpdateHighlights() | ||||
|     autocmd BufHidden * call ale#highlight#BufferHidden(expand('<abuf>')) | ||||
| augroup END | ||||
|  | ||||
| function! ale#highlight#SetHighlights(buffer, loclist) abort | ||||
|     let l:new_list = getbufvar(a:buffer, 'ale_enabled', 1) && g:ale_enabled | ||||
|     \   ? filter(copy(a:loclist), 'v:val.bufnr == a:buffer && v:val.col > 0') | ||||
|     \   : [] | ||||
|  | ||||
|     " Set the list in the buffer variable. | ||||
|     call setbufvar(str2nr(a:buffer), 'ale_highlight_items', l:new_list) | ||||
|  | ||||
|     " Update highlights for the current buffer, which may or may not | ||||
|     " be the buffer we just set highlights for. | ||||
|     call ale#highlight#UpdateHighlights() | ||||
| endfunction | ||||
							
								
								
									
										59
									
								
								sources_non_forked/ale/autoload/ale/history.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								sources_non_forked/ale/autoload/ale/history.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Tools for managing command history | ||||
|  | ||||
| " Return a shallow copy of the command history for a given buffer number. | ||||
| function! ale#history#Get(buffer) abort | ||||
|     return copy(getbufvar(a:buffer, 'ale_history', [])) | ||||
| endfunction | ||||
|  | ||||
| function! ale#history#Add(buffer, status, job_id, command) abort | ||||
|     if g:ale_max_buffer_history_size <= 0 | ||||
|         " Don't save anything if the history isn't a positive number. | ||||
|         call setbufvar(a:buffer, 'ale_history', []) | ||||
|  | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let l:history = getbufvar(a:buffer, 'ale_history', []) | ||||
|  | ||||
|     " Remove the first item if we hit the max history size. | ||||
|     if len(l:history) >= g:ale_max_buffer_history_size | ||||
|         let l:history = l:history[1:] | ||||
|     endif | ||||
|  | ||||
|     call add(l:history, { | ||||
|     \   'status': a:status, | ||||
|     \   'job_id': a:job_id, | ||||
|     \   'command': a:command, | ||||
|     \}) | ||||
|  | ||||
|     call setbufvar(a:buffer, 'ale_history', l:history) | ||||
| endfunction | ||||
|  | ||||
| function! s:FindHistoryItem(buffer, job_id) abort | ||||
|     " Search backwards to find a matching job ID. IDs might be recycled, | ||||
|     " so finding the last one should be good enough. | ||||
|     for l:obj in reverse(ale#history#Get(a:buffer)) | ||||
|         if l:obj.job_id == a:job_id | ||||
|             return l:obj | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return {} | ||||
| endfunction | ||||
|  | ||||
| " Set an exit code for a command which finished. | ||||
| function! ale#history#SetExitCode(buffer, job_id, exit_code) abort | ||||
|     let l:obj = s:FindHistoryItem(a:buffer, a:job_id) | ||||
|  | ||||
|     " If we find a match, then set the code and status. | ||||
|     let l:obj.exit_code = a:exit_code | ||||
|     let l:obj.status = 'finished' | ||||
| endfunction | ||||
|  | ||||
| " Set the output for a command which finished. | ||||
| function! ale#history#RememberOutput(buffer, job_id, output) abort | ||||
|     let l:obj = s:FindHistoryItem(a:buffer, a:job_id) | ||||
|  | ||||
|     let l:obj.output = a:output | ||||
| endfunction | ||||
							
								
								
									
										341
									
								
								sources_non_forked/ale/autoload/ale/job.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										341
									
								
								sources_non_forked/ale/autoload/ale/job.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,341 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: APIs for working with Asynchronous jobs, with an API normalised | ||||
| " between Vim 8 and NeoVim. | ||||
| " | ||||
| " Important functions are described below. They are: | ||||
| " | ||||
| "   ale#job#Start(command, options) -> job_id | ||||
| "   ale#job#IsRunning(job_id) -> 1 if running, 0 otherwise. | ||||
| "   ale#job#Stop(job_id) | ||||
|  | ||||
| if !has_key(s:, 'job_map') | ||||
|     let s:job_map = {} | ||||
| endif | ||||
|  | ||||
| " A map from timer IDs to jobs, for tracking jobs that need to be killed | ||||
| " with SIGKILL if they don't terminate right away. | ||||
| if !has_key(s:, 'job_kill_timers') | ||||
|     let s:job_kill_timers = {} | ||||
| endif | ||||
|  | ||||
| function! s:KillHandler(timer) abort | ||||
|     let l:job = remove(s:job_kill_timers, a:timer) | ||||
|     call job_stop(l:job, 'kill') | ||||
| endfunction | ||||
|  | ||||
| " Note that jobs and IDs are the same thing on NeoVim. | ||||
| function! ale#job#JoinNeovimOutput(job, last_line, data, mode, callback) abort | ||||
|     if a:mode is# 'raw' | ||||
|         call a:callback(a:job, join(a:data, "\n")) | ||||
|         return '' | ||||
|     endif | ||||
|  | ||||
|     let l:lines = a:data[:-2] | ||||
|  | ||||
|     if len(a:data) > 1 | ||||
|         let l:lines[0] = a:last_line . l:lines[0] | ||||
|         let l:new_last_line = a:data[-1] | ||||
|     else | ||||
|         let l:new_last_line = a:last_line . get(a:data, 0, '') | ||||
|     endif | ||||
|  | ||||
|     for l:line in l:lines | ||||
|         call a:callback(a:job, l:line) | ||||
|     endfor | ||||
|  | ||||
|     return l:new_last_line | ||||
| endfunction | ||||
|  | ||||
| function! s:NeoVimCallback(job, data, event) abort | ||||
|     let l:info = s:job_map[a:job] | ||||
|  | ||||
|     if a:event is# 'stdout' | ||||
|         let l:info.out_cb_line = ale#job#JoinNeovimOutput( | ||||
|         \   a:job, | ||||
|         \   l:info.out_cb_line, | ||||
|         \   a:data, | ||||
|         \   l:info.mode, | ||||
|         \   ale#util#GetFunction(l:info.out_cb), | ||||
|         \) | ||||
|     elseif a:event is# 'stderr' | ||||
|         let l:info.err_cb_line = ale#job#JoinNeovimOutput( | ||||
|         \   a:job, | ||||
|         \   l:info.err_cb_line, | ||||
|         \   a:data, | ||||
|         \   l:info.mode, | ||||
|         \   ale#util#GetFunction(l:info.err_cb), | ||||
|         \) | ||||
|     else | ||||
|         if has_key(l:info, 'out_cb') && !empty(l:info.out_cb_line) | ||||
|             call ale#util#GetFunction(l:info.out_cb)(a:job, l:info.out_cb_line) | ||||
|         endif | ||||
|  | ||||
|         if has_key(l:info, 'err_cb') && !empty(l:info.err_cb_line) | ||||
|             call ale#util#GetFunction(l:info.err_cb)(a:job, l:info.err_cb_line) | ||||
|         endif | ||||
|  | ||||
|         try | ||||
|             call ale#util#GetFunction(l:info.exit_cb)(a:job, a:data) | ||||
|         finally | ||||
|             " Automatically forget about the job after it's done. | ||||
|             if has_key(s:job_map, a:job) | ||||
|                 call remove(s:job_map, a:job) | ||||
|             endif | ||||
|         endtry | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! s:VimOutputCallback(channel, data) abort | ||||
|     let l:job = ch_getjob(a:channel) | ||||
|     let l:job_id = ale#job#ParseVim8ProcessID(string(l:job)) | ||||
|  | ||||
|     " Only call the callbacks for jobs which are valid. | ||||
|     if l:job_id > 0 && has_key(s:job_map, l:job_id) | ||||
|         call ale#util#GetFunction(s:job_map[l:job_id].out_cb)(l:job_id, a:data) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! s:VimErrorCallback(channel, data) abort | ||||
|     let l:job = ch_getjob(a:channel) | ||||
|     let l:job_id = ale#job#ParseVim8ProcessID(string(l:job)) | ||||
|  | ||||
|     " Only call the callbacks for jobs which are valid. | ||||
|     if l:job_id > 0 && has_key(s:job_map, l:job_id) | ||||
|         call ale#util#GetFunction(s:job_map[l:job_id].err_cb)(l:job_id, a:data) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! s:VimCloseCallback(channel) abort | ||||
|     let l:job = ch_getjob(a:channel) | ||||
|     let l:job_id = ale#job#ParseVim8ProcessID(string(l:job)) | ||||
|     let l:info = get(s:job_map, l:job_id, {}) | ||||
|  | ||||
|     if empty(l:info) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " job_status() can trigger the exit handler. | ||||
|     " The channel can close before the job has exited. | ||||
|     if job_status(l:job) is# 'dead' | ||||
|         try | ||||
|             if !empty(l:info) && has_key(l:info, 'exit_cb') | ||||
|                 call ale#util#GetFunction(l:info.exit_cb)(l:job_id, l:info.exit_code) | ||||
|             endif | ||||
|         finally | ||||
|             " Automatically forget about the job after it's done. | ||||
|             if has_key(s:job_map, l:job_id) | ||||
|                 call remove(s:job_map, l:job_id) | ||||
|             endif | ||||
|         endtry | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! s:VimExitCallback(job, exit_code) abort | ||||
|     let l:job_id = ale#job#ParseVim8ProcessID(string(a:job)) | ||||
|     let l:info = get(s:job_map, l:job_id, {}) | ||||
|  | ||||
|     if empty(l:info) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let l:info.exit_code = a:exit_code | ||||
|  | ||||
|     " The program can exit before the data has finished being read. | ||||
|     if ch_status(job_getchannel(a:job)) is# 'closed' | ||||
|         try | ||||
|             if !empty(l:info) && has_key(l:info, 'exit_cb') | ||||
|                 call ale#util#GetFunction(l:info.exit_cb)(l:job_id, a:exit_code) | ||||
|             endif | ||||
|         finally | ||||
|             " Automatically forget about the job after it's done. | ||||
|             if has_key(s:job_map, l:job_id) | ||||
|                 call remove(s:job_map, l:job_id) | ||||
|             endif | ||||
|         endtry | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#job#ParseVim8ProcessID(job_string) abort | ||||
|     return matchstr(a:job_string, '\d\+') + 0 | ||||
| endfunction | ||||
|  | ||||
| function! ale#job#ValidateArguments(command, options) abort | ||||
|     if a:options.mode isnot# 'nl' && a:options.mode isnot# 'raw' | ||||
|         throw 'Invalid mode: ' . a:options.mode | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! s:PrepareWrappedCommand(original_wrapper, command) abort | ||||
|     let l:match = matchlist(a:command, '\v^(.*(\&\&|;)) *(.*)$') | ||||
|     let l:prefix = '' | ||||
|     let l:command = a:command | ||||
|  | ||||
|     if !empty(l:match) | ||||
|         let l:prefix = l:match[1] . ' ' | ||||
|         let l:command = l:match[3] | ||||
|     endif | ||||
|  | ||||
|     let l:format = a:original_wrapper | ||||
|  | ||||
|     if l:format =~# '%@' | ||||
|         let l:wrapped = substitute(l:format, '%@', ale#Escape(l:command), '') | ||||
|     else | ||||
|         if l:format !~# '%\*' | ||||
|             let l:format .= ' %*' | ||||
|         endif | ||||
|  | ||||
|         let l:wrapped = substitute(l:format, '%\*', l:command, '') | ||||
|     endif | ||||
|  | ||||
|     return l:prefix . l:wrapped | ||||
| endfunction | ||||
|  | ||||
| function! ale#job#PrepareCommand(buffer, command) abort | ||||
|     let l:wrapper = ale#Var(a:buffer, 'command_wrapper') | ||||
|  | ||||
|     let l:command = !empty(l:wrapper) | ||||
|     \ ? s:PrepareWrappedCommand(l:wrapper, a:command) | ||||
|     \ : a:command | ||||
|  | ||||
|     " The command will be executed in a subshell. This fixes a number of | ||||
|     " issues, including reading the PATH variables correctly, %PATHEXT% | ||||
|     " expansion on Windows, etc. | ||||
|     " | ||||
|     " NeoVim handles this issue automatically if the command is a String, | ||||
|     " but we'll do this explicitly, so we use the same exact command for both | ||||
|     " versions. | ||||
|     if has('win32') | ||||
|         return 'cmd /s/c "' . l:command . '"' | ||||
|     endif | ||||
|  | ||||
|     if &shell =~? 'fish$' | ||||
|         return ['/bin/sh', '-c', l:command] | ||||
|     endif | ||||
|  | ||||
|     return split(&shell) + split(&shellcmdflag) + [l:command] | ||||
| endfunction | ||||
|  | ||||
| " Start a job with options which are agnostic to Vim and NeoVim. | ||||
| " | ||||
| " The following options are accepted: | ||||
| " | ||||
| " out_cb  - A callback for receiving stdin.  Arguments: (job_id, data) | ||||
| " err_cb  - A callback for receiving stderr. Arguments: (job_id, data) | ||||
| " exit_cb - A callback for program exit.     Arguments: (job_id, status_code) | ||||
| " mode    - A mode for I/O. Can be 'nl' for split lines or 'raw'. | ||||
| function! ale#job#Start(command, options) abort | ||||
|     call ale#job#ValidateArguments(a:command, a:options) | ||||
|  | ||||
|     let l:job_info = copy(a:options) | ||||
|     let l:job_options = {} | ||||
|  | ||||
|     if has('nvim') | ||||
|         if has_key(a:options, 'out_cb') | ||||
|             let l:job_options.on_stdout = function('s:NeoVimCallback') | ||||
|             let l:job_info.out_cb_line = '' | ||||
|         endif | ||||
|  | ||||
|         if has_key(a:options, 'err_cb') | ||||
|             let l:job_options.on_stderr = function('s:NeoVimCallback') | ||||
|             let l:job_info.err_cb_line = '' | ||||
|         endif | ||||
|  | ||||
|         if has_key(a:options, 'exit_cb') | ||||
|             let l:job_options.on_exit = function('s:NeoVimCallback') | ||||
|         endif | ||||
|  | ||||
|         let l:job_info.job = jobstart(a:command, l:job_options) | ||||
|         let l:job_id = l:job_info.job | ||||
|     else | ||||
|         let l:job_options = { | ||||
|         \   'in_mode': l:job_info.mode, | ||||
|         \   'out_mode': l:job_info.mode, | ||||
|         \   'err_mode': l:job_info.mode, | ||||
|         \} | ||||
|  | ||||
|         if has_key(a:options, 'out_cb') | ||||
|             let l:job_options.out_cb = function('s:VimOutputCallback') | ||||
|         endif | ||||
|  | ||||
|         if has_key(a:options, 'err_cb') | ||||
|             let l:job_options.err_cb = function('s:VimErrorCallback') | ||||
|         endif | ||||
|  | ||||
|         if has_key(a:options, 'exit_cb') | ||||
|             " Set a close callback to which simply calls job_status() | ||||
|             " when the channel is closed, which can trigger the exit callback | ||||
|             " earlier on. | ||||
|             let l:job_options.close_cb = function('s:VimCloseCallback') | ||||
|             let l:job_options.exit_cb = function('s:VimExitCallback') | ||||
|         endif | ||||
|  | ||||
|         " Vim 8 will read the stdin from the file's buffer. | ||||
|         let l:job_info.job = job_start(a:command, l:job_options) | ||||
|         let l:job_id = ale#job#ParseVim8ProcessID(string(l:job_info.job)) | ||||
|     endif | ||||
|  | ||||
|     if l:job_id > 0 | ||||
|         " Store the job in the map for later only if we can get the ID. | ||||
|         let s:job_map[l:job_id] = l:job_info | ||||
|     endif | ||||
|  | ||||
|     return l:job_id | ||||
| endfunction | ||||
|  | ||||
| " Send raw data to the job. | ||||
| function! ale#job#SendRaw(job_id, string) abort | ||||
|     if has('nvim') | ||||
|         call jobsend(a:job_id, a:string) | ||||
|     else | ||||
|         call ch_sendraw(job_getchannel(s:job_map[a:job_id].job), a:string) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| " Given a job ID, return 1 if the job is currently running. | ||||
| " Invalid job IDs will be ignored. | ||||
| function! ale#job#IsRunning(job_id) abort | ||||
|     if has('nvim') | ||||
|         try | ||||
|             " In NeoVim, if the job isn't running, jobpid() will throw. | ||||
|             call jobpid(a:job_id) | ||||
|             return 1 | ||||
|         catch | ||||
|         endtry | ||||
|     elseif has_key(s:job_map, a:job_id) | ||||
|         let l:job = s:job_map[a:job_id].job | ||||
|         return job_status(l:job) is# 'run' | ||||
|     endif | ||||
|  | ||||
|     return 0 | ||||
| endfunction | ||||
|  | ||||
| " Given a Job ID, stop that job. | ||||
| " Invalid job IDs will be ignored. | ||||
| function! ale#job#Stop(job_id) abort | ||||
|     if !has_key(s:job_map, a:job_id) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     if has('nvim') | ||||
|         " FIXME: NeoVim kills jobs on a timer, but will not kill any processes | ||||
|         " which are child processes on Unix. Some work needs to be done to | ||||
|         " kill child processes to stop long-running processes like pylint. | ||||
|         silent! call jobstop(a:job_id) | ||||
|     else | ||||
|         let l:job = s:job_map[a:job_id].job | ||||
|  | ||||
|         " We must close the channel for reading the buffer if it is open | ||||
|         " when stopping a job. Otherwise, we will get errors in the status line. | ||||
|         if ch_status(job_getchannel(l:job)) is# 'open' | ||||
|             call ch_close_in(job_getchannel(l:job)) | ||||
|         endif | ||||
|  | ||||
|         " Ask nicely for the job to stop. | ||||
|         call job_stop(l:job) | ||||
|  | ||||
|         if ale#job#IsRunning(l:job) | ||||
|             " Set a 100ms delay for killing the job with SIGKILL. | ||||
|             let s:job_kill_timers[timer_start(100, function('s:KillHandler'))] = l:job | ||||
|         endif | ||||
|     endif | ||||
| endfunction | ||||
							
								
								
									
										474
									
								
								sources_non_forked/ale/autoload/ale/linter.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										474
									
								
								sources_non_forked/ale/autoload/ale/linter.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,474 @@ | ||||
| call ale#Set('wrap_command_as_one_argument', 0) | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Linter registration and lazy-loading | ||||
| "   Retrieves linters as requested by the engine, loading them if needed. | ||||
|  | ||||
| let s:linters = {} | ||||
|  | ||||
| " Default filetype aliases. | ||||
| " The user defined aliases will be merged with this Dictionary. | ||||
| let s:default_ale_linter_aliases = { | ||||
| \   'Dockerfile': 'dockerfile', | ||||
| \   'csh': 'sh', | ||||
| \   'plaintex': 'tex', | ||||
| \   'systemverilog': 'verilog', | ||||
| \   'zsh': 'sh', | ||||
| \} | ||||
|  | ||||
| " Default linters to run for particular filetypes. | ||||
| " The user defined linter selections will be merged with this Dictionary. | ||||
| " | ||||
| " No linters are used for plaintext files by default. | ||||
| " | ||||
| " Only cargo is enabled for Rust by default. | ||||
| " rpmlint is disabled by default because it can result in code execution. | ||||
| " | ||||
| " NOTE: Update the g:ale_linters documentation when modifying this. | ||||
| let s:default_ale_linters = { | ||||
| \   'csh': ['shell'], | ||||
| \   'go': ['gofmt', 'golint', 'go vet'], | ||||
| \   'help': [], | ||||
| \   'perl': ['perlcritic'], | ||||
| \   'python': ['flake8', 'mypy', 'pylint'], | ||||
| \   'rust': ['cargo'], | ||||
| \   'spec': [], | ||||
| \   'text': [], | ||||
| \   'zsh': ['shell'], | ||||
| \} | ||||
|  | ||||
| " Testing/debugging helper to unload all linters. | ||||
| function! ale#linter#Reset() abort | ||||
|     let s:linters = {} | ||||
| endfunction | ||||
|  | ||||
| function! s:IsCallback(value) abort | ||||
|     return type(a:value) == type('') || type(a:value) == type(function('type')) | ||||
| endfunction | ||||
|  | ||||
| function! s:IsBoolean(value) abort | ||||
|     return type(a:value) == type(0) && (a:value == 0 || a:value == 1) | ||||
| endfunction | ||||
|  | ||||
| function! ale#linter#PreProcess(linter) abort | ||||
|     if type(a:linter) != type({}) | ||||
|         throw 'The linter object must be a Dictionary' | ||||
|     endif | ||||
|  | ||||
|     let l:obj = { | ||||
|     \   'add_newline': get(a:linter, 'add_newline', 0), | ||||
|     \   'name': get(a:linter, 'name'), | ||||
|     \   'lsp': get(a:linter, 'lsp', ''), | ||||
|     \} | ||||
|  | ||||
|     if type(l:obj.name) != type('') | ||||
|         throw '`name` must be defined to name the linter' | ||||
|     endif | ||||
|  | ||||
|     let l:needs_address = l:obj.lsp is# 'socket' | ||||
|     let l:needs_executable = l:obj.lsp isnot# 'socket' | ||||
|     let l:needs_command = l:obj.lsp isnot# 'socket' | ||||
|     let l:needs_lsp_details = !empty(l:obj.lsp) | ||||
|  | ||||
|     if empty(l:obj.lsp) | ||||
|         let l:obj.callback = get(a:linter, 'callback') | ||||
|  | ||||
|         if !s:IsCallback(l:obj.callback) | ||||
|             throw '`callback` must be defined with a callback to accept output' | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     if index(['', 'socket', 'stdio', 'tsserver'], l:obj.lsp) < 0 | ||||
|         throw '`lsp` must be either `''lsp''` or `''tsserver''` if defined' | ||||
|     endif | ||||
|  | ||||
|     if !l:needs_executable | ||||
|         if has_key(a:linter, 'executable') | ||||
|         \|| has_key(a:linter, 'executable_callback') | ||||
|             throw '`executable` and `executable_callback` cannot be used when lsp == ''socket''' | ||||
|         endif | ||||
|     elseif has_key(a:linter, 'executable_callback') | ||||
|         let l:obj.executable_callback = a:linter.executable_callback | ||||
|  | ||||
|         if !s:IsCallback(l:obj.executable_callback) | ||||
|             throw '`executable_callback` must be a callback if defined' | ||||
|         endif | ||||
|     elseif has_key(a:linter, 'executable') | ||||
|         let l:obj.executable = a:linter.executable | ||||
|  | ||||
|         if type(l:obj.executable) != type('') | ||||
|             throw '`executable` must be a string if defined' | ||||
|         endif | ||||
|     else | ||||
|         throw 'Either `executable` or `executable_callback` must be defined' | ||||
|     endif | ||||
|  | ||||
|     if !l:needs_command | ||||
|         if has_key(a:linter, 'command') | ||||
|         \|| has_key(a:linter, 'command_callback') | ||||
|         \|| has_key(a:linter, 'command_chain') | ||||
|             throw '`command` and `command_callback` and `command_chain` cannot be used when lsp == ''socket''' | ||||
|         endif | ||||
|     elseif has_key(a:linter, 'command_chain') | ||||
|         let l:obj.command_chain = a:linter.command_chain | ||||
|  | ||||
|         if type(l:obj.command_chain) != type([]) | ||||
|             throw '`command_chain` must be a List' | ||||
|         endif | ||||
|  | ||||
|         if empty(l:obj.command_chain) | ||||
|             throw '`command_chain` must contain at least one item' | ||||
|         endif | ||||
|  | ||||
|         let l:link_index = 0 | ||||
|  | ||||
|         for l:link in l:obj.command_chain | ||||
|             let l:err_prefix = 'The `command_chain` item ' . l:link_index . ' ' | ||||
|  | ||||
|             if !s:IsCallback(get(l:link, 'callback')) | ||||
|                 throw l:err_prefix . 'must define a `callback` function' | ||||
|             endif | ||||
|  | ||||
|             if has_key(l:link, 'output_stream') | ||||
|                 if type(l:link.output_stream) != type('') | ||||
|                 \|| index(['stdout', 'stderr', 'both'], l:link.output_stream) < 0 | ||||
|                     throw l:err_prefix . '`output_stream` flag must be ' | ||||
|                     \   . "'stdout', 'stderr', or 'both'" | ||||
|                 endif | ||||
|             endif | ||||
|  | ||||
|             if has_key(l:link, 'read_buffer') && !s:IsBoolean(l:link.read_buffer) | ||||
|                 throw l:err_prefix . 'value for `read_buffer` must be `0` or `1`' | ||||
|             endif | ||||
|  | ||||
|             let l:link_index += 1 | ||||
|         endfor | ||||
|     elseif has_key(a:linter, 'command_callback') | ||||
|         let l:obj.command_callback = a:linter.command_callback | ||||
|  | ||||
|         if !s:IsCallback(l:obj.command_callback) | ||||
|             throw '`command_callback` must be a callback if defined' | ||||
|         endif | ||||
|     elseif has_key(a:linter, 'command') | ||||
|         let l:obj.command = a:linter.command | ||||
|  | ||||
|         if type(l:obj.command) != type('') | ||||
|             throw '`command` must be a string if defined' | ||||
|         endif | ||||
|     else | ||||
|         throw 'Either `command`, `executable_callback`, `command_chain` ' | ||||
|         \   . 'must be defined' | ||||
|     endif | ||||
|  | ||||
|     if ( | ||||
|     \   has_key(a:linter, 'command') | ||||
|     \   + has_key(a:linter, 'command_chain') | ||||
|     \   + has_key(a:linter, 'command_callback') | ||||
|     \) > 1 | ||||
|         throw 'Only one of `command`, `command_callback`, or `command_chain` ' | ||||
|         \   . 'should be set' | ||||
|     endif | ||||
|  | ||||
|     if !l:needs_address | ||||
|         if has_key(a:linter, 'address_callback') | ||||
|             throw '`address_callback` cannot be used when lsp != ''socket''' | ||||
|         endif | ||||
|     elseif has_key(a:linter, 'address_callback') | ||||
|         let l:obj.address_callback = a:linter.address_callback | ||||
|  | ||||
|         if !s:IsCallback(l:obj.address_callback) | ||||
|             throw '`address_callback` must be a callback if defined' | ||||
|         endif | ||||
|     else | ||||
|         throw '`address_callback` must be defined for getting the LSP address' | ||||
|     endif | ||||
|  | ||||
|     if l:needs_lsp_details | ||||
|         let l:obj.language_callback = get(a:linter, 'language_callback') | ||||
|  | ||||
|         if !s:IsCallback(l:obj.language_callback) | ||||
|             throw '`language_callback` must be a callback for LSP linters' | ||||
|         endif | ||||
|  | ||||
|         let l:obj.project_root_callback = get(a:linter, 'project_root_callback') | ||||
|  | ||||
|         if !s:IsCallback(l:obj.project_root_callback) | ||||
|             throw '`project_root_callback` must be a callback for LSP linters' | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     let l:obj.output_stream = get(a:linter, 'output_stream', 'stdout') | ||||
|  | ||||
|     if type(l:obj.output_stream) != type('') | ||||
|     \|| index(['stdout', 'stderr', 'both'], l:obj.output_stream) < 0 | ||||
|         throw "`output_stream` must be 'stdout', 'stderr', or 'both'" | ||||
|     endif | ||||
|  | ||||
|     " An option indicating that this linter should only be run against the | ||||
|     " file on disk. | ||||
|     let l:obj.lint_file = get(a:linter, 'lint_file', 0) | ||||
|  | ||||
|     if !s:IsBoolean(l:obj.lint_file) | ||||
|         throw '`lint_file` must be `0` or `1`' | ||||
|     endif | ||||
|  | ||||
|     " An option indicating that the buffer should be read. | ||||
|     let l:obj.read_buffer = get(a:linter, 'read_buffer', !l:obj.lint_file) | ||||
|  | ||||
|     if !s:IsBoolean(l:obj.read_buffer) | ||||
|         throw '`read_buffer` must be `0` or `1`' | ||||
|     endif | ||||
|  | ||||
|     if l:obj.lint_file && l:obj.read_buffer | ||||
|         throw 'Only one of `lint_file` or `read_buffer` can be `1`' | ||||
|     endif | ||||
|  | ||||
|     let l:obj.aliases = get(a:linter, 'aliases', []) | ||||
|  | ||||
|     if type(l:obj.aliases) != type([]) | ||||
|     \|| len(filter(copy(l:obj.aliases), 'type(v:val) != type('''')')) > 0 | ||||
|         throw '`aliases` must be a List of String values' | ||||
|     endif | ||||
|  | ||||
|     return l:obj | ||||
| endfunction | ||||
|  | ||||
| function! ale#linter#Define(filetype, linter) abort | ||||
|     if !has_key(s:linters, a:filetype) | ||||
|         let s:linters[a:filetype] = [] | ||||
|     endif | ||||
|  | ||||
|     let l:new_linter = ale#linter#PreProcess(a:linter) | ||||
|  | ||||
|     call add(s:linters[a:filetype], l:new_linter) | ||||
| endfunction | ||||
|  | ||||
| function! ale#linter#GetAll(filetypes) abort | ||||
|     let l:combined_linters = [] | ||||
|  | ||||
|     for l:filetype in a:filetypes | ||||
|         " Load linter defintions from files if we haven't loaded them yet. | ||||
|         if !has_key(s:linters, l:filetype) | ||||
|             execute 'silent! runtime! ale_linters/' . l:filetype . '/*.vim' | ||||
|  | ||||
|             " Always set an empty List for the loaded linters if we don't find | ||||
|             " any. This will prevent us from executing the runtime command | ||||
|             " many times, redundantly. | ||||
|             if !has_key(s:linters, l:filetype) | ||||
|                 let s:linters[l:filetype] = [] | ||||
|             endif | ||||
|         endif | ||||
|  | ||||
|         call extend(l:combined_linters, get(s:linters, l:filetype, [])) | ||||
|     endfor | ||||
|  | ||||
|     return l:combined_linters | ||||
| endfunction | ||||
|  | ||||
| function! s:GetAliasedFiletype(original_filetype) abort | ||||
|     let l:buffer_aliases = get(b:, 'ale_linter_aliases', {}) | ||||
|  | ||||
|     " b:ale_linter_aliases can be set to a List. | ||||
|     if type(l:buffer_aliases) is type([]) | ||||
|         return l:buffer_aliases | ||||
|     endif | ||||
|  | ||||
|     " Check for aliased filetypes first in a buffer variable, | ||||
|     " then the global variable, | ||||
|     " then in the default mapping, | ||||
|     " otherwise use the original filetype. | ||||
|     for l:dict in [ | ||||
|     \   l:buffer_aliases, | ||||
|     \   g:ale_linter_aliases, | ||||
|     \   s:default_ale_linter_aliases, | ||||
|     \] | ||||
|         if has_key(l:dict, a:original_filetype) | ||||
|             return l:dict[a:original_filetype] | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return a:original_filetype | ||||
| endfunction | ||||
|  | ||||
| function! ale#linter#ResolveFiletype(original_filetype) abort | ||||
|     let l:filetype = s:GetAliasedFiletype(a:original_filetype) | ||||
|  | ||||
|     if type(l:filetype) != type([]) | ||||
|         return [l:filetype] | ||||
|     endif | ||||
|  | ||||
|     return l:filetype | ||||
| endfunction | ||||
|  | ||||
| function! s:GetLinterNames(original_filetype) abort | ||||
|     let l:buffer_ale_linters = get(b:, 'ale_linters', {}) | ||||
|  | ||||
|     " b:ale_linters can be set to 'all' | ||||
|     if l:buffer_ale_linters is# 'all' | ||||
|         return 'all' | ||||
|     endif | ||||
|  | ||||
|     " b:ale_linters can be set to a List. | ||||
|     if type(l:buffer_ale_linters) is type([]) | ||||
|         return l:buffer_ale_linters | ||||
|     endif | ||||
|  | ||||
|     " Try to get a buffer-local setting for the filetype | ||||
|     if has_key(l:buffer_ale_linters, a:original_filetype) | ||||
|         return l:buffer_ale_linters[a:original_filetype] | ||||
|     endif | ||||
|  | ||||
|     " Try to get a global setting for the filetype | ||||
|     if has_key(g:ale_linters, a:original_filetype) | ||||
|         return g:ale_linters[a:original_filetype] | ||||
|     endif | ||||
|  | ||||
|     " If the user has configured ALE to only enable linters explicitly, then | ||||
|     " don't enable any linters by default. | ||||
|     if g:ale_linters_explicit | ||||
|         return [] | ||||
|     endif | ||||
|  | ||||
|     " Try to get a default setting for the filetype | ||||
|     if has_key(s:default_ale_linters, a:original_filetype) | ||||
|         return s:default_ale_linters[a:original_filetype] | ||||
|     endif | ||||
|  | ||||
|     return 'all' | ||||
| endfunction | ||||
|  | ||||
| function! ale#linter#Get(original_filetypes) abort | ||||
|     let l:possibly_duplicated_linters = [] | ||||
|  | ||||
|     " Handle dot-separated filetypes. | ||||
|     for l:original_filetype in split(a:original_filetypes, '\.') | ||||
|         let l:filetype = ale#linter#ResolveFiletype(l:original_filetype) | ||||
|         let l:linter_names = s:GetLinterNames(l:original_filetype) | ||||
|         let l:all_linters = ale#linter#GetAll(l:filetype) | ||||
|         let l:filetype_linters = [] | ||||
|  | ||||
|         if type(l:linter_names) == type('') && l:linter_names is# 'all' | ||||
|             let l:filetype_linters = l:all_linters | ||||
|         elseif type(l:linter_names) == type([]) | ||||
|             " Select only the linters we or the user has specified. | ||||
|             for l:linter in l:all_linters | ||||
|                 let l:name_list = [l:linter.name] + l:linter.aliases | ||||
|  | ||||
|                 for l:name in l:name_list | ||||
|                     if index(l:linter_names, l:name) >= 0 | ||||
|                         call add(l:filetype_linters, l:linter) | ||||
|                         break | ||||
|                     endif | ||||
|                 endfor | ||||
|             endfor | ||||
|         endif | ||||
|  | ||||
|         call extend(l:possibly_duplicated_linters, l:filetype_linters) | ||||
|     endfor | ||||
|  | ||||
|     let l:name_list = [] | ||||
|     let l:combined_linters = [] | ||||
|  | ||||
|     " Make sure we override linters so we don't get two with the same name, | ||||
|     " like 'eslint' for both 'javascript' and 'typescript' | ||||
|     " | ||||
|     " Note that the reverse calls here modify the List variables. | ||||
|     for l:linter in reverse(l:possibly_duplicated_linters) | ||||
|         if index(l:name_list, l:linter.name) < 0 | ||||
|             call add(l:name_list, l:linter.name) | ||||
|             call add(l:combined_linters, l:linter) | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return reverse(l:combined_linters) | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer and linter, get the executable String for the linter. | ||||
| function! ale#linter#GetExecutable(buffer, linter) abort | ||||
|     return has_key(a:linter, 'executable_callback') | ||||
|     \   ? ale#util#GetFunction(a:linter.executable_callback)(a:buffer) | ||||
|     \   : a:linter.executable | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer and linter, get the command String for the linter. | ||||
| " The command_chain key is not supported. | ||||
| function! ale#linter#GetCommand(buffer, linter) abort | ||||
|     return has_key(a:linter, 'command_callback') | ||||
|     \   ? ale#util#GetFunction(a:linter.command_callback)(a:buffer) | ||||
|     \   : a:linter.command | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer and linter, get the address for connecting to the server. | ||||
| function! ale#linter#GetAddress(buffer, linter) abort | ||||
|     return has_key(a:linter, 'address_callback') | ||||
|     \   ? ale#util#GetFunction(a:linter.address_callback)(a:buffer) | ||||
|     \   : a:linter.address | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer, an LSP linter, and a callback to register for handling | ||||
| " messages, start up an LSP linter and get ready to receive errors or | ||||
| " completions. | ||||
| function! ale#linter#StartLSP(buffer, linter, callback) abort | ||||
|     let l:command = '' | ||||
|     let l:address = '' | ||||
|     let l:root = ale#util#GetFunction(a:linter.project_root_callback)(a:buffer) | ||||
|  | ||||
|     if empty(l:root) && a:linter.lsp isnot# '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 is# 'socket' | ||||
|         let l:address = ale#linter#GetAddress(a:buffer, a:linter) | ||||
|         let l:conn_id = ale#lsp#ConnectToAddress( | ||||
|         \   l:address, | ||||
|         \   l:root, | ||||
|         \   a:callback, | ||||
|         \) | ||||
|     else | ||||
|         let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) | ||||
|  | ||||
|         if !executable(l:executable) | ||||
|             return {} | ||||
|         endif | ||||
|  | ||||
|         let l:command = ale#job#PrepareCommand( | ||||
|         \   a:buffer, | ||||
|         \   ale#linter#GetCommand(a:buffer, a:linter), | ||||
|         \) | ||||
|         let l:conn_id = ale#lsp#StartProgram( | ||||
|         \   l:executable, | ||||
|         \   l:command, | ||||
|         \   l:root, | ||||
|         \   a:callback, | ||||
|         \) | ||||
|     endif | ||||
|  | ||||
|     let l:language_id = ale#util#GetFunction(a:linter.language_callback)(a:buffer) | ||||
|  | ||||
|     if !l:conn_id | ||||
|         if g:ale_history_enabled && !empty(l:command) | ||||
|             call ale#history#Add(a:buffer, 'failed', l:conn_id, l:command) | ||||
|         endif | ||||
|  | ||||
|         return {} | ||||
|     endif | ||||
|  | ||||
|     if ale#lsp#OpenDocumentIfNeeded(l:conn_id, a:buffer, l:root, l:language_id) | ||||
|         if g:ale_history_enabled && !empty(l:command) | ||||
|             call ale#history#Add(a:buffer, 'started', l:conn_id, l:command) | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     " The change message needs to be sent for tsserver before doing anything. | ||||
|     if a:linter.lsp is# 'tsserver' | ||||
|         call ale#lsp#Send(l:conn_id, ale#lsp#tsserver_message#Change(a:buffer)) | ||||
|     endif | ||||
|  | ||||
|     return { | ||||
|     \   'connection_id': l:conn_id, | ||||
|     \   'command': l:command, | ||||
|     \   'project_root': l:root, | ||||
|     \   'language_id': l:language_id, | ||||
|     \} | ||||
| endfunction | ||||
							
								
								
									
										177
									
								
								sources_non_forked/ale/autoload/ale/list.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								sources_non_forked/ale/autoload/ale/list.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,177 @@ | ||||
| " Author: Bjorn Neergaard <bjorn@neersighted.com>, modified by Yann fery <yann@fery.me> | ||||
| " Description: Manages the loclist and quickfix lists | ||||
|  | ||||
| if !exists('s:timer_args') | ||||
|     let s:timer_args = {} | ||||
| endif | ||||
|  | ||||
| " Return 1 if there is a buffer with buftype == 'quickfix' in bufffer list | ||||
| function! ale#list#IsQuickfixOpen() abort | ||||
|     for l:buf in range(1, bufnr('$')) | ||||
|         if getbufvar(l:buf, '&buftype') is# 'quickfix' | ||||
|             return 1 | ||||
|         endif | ||||
|     endfor | ||||
|     return 0 | ||||
| endfunction | ||||
|  | ||||
| " Check if we should open the list, based on the save event being fired, and | ||||
| " that setting being on, or the setting just being set to `1`. | ||||
| function! s:ShouldOpen(buffer) abort | ||||
|     let l:val = ale#Var(a:buffer, 'open_list') | ||||
|     let l:saved = getbufvar(a:buffer, 'ale_save_event_fired', 0) | ||||
|  | ||||
|     return l:val is 1 || (l:val is# 'on_save' && l:saved) | ||||
| endfunction | ||||
|  | ||||
| function! ale#list#GetCombinedList() abort | ||||
|     let l:list = [] | ||||
|  | ||||
|     for l:info in values(g:ale_buffer_info) | ||||
|         call extend(l:list, l:info.loclist) | ||||
|     endfor | ||||
|  | ||||
|     call sort(l:list, function('ale#util#LocItemCompareWithText')) | ||||
|     call uniq(l:list, function('ale#util#LocItemCompareWithText')) | ||||
|  | ||||
|     return l:list | ||||
| endfunction | ||||
|  | ||||
| function! s:FixList(buffer, list) abort | ||||
|     let l:format = ale#Var(a:buffer, 'loclist_msg_format') | ||||
|     let l:new_list = [] | ||||
|  | ||||
|     for l:item in a:list | ||||
|         let l:fixed_item = copy(l:item) | ||||
|  | ||||
|         let l:fixed_item.text = ale#GetLocItemMessage(l:item, l:format) | ||||
|  | ||||
|         if l:item.bufnr == -1 | ||||
|             " If the buffer number is invalid, remove it. | ||||
|             call remove(l:fixed_item, 'bufnr') | ||||
|         endif | ||||
|  | ||||
|         call add(l:new_list, l:fixed_item) | ||||
|     endfor | ||||
|  | ||||
|     return l:new_list | ||||
| endfunction | ||||
|  | ||||
| function! s:BufWinId(buffer) abort | ||||
|     return exists('*bufwinid') ? bufwinid(str2nr(a:buffer)) : 0 | ||||
| endfunction | ||||
|  | ||||
| function! s:SetListsImpl(timer_id, buffer, loclist) abort | ||||
|     let l:title = expand('#' . a:buffer . ':p') | ||||
|  | ||||
|     if g:ale_set_quickfix | ||||
|         let l:quickfix_list = ale#list#GetCombinedList() | ||||
|  | ||||
|         if has('nvim') | ||||
|             call setqflist(s:FixList(a:buffer, l:quickfix_list), ' ', l:title) | ||||
|         else | ||||
|             call setqflist(s:FixList(a:buffer, l:quickfix_list)) | ||||
|             call setqflist([], 'r', {'title': l:title}) | ||||
|         endif | ||||
|     elseif g:ale_set_loclist | ||||
|         " If windows support is off, bufwinid() may not exist. | ||||
|         " We'll set result in the current window, which might not be correct, | ||||
|         " but it's better than nothing. | ||||
|         let l:id = s:BufWinId(a:buffer) | ||||
|  | ||||
|         if has('nvim') | ||||
|             call setloclist(l:id, s:FixList(a:buffer, a:loclist), ' ', l:title) | ||||
|         else | ||||
|             call setloclist(l:id, s:FixList(a:buffer, a:loclist)) | ||||
|             call setloclist(l:id, [], 'r', {'title': l:title}) | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     " Open a window to show the problems if we need to. | ||||
|     " | ||||
|     " We'll check if the current buffer's List is not empty here, so the | ||||
|     " window will only be opened if the current buffer has problems. | ||||
|     if s:ShouldOpen(a:buffer) && !empty(a:loclist) | ||||
|         let l:winnr = winnr() | ||||
|         let l:mode = mode() | ||||
|         let l:reset_visual_selection = l:mode is? 'v' || l:mode is# "\<c-v>" | ||||
|         let l:reset_character_selection = l:mode is? 's' || l:mode is# "\<c-s>" | ||||
|  | ||||
|         " open windows vertically instead of default horizontally | ||||
|         let l:open_type = '' | ||||
|         if ale#Var(a:buffer, 'list_vertical') == 1 | ||||
|             let l:open_type = 'vert ' | ||||
|         endif | ||||
|         if g:ale_set_quickfix | ||||
|             if !ale#list#IsQuickfixOpen() | ||||
|                 silent! execute l:open_type . 'copen ' . str2nr(ale#Var(a:buffer, 'list_window_size')) | ||||
|             endif | ||||
|         elseif g:ale_set_loclist | ||||
|             silent! execute l:open_type . 'lopen ' . str2nr(ale#Var(a:buffer, 'list_window_size')) | ||||
|         endif | ||||
|  | ||||
|         " If focus changed, restore it (jump to the last window). | ||||
|         if l:winnr isnot# winnr() | ||||
|             wincmd p | ||||
|         endif | ||||
|  | ||||
|         if l:reset_visual_selection || l:reset_character_selection | ||||
|             " If we were in a selection mode before, select the last selection. | ||||
|             normal! gv | ||||
|  | ||||
|             if l:reset_character_selection | ||||
|                 " Switch back to Select mode, if we were in that. | ||||
|                 normal! "\<c-g>" | ||||
|             endif | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     " If ALE isn't currently checking for more problems, close the window if | ||||
|     " needed now. This check happens inside of this timer function, so | ||||
|     " the window can be closed reliably. | ||||
|     if !ale#engine#IsCheckingBuffer(a:buffer) | ||||
|         call s:CloseWindowIfNeeded(a:buffer) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#list#SetLists(buffer, loclist) abort | ||||
|     if get(g:, 'ale_set_lists_synchronously') == 1 | ||||
|     \|| getbufvar(a:buffer, 'ale_save_event_fired', 0) | ||||
|         " Update lists immediately if running a test synchronously, or if the | ||||
|         " buffer was saved. | ||||
|         " | ||||
|         " The lists need to be updated immediately when saving a buffer so | ||||
|         " that we can reliably close window automatically, if so configured. | ||||
|         call s:SetListsImpl(-1, a:buffer, a:loclist) | ||||
|     else | ||||
|         call ale#util#StartPartialTimer( | ||||
|         \   0, | ||||
|         \   function('s:SetListsImpl'), | ||||
|         \   [a:buffer, a:loclist], | ||||
|         \) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! s:CloseWindowIfNeeded(buffer) abort | ||||
|     if ale#Var(a:buffer, 'keep_list_window_open') || !s:ShouldOpen(a:buffer) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     try | ||||
|         " Only close windows if the quickfix list or loclist is completely empty, | ||||
|         " including errors set through other means. | ||||
|         if g:ale_set_quickfix | ||||
|             if empty(getqflist()) | ||||
|                 cclose | ||||
|             endif | ||||
|         else | ||||
|             let l:win_id = s:BufWinId(a:buffer) | ||||
|  | ||||
|             if g:ale_set_loclist && empty(getloclist(l:win_id)) | ||||
|                 lclose | ||||
|             endif | ||||
|         endif | ||||
|     " Ignore 'Cannot close last window' errors. | ||||
|     catch /E444/ | ||||
|     endtry | ||||
| endfunction | ||||
							
								
								
									
										87
									
								
								sources_non_forked/ale/autoload/ale/loclist_jumping.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								sources_non_forked/ale/autoload/ale/loclist_jumping.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: This file implements functions for jumping around in a file | ||||
| "   based on ALE's internal loclist. | ||||
|  | ||||
| " Search for the nearest line either before or after the current position | ||||
| " in the loclist. The argument 'wrap' can be passed to enable wrapping | ||||
| " around the end of the list. | ||||
| " | ||||
| " If there are no items or we have hit the end with wrapping off, an empty | ||||
| " List will be returned, otherwise a pair of [line_number, column_number] will | ||||
| " be returned. | ||||
| function! ale#loclist_jumping#FindNearest(direction, wrap) abort | ||||
|     let l:buffer = bufnr('') | ||||
|     let l:pos = getcurpos() | ||||
|     let l:info = get(g:ale_buffer_info, bufnr('%'), {'loclist': []}) | ||||
|     " Copy the list and filter to only the items in this buffer. | ||||
|     let l:loclist = filter(copy(l:info.loclist), 'v:val.bufnr == l:buffer') | ||||
|     let l:search_item = {'bufnr': l:buffer, 'lnum': l:pos[1], 'col': l:pos[2]} | ||||
|  | ||||
|     " When searching backwards, so we can find the next smallest match. | ||||
|     if a:direction is# 'before' | ||||
|         call reverse(l:loclist) | ||||
|     endif | ||||
|  | ||||
|     " Look for items before or after the current position. | ||||
|     for l:item in l:loclist | ||||
|         " Compare the cursor with a item where the column number is bounded, | ||||
|         " such that it's possible for the cursor to actually be on the given | ||||
|         " column number, without modifying the cursor number we return. This | ||||
|         " will allow us to move through matches, but still let us move the | ||||
|         " cursor to a line without changing the column, in some cases. | ||||
|         let l:cmp_value = ale#util#LocItemCompare( | ||||
|         \   { | ||||
|         \       'bufnr': l:buffer, | ||||
|         \       'lnum': l:item.lnum, | ||||
|         \       'col': min([ | ||||
|         \           max([l:item.col, 1]), | ||||
|         \           max([len(getline(l:item.lnum)), 1]), | ||||
|         \       ]), | ||||
|         \   }, | ||||
|         \   l:search_item | ||||
|         \) | ||||
|  | ||||
|         if a:direction is# 'before' && l:cmp_value < 0 | ||||
|             return [l:item.lnum, l:item.col] | ||||
|         endif | ||||
|  | ||||
|         if a:direction is# 'after' && l:cmp_value > 0 | ||||
|             return [l:item.lnum, l:item.col] | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     " If we found nothing, and the wrap option is set to 1, then we should | ||||
|     " wrap around the list of warnings/errors | ||||
|     if a:wrap && !empty(l:loclist) | ||||
|         let l:item = l:loclist[0] | ||||
|  | ||||
|         return [l:item.lnum, l:item.col] | ||||
|     endif | ||||
|  | ||||
|     return [] | ||||
| endfunction | ||||
|  | ||||
| " As before, find the nearest match, but position the cursor at it. | ||||
| function! ale#loclist_jumping#Jump(direction, wrap) abort | ||||
|     let l:nearest = ale#loclist_jumping#FindNearest(a:direction, a:wrap) | ||||
|  | ||||
|     if !empty(l:nearest) | ||||
|         call cursor(l:nearest) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#loclist_jumping#JumpToIndex(index) abort | ||||
|     let l:buffer = bufnr('') | ||||
|     let l:info = get(g:ale_buffer_info, l:buffer, {'loclist': []}) | ||||
|     let l:loclist = filter(copy(l:info.loclist), 'v:val.bufnr == l:buffer') | ||||
|  | ||||
|     if empty(l:loclist) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let l:item = l:loclist[a:index] | ||||
|  | ||||
|     if !empty(l:item) | ||||
|         call cursor([l:item.lnum, l:item.col]) | ||||
|     endif | ||||
| endfunction | ||||
							
								
								
									
										420
									
								
								sources_non_forked/ale/autoload/ale/lsp.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										420
									
								
								sources_non_forked/ale/autoload/ale/lsp.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,420 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Language Server Protocol client code | ||||
|  | ||||
| " A List of connections, used for tracking servers which have been connected | ||||
| " to, and programs which are run. | ||||
| let s:connections = [] | ||||
| let g:ale_lsp_next_message_id = 1 | ||||
|  | ||||
| function! s:NewConnection() abort | ||||
|     " id: The job ID as a Number, or the server address as a string. | ||||
|     " data: The message data received so far. | ||||
|     " executable: An executable only set for program connections. | ||||
|     " open_documents: A list of buffers we told the server we opened. | ||||
|     " callback_list: A list of callbacks for handling LSP responses. | ||||
|     let l:conn = { | ||||
|     \   'id': '', | ||||
|     \   'data': '', | ||||
|     \   'projects': {}, | ||||
|     \   'open_documents': [], | ||||
|     \   'callback_list': [], | ||||
|     \} | ||||
|  | ||||
|     call add(s:connections, l:conn) | ||||
|  | ||||
|     return l:conn | ||||
| endfunction | ||||
|  | ||||
| function! s:FindConnection(key, value) abort | ||||
|     for l:conn in s:connections | ||||
|         if has_key(l:conn, a:key) && get(l:conn, a:key) == a:value | ||||
|             return l:conn | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return {} | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#GetNextMessageID() abort | ||||
|     " Use the current ID | ||||
|     let l:id = g:ale_lsp_next_message_id | ||||
|  | ||||
|     " Increment the ID variable. | ||||
|     let g:ale_lsp_next_message_id += 1 | ||||
|  | ||||
|     " When the ID overflows, reset it to 1. By the time we hit the initial ID | ||||
|     " again, the messages will be long gone. | ||||
|     if g:ale_lsp_next_message_id < 1 | ||||
|         let g:ale_lsp_next_message_id = 1 | ||||
|     endif | ||||
|  | ||||
|     return l:id | ||||
| endfunction | ||||
|  | ||||
| " TypeScript messages use a different format. | ||||
| function! s:CreateTSServerMessageData(message) abort | ||||
|     let l:is_notification = a:message[0] | ||||
|  | ||||
|     let l:obj = { | ||||
|     \   'seq': v:null, | ||||
|     \   'type': 'request', | ||||
|     \   'command': a:message[1][3:], | ||||
|     \} | ||||
|  | ||||
|     if !l:is_notification | ||||
|         let l:obj.seq = ale#lsp#GetNextMessageID() | ||||
|     endif | ||||
|  | ||||
|     if len(a:message) > 2 | ||||
|         let l:obj.arguments = a:message[2] | ||||
|     endif | ||||
|  | ||||
|     let l:data = json_encode(l:obj) . "\n" | ||||
|     return [l:is_notification ? 0 : l:obj.seq, l:data] | ||||
| endfunction | ||||
|  | ||||
| " Given a List of one or two items, [method_name] or [method_name, params], | ||||
| " return a List containing [message_id, message_data] | ||||
| function! ale#lsp#CreateMessageData(message) abort | ||||
|     if a:message[1] =~# '^ts@' | ||||
|         return s:CreateTSServerMessageData(a:message) | ||||
|     endif | ||||
|  | ||||
|     let l:is_notification = a:message[0] | ||||
|  | ||||
|     let l:obj = { | ||||
|     \   'method': a:message[1], | ||||
|     \   'jsonrpc': '2.0', | ||||
|     \} | ||||
|  | ||||
|     if !l:is_notification | ||||
|         let l:obj.id = ale#lsp#GetNextMessageID() | ||||
|     endif | ||||
|  | ||||
|     if len(a:message) > 2 | ||||
|         let l:obj.params = a:message[2] | ||||
|     endif | ||||
|  | ||||
|     let l:body = json_encode(l:obj) | ||||
|     let l:data = 'Content-Length: ' . strlen(l:body) . "\r\n\r\n" . l:body | ||||
|  | ||||
|     return [l:is_notification ? 0 : l:obj.id, l:data] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#ReadMessageData(data) abort | ||||
|     let l:response_list = [] | ||||
|     let l:remainder = a:data | ||||
|  | ||||
|     while 1 | ||||
|         " Look for the end of the HTTP headers | ||||
|         let l:body_start_index = matchend(l:remainder, "\r\n\r\n") | ||||
|  | ||||
|         if l:body_start_index < 0 | ||||
|             " No header end was found yet. | ||||
|             break | ||||
|         endif | ||||
|  | ||||
|         " Parse the Content-Length header. | ||||
|         let l:header_data = l:remainder[:l:body_start_index - 4] | ||||
|         let l:length_match = matchlist( | ||||
|         \   l:header_data, | ||||
|         \   '\vContent-Length: *(\d+)' | ||||
|         \) | ||||
|  | ||||
|         if empty(l:length_match) | ||||
|             throw "Invalid JSON-RPC header:\n" . l:header_data | ||||
|         endif | ||||
|  | ||||
|         " Split the body and the remainder of the text. | ||||
|         let l:remainder_start_index = l:body_start_index + str2nr(l:length_match[1]) | ||||
|  | ||||
|         if len(l:remainder) < l:remainder_start_index | ||||
|             " We don't have enough data yet. | ||||
|             break | ||||
|         endif | ||||
|  | ||||
|         let l:body = l:remainder[l:body_start_index : l:remainder_start_index - 1] | ||||
|         let l:remainder = l:remainder[l:remainder_start_index :] | ||||
|  | ||||
|         " Parse the JSON object and add it to the list. | ||||
|         call add(l:response_list, json_decode(l:body)) | ||||
|     endwhile | ||||
|  | ||||
|     return [l:remainder, l:response_list] | ||||
| endfunction | ||||
|  | ||||
| function! s:FindProjectWithInitRequestID(conn, init_request_id) abort | ||||
|     for l:project_root in keys(a:conn.projects) | ||||
|         let l:project = a:conn.projects[l:project_root] | ||||
|  | ||||
|         if l:project.init_request_id == a:init_request_id | ||||
|             return l:project | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return {} | ||||
| endfunction | ||||
|  | ||||
| function! s:MarkProjectAsInitialized(conn, project) abort | ||||
|     let a:project.initialized = 1 | ||||
|  | ||||
|     " After the server starts, send messages we had queued previously. | ||||
|     for l:message_data in a:project.message_queue | ||||
|         call s:SendMessageData(a:conn, l:message_data) | ||||
|     endfor | ||||
|  | ||||
|     " Remove the messages now. | ||||
|     let a:conn.message_queue = [] | ||||
| endfunction | ||||
|  | ||||
| function! s:HandleInitializeResponse(conn, response) abort | ||||
|     let l:request_id = a:response.request_id | ||||
|     let l:project = s:FindProjectWithInitRequestID(a:conn, l:request_id) | ||||
|  | ||||
|     if !empty(l:project) | ||||
|         call s:MarkProjectAsInitialized(a:conn, l:project) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#HandleOtherInitializeResponses(conn, response) abort | ||||
|     let l:uninitialized_projects = [] | ||||
|  | ||||
|     for [l:key, l:value] in items(a:conn.projects) | ||||
|         if l:value.initialized == 0 | ||||
|             call add(l:uninitialized_projects, [l:key, l:value]) | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     if empty(l:uninitialized_projects) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     if get(a:response, 'method', '') is# '' | ||||
|         if has_key(get(a:response, 'result', {}), 'capabilities') | ||||
|             for [l:dir, l:project] in l:uninitialized_projects | ||||
|                 call s:MarkProjectAsInitialized(a:conn, l:project) | ||||
|             endfor | ||||
|         endif | ||||
|     elseif get(a:response, 'method', '') is# 'textDocument/publishDiagnostics' | ||||
|         let l:filename = ale#path#FromURI(a:response.params.uri) | ||||
|  | ||||
|         for [l:dir, l:project] in l:uninitialized_projects | ||||
|             if l:filename[:len(l:dir) - 1] is# l:dir | ||||
|                 call s:MarkProjectAsInitialized(a:conn, l:project) | ||||
|             endif | ||||
|         endfor | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#HandleMessage(conn, message) abort | ||||
|     let a:conn.data .= a:message | ||||
|  | ||||
|     " Parse the objects now if we can, and keep the remaining text. | ||||
|     let [a:conn.data, l:response_list] = ale#lsp#ReadMessageData(a:conn.data) | ||||
|  | ||||
|     " Call our callbacks. | ||||
|     for l:response in l:response_list | ||||
|         if get(l:response, 'method', '') is# 'initialize' | ||||
|             call s:HandleInitializeResponse(a:conn, l:response) | ||||
|         else | ||||
|             call ale#lsp#HandleOtherInitializeResponses(a:conn, l:response) | ||||
|  | ||||
|             " Call all of the registered handlers with the response. | ||||
|             for l:Callback in a:conn.callback_list | ||||
|                 call ale#util#GetFunction(l:Callback)(a:conn.id, l:response) | ||||
|             endfor | ||||
|         endif | ||||
|     endfor | ||||
| endfunction | ||||
|  | ||||
| function! s:HandleChannelMessage(channel, message) abort | ||||
|     let l:info = ch_info(a:channel) | ||||
|     let l:address = l:info.hostname . l:info.address | ||||
|     let l:conn = s:FindConnection('id', l:address) | ||||
|  | ||||
|     call ale#lsp#HandleMessage(l:conn, a:message) | ||||
| endfunction | ||||
|  | ||||
| function! s:HandleCommandMessage(job_id, message) abort | ||||
|     let l:conn = s:FindConnection('id', a:job_id) | ||||
|  | ||||
|     call ale#lsp#HandleMessage(l:conn, a:message) | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#RegisterProject(conn, project_root) abort | ||||
|     " Empty strings can't be used for Dictionary keys in NeoVim, due to E713. | ||||
|     " This appears to be a nonsensical bug in NeoVim. | ||||
|     let l:key = empty(a:project_root) ? '<<EMPTY>>' : a:project_root | ||||
|  | ||||
|     if !has_key(a:conn.projects, l:key) | ||||
|         " Tools without project roots are ready right away, like tsserver. | ||||
|         let a:conn.projects[l:key] = { | ||||
|         \   'initialized': empty(a:project_root), | ||||
|         \   'init_request_id': 0, | ||||
|         \   'message_queue': [], | ||||
|         \} | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#GetProject(conn, project_root) abort | ||||
|     let l:key = empty(a:project_root) ? '<<EMPTY>>' : a:project_root | ||||
|  | ||||
|     return get(a:conn.projects, l:key, {}) | ||||
| endfunction | ||||
|  | ||||
| " Start a program for LSP servers which run with executables. | ||||
| " | ||||
| " The job ID will be returned for for the program if it ran, otherwise | ||||
| " 0 will be returned. | ||||
| function! ale#lsp#StartProgram(executable, command, project_root, callback) abort | ||||
|     if !executable(a:executable) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:conn = s:FindConnection('executable', a:executable) | ||||
|  | ||||
|     " Get the current connection or a new one. | ||||
|     let l:conn = !empty(l:conn) ? l:conn : s:NewConnection() | ||||
|     let l:conn.executable = a:executable | ||||
|  | ||||
|     if !has_key(l:conn, 'id') || !ale#job#IsRunning(l:conn.id) | ||||
|         let l:options = { | ||||
|         \   'mode': 'raw', | ||||
|         \   'out_cb': function('s:HandleCommandMessage'), | ||||
|         \} | ||||
|         let l:job_id = ale#job#Start(a:command, l:options) | ||||
|     else | ||||
|         let l:job_id = l:conn.id | ||||
|     endif | ||||
|  | ||||
|     if l:job_id <= 0 | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:conn.id = l:job_id | ||||
|     " Add the callback to the List if it's not there already. | ||||
|     call uniq(sort(add(l:conn.callback_list, a:callback))) | ||||
|     call ale#lsp#RegisterProject(l:conn, a:project_root) | ||||
|  | ||||
|     return l:job_id | ||||
| endfunction | ||||
|  | ||||
| " Connect to an address and set up a callback for handling responses. | ||||
| function! ale#lsp#ConnectToAddress(address, project_root, callback) abort | ||||
|     let l:conn = s:FindConnection('id', a:address) | ||||
|     " Get the current connection or a new one. | ||||
|     let l:conn = !empty(l:conn) ? l:conn : s:NewConnection() | ||||
|  | ||||
|     if !has_key(l:conn, 'channel') || ch_status(l:conn.channel) isnot# 'open' | ||||
|         let l:conn.channnel = ch_open(a:address, { | ||||
|         \   'mode': 'raw', | ||||
|         \   'waittime': 0, | ||||
|         \   'callback': function('s:HandleChannelMessage'), | ||||
|         \}) | ||||
|     endif | ||||
|  | ||||
|     if ch_status(l:conn.channnel) is# 'fail' | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:conn.id = a:address | ||||
|     " Add the callback to the List if it's not there already. | ||||
|     call uniq(sort(add(l:conn.callback_list, a:callback))) | ||||
|     call ale#lsp#RegisterProject(l:conn, a:project_root) | ||||
|  | ||||
|     return 1 | ||||
| endfunction | ||||
|  | ||||
| " Stop all LSP connections, closing all jobs and channels, and removing any | ||||
| " queued messages. | ||||
| function! ale#lsp#StopAll() abort | ||||
|     for l:conn in s:connections | ||||
|         if has_key(l:conn, 'channel') | ||||
|             call ch_close(l:conn.channel) | ||||
|         else | ||||
|             call ale#job#Stop(l:conn.id) | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     let s:connections = [] | ||||
| endfunction | ||||
|  | ||||
| function! s:SendMessageData(conn, data) abort | ||||
|     if has_key(a:conn, 'executable') | ||||
|         call ale#job#SendRaw(a:conn.id, a:data) | ||||
|     elseif has_key(a:conn, 'channel') && ch_status(a:conn.channnel) is# 'open' | ||||
|         " Send the message to the server | ||||
|         call ch_sendraw(a:conn.channel, a:data) | ||||
|     else | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     return 1 | ||||
| endfunction | ||||
|  | ||||
| " Send a message to an LSP server. | ||||
| " Notifications do not need to be handled. | ||||
| " | ||||
| " Returns -1 when a message is sent, but no response is expected | ||||
| "          0 when the message is not sent and | ||||
| "          >= 1 with the message ID when a response is expected. | ||||
| function! ale#lsp#Send(conn_id, message, ...) abort | ||||
|     let l:project_root = get(a:000, 0, '') | ||||
|  | ||||
|     let l:conn = s:FindConnection('id', a:conn_id) | ||||
|  | ||||
|     if empty(l:conn) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:project = ale#lsp#GetProject(l:conn, l:project_root) | ||||
|  | ||||
|     if empty(l:project) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     " If we haven't initialized the server yet, then send the message for it. | ||||
|     if !l:project.initialized | ||||
|         " Only send the init message once. | ||||
|         if !l:project.init_request_id | ||||
|             let [l:init_id, l:init_data] = ale#lsp#CreateMessageData( | ||||
|             \   ale#lsp#message#Initialize(l:project_root), | ||||
|             \) | ||||
|  | ||||
|             let l:project.init_request_id = l:init_id | ||||
|  | ||||
|             call s:SendMessageData(l:conn, l:init_data) | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     let [l:id, l:data] = ale#lsp#CreateMessageData(a:message) | ||||
|  | ||||
|     if l:project.initialized | ||||
|         " Send the message now. | ||||
|         call s:SendMessageData(l:conn, l:data) | ||||
|     else | ||||
|         " Add the message we wanted to send to a List to send later. | ||||
|         call add(l:project.message_queue, l:data) | ||||
|     endif | ||||
|  | ||||
|     return l:id == 0 ? -1 : l:id | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#OpenDocumentIfNeeded(conn_id, buffer, project_root, language_id) abort | ||||
|     let l:conn = s:FindConnection('id', a:conn_id) | ||||
|     let l:opened = 0 | ||||
|  | ||||
|     if !empty(l:conn) && index(l:conn.open_documents, a:buffer) < 0 | ||||
|         if empty(a:language_id) | ||||
|             let l:message = ale#lsp#tsserver_message#Open(a:buffer) | ||||
|         else | ||||
|             let l:message = ale#lsp#message#DidOpen(a:buffer, a:language_id) | ||||
|         endif | ||||
|  | ||||
|         call ale#lsp#Send(a:conn_id, l:message, a:project_root) | ||||
|         call add(l:conn.open_documents, a:buffer) | ||||
|         let l:opened = 1 | ||||
|     endif | ||||
|  | ||||
|     return l:opened | ||||
| endfunction | ||||
							
								
								
									
										118
									
								
								sources_non_forked/ale/autoload/ale/lsp/message.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								sources_non_forked/ale/autoload/ale/lsp/message.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,118 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Language Server Protocol message implementations | ||||
| " | ||||
| " Messages in this movie will be returned in the format | ||||
| " [is_notification, method_name, params?] | ||||
| let g:ale_lsp_next_version_id = 1 | ||||
|  | ||||
| " The LSP protocols demands that we send every change to a document, including | ||||
| " undo, with incrementing version numbers, so we'll just use one incrementing | ||||
| " ID for everything. | ||||
| function! ale#lsp#message#GetNextVersionID() abort | ||||
|     " Use the current ID | ||||
|     let l:id = g:ale_lsp_next_version_id | ||||
|  | ||||
|     " Increment the ID variable. | ||||
|     let g:ale_lsp_next_version_id += 1 | ||||
|  | ||||
|     " When the ID overflows, reset it to 1. By the time we hit the initial ID | ||||
|     " again, the messages will be long gone. | ||||
|     if g:ale_lsp_next_version_id < 1 | ||||
|         let g:ale_lsp_next_version_id = 1 | ||||
|     endif | ||||
|  | ||||
|     return l:id | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#message#Initialize(root_path) abort | ||||
|     " TODO: Define needed capabilities. | ||||
|     return [0, 'initialize', { | ||||
|     \   'processId': getpid(), | ||||
|     \   'rootPath': a:root_path, | ||||
|     \   'capabilities': {}, | ||||
|     \}] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#message#Initialized() abort | ||||
|     return [1, 'initialized'] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#message#Shutdown() abort | ||||
|     return [0, 'shutdown'] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#message#Exit() abort | ||||
|     return [1, 'exit'] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#message#DidOpen(buffer, language_id) abort | ||||
|     let l:lines = getbufline(a:buffer, 1, '$') | ||||
|  | ||||
|     return [1, 'textDocument/didOpen', { | ||||
|     \   'textDocument': { | ||||
|     \       'uri': ale#path#ToURI(expand('#' . a:buffer . ':p')), | ||||
|     \       'languageId': a:language_id, | ||||
|     \       'version': ale#lsp#message#GetNextVersionID(), | ||||
|     \       'text': join(l:lines, "\n") . "\n", | ||||
|     \   }, | ||||
|     \}] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#message#DidChange(buffer) abort | ||||
|     let l:lines = getbufline(a:buffer, 1, '$') | ||||
|  | ||||
|     " For changes, we simply send the full text of the document to the server. | ||||
|     return [1, 'textDocument/didChange', { | ||||
|     \   'textDocument': { | ||||
|     \       'uri': ale#path#ToURI(expand('#' . a:buffer . ':p')), | ||||
|     \       'version': ale#lsp#message#GetNextVersionID(), | ||||
|     \   }, | ||||
|     \   'contentChanges': [{'text': join(l:lines, "\n") . "\n"}] | ||||
|     \}] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#message#DidSave(buffer) abort | ||||
|     return [1, 'textDocument/didSave', { | ||||
|     \   'textDocument': { | ||||
|     \       'uri': ale#path#ToURI(expand('#' . a:buffer . ':p')), | ||||
|     \   }, | ||||
|     \}] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#message#DidClose(buffer) abort | ||||
|     return [1, 'textDocument/didClose', { | ||||
|     \   'textDocument': { | ||||
|     \       'uri': ale#path#ToURI(expand('#' . a:buffer . ':p')), | ||||
|     \   }, | ||||
|     \}] | ||||
| endfunction | ||||
|  | ||||
| let s:COMPLETION_TRIGGER_INVOKED = 1 | ||||
| let s:COMPLETION_TRIGGER_CHARACTER = 2 | ||||
|  | ||||
| function! ale#lsp#message#Completion(buffer, line, column, trigger_character) abort | ||||
|     let l:message = [0, 'textDocument/completion', { | ||||
|     \   'textDocument': { | ||||
|     \       'uri': ale#path#ToURI(expand('#' . a:buffer . ':p')), | ||||
|     \   }, | ||||
|     \   'position': {'line': a:line - 1, 'character': a:column}, | ||||
|     \}] | ||||
|  | ||||
|     if !empty(a:trigger_character) | ||||
|         let l:message[2].context = { | ||||
|         \   'triggerKind': s:COMPLETION_TRIGGER_CHARACTER, | ||||
|         \   'triggerCharacter': a:trigger_character, | ||||
|         \} | ||||
|     endif | ||||
|  | ||||
|     return l:message | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#message#Definition(buffer, line, column) abort | ||||
|     return [0, 'textDocument/definition', { | ||||
|     \   'textDocument': { | ||||
|     \       'uri': ale#path#ToURI(expand('#' . a:buffer . ':p')), | ||||
|     \   }, | ||||
|     \   'position': {'line': a:line - 1, 'character': a:column}, | ||||
|     \}] | ||||
| endfunction | ||||
							
								
								
									
										25
									
								
								sources_non_forked/ale/autoload/ale/lsp/reset.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								sources_non_forked/ale/autoload/ale/lsp/reset.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| " Stop all LSPs and remove all of the data for them. | ||||
| function! ale#lsp#reset#StopAllLSPs() abort | ||||
|     call ale#lsp#StopAll() | ||||
|  | ||||
|     if exists('*ale#definition#ClearLSPData') | ||||
|         " Clear the mapping for connections, etc. | ||||
|         call ale#definition#ClearLSPData() | ||||
|     endif | ||||
|  | ||||
|     if exists('*ale#engine#ClearLSPData') | ||||
|         " Clear the mapping for connections, etc. | ||||
|         call ale#engine#ClearLSPData() | ||||
|  | ||||
|         " Remove the problems for all of the LSP linters in every buffer. | ||||
|         for l:buffer_string in keys(g:ale_buffer_info) | ||||
|             let l:buffer = str2nr(l:buffer_string) | ||||
|  | ||||
|             for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype')) | ||||
|                 if !empty(l:linter.lsp) | ||||
|                     call ale#engine#HandleLoclist(l:linter.name, l:buffer, []) | ||||
|                 endif | ||||
|             endfor | ||||
|         endfor | ||||
|     endif | ||||
| endfunction | ||||
							
								
								
									
										74
									
								
								sources_non_forked/ale/autoload/ale/lsp/response.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								sources_non_forked/ale/autoload/ale/lsp/response.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,74 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Parsing and transforming of LSP server responses. | ||||
|  | ||||
| " Constants for message severity codes. | ||||
| let s:SEVERITY_ERROR = 1 | ||||
| let s:SEVERITY_WARNING = 2 | ||||
| let s:SEVERITY_INFORMATION = 3 | ||||
| let s:SEVERITY_HINT = 4 | ||||
|  | ||||
| " Parse the message for textDocument/publishDiagnostics | ||||
| function! ale#lsp#response#ReadDiagnostics(response) abort | ||||
|     let l:loclist = [] | ||||
|  | ||||
|     for l:diagnostic in a:response.params.diagnostics | ||||
|         let l:severity = get(l:diagnostic, 'severity', 0) | ||||
|         let l:loclist_item = { | ||||
|         \   'text': l:diagnostic.message, | ||||
|         \   'type': 'E', | ||||
|         \   'lnum': l:diagnostic.range.start.line + 1, | ||||
|         \   'col': l:diagnostic.range.start.character + 1, | ||||
|         \   'end_lnum': l:diagnostic.range.end.line + 1, | ||||
|         \   'end_col': l:diagnostic.range.end.character + 1, | ||||
|         \} | ||||
|  | ||||
|         if l:severity == s:SEVERITY_WARNING | ||||
|             let l:loclist_item.type = 'W' | ||||
|         elseif l:severity == s:SEVERITY_INFORMATION | ||||
|             " TODO: Use 'I' here in future. | ||||
|             let l:loclist_item.type = 'W' | ||||
|         elseif l:severity == s:SEVERITY_HINT | ||||
|             " TODO: Use 'H' here in future | ||||
|             let l:loclist_item.type = 'W' | ||||
|         endif | ||||
|  | ||||
|         if has_key(l:diagnostic, 'code') | ||||
|             let l:loclist_item.nr = l:diagnostic.code | ||||
|         endif | ||||
|  | ||||
|         call add(l:loclist, l:loclist_item) | ||||
|     endfor | ||||
|  | ||||
|     return l:loclist | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#response#ReadTSServerDiagnostics(response) abort | ||||
|     let l:loclist = [] | ||||
|  | ||||
|     for l:diagnostic in a:response.body.diagnostics | ||||
|         let l:loclist_item = { | ||||
|         \   'text': l:diagnostic.text, | ||||
|         \   'type': 'E', | ||||
|         \   'lnum': l:diagnostic.start.line, | ||||
|         \   'col': l:diagnostic.start.offset, | ||||
|         \   'end_lnum': l:diagnostic.end.line, | ||||
|         \   'end_col': l:diagnostic.end.offset, | ||||
|         \} | ||||
|  | ||||
|         if has_key(l:diagnostic, 'code') | ||||
|             let l:loclist_item.nr = l:diagnostic.code | ||||
|         endif | ||||
|  | ||||
|         if get(l:diagnostic, 'category') is# 'warning' | ||||
|             let l:loclist_item.type = 'W' | ||||
|         endif | ||||
|  | ||||
|         if get(l:diagnostic, 'category') is# 'suggestion' | ||||
|             let l:loclist_item.type = 'I' | ||||
|         endif | ||||
|  | ||||
|         call add(l:loclist, l:loclist_item) | ||||
|     endfor | ||||
|  | ||||
|     return l:loclist | ||||
| endfunction | ||||
							
								
								
									
										63
									
								
								sources_non_forked/ale/autoload/ale/lsp/tsserver_message.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								sources_non_forked/ale/autoload/ale/lsp/tsserver_message.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: tsserver message implementations | ||||
| " | ||||
| " Messages in this movie will be returned in the format | ||||
| " [is_notification, command_name, params?] | ||||
| " | ||||
| " Every command must begin with the string 'ts@', which will be used to | ||||
| " detect the different message format for tsserver, and this string will | ||||
| " be removed from the actual command name, | ||||
|  | ||||
| function! ale#lsp#tsserver_message#Open(buffer) abort | ||||
|     return [1, 'ts@open', {'file': expand('#' . a:buffer . ':p')}] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#tsserver_message#Close(buffer) abort | ||||
|     return [1, 'ts@close', {'file': expand('#' . a:buffer . ':p')}] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#tsserver_message#Change(buffer) abort | ||||
|     let l:lines = getbufline(a:buffer, 1, '$') | ||||
|  | ||||
|     " We will always use a very high endLine number, so we can delete | ||||
|     " lines from files. tsserver will gladly accept line numbers beyond the | ||||
|     " end. | ||||
|     return [1, 'ts@change', { | ||||
|     \   'file': expand('#' . a:buffer . ':p'), | ||||
|     \   'line': 1, | ||||
|     \   'offset': 1, | ||||
|     \   'endLine': 1073741824, | ||||
|     \   'endOffset': 1, | ||||
|     \   'insertString': join(l:lines, "\n") . "\n", | ||||
|     \}] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#tsserver_message#Geterr(buffer) abort | ||||
|     return [1, 'ts@geterr', {'files': [expand('#' . a:buffer . ':p')]}] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#tsserver_message#Completions(buffer, line, column, prefix) abort | ||||
|     return [0, 'ts@completions', { | ||||
|     \   'line': a:line, | ||||
|     \   'offset': a:column, | ||||
|     \   'file': expand('#' . a:buffer . ':p'), | ||||
|     \   'prefix': a:prefix, | ||||
|     \}] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#tsserver_message#CompletionEntryDetails(buffer, line, column, entry_names) abort | ||||
|     return [0, 'ts@completionEntryDetails', { | ||||
|     \   'line': a:line, | ||||
|     \   'offset': a:column, | ||||
|     \   'file': expand('#' . a:buffer . ':p'), | ||||
|     \   'entryNames': a:entry_names, | ||||
|     \}] | ||||
| endfunction | ||||
|  | ||||
| function! ale#lsp#tsserver_message#Definition(buffer, line, column) abort | ||||
|     return [0, 'ts@definition', { | ||||
|     \   'line': a:line, | ||||
|     \   'offset': a:column, | ||||
|     \   'file': expand('#' . a:buffer . ':p'), | ||||
|     \}] | ||||
| endfunction | ||||
							
								
								
									
										42
									
								
								sources_non_forked/ale/autoload/ale/node.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								sources_non_forked/ale/autoload/ale/node.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Functions for working with Node executables. | ||||
|  | ||||
| call ale#Set('windows_node_executable_path', 'node.exe') | ||||
|  | ||||
| " Given a buffer number, a base variable name, and a list of paths to search | ||||
| " for in ancestor directories, detect the executable path for a Node program. | ||||
| " | ||||
| " The use_global and executable options for the relevant program will be used. | ||||
| function! ale#node#FindExecutable(buffer, base_var_name, path_list) abort | ||||
|     if ale#Var(a:buffer, a:base_var_name . '_use_global') | ||||
|         return ale#Var(a:buffer, a:base_var_name . '_executable') | ||||
|     endif | ||||
|  | ||||
|     for l:path in a:path_list | ||||
|         let l:executable = ale#path#FindNearestFile(a:buffer, l:path) | ||||
|  | ||||
|         if !empty(l:executable) | ||||
|             return l:executable | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return ale#Var(a:buffer, a:base_var_name . '_executable') | ||||
| endfunction | ||||
|  | ||||
| " Create a executable string which executes a Node.js script command with a | ||||
| " Node.js executable if needed. | ||||
| " | ||||
| " The executable string should not be escaped before passing it to this | ||||
| " function, the executable string will be escaped when returned by this | ||||
| " function. | ||||
| " | ||||
| " The executable is only prefixed for Windows machines | ||||
| function! ale#node#Executable(buffer, executable) abort | ||||
|     if ale#Has('win32') && a:executable =~? '\.js$' | ||||
|         let l:node = ale#Var(a:buffer, 'windows_node_executable_path') | ||||
|  | ||||
|         return ale#Escape(l:node) . ' ' . ale#Escape(a:executable) | ||||
|     endif | ||||
|  | ||||
|     return ale#Escape(a:executable) | ||||
| endfunction | ||||
							
								
								
									
										192
									
								
								sources_non_forked/ale/autoload/ale/path.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								sources_non_forked/ale/autoload/ale/path.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,192 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Functions for working with paths in the filesystem. | ||||
|  | ||||
| " simplify a path, and fix annoying issues with paths on Windows. | ||||
| " | ||||
| " Forward slashes are changed to back slashes so path equality works better. | ||||
| " | ||||
| " Paths starting with more than one forward slash are changed to only one | ||||
| " forward slash, to prevent the paths being treated as special MSYS paths. | ||||
| function! ale#path#Simplify(path) abort | ||||
|     if has('unix') | ||||
|         return substitute(simplify(a:path), '^//\+', '/', 'g') " no-custom-checks | ||||
|     endif | ||||
|  | ||||
|     let l:win_path = substitute(a:path, '/', '\\', 'g') | ||||
|  | ||||
|     return substitute(simplify(l:win_path), '^\\\+', '\', 'g') " no-custom-checks | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer and a filename, find the nearest file by searching upwards | ||||
| " through the paths relative to the given buffer. | ||||
| function! ale#path#FindNearestFile(buffer, filename) abort | ||||
|     let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p') | ||||
|     let l:buffer_filename = fnameescape(l:buffer_filename) | ||||
|  | ||||
|     let l:relative_path = findfile(a:filename, l:buffer_filename . ';') | ||||
|  | ||||
|     if !empty(l:relative_path) | ||||
|         return fnamemodify(l:relative_path, ':p') | ||||
|     endif | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer and a directory name, find the nearest directory by searching upwards | ||||
| " through the paths relative to the given buffer. | ||||
| function! ale#path#FindNearestDirectory(buffer, directory_name) abort | ||||
|     let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p') | ||||
|     let l:buffer_filename = fnameescape(l:buffer_filename) | ||||
|  | ||||
|     let l:relative_path = finddir(a:directory_name, l:buffer_filename . ';') | ||||
|  | ||||
|     if !empty(l:relative_path) | ||||
|         return fnamemodify(l:relative_path, ':p') | ||||
|     endif | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer, a string to search for, an a global fallback for when | ||||
| " the search fails, look for a file in parent paths, and if that fails, | ||||
| " use the global fallback path instead. | ||||
| function! ale#path#ResolveLocalPath(buffer, search_string, global_fallback) abort | ||||
|     " Search for a locally installed file first. | ||||
|     let l:path = ale#path#FindNearestFile(a:buffer, a:search_string) | ||||
|  | ||||
|     " If the serach fails, try the global executable instead. | ||||
|     if empty(l:path) | ||||
|         let l:path = a:global_fallback | ||||
|     endif | ||||
|  | ||||
|     return l:path | ||||
| endfunction | ||||
|  | ||||
| " Output 'cd <directory> && ' | ||||
| " This function can be used changing the directory for a linter command. | ||||
| function! ale#path#CdString(directory) abort | ||||
|     return 'cd ' . ale#Escape(a:directory) . ' && ' | ||||
| endfunction | ||||
|  | ||||
| " Output 'cd <buffer_filename_directory> && ' | ||||
| " This function can be used changing the directory for a linter command. | ||||
| function! ale#path#BufferCdString(buffer) abort | ||||
|     return ale#path#CdString(fnamemodify(bufname(a:buffer), ':p:h')) | ||||
| endfunction | ||||
|  | ||||
| " Return 1 if a path is an absolute path. | ||||
| function! ale#path#IsAbsolute(filename) abort | ||||
|     if has('win32') && a:filename[:0] is# '\' | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     " Check for /foo and C:\foo, etc. | ||||
|     return a:filename[:0] is# '/' || a:filename[1:2] is# ':\' | ||||
| endfunction | ||||
|  | ||||
| let s:temp_dir = ale#path#Simplify(fnamemodify(tempname(), ':h')) | ||||
|  | ||||
| " Given a filename, return 1 if the file represents some temporary file | ||||
| " created by Vim. | ||||
| function! ale#path#IsTempName(filename) abort | ||||
|     return ale#path#Simplify(a:filename)[:len(s:temp_dir) - 1] is# s:temp_dir | ||||
| endfunction | ||||
|  | ||||
| " Given a base directory, which must not have a trailing slash, and a | ||||
| " filename, which may have an absolute path a path relative to the base | ||||
| " directory, return the absolute path to the file. | ||||
| function! ale#path#GetAbsPath(base_directory, filename) abort | ||||
|     if ale#path#IsAbsolute(a:filename) | ||||
|         return ale#path#Simplify(a:filename) | ||||
|     endif | ||||
|  | ||||
|     let l:sep = has('win32') ? '\' : '/' | ||||
|  | ||||
|     return ale#path#Simplify(a:base_directory . l:sep . a:filename) | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer number and a relative or absolute path, return 1 if the | ||||
| " two paths represent the same file on disk. | ||||
| function! ale#path#IsBufferPath(buffer, complex_filename) abort | ||||
|     " If the path is one of many different names for stdin, we have a match. | ||||
|     if a:complex_filename is# '-' | ||||
|     \|| a:complex_filename is# 'stdin' | ||||
|     \|| a:complex_filename[:0] is# '<' | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     let l:test_filename = ale#path#Simplify(a:complex_filename) | ||||
|  | ||||
|     if l:test_filename[:1] is# './' | ||||
|         let l:test_filename = l:test_filename[2:] | ||||
|     endif | ||||
|  | ||||
|     if l:test_filename[:1] is# '..' | ||||
|         " Remove ../../ etc. from the front of the path. | ||||
|         let l:test_filename = substitute(l:test_filename, '\v^(\.\.[/\\])+', '/', '') | ||||
|     endif | ||||
|  | ||||
|     " Use the basename for temporary files, as they are likely our files. | ||||
|     if ale#path#IsTempName(l:test_filename) | ||||
|         let l:test_filename = fnamemodify(l:test_filename, ':t') | ||||
|     endif | ||||
|  | ||||
|     let l:buffer_filename = expand('#' . a:buffer . ':p') | ||||
|  | ||||
|     return l:buffer_filename is# l:test_filename | ||||
|     \   || l:buffer_filename[-len(l:test_filename):] is# l:test_filename | ||||
| endfunction | ||||
|  | ||||
| " Given a path, return every component of the path, moving upwards. | ||||
| function! ale#path#Upwards(path) abort | ||||
|     let l:pattern = has('win32') ? '\v/+|\\+' : '\v/+' | ||||
|     let l:sep = has('win32') ? '\' : '/' | ||||
|     let l:parts = split(ale#path#Simplify(a:path), l:pattern) | ||||
|     let l:path_list = [] | ||||
|  | ||||
|     while !empty(l:parts) | ||||
|         call add(l:path_list, join(l:parts, l:sep)) | ||||
|         let l:parts = l:parts[:-2] | ||||
|     endwhile | ||||
|  | ||||
|     if has('win32') && a:path =~# '^[a-zA-z]:\' | ||||
|         " Add \ to C: for C:\, etc. | ||||
|         let l:path_list[-1] .= '\' | ||||
|     elseif a:path[0] is# '/' | ||||
|         " If the path starts with /, even on Windows, add / and / to all paths. | ||||
|         call map(l:path_list, '''/'' . v:val') | ||||
|         call add(l:path_list, '/') | ||||
|     endif | ||||
|  | ||||
|     return l:path_list | ||||
| endfunction | ||||
|  | ||||
| " Convert a filesystem path to a file:// URI | ||||
| " relatives paths will not be prefixed with the protocol. | ||||
| " For Windows paths, the `:` in C:\ etc. will not be percent-encoded. | ||||
| function! ale#path#ToURI(path) abort | ||||
|     let l:has_drive_letter = a:path[1:2] is# ':\' | ||||
|  | ||||
|     return substitute( | ||||
|     \   ((l:has_drive_letter || a:path[:0] is# '/') ? 'file://' : '') | ||||
|     \       . (l:has_drive_letter ? '/' . a:path[:2] : '') | ||||
|     \       . ale#uri#Encode(l:has_drive_letter ? a:path[3:] : a:path), | ||||
|     \   '\\', | ||||
|     \   '/', | ||||
|     \   'g', | ||||
|     \) | ||||
| endfunction | ||||
|  | ||||
| function! ale#path#FromURI(uri) abort | ||||
|     let l:i = len('file://') | ||||
|     let l:encoded_path = a:uri[: l:i - 1] is# 'file://' ? a:uri[l:i :] : a:uri | ||||
|  | ||||
|     let l:path = ale#uri#Decode(l:encoded_path) | ||||
|  | ||||
|     " If the path is like /C:/foo/bar, it should be C:\foo\bar instead. | ||||
|     if l:path =~# '^/[a-zA-Z]:' | ||||
|         let l:path = substitute(l:path[1:], '/', '\\', 'g') | ||||
|     endif | ||||
|  | ||||
|     return l:path | ||||
| endfunction | ||||
							
								
								
									
										44
									
								
								sources_non_forked/ale/autoload/ale/pattern_options.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								sources_non_forked/ale/autoload/ale/pattern_options.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Set options in files based on regex patterns. | ||||
|  | ||||
| " These variables are used to cache the sorting of patterns below. | ||||
| let s:last_pattern_options = {} | ||||
| let s:sorted_items = [] | ||||
|  | ||||
| function! s:CmpPatterns(left_item, right_item) abort | ||||
|     if a:left_item[0] < a:right_item[0] | ||||
|         return -1 | ||||
|     endif | ||||
|  | ||||
|     if a:left_item[0] > a:right_item[0] | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     return 0 | ||||
| endfunction | ||||
|  | ||||
| function! ale#pattern_options#SetOptions(buffer) abort | ||||
|     if !g:ale_pattern_options_enabled || empty(g:ale_pattern_options) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " The items will only be sorted whenever the patterns change. | ||||
|     if g:ale_pattern_options != s:last_pattern_options | ||||
|         let s:last_pattern_options = deepcopy(g:ale_pattern_options) | ||||
|         " The patterns are sorted, so they are applied consistently. | ||||
|         let s:sorted_items = sort( | ||||
|         \   items(g:ale_pattern_options), | ||||
|         \   function('s:CmpPatterns') | ||||
|         \) | ||||
|     endif | ||||
|  | ||||
|     let l:filename = expand('#' . a:buffer . ':p') | ||||
|  | ||||
|     for [l:pattern, l:options] in s:sorted_items | ||||
|         if match(l:filename, l:pattern) >= 0 | ||||
|             for [l:key, l:value] in items(l:options) | ||||
|                 call setbufvar(a:buffer, l:key, l:value) | ||||
|             endfor | ||||
|         endif | ||||
|     endfor | ||||
| endfunction | ||||
							
								
								
									
										18
									
								
								sources_non_forked/ale/autoload/ale/preview.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								sources_non_forked/ale/autoload/ale/preview.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Preview windows for showing whatever information in. | ||||
|  | ||||
| " Open a preview window and show some lines in it. | ||||
| function! ale#preview#Show(lines) abort | ||||
|     silent pedit ALEPreviewWindow | ||||
|     wincmd P | ||||
|     setlocal modifiable | ||||
|     setlocal noreadonly | ||||
|     setlocal nobuflisted | ||||
|     setlocal filetype=ale-preview | ||||
|     setlocal buftype=nofile | ||||
|     setlocal bufhidden=wipe | ||||
|     :%d | ||||
|     call setline(1, a:lines) | ||||
|     setlocal nomodifiable | ||||
|     setlocal readonly | ||||
| endfunction | ||||
							
								
								
									
										104
									
								
								sources_non_forked/ale/autoload/ale/python.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								sources_non_forked/ale/autoload/ale/python.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Functions for integrating with Python linters. | ||||
|  | ||||
| let s:sep = has('win32') ? '\' : '/' | ||||
| " bin is used for Unix virtualenv directories, and Scripts is for Windows. | ||||
| let s:bin_dir = has('unix') ? 'bin' : 'Scripts' | ||||
| let g:ale_virtualenv_dir_names = get(g:, 'ale_virtualenv_dir_names', [ | ||||
| \   '.env', | ||||
| \   'env', | ||||
| \   've-py3', | ||||
| \   've', | ||||
| \   'virtualenv', | ||||
| \   'venv', | ||||
| \]) | ||||
|  | ||||
| function! ale#python#FindProjectRootIni(buffer) abort | ||||
|     for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) | ||||
|         if filereadable(l:path . '/MANIFEST.in') | ||||
|         \|| filereadable(l:path . '/setup.cfg') | ||||
|         \|| filereadable(l:path . '/pytest.ini') | ||||
|         \|| filereadable(l:path . '/tox.ini') | ||||
|         \|| filereadable(l:path . '/mypy.ini') | ||||
|         \|| filereadable(l:path . '/pycodestyle.cfg') | ||||
|         \|| filereadable(l:path . '/flake8.cfg') | ||||
|             return l:path | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer number, find the project root directory for Python. | ||||
| " The root directory is defined as the first directory found while searching | ||||
| " upwards through paths, including the current directory, until a path | ||||
| " containing an init file (one from MANIFEST.in, setup.cfg, pytest.ini, | ||||
| " tox.ini) is found. If it is not possible to find the project root directory | ||||
| " via init file, then it will be defined as the first directory found | ||||
| " searching upwards through paths, including the current directory, until no | ||||
| " __init__.py files is found. | ||||
| function! ale#python#FindProjectRoot(buffer) abort | ||||
|     let l:ini_root = ale#python#FindProjectRootIni(a:buffer) | ||||
|  | ||||
|     if !empty(l:ini_root) | ||||
|       return l:ini_root | ||||
|     endif | ||||
|  | ||||
|     for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) | ||||
|         if !filereadable(l:path . '/__init__.py') | ||||
|             return l:path | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer number, find a virtualenv path for Python. | ||||
| function! ale#python#FindVirtualenv(buffer) abort | ||||
|     for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) | ||||
|         " Skip empty path components returned in MSYS. | ||||
|         if empty(l:path) | ||||
|             continue | ||||
|         endif | ||||
|  | ||||
|         for l:dirname in ale#Var(a:buffer, 'virtualenv_dir_names') | ||||
|             let l:venv_dir = ale#path#Simplify( | ||||
|             \   join([l:path, l:dirname], s:sep) | ||||
|             \) | ||||
|             let l:script_filename = ale#path#Simplify( | ||||
|             \   join([l:venv_dir, s:bin_dir, 'activate'], s:sep) | ||||
|             \) | ||||
|  | ||||
|             if filereadable(l:script_filename) | ||||
|                 return l:venv_dir | ||||
|             endif | ||||
|         endfor | ||||
|     endfor | ||||
|  | ||||
|     return $VIRTUAL_ENV | ||||
| endfunction | ||||
|  | ||||
| " Given a buffer number and a command name, find the path to the executable. | ||||
| " First search on a virtualenv for Python, if nothing is found, try the global | ||||
| " command. Returns an empty string if cannot find the executable | ||||
| function! ale#python#FindExecutable(buffer, base_var_name, path_list) abort | ||||
|     if ale#Var(a:buffer, a:base_var_name . '_use_global') | ||||
|         return ale#Var(a:buffer, a:base_var_name . '_executable') | ||||
|     endif | ||||
|  | ||||
|     let l:virtualenv = ale#python#FindVirtualenv(a:buffer) | ||||
|  | ||||
|     if !empty(l:virtualenv) | ||||
|         for l:path in a:path_list | ||||
|             let l:ve_executable = ale#path#Simplify( | ||||
|             \   join([l:virtualenv, s:bin_dir, l:path], s:sep) | ||||
|             \) | ||||
|  | ||||
|             if executable(l:ve_executable) | ||||
|                 return l:ve_executable | ||||
|             endif | ||||
|         endfor | ||||
|     endif | ||||
|  | ||||
|     return ale#Var(a:buffer, a:base_var_name . '_executable') | ||||
| endfunction | ||||
							
								
								
									
										22
									
								
								sources_non_forked/ale/autoload/ale/ruby.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								sources_non_forked/ale/autoload/ale/ruby.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| " Author: Eddie Lebow https://github.com/elebow | ||||
| " Description: Functions for integrating with Ruby tools | ||||
|  | ||||
| " Find the nearest dir contining "app", "db", and "config", and assume it is | ||||
| " the root of a Rails app. | ||||
| function! ale#ruby#FindRailsRoot(buffer) abort | ||||
|     for l:name in ['app', 'config', 'db'] | ||||
|         let l:dir = fnamemodify( | ||||
|         \   ale#path#FindNearestDirectory(a:buffer, l:name), | ||||
|         \   ':h:h' | ||||
|         \) | ||||
|  | ||||
|         if l:dir isnot# '.' | ||||
|         \&& isdirectory(l:dir . '/app') | ||||
|         \&& isdirectory(l:dir . '/config') | ||||
|         \&& isdirectory(l:dir . '/db') | ||||
|             return l:dir | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
							
								
								
									
										57
									
								
								sources_non_forked/ale/autoload/ale/semver.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								sources_non_forked/ale/autoload/ale/semver.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | ||||
| let s:version_cache = {} | ||||
|  | ||||
| " Reset the version cache used for parsing the version. | ||||
| function! ale#semver#ResetVersionCache() abort | ||||
|     let s:version_cache = {} | ||||
| endfunction | ||||
|  | ||||
| " Given an executable name and some lines of output, which can be empty, | ||||
| " parse the version from the lines of output, or return the cached version | ||||
| " triple [major, minor, patch] | ||||
| " | ||||
| " If the version cannot be found, an empty List will be returned instead. | ||||
| function! ale#semver#GetVersion(executable, version_lines) abort | ||||
|     let l:version = get(s:version_cache, a:executable, []) | ||||
|  | ||||
|     for l:line in a:version_lines | ||||
|         let l:match = matchlist(l:line, '\v(\d+)\.(\d+)\.(\d+)') | ||||
|  | ||||
|         if !empty(l:match) | ||||
|             let l:version = [l:match[1] + 0, l:match[2] + 0, l:match[3] + 0] | ||||
|             let s:version_cache[a:executable] = l:version | ||||
|  | ||||
|             break | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return l:version | ||||
| endfunction | ||||
|  | ||||
| " Return 1 if the semver version has been cached for a given executable. | ||||
| function! ale#semver#HasVersion(executable) abort | ||||
|     return has_key(s:version_cache, a:executable) | ||||
| endfunction | ||||
|  | ||||
| " Given two triples of integers [major, minor, patch], compare the triples | ||||
| " and return 1 if the LHS is greater than or equal to the RHS. | ||||
| " | ||||
| " Pairs of [major, minor] can also be used for either argument. | ||||
| " | ||||
| " 0 will be returned if the LHS is an empty List. | ||||
| function! ale#semver#GTE(lhs, rhs) abort | ||||
|     if empty(a:lhs) | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     if a:lhs[0] > a:rhs[0] | ||||
|         return 1 | ||||
|     elseif a:lhs[0] == a:rhs[0] | ||||
|         if a:lhs[1] > a:rhs[1] | ||||
|             return 1 | ||||
|         elseif a:lhs[1] == a:rhs[1] | ||||
|             return get(a:lhs, 2) >= get(a:rhs, 2) | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     return 0 | ||||
| endfunction | ||||
							
								
								
									
										386
									
								
								sources_non_forked/ale/autoload/ale/sign.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										386
									
								
								sources_non_forked/ale/autoload/ale/sign.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,386 @@ | ||||
| scriptencoding utf8 | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Draws error and warning signs into signcolumn | ||||
|  | ||||
| if !hlexists('ALEErrorSign') | ||||
|     highlight link ALEErrorSign error | ||||
| endif | ||||
|  | ||||
| if !hlexists('ALEStyleErrorSign') | ||||
|     highlight link ALEStyleErrorSign ALEErrorSign | ||||
| endif | ||||
|  | ||||
| if !hlexists('ALEWarningSign') | ||||
|     highlight link ALEWarningSign todo | ||||
| endif | ||||
|  | ||||
| if !hlexists('ALEStyleWarningSign') | ||||
|     highlight link ALEStyleWarningSign ALEWarningSign | ||||
| endif | ||||
|  | ||||
| if !hlexists('ALEInfoSign') | ||||
|     highlight link ALEInfoSign ALEWarningSign | ||||
| endif | ||||
|  | ||||
| if !hlexists('ALESignColumnWithErrors') | ||||
|     highlight link ALESignColumnWithErrors error | ||||
| endif | ||||
|  | ||||
| if !hlexists('ALESignColumnWithoutErrors') | ||||
|     function! s:SetSignColumnWithoutErrorsHighlight() abort | ||||
|         redir => l:output | ||||
|             silent highlight SignColumn | ||||
|         redir end | ||||
|  | ||||
|         let l:highlight_syntax = join(split(l:output)[2:]) | ||||
|  | ||||
|         let l:match = matchlist(l:highlight_syntax, '\vlinks to (.+)$') | ||||
|  | ||||
|         if !empty(l:match) | ||||
|             execute 'highlight link ALESignColumnWithoutErrors ' . l:match[1] | ||||
|         elseif l:highlight_syntax isnot# 'cleared' | ||||
|             execute 'highlight ALESignColumnWithoutErrors ' . l:highlight_syntax | ||||
|         endif | ||||
|     endfunction | ||||
|  | ||||
|     call s:SetSignColumnWithoutErrorsHighlight() | ||||
|     delfunction s:SetSignColumnWithoutErrorsHighlight | ||||
| endif | ||||
|  | ||||
| " Signs show up on the left for error markers. | ||||
| execute 'sign define ALEErrorSign text=' . g:ale_sign_error | ||||
| \   . ' texthl=ALEErrorSign linehl=ALEErrorLine' | ||||
| execute 'sign define ALEStyleErrorSign text=' . g:ale_sign_style_error | ||||
| \   . ' texthl=ALEStyleErrorSign linehl=ALEErrorLine' | ||||
| execute 'sign define ALEWarningSign text=' . g:ale_sign_warning | ||||
| \   . ' texthl=ALEWarningSign linehl=ALEWarningLine' | ||||
| execute 'sign define ALEStyleWarningSign text=' . g:ale_sign_style_warning | ||||
| \   . ' texthl=ALEStyleWarningSign linehl=ALEWarningLine' | ||||
| execute 'sign define ALEInfoSign text=' . g:ale_sign_info | ||||
| \   . ' texthl=ALEInfoSign linehl=ALEInfoLine' | ||||
| sign define ALEDummySign | ||||
|  | ||||
| let s:error_priority = 1 | ||||
| let s:warning_priority = 2 | ||||
| let s:info_priority = 3 | ||||
| let s:style_error_priority = 4 | ||||
| let s:style_warning_priority = 5 | ||||
|  | ||||
| function! ale#sign#GetSignName(sublist) abort | ||||
|     let l:priority = s:style_warning_priority | ||||
|  | ||||
|     " Determine the highest priority item for the line. | ||||
|     for l:item in a:sublist | ||||
|         if l:item.type is# 'I' | ||||
|             let l:item_priority = s:info_priority | ||||
|         elseif l:item.type is# 'W' | ||||
|             if get(l:item, 'sub_type', '') is# 'style' | ||||
|                 let l:item_priority = s:style_warning_priority | ||||
|             else | ||||
|                 let l:item_priority = s:warning_priority | ||||
|             endif | ||||
|         else | ||||
|             if get(l:item, 'sub_type', '') is# 'style' | ||||
|                 let l:item_priority = s:style_error_priority | ||||
|             else | ||||
|                 let l:item_priority = s:error_priority | ||||
|             endif | ||||
|         endif | ||||
|  | ||||
|         if l:item_priority < l:priority | ||||
|             let l:priority = l:item_priority | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     if l:priority is# s:error_priority | ||||
|         return 'ALEErrorSign' | ||||
|     endif | ||||
|  | ||||
|     if l:priority is# s:warning_priority | ||||
|         return 'ALEWarningSign' | ||||
|     endif | ||||
|  | ||||
|     if l:priority is# s:style_error_priority | ||||
|         return 'ALEStyleErrorSign' | ||||
|     endif | ||||
|  | ||||
|     if l:priority is# s:style_warning_priority | ||||
|         return 'ALEStyleWarningSign' | ||||
|     endif | ||||
|  | ||||
|     if l:priority is# s:info_priority | ||||
|         return 'ALEInfoSign' | ||||
|     endif | ||||
|  | ||||
|     " Use the error sign for invalid severities. | ||||
|     return 'ALEErrorSign' | ||||
| endfunction | ||||
|  | ||||
| " Read sign data for a buffer to a list of lines. | ||||
| function! ale#sign#ReadSigns(buffer) abort | ||||
|     redir => l:output | ||||
|        silent execute 'sign place buffer=' . a:buffer | ||||
|     redir end | ||||
|  | ||||
|     return split(l:output, "\n") | ||||
| endfunction | ||||
|  | ||||
| " Given a list of lines for sign output, return a List of [line, id, group] | ||||
| function! ale#sign#ParseSigns(line_list) abort | ||||
|     " Matches output like : | ||||
|     " line=4  id=1  name=ALEErrorSign | ||||
|     " строка=1  id=1000001  имя=ALEErrorSign | ||||
|     " 行=1  識別子=1000001  名前=ALEWarningSign | ||||
|     " línea=12 id=1000001 nombre=ALEWarningSign | ||||
|     " riga=1 id=1000001, nome=ALEWarningSign | ||||
|     let l:pattern = '\v^.*\=(\d+).*\=(\d+).*\=(ALE[a-zA-Z]+Sign)' | ||||
|     let l:result = [] | ||||
|     let l:is_dummy_sign_set = 0 | ||||
|  | ||||
|     for l:line in a:line_list | ||||
|         let l:match = matchlist(l:line, l:pattern) | ||||
|  | ||||
|         if len(l:match) > 0 | ||||
|             if l:match[3] is# 'ALEDummySign' | ||||
|                 let l:is_dummy_sign_set = 1 | ||||
|             else | ||||
|                 call add(l:result, [ | ||||
|                 \   str2nr(l:match[1]), | ||||
|                 \   str2nr(l:match[2]), | ||||
|                 \   l:match[3], | ||||
|                 \]) | ||||
|             endif | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     return [l:is_dummy_sign_set, l:result] | ||||
| endfunction | ||||
|  | ||||
| function! ale#sign#FindCurrentSigns(buffer) abort | ||||
|     let l:line_list = ale#sign#ReadSigns(a:buffer) | ||||
|  | ||||
|     return ale#sign#ParseSigns(l:line_list) | ||||
| endfunction | ||||
|  | ||||
| " Given a loclist, group the List into with one List per line. | ||||
| function! s:GroupLoclistItems(buffer, loclist) abort | ||||
|     let l:grouped_items = [] | ||||
|     let l:last_lnum = -1 | ||||
|  | ||||
|     for l:obj in a:loclist | ||||
|         if l:obj.bufnr != a:buffer | ||||
|             continue | ||||
|         endif | ||||
|  | ||||
|         " Create a new sub-List when we hit a new line. | ||||
|         if l:obj.lnum != l:last_lnum | ||||
|             call add(l:grouped_items, []) | ||||
|         endif | ||||
|  | ||||
|         call add(l:grouped_items[-1], l:obj) | ||||
|         let l:last_lnum = l:obj.lnum | ||||
|     endfor | ||||
|  | ||||
|     return l:grouped_items | ||||
| endfunction | ||||
|  | ||||
| function! s:UpdateLineNumbers(buffer, current_sign_list, loclist) abort | ||||
|     let l:line_map = {} | ||||
|     let l:line_numbers_changed = 0 | ||||
|  | ||||
|     for [l:line, l:sign_id, l:name] in a:current_sign_list | ||||
|         let l:line_map[l:sign_id] = l:line | ||||
|     endfor | ||||
|  | ||||
|     for l:item in a:loclist | ||||
|         if l:item.bufnr == a:buffer | ||||
|             let l:lnum = get(l:line_map, get(l:item, 'sign_id', 0), 0) | ||||
|  | ||||
|             if l:lnum && l:item.lnum != l:lnum | ||||
|                 let l:item.lnum = l:lnum | ||||
|                 let l:line_numbers_changed = 1 | ||||
|             endif | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     " When the line numbers change, sort the list again | ||||
|     if l:line_numbers_changed | ||||
|         call sort(a:loclist, 'ale#util#LocItemCompare') | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! s:BuildSignMap(buffer, current_sign_list, grouped_items) abort | ||||
|     let l:max_signs = ale#Var(a:buffer, 'max_signs') | ||||
|  | ||||
|     if l:max_signs is 0 | ||||
|         let l:selected_grouped_items = [] | ||||
|     elseif type(l:max_signs) is type(0) && l:max_signs > 0 | ||||
|         let l:selected_grouped_items = a:grouped_items[:l:max_signs - 1] | ||||
|     else | ||||
|         let l:selected_grouped_items = a:grouped_items | ||||
|     endif | ||||
|  | ||||
|     let l:sign_map = {} | ||||
|     let l:sign_offset = g:ale_sign_offset | ||||
|  | ||||
|     for [l:line, l:sign_id, l:name] in a:current_sign_list | ||||
|         let l:sign_info = get(l:sign_map, l:line, { | ||||
|         \   'current_id_list': [], | ||||
|         \   'current_name_list': [], | ||||
|         \   'new_id': 0, | ||||
|         \   'new_name': '', | ||||
|         \   'items': [], | ||||
|         \}) | ||||
|  | ||||
|         " Increment the sign offset for new signs, by the maximum sign ID. | ||||
|         if l:sign_id > l:sign_offset | ||||
|             let l:sign_offset = l:sign_id | ||||
|         endif | ||||
|  | ||||
|         " Remember the sign names and IDs in separate Lists, so they are easy | ||||
|         " to work with. | ||||
|         call add(l:sign_info.current_id_list, l:sign_id) | ||||
|         call add(l:sign_info.current_name_list, l:name) | ||||
|  | ||||
|         let l:sign_map[l:line] = l:sign_info | ||||
|     endfor | ||||
|  | ||||
|     for l:group in l:selected_grouped_items | ||||
|         let l:line = l:group[0].lnum | ||||
|         let l:sign_info = get(l:sign_map, l:line, { | ||||
|         \   'current_id_list': [], | ||||
|         \   'current_name_list': [], | ||||
|         \   'new_id': 0, | ||||
|         \   'new_name': '', | ||||
|         \   'items': [], | ||||
|         \}) | ||||
|  | ||||
|         let l:sign_info.new_name = ale#sign#GetSignName(l:group) | ||||
|         let l:sign_info.items = l:group | ||||
|  | ||||
|         let l:index = index( | ||||
|         \   l:sign_info.current_name_list, | ||||
|         \   l:sign_info.new_name | ||||
|         \) | ||||
|  | ||||
|         if l:index >= 0 | ||||
|             " We have a sign with this name already, so use the same ID. | ||||
|             let l:sign_info.new_id = l:sign_info.current_id_list[l:index] | ||||
|         else | ||||
|             " This sign name replaces the previous name, so use a new ID. | ||||
|             let l:sign_info.new_id = l:sign_offset + 1 | ||||
|             let l:sign_offset += 1 | ||||
|         endif | ||||
|  | ||||
|         let l:sign_map[l:line] = l:sign_info | ||||
|     endfor | ||||
|  | ||||
|     return l:sign_map | ||||
| endfunction | ||||
|  | ||||
| function! ale#sign#GetSignCommands(buffer, was_sign_set, sign_map) abort | ||||
|     let l:command_list = [] | ||||
|     let l:is_dummy_sign_set = a:was_sign_set | ||||
|  | ||||
|     " Set the dummy sign if we need to. | ||||
|     " The dummy sign is needed to keep the sign column open while we add | ||||
|     " and remove signs. | ||||
|     if !l:is_dummy_sign_set && (!empty(a:sign_map) || g:ale_sign_column_always) | ||||
|         call add(l:command_list, 'sign place ' | ||||
|         \   .  g:ale_sign_offset | ||||
|         \   . ' line=1 name=ALEDummySign buffer=' | ||||
|         \   . a:buffer | ||||
|         \) | ||||
|         let l:is_dummy_sign_set = 1 | ||||
|     endif | ||||
|  | ||||
|     " Place new items first. | ||||
|     for [l:line_str, l:info] in items(a:sign_map) | ||||
|         if l:info.new_id | ||||
|             " Save the sign IDs we are setting back on our loclist objects. | ||||
|             " These IDs will be used to preserve items which are set many times. | ||||
|             for l:item in l:info.items | ||||
|                 let l:item.sign_id = l:info.new_id | ||||
|             endfor | ||||
|  | ||||
|             if index(l:info.current_id_list, l:info.new_id) < 0 | ||||
|                 call add(l:command_list, 'sign place ' | ||||
|                 \   . (l:info.new_id) | ||||
|                 \   . ' line=' . l:line_str | ||||
|                 \   . ' name=' . (l:info.new_name) | ||||
|                 \   . ' buffer=' . a:buffer | ||||
|                 \) | ||||
|             endif | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     " Remove signs without new IDs. | ||||
|     for l:info in values(a:sign_map) | ||||
|         for l:current_id in l:info.current_id_list | ||||
|             if l:current_id isnot l:info.new_id | ||||
|                 call add(l:command_list, 'sign unplace ' | ||||
|                 \   . l:current_id | ||||
|                 \   . ' buffer=' . a:buffer | ||||
|                 \) | ||||
|             endif | ||||
|         endfor | ||||
|     endfor | ||||
|  | ||||
|     " Remove the dummy sign to close the sign column if we need to. | ||||
|     if l:is_dummy_sign_set && !g:ale_sign_column_always | ||||
|         call add(l:command_list, 'sign unplace ' | ||||
|         \   . g:ale_sign_offset | ||||
|         \   . ' buffer=' . a:buffer | ||||
|         \) | ||||
|     endif | ||||
|  | ||||
|     return l:command_list | ||||
| endfunction | ||||
|  | ||||
| " This function will set the signs which show up on the left. | ||||
| function! ale#sign#SetSigns(buffer, loclist) abort | ||||
|     if !bufexists(str2nr(a:buffer)) | ||||
|         " Stop immediately when attempting to set signs for a buffer which | ||||
|         " does not exist. | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     " Find the current markers | ||||
|     let [l:is_dummy_sign_set, l:current_sign_list] = | ||||
|     \   ale#sign#FindCurrentSigns(a:buffer) | ||||
|  | ||||
|     " Update the line numbers for items from before which may have moved. | ||||
|     call s:UpdateLineNumbers(a:buffer, l:current_sign_list, a:loclist) | ||||
|  | ||||
|     " Group items after updating the line numbers. | ||||
|     let l:grouped_items = s:GroupLoclistItems(a:buffer, a:loclist) | ||||
|  | ||||
|     " Build a map of current and new signs, with the lines as the keys. | ||||
|     let l:sign_map = s:BuildSignMap( | ||||
|     \   a:buffer, | ||||
|     \   l:current_sign_list, | ||||
|     \   l:grouped_items, | ||||
|     \) | ||||
|  | ||||
|     let l:command_list = ale#sign#GetSignCommands( | ||||
|     \   a:buffer, | ||||
|     \   l:is_dummy_sign_set, | ||||
|     \   l:sign_map, | ||||
|     \) | ||||
|  | ||||
|     " Change the sign column color if the option is on. | ||||
|     if g:ale_change_sign_column_color && !empty(a:loclist) | ||||
|         highlight clear SignColumn | ||||
|         highlight link SignColumn ALESignColumnWithErrors | ||||
|     endif | ||||
|  | ||||
|     for l:command in l:command_list | ||||
|         silent! execute l:command | ||||
|     endfor | ||||
|  | ||||
|     " Reset the sign column color when there are no more errors. | ||||
|     if g:ale_change_sign_column_color && empty(a:loclist) | ||||
|         highlight clear SignColumn | ||||
|         highlight link SignColumn ALESignColumnWithoutErrors | ||||
|     endif | ||||
| endfunction | ||||
							
								
								
									
										112
									
								
								sources_non_forked/ale/autoload/ale/statusline.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								sources_non_forked/ale/autoload/ale/statusline.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,112 @@ | ||||
| " Author: KabbAmine <amine.kabb@gmail.com> | ||||
| " Description: Statusline related function(s) | ||||
|  | ||||
| function! s:CreateCountDict() abort | ||||
|     " Keys 0 and 1 are for backwards compatibility. | ||||
|     " The count object used to be a List of [error_count, warning_count]. | ||||
|     return { | ||||
|     \   '0': 0, | ||||
|     \   '1': 0, | ||||
|     \   'error': 0, | ||||
|     \   'warning': 0, | ||||
|     \   'info': 0, | ||||
|     \   'style_error': 0, | ||||
|     \   'style_warning': 0, | ||||
|     \   'total': 0, | ||||
|     \} | ||||
| endfunction | ||||
|  | ||||
| " Update the buffer error/warning count with data from loclist. | ||||
| function! ale#statusline#Update(buffer, loclist) abort | ||||
|     if !exists('g:ale_buffer_info') || !has_key(g:ale_buffer_info, a:buffer) | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     let l:loclist = filter(copy(a:loclist), 'v:val.bufnr == a:buffer') | ||||
|     let l:count = s:CreateCountDict() | ||||
|     let l:count.total = len(l:loclist) | ||||
|  | ||||
|     for l:entry in l:loclist | ||||
|         if l:entry.type is# 'W' | ||||
|             if get(l:entry, 'sub_type', '') is# 'style' | ||||
|                 let l:count.style_warning += 1 | ||||
|             else | ||||
|                 let l:count.warning += 1 | ||||
|             endif | ||||
|         elseif l:entry.type is# 'I' | ||||
|             let l:count.info += 1 | ||||
|         elseif get(l:entry, 'sub_type', '') is# 'style' | ||||
|             let l:count.style_error += 1 | ||||
|         else | ||||
|             let l:count.error += 1 | ||||
|         endif | ||||
|     endfor | ||||
|  | ||||
|     " Set keys for backwards compatibility. | ||||
|     let l:count[0] = l:count.error + l:count.style_error | ||||
|     let l:count[1] = l:count.total - l:count[0] | ||||
|  | ||||
|     let g:ale_buffer_info[a:buffer].count = l:count | ||||
| endfunction | ||||
|  | ||||
| " Get the counts for the buffer, and update the counts if needed. | ||||
| function! s:GetCounts(buffer) abort | ||||
|     if !exists('g:ale_buffer_info') || !has_key(g:ale_buffer_info, a:buffer) | ||||
|         return s:CreateCountDict() | ||||
|     endif | ||||
|  | ||||
|     " Cache is cold, so manually ask for an update. | ||||
|     if !has_key(g:ale_buffer_info[a:buffer], 'count') | ||||
|         call ale#statusline#Update(a:buffer, g:ale_buffer_info[a:buffer].loclist) | ||||
|     endif | ||||
|  | ||||
|     return g:ale_buffer_info[a:buffer].count | ||||
| endfunction | ||||
|  | ||||
| " Returns a Dictionary with counts for use in third party integrations. | ||||
| function! ale#statusline#Count(buffer) abort | ||||
|     " The Dictionary is copied here before exposing it to other plugins. | ||||
|     return copy(s:GetCounts(a:buffer)) | ||||
| endfunction | ||||
|  | ||||
| " This is the historical format setting which could be configured before. | ||||
| function! s:StatusForListFormat() abort | ||||
|     let [l:error_format, l:warning_format, l:no_errors] = g:ale_statusline_format | ||||
|     let l:counts = s:GetCounts(bufnr('')) | ||||
|  | ||||
|     " Build strings based on user formatting preferences. | ||||
|     let l:errors = l:counts[0] ? printf(l:error_format, l:counts[0]) : '' | ||||
|     let l:warnings = l:counts[1] ? printf(l:warning_format, l:counts[1]) : '' | ||||
|  | ||||
|     " Different formats based on the combination of errors and warnings. | ||||
|     if empty(l:errors) && empty(l:warnings) | ||||
|         let l:res = l:no_errors | ||||
|     elseif !empty(l:errors) && !empty(l:warnings) | ||||
|         let l:res = printf('%s %s', l:errors, l:warnings) | ||||
|     else | ||||
|         let l:res = empty(l:errors) ? l:warnings : l:errors | ||||
|     endif | ||||
|  | ||||
|     return l:res | ||||
| endfunction | ||||
|  | ||||
| " Returns a formatted string that can be integrated in the statusline. | ||||
| " | ||||
| " This function is deprecated, and should not be used. Use the airline plugin | ||||
| " instead, or write your own status function with ale#statusline#Count() | ||||
| function! ale#statusline#Status() abort | ||||
|     if !get(g:, 'ale_deprecation_ale_statusline_status', 0) | ||||
|         execute 'echom ''ale#statusline#Status() is deprecated, use ale#statusline#Count() to write your own function.''' | ||||
|         let g:ale_deprecation_ale_statusline_status = 1 | ||||
|     endif | ||||
|  | ||||
|     if !exists('g:ale_statusline_format') | ||||
|         return 'OK' | ||||
|     endif | ||||
|  | ||||
|     if type(g:ale_statusline_format) == type([]) | ||||
|         return s:StatusForListFormat() | ||||
|     endif | ||||
|  | ||||
|     return '' | ||||
| endfunction | ||||
							
								
								
									
										54
									
								
								sources_non_forked/ale/autoload/ale/test.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								sources_non_forked/ale/autoload/ale/test.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Functions for making testing ALE easier. | ||||
| " | ||||
| " This file should not typically be loaded during the normal execution of ALE. | ||||
|  | ||||
| " Change the directory for checking things in particular test directories | ||||
| " | ||||
| " This function will set the g:dir variable, which represents the working | ||||
| " directory after changing the path. This variable allows a test to change | ||||
| " directories, and then switch back to a directory at the start of the test | ||||
| " run. | ||||
| " | ||||
| " This function should be run in a Vader Before: block. | ||||
| function! ale#test#SetDirectory(docker_path) abort | ||||
|     if a:docker_path[:len('/testplugin/') - 1] isnot# '/testplugin/' | ||||
|         throw 'docker_path must start with /testplugin/!' | ||||
|     endif | ||||
|  | ||||
|     " Try to switch directory, which will fail when running tests directly, | ||||
|     " and not through the Docker image. | ||||
|     silent! execute 'cd ' . fnameescape(a:docker_path) | ||||
|     let g:dir = getcwd() " no-custom-checks | ||||
| endfunction | ||||
|  | ||||
| " When g:dir is defined, switch back to the directory we saved, and then | ||||
| " delete that variable. | ||||
| " | ||||
| " The filename will be reset to dummy.txt | ||||
| " | ||||
| " This function should be run in a Vader After: block. | ||||
| function! ale#test#RestoreDirectory() abort | ||||
|     call ale#test#SetFilename('dummy.txt') | ||||
|     silent execute 'cd ' . fnameescape(g:dir) | ||||
|     unlet! g:dir | ||||
| endfunction | ||||
|  | ||||
| " Change the filename for the current buffer using a relative path to | ||||
| " the script without running autocmd commands. | ||||
| " | ||||
| " If a g:dir variable is set, it will be used as the path to the directory | ||||
| " containing the test file. | ||||
| function! ale#test#SetFilename(path) abort | ||||
|     let l:dir = get(g:, 'dir', '') | ||||
|  | ||||
|     if empty(l:dir) | ||||
|         let l:dir = getcwd() " no-custom-checks | ||||
|     endif | ||||
|  | ||||
|     let l:full_path = ale#path#IsAbsolute(a:path) | ||||
|     \   ? a:path | ||||
|     \   : l:dir . '/' . a:path | ||||
|  | ||||
|     silent! noautocmd execute 'file ' . fnameescape(ale#path#Simplify(l:full_path)) | ||||
| endfunction | ||||
							
								
								
									
										193
									
								
								sources_non_forked/ale/autoload/ale/toggle.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								sources_non_forked/ale/autoload/ale/toggle.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,193 @@ | ||||
| function! ale#toggle#InitAuGroups() abort | ||||
|     " This value used to be a Boolean as a Number, and is now a String. | ||||
|     let l:text_changed = '' . g:ale_lint_on_text_changed | ||||
|  | ||||
|     augroup ALEPatternOptionsGroup | ||||
|         autocmd! | ||||
|         autocmd BufEnter,BufRead * call ale#pattern_options#SetOptions(str2nr(expand('<abuf>'))) | ||||
|     augroup END | ||||
|  | ||||
|     augroup ALERunOnTextChangedGroup | ||||
|         autocmd! | ||||
|         if g:ale_enabled | ||||
|             if l:text_changed is? 'always' || l:text_changed is# '1' | ||||
|                 autocmd TextChanged,TextChangedI * call ale#Queue(g:ale_lint_delay) | ||||
|             elseif l:text_changed is? 'normal' | ||||
|                 autocmd TextChanged * call ale#Queue(g:ale_lint_delay) | ||||
|             elseif l:text_changed is? 'insert' | ||||
|                 autocmd TextChangedI * call ale#Queue(g:ale_lint_delay) | ||||
|             endif | ||||
|         endif | ||||
|     augroup END | ||||
|  | ||||
|     augroup ALERunOnEnterGroup | ||||
|         autocmd! | ||||
|         if g:ale_enabled | ||||
|             " Handle everything that needs to happen when buffers are entered. | ||||
|             autocmd BufEnter * call ale#events#EnterEvent(str2nr(expand('<abuf>'))) | ||||
|         endif | ||||
|         if g:ale_enabled && g:ale_lint_on_enter | ||||
|             autocmd BufWinEnter,BufRead * call ale#Queue(0, 'lint_file', str2nr(expand('<abuf>'))) | ||||
|             " Track when the file is changed outside of Vim. | ||||
|             autocmd FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand('<abuf>'))) | ||||
|         endif | ||||
|     augroup END | ||||
|  | ||||
|     augroup ALERunOnFiletypeChangeGroup | ||||
|         autocmd! | ||||
|         if g:ale_enabled && g:ale_lint_on_filetype_changed | ||||
|             " Only start linting if the FileType actually changes after | ||||
|             " opening a buffer. The FileType will fire when buffers are opened. | ||||
|             autocmd FileType * call ale#events#FileTypeEvent( | ||||
|             \   str2nr(expand('<abuf>')), | ||||
|             \   expand('<amatch>') | ||||
|             \) | ||||
|         endif | ||||
|     augroup END | ||||
|  | ||||
|     augroup ALERunOnSaveGroup | ||||
|         autocmd! | ||||
|         autocmd BufWritePost * call ale#events#SaveEvent(str2nr(expand('<abuf>'))) | ||||
|     augroup END | ||||
|  | ||||
|     augroup ALERunOnInsertLeave | ||||
|         autocmd! | ||||
|         if g:ale_enabled && g:ale_lint_on_insert_leave | ||||
|             autocmd InsertLeave * call ale#Queue(0) | ||||
|         endif | ||||
|     augroup END | ||||
|  | ||||
|     augroup ALECursorGroup | ||||
|         autocmd! | ||||
|         if g:ale_enabled && g:ale_echo_cursor | ||||
|             autocmd CursorMoved,CursorHold * call ale#cursor#EchoCursorWarningWithDelay() | ||||
|             " Look for a warning to echo as soon as we leave Insert mode. | ||||
|             " The script's position variable used when moving the cursor will | ||||
|             " not be changed here. | ||||
|             autocmd InsertLeave * call ale#cursor#EchoCursorWarning() | ||||
|         endif | ||||
|     augroup END | ||||
|  | ||||
|     if !g:ale_enabled | ||||
|         augroup! ALERunOnTextChangedGroup | ||||
|         augroup! ALERunOnEnterGroup | ||||
|         augroup! ALERunOnInsertLeave | ||||
|         augroup! ALECursorGroup | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! s:EnablePreamble() abort | ||||
|     " Set pattern options again, if enabled. | ||||
|     if g:ale_pattern_options_enabled | ||||
|         call ale#pattern_options#SetOptions(bufnr('')) | ||||
|     endif | ||||
|  | ||||
|     " Lint immediately, including running linters against the file. | ||||
|     call ale#Queue(0, 'lint_file') | ||||
| endfunction | ||||
|  | ||||
| function! s:DisablePostamble() abort | ||||
|     " Remove highlights for the current buffer now. | ||||
|     if g:ale_set_highlights | ||||
|         call ale#highlight#UpdateHighlights() | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! s:CleanupEveryBuffer() abort | ||||
|     for l:key in keys(g:ale_buffer_info) | ||||
|         " The key could be a filename or a buffer number, so try and | ||||
|         " convert it to a number. We need a number for the other | ||||
|         " functions. | ||||
|         let l:buffer = str2nr(l:key) | ||||
|  | ||||
|         if l:buffer > 0 | ||||
|             " Stop all jobs and clear the results for everything, and delete | ||||
|             " all of the data we stored for the buffer. | ||||
|             call ale#engine#Cleanup(l:buffer) | ||||
|         endif | ||||
|     endfor | ||||
| endfunction | ||||
|  | ||||
| function! ale#toggle#Toggle() abort | ||||
|     let g:ale_enabled = !get(g:, 'ale_enabled') | ||||
|  | ||||
|     if g:ale_enabled | ||||
|         call s:EnablePreamble() | ||||
|  | ||||
|         if g:ale_set_balloons | ||||
|             call ale#balloon#Enable() | ||||
|         endif | ||||
|     else | ||||
|         call s:CleanupEveryBuffer() | ||||
|         call s:DisablePostamble() | ||||
|  | ||||
|         if has('balloon_eval') | ||||
|             call ale#balloon#Disable() | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     call ale#toggle#InitAuGroups() | ||||
| endfunction | ||||
|  | ||||
| function! ale#toggle#Enable() abort | ||||
|     if !g:ale_enabled | ||||
|         " Set pattern options again, if enabled. | ||||
|         if g:ale_pattern_options_enabled | ||||
|             call ale#pattern_options#SetOptions(bufnr('')) | ||||
|         endif | ||||
|  | ||||
|         call ale#toggle#Toggle() | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#toggle#Disable() abort | ||||
|     if g:ale_enabled | ||||
|         call ale#toggle#Toggle() | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#toggle#Reset() abort | ||||
|     call s:CleanupEveryBuffer() | ||||
|     call ale#highlight#UpdateHighlights() | ||||
| endfunction | ||||
|  | ||||
| function! ale#toggle#ToggleBuffer(buffer) abort | ||||
|     " Get the new value for the toggle. | ||||
|     let l:enabled = !getbufvar(a:buffer, 'ale_enabled', 1) | ||||
|  | ||||
|     " 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''' | ||||
|         return | ||||
|     endif | ||||
|  | ||||
|     call setbufvar(a:buffer, 'ale_enabled', l:enabled) | ||||
|  | ||||
|     if l:enabled | ||||
|         call s:EnablePreamble() | ||||
|     else | ||||
|         " Stop all jobs and clear the results for everything, and delete | ||||
|         " all of the data we stored for the buffer. | ||||
|         call ale#engine#Cleanup(a:buffer) | ||||
|         call s:DisablePostamble() | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#toggle#EnableBuffer(buffer) abort | ||||
|     " ALE is enabled by default for all buffers. | ||||
|     if !getbufvar(a:buffer, 'ale_enabled', 1) | ||||
|         call ale#toggle#ToggleBuffer(a:buffer) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#toggle#DisableBuffer(buffer) abort | ||||
|     if getbufvar(a:buffer, 'ale_enabled', 1) | ||||
|         call ale#toggle#ToggleBuffer(a:buffer) | ||||
|     endif | ||||
| endfunction | ||||
|  | ||||
| function! ale#toggle#ResetBuffer(buffer) abort | ||||
|     call ale#engine#Cleanup(a:buffer) | ||||
|     call ale#highlight#UpdateHighlights() | ||||
| endfunction | ||||
							
								
								
									
										18
									
								
								sources_non_forked/ale/autoload/ale/uri.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								sources_non_forked/ale/autoload/ale/uri.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| " This probably doesn't handle Unicode characters well. | ||||
| function! ale#uri#Encode(value) abort | ||||
|     return substitute( | ||||
|     \   a:value, | ||||
|     \   '\([^a-zA-Z0-9\\/$\-_.!*''(),]\)', | ||||
|     \   '\=printf(''%%%02x'', char2nr(submatch(1)))', | ||||
|     \   'g' | ||||
|     \) | ||||
| endfunction | ||||
|  | ||||
| function! ale#uri#Decode(value) abort | ||||
|     return substitute( | ||||
|     \   a:value, | ||||
|     \   '%\(\x\x\)', | ||||
|     \   '\=nr2char(''0x'' . submatch(1))', | ||||
|     \   'g' | ||||
|     \) | ||||
| endfunction | ||||
							
								
								
									
										313
									
								
								sources_non_forked/ale/autoload/ale/util.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								sources_non_forked/ale/autoload/ale/util.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,313 @@ | ||||
| " Author: w0rp <devw0rp@gmail.com> | ||||
| " Description: Contains miscellaneous functions | ||||
|  | ||||
| " A wrapper function for mode() so we can test calls for it. | ||||
| function! ale#util#Mode(...) abort | ||||
|     return call('mode', a:000) | ||||
| endfunction | ||||
|  | ||||
| " A wrapper function for feedkeys so we can test calls for it. | ||||
| function! ale#util#FeedKeys(...) abort | ||||
|     return call('feedkeys', a:000) | ||||
| endfunction | ||||
|  | ||||
| if !exists('g:ale#util#nul_file') | ||||
|     " A null file for sending output to nothing. | ||||
|     let g:ale#util#nul_file = '/dev/null' | ||||
|  | ||||
|     if has('win32') | ||||
|         let g:ale#util#nul_file = 'nul' | ||||
|     endif | ||||
| endif | ||||
|  | ||||
| " Return the number of lines for a given buffer. | ||||
| function! ale#util#GetLineCount(buffer) abort | ||||
|     return len(getbufline(a:buffer, 1, '$')) | ||||
| endfunction | ||||
|  | ||||
| function! ale#util#GetFunction(string_or_ref) abort | ||||
|     if type(a:string_or_ref) == type('') | ||||
|         return function(a:string_or_ref) | ||||
|     endif | ||||
|  | ||||
|     return a:string_or_ref | ||||
| endfunction | ||||
|  | ||||
| " Compare two loclist items for ALE, sorted by their buffers, filenames, and | ||||
| " line numbers and column numbers. | ||||
| function! ale#util#LocItemCompare(left, right) abort | ||||
|     if a:left.bufnr < a:right.bufnr | ||||
|         return -1 | ||||
|     endif | ||||
|  | ||||
|     if a:left.bufnr > a:right.bufnr | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     if a:left.bufnr == -1 | ||||
|         if a:left.filename < a:right.filename | ||||
|             return -1 | ||||
|         endif | ||||
|  | ||||
|         if a:left.filename > a:right.filename | ||||
|             return 1 | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     if a:left.lnum < a:right.lnum | ||||
|         return -1 | ||||
|     endif | ||||
|  | ||||
|     if a:left.lnum > a:right.lnum | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     if a:left.col < a:right.col | ||||
|         return -1 | ||||
|     endif | ||||
|  | ||||
|     if a:left.col > a:right.col | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     return 0 | ||||
| endfunction | ||||
|  | ||||
| " Compare two loclist items, including the text for the items. | ||||
| " | ||||
| " This function can be used for de-duplicating lists. | ||||
| function! ale#util#LocItemCompareWithText(left, right) abort | ||||
|     let l:cmp_value = ale#util#LocItemCompare(a:left, a:right) | ||||
|  | ||||
|     if l:cmp_value | ||||
|         return l:cmp_value | ||||
|     endif | ||||
|  | ||||
|     if a:left.text < a:right.text | ||||
|         return -1 | ||||
|     endif | ||||
|  | ||||
|     if a:left.text > a:right.text | ||||
|         return 1 | ||||
|     endif | ||||
|  | ||||
|     return 0 | ||||
| endfunction | ||||
|  | ||||
| " This function will perform a binary search and a small sequential search | ||||
| " on the list to find the last problem in the buffer and line which is | ||||
| " on or before the column. The index of the problem will be returned. | ||||
| " | ||||
| " -1 will be returned if nothing can be found. | ||||
| function! ale#util#BinarySearch(loclist, buffer, line, column) abort | ||||
|     let l:min = 0 | ||||
|     let l:max = len(a:loclist) - 1 | ||||
|  | ||||
|     while 1 | ||||
|         if l:max < l:min | ||||
|             return -1 | ||||
|         endif | ||||
|  | ||||
|         let l:mid = (l:min + l:max) / 2 | ||||
|         let l:item = a:loclist[l:mid] | ||||
|  | ||||
|         " Binary search for equal buffers, equal lines, then near columns. | ||||
|         if l:item.bufnr < a:buffer | ||||
|             let l:min = l:mid + 1 | ||||
|         elseif l:item.bufnr > a:buffer | ||||
|             let l:max = l:mid - 1 | ||||
|         elseif l:item.lnum < a:line | ||||
|             let l:min = l:mid + 1 | ||||
|         elseif l:item.lnum > a:line | ||||
|             let l:max = l:mid - 1 | ||||
|         else | ||||
|             " This part is a small sequential search. | ||||
|             let l:index = l:mid | ||||
|  | ||||
|             " Search backwards to find the first problem on the line. | ||||
|             while l:index > 0 | ||||
|             \&& a:loclist[l:index - 1].bufnr == a:buffer | ||||
|             \&& a:loclist[l:index - 1].lnum == a:line | ||||
|                 let l:index -= 1 | ||||
|             endwhile | ||||
|  | ||||
|             " Find the last problem on or before this column. | ||||
|             while l:index < l:max | ||||
|             \&& a:loclist[l:index + 1].bufnr == a:buffer | ||||
|             \&& a:loclist[l:index + 1].lnum == a:line | ||||
|             \&& a:loclist[l:index + 1].col <= a:column | ||||
|                 let l:index += 1 | ||||
|             endwhile | ||||
|  | ||||
|             return l:index | ||||
|         endif | ||||
|     endwhile | ||||
| endfunction | ||||
|  | ||||
| " A function for testing if a function is running inside a sandbox. | ||||
| " See :help sandbox | ||||
| function! ale#util#InSandbox() abort | ||||
|     try | ||||
|         function! s:SandboxCheck() abort | ||||
|         endfunction | ||||
|     catch /^Vim\%((\a\+)\)\=:E48/ | ||||
|         " E48 is the sandbox error. | ||||
|         return 1 | ||||
|     endtry | ||||
|  | ||||
|     return 0 | ||||
| endfunction | ||||
|  | ||||
| " Get the number of milliseconds since some vague, but consistent, point in | ||||
| " the past. | ||||
| " | ||||
| " This function can be used for timing execution, etc. | ||||
| " | ||||
| " The time will be returned as a Number. | ||||
| function! ale#util#ClockMilliseconds() abort | ||||
|     return float2nr(reltimefloat(reltime()) * 1000) | ||||
| endfunction | ||||
|  | ||||
| " Given a single line, or a List of lines, and a single pattern, or a List | ||||
| " of patterns, return all of the matches for the lines(s) from the given | ||||
| " patterns, using matchlist(). | ||||
| " | ||||
| " Only the first pattern which matches a line will be returned. | ||||
| function! ale#util#GetMatches(lines, patterns) abort | ||||
|     let l:matches = [] | ||||
|     let l:lines = type(a:lines) == type([]) ? a:lines : [a:lines] | ||||
|     let l:patterns = type(a:patterns) == type([]) ? a:patterns : [a:patterns] | ||||
|  | ||||
|     for l:line in l:lines | ||||
|         for l:pattern in l:patterns | ||||
|             let l:match = matchlist(l:line, l:pattern) | ||||
|  | ||||
|             if !empty(l:match) | ||||
|                 call add(l:matches, l:match) | ||||
|                 break | ||||
|             endif | ||||
|         endfor | ||||
|     endfor | ||||
|  | ||||
|     return l:matches | ||||
| endfunction | ||||
|  | ||||
| function! s:LoadArgCount(function) abort | ||||
|     let l:Function = a:function | ||||
|  | ||||
|     redir => l:output | ||||
|         silent! function Function | ||||
|     redir END | ||||
|  | ||||
|     if !exists('l:output') | ||||
|         return 0 | ||||
|     endif | ||||
|  | ||||
|     let l:match = matchstr(split(l:output, "\n")[0], '\v\([^)]+\)')[1:-2] | ||||
|     let l:arg_list = filter(split(l:match, ', '), 'v:val isnot# ''...''') | ||||
|  | ||||
|     return len(l:arg_list) | ||||
| endfunction | ||||
|  | ||||
| " Given the name of a function, a Funcref, or a lambda, return the number | ||||
| " of named arguments for a function. | ||||
| function! ale#util#FunctionArgCount(function) abort | ||||
|     let l:Function = ale#util#GetFunction(a:function) | ||||
|     let l:count = s:LoadArgCount(l:Function) | ||||
|  | ||||
|     " If we failed to get the count, forcibly load the autoload file, if the | ||||
|     " function is an autoload function. autoload functions aren't normally | ||||
|     " defined until they are called. | ||||
|     if l:count == 0 | ||||
|         let l:function_name = matchlist(string(l:Function), 'function([''"]\(.\+\)[''"])')[1] | ||||
|  | ||||
|         if l:function_name =~# '#' | ||||
|             execute 'runtime autoload/' . join(split(l:function_name, '#')[:-2], '/') . '.vim' | ||||
|             let l:count = s:LoadArgCount(l:Function) | ||||
|         endif | ||||
|     endif | ||||
|  | ||||
|     return l:count | ||||
| endfunction | ||||
|  | ||||
| " Escape a string so the characters in it will be safe for use inside of PCRE | ||||
| " or RE2 regular expressions without characters having special meanings. | ||||
| function! ale#util#EscapePCRE(unsafe_string) abort | ||||
|     return substitute(a:unsafe_string, '\([\-\[\]{}()*+?.^$|]\)', '\\\1', 'g') | ||||
| endfunction | ||||
|  | ||||
| " Escape a string so that it can be used as a literal string inside an evaled | ||||
| " vim command. | ||||
| function! ale#util#EscapeVim(unsafe_string) abort | ||||
|     return "'" . substitute(a:unsafe_string, "'", "''", 'g') . "'" | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| " Given a String or a List of String values, try and decode the string(s) | ||||
| " as a JSON value which can be decoded with json_decode. If the JSON string | ||||
| " is invalid, the default argument value will be returned instead. | ||||
| " | ||||
| " This function is useful in code where the data can't be trusted to be valid | ||||
| " JSON, and where throwing exceptions is mostly just irritating. | ||||
| function! ale#util#FuzzyJSONDecode(data, default) abort | ||||
|     if empty(a:data) | ||||
|         return a:default | ||||
|     endif | ||||
|  | ||||
|     let l:str = type(a:data) == type('') ? a:data : join(a:data, '') | ||||
|  | ||||
|     try | ||||
|         let l:result = json_decode(l:str) | ||||
|  | ||||
|         " Vim 8 only uses the value v:none for decoding blank strings. | ||||
|         if !has('nvim') && l:result is v:none | ||||
|             return a:default | ||||
|         endif | ||||
|  | ||||
|         return l:result | ||||
|     catch /E474/ | ||||
|         return a:default | ||||
|     endtry | ||||
| endfunction | ||||
|  | ||||
| " Write a file, including carriage return characters for DOS files. | ||||
| " | ||||
| " The buffer number is required for determining the fileformat setting for | ||||
| " the buffer. | ||||
| function! ale#util#Writefile(buffer, lines, filename) abort | ||||
|     let l:corrected_lines = getbufvar(a:buffer, '&fileformat') is# 'dos' | ||||
|     \   ? map(copy(a:lines), 'v:val . "\r"') | ||||
|     \   : a:lines | ||||
|  | ||||
|     call writefile(l:corrected_lines, a:filename) " no-custom-checks | ||||
| endfunction | ||||
|  | ||||
| if !exists('s:patial_timers') | ||||
|     let s:partial_timers = {} | ||||
| endif | ||||
|  | ||||
| function! s:ApplyPartialTimer(timer_id) abort | ||||
|     let [l:Callback, l:args] = remove(s:partial_timers, a:timer_id) | ||||
|     call call(l:Callback, [a:timer_id] + l:args) | ||||
| endfunction | ||||
|  | ||||
| " Given a delay, a callback, a List of arguments, start a timer with | ||||
| " timer_start() and call the callback provided with [timer_id] + args. | ||||
| " | ||||
| " The timer must not be stopped with timer_stop(). | ||||
| " Use ale#util#StopPartialTimer() instead, which can stop any timer, and will | ||||
| " clear any arguments saved for executing callbacks later. | ||||
| function! ale#util#StartPartialTimer(delay, callback, args) abort | ||||
|     let l:timer_id = timer_start(a:delay, function('s:ApplyPartialTimer')) | ||||
|     let s:partial_timers[l:timer_id] = [a:callback, a:args] | ||||
|  | ||||
|     return l:timer_id | ||||
| endfunction | ||||
|  | ||||
| function! ale#util#StopPartialTimer(timer_id) abort | ||||
|     call timer_stop(a:timer_id) | ||||
|  | ||||
|     if has_key(s:partial_timers, a:timer_id) | ||||
|         call remove(s:partial_timers, a:timer_id) | ||||
|     endif | ||||
| endfunction | ||||
		Reference in New Issue
	
	Block a user
	 Amir Salihefendic
					Amir Salihefendic