summaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
authorBjorn Neergaard <bjorn@neersighted.com>2016-10-10 13:51:29 -0500
committerw0rp <w0rp@users.noreply.github.com>2016-10-10 19:51:29 +0100
commit7f0ce89d2b574fd5bdd0c050eaad92deeb63086d (patch)
treec508480ff3ccbf36ef7283610fdcaefe476ae6e1 /plugin
parent0680f875fe9ef07daceb3e9a90224bee613730df (diff)
downloadale-7f0ce89d2b574fd5bdd0c050eaad92deeb63086d.zip
First pass at optimizing ale to autoload (#80)
* First pass at optimizing ale to autoload First off, the structure/function names should be revised a bit, but I will wait for @w0rp's input before unifying the naming style. Second off, the docs probably need some more work, I just did some simple find-and-replace work. With that said, this pull brings major performance gains for ale. On my slowest system, fully loading ale and all its code takes around 150ms. I have moved all of ale's autoload-able code to autoload/, and in addition, implemented lazy-loading of linters. This brings load time on that same system down to 5ms. The only downside of lazy loading is that `g:ale_linters` cannot be changed at runtime; however, it also speeds up performance at runtime by simplfying the logic greatly. Please let me know what you think! Closes #59 * Address Travis/Vint errors For some reason, ale isn't running vint for me... * Incorporate feedback, make fixes Lazy-loading logic is much improved. * Add header comments; remove incorrect workaround * Remove unneeded plugin guards * Fix lazy-loading linter logic Set the wrong variable.... * Fix capitialization
Diffstat (limited to 'plugin')
-rw-r--r--plugin/ale.vim (renamed from plugin/ale/aaflags.vim)58
-rw-r--r--plugin/ale/cursor.vim125
-rw-r--r--plugin/ale/handlers.vim82
-rw-r--r--plugin/ale/sign.vim143
-rw-r--r--plugin/ale/statusline.vim39
-rw-r--r--plugin/ale/util.vim43
-rw-r--r--plugin/ale/zmain.vim437
7 files changed, 53 insertions, 874 deletions
diff --git a/plugin/ale/aaflags.vim b/plugin/ale.vim
index 56ed4175..3982ee69 100644
--- a/plugin/ale/aaflags.vim
+++ b/plugin/ale.vim
@@ -1,12 +1,11 @@
" Author: w0rp <devw0rp@gmail.com>
-" Description: This file sets up configuration settings for the ALE plugin.
-" Flags can be set in vimrc files and so on to disable particular features
+" Description: Main entry point for the plugin: sets up prefs and autocommands
+" Preferences can be set in vimrc files and so on to configure ale
-if exists('g:loaded_ale_flags')
+if exists('g:loaded_ale')
finish
endif
-
-let g:loaded_ale_flags = 1
+let g:loaded_ale = 1
" A flag for detecting if the required features are set.
if has('nvim')
@@ -15,6 +14,15 @@ else
let g:ale_has_required_features = has('timers') && has('job') && has('channel')
endif
+if !g:ale_has_required_features
+ echoerr 'ALE requires NeoVim >= 0.1.5 or Vim 8 with +timers +job +channel'
+ echoerr 'Please update your editor appropriately.'
+ finish
+endif
+
+" This list configures which linters are enabled for which languages.
+let g:ale_linters = get(g:, 'ale_linters', {})
+
" This flag can be set to 0 to disable linting when text is changed.
let g:ale_lint_on_text_changed = get(g:, 'ale_lint_on_text_changed', 1)
@@ -64,3 +72,43 @@ let g:ale_echo_msg_format = get(g:, 'ale_echo_msg_format', '%s')
" Strings used for severity in the echoed message
let g:ale_echo_msg_error_str = get(g:, 'ale_echo_msg_error_str', 'Error')
let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning')
+
+if g:ale_lint_on_text_changed
+ augroup ALERunOnTextChangedGroup
+ autocmd!
+ autocmd TextChanged,TextChangedI * call ale#Queue(g:ale_lint_delay)
+ augroup END
+endif
+
+if g:ale_lint_on_enter
+ augroup ALERunOnEnterGroup
+ autocmd!
+ autocmd BufEnter,BufRead * call ale#Queue(100)
+ augroup END
+endif
+
+if g:ale_lint_on_save
+ augroup ALERunOnSaveGroup
+ autocmd!
+ autocmd BufWrite * call ale#Queue(0)
+ augroup END
+endif
+
+" Clean up buffers automatically when they are unloaded.
+augroup ALEBufferCleanup
+ autocmd!
+ autocmd BufUnload * call ale#cleanup#Buffer('<abuf>')
+augroup END
+
+" Globals which each part of the plugin should use.
+let g:ale_buffer_loclist_map = {}
+let g:ale_buffer_should_reset_map = {}
+let g:ale_buffer_sign_dummy_map = {}
+
+" Backwards compatibility
+function! ALELint(delay)
+ call ale#Queue(a:delay)
+endfunction
+function! ALEGetStatusLine()
+ call ale#statusline#Status()
+endfunction
diff --git a/plugin/ale/cursor.vim b/plugin/ale/cursor.vim
deleted file mode 100644
index a6d23979..00000000
--- a/plugin/ale/cursor.vim
+++ /dev/null
@@ -1,125 +0,0 @@
-" Author: w0rp <devw0rp@gmail.com>
-" Description: Echoes lint message for the current line, if any
-
-if exists('g:loaded_ale_cursor')
- finish
-endif
-
-let g:loaded_ale_cursor = 1
-
-" Return a formatted message according to g:ale_echo_msg_format variable
-function! s:GetMessage(linter, type, text) abort
- let msg = g:ale_echo_msg_format
- let type = a:type ==# 'E'
- \ ? g:ale_echo_msg_error_str
- \ : g:ale_echo_msg_warning_str
- " Capitalize the 1st character
- let text = toupper(a:text[0]) . a:text[1:-1]
-
- " Replace handlers if they exist
- for [k, v] in items({'linter': a:linter, 'severity': type})
- let msg = substitute(msg, '\V%' . k . '%', v, '')
- endfor
-
- return printf(msg, text)
-endfunction
-
-" This function will perform a binary search to find a message from the
-" loclist to echo when the cursor moves.
-function! s:BinarySearch(loclist, line, column)
- let min = 0
- let max = len(a:loclist) - 1
- let last_column_match = -1
-
- while 1
- if max < min
- return last_column_match
- endif
-
- let mid = (min + max) / 2
- let obj = a:loclist[mid]
-
- " Binary search to get on the same line
- if a:loclist[mid]['lnum'] < a:line
- let min = mid + 1
- elseif a:loclist[mid]['lnum'] > a:line
- let max = mid - 1
- else
- let last_column_match = mid
-
- " Binary search to get the same column, or near it
- if a:loclist[mid]['col'] < a:column
- let min = mid + 1
- elseif a:loclist[mid]['col'] > a:column
- let max = mid - 1
- else
- return mid
- endif
- endif
- endwhile
-endfunction
-
-function! ale#cursor#TruncatedEcho(message)
- let message = a:message
- " Change tabs to spaces.
- let message = substitute(message, "\t", ' ', 'g')
- " Remove any newlines in the message.
- let message = substitute(message, "\n", '', 'g')
-
- " We need to turn T for truncated messages on for shortmess,
- " and then then we need to reset the option back to what it was.
- let shortmess_options = getbufvar('%', '&shortmess')
-
- try
- " Echo the message truncated to fit without creating a prompt.
- setlocal shortmess+=T
- exec "norm :echomsg message\n"
- finally
- call setbufvar('%', '&shortmess', shortmess_options)
- endtry
-endfunction
-
-function! ale#cursor#EchoCursorWarning(...)
- " Only echo the warnings in normal mode, otherwise we will get problems.
- if mode() !=# 'n'
- return
- endif
-
- let buffer = bufnr('%')
-
- if !has_key(g:ale_buffer_loclist_map, buffer)
- return
- endif
-
- let loclist = g:ale_buffer_loclist_map[buffer]
-
- let pos = getcurpos()
-
- let index = s:BinarySearch(loclist, pos[1], pos[2])
-
- if index >= 0
- let l = loclist[index]
- let msg = s:GetMessage(l.linter_name, l.type, l.text)
- call ale#cursor#TruncatedEcho(msg)
- else
- echo
- endif
-endfunction
-
-let s:cursor_timer = -1
-
-function! ale#cursor#EchoCursorWarningWithDelay()
- if s:cursor_timer != -1
- call timer_stop(s:cursor_timer)
- let s:cursor_timer = -1
- endif
-
- let s:cursor_timer = timer_start(10, function('ale#cursor#EchoCursorWarning'))
-endfunction
-
-if g:ale_has_required_features && g:ale_echo_cursor
- augroup ALECursorGroup
- autocmd!
- autocmd CursorMoved,CursorHold * call ale#cursor#EchoCursorWarningWithDelay()
- augroup END
-endif
diff --git a/plugin/ale/handlers.vim b/plugin/ale/handlers.vim
deleted file mode 100644
index a348ad30..00000000
--- a/plugin/ale/handlers.vim
+++ /dev/null
@@ -1,82 +0,0 @@
-scriptencoding utf-8
-" Author: w0rp <devw0rp@gmail.com>
-" Description: This file defines some standard error format handlers. Any
-" linter which outputs warnings and errors in a format accepted by one of
-" these functions can simply use one of these pre-defined error handlers.
-
-if exists('g:loaded_ale_handlers')
- finish
-endif
-
-let g:loaded_ale_handlers = 1
-
-function! ale#handlers#HandleGCCFormat(buffer, lines)
- " 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 pattern = '^.\+:\(\d\+\):\(\d\+\): \([^:]\+\): \(.\+\)$'
- let output = []
-
- for line in a:lines
- let l:match = matchlist(line, pattern)
-
- if len(l:match) == 0
- continue
- endif
-
- call add(output, {
- \ 'bufnr': a:buffer,
- \ 'lnum': l:match[1] + 0,
- \ 'vcol': 0,
- \ 'col': l:match[2] + 0,
- \ 'text': l:match[4],
- \ 'type': l:match[3] ==# 'error' ? 'E' : 'W',
- \ 'nr': -1,
- \})
- endfor
-
- return output
-endfunction
-
-function! ale#handlers#HandleCSSLintFormat(buffer, lines)
- " 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 pattern = '^.*: line \(\d\+\), col \(\d\+\), \(Error\|Warning\) - \(.\+\) (\([^)]\+\))$'
- let output = []
-
- for line in a:lines
- let l:match = matchlist(line, pattern)
-
- if len(l:match) == 0
- continue
- endif
-
- let text = l:match[4]
- let type = l:match[3]
- let errorGroup = l:match[5]
-
- " Put the error group at the front, so we can see what kind of error
- " it is on small echo lines.
- let text = '(' . errorGroup . ') ' . text
-
- " vcol is Needed to indicate that the column is a character.
- call add(output, {
- \ 'bufnr': a:buffer,
- \ 'lnum': l:match[1] + 0,
- \ 'vcol': 0,
- \ 'col': l:match[2] + 0,
- \ 'text': text,
- \ 'type': type ==# 'Warning' ? 'W' : 'E',
- \ 'nr': -1,
- \})
- endfor
-
- return output
-endfunction
diff --git a/plugin/ale/sign.vim b/plugin/ale/sign.vim
deleted file mode 100644
index 5950ae99..00000000
--- a/plugin/ale/sign.vim
+++ /dev/null
@@ -1,143 +0,0 @@
-scriptencoding utf-8
-" Author: w0rp <devw0rp@gmail.com>
-" Description: Draws error and warning signs into signcolumn
-
-if exists('g:loaded_ale_sign')
- finish
-endif
-
-let g:loaded_ale_sign = 1
-let b:dummy_sign_set_map = {}
-
-if !hlexists('ALEErrorSign')
- highlight link ALEErrorSign error
-endif
-
-if !hlexists('ALEWarningSign')
- highlight link ALEWarningSign todo
-endif
-
-if !hlexists('ALEError')
- highlight link ALEError SpellBad
-endif
-
-if !hlexists('ALEWarning')
- highlight link ALEWarning SpellCap
-endif
-
-" Global variables for signs
-let g:ale_sign_error = get(g:, 'ale_sign_error', '>>')
-let g:ale_sign_warning = get(g:, 'ale_sign_warning', '--')
-" An offset which can be set for sign IDs.
-" This ID can be changed depending on what IDs are set for other plugins.
-" The dummy sign will use the ID exactly equal to the offset.
-let g:ale_sign_offset = get(g:, 'ale_sign_offset', 1000000)
-
-" Signs show up on the left for error markers.
-execute 'sign define ALEErrorSign text=' . g:ale_sign_error
-\ . ' texthl=ALEErrorSign'
-execute 'sign define ALEWarningSign text=' . g:ale_sign_warning
-\ . ' texthl=ALEWarningSign'
-sign define ALEDummySign
-
-function! ale#sign#FindCurrentSigns(buffer)
- " Matches output like :
- " line=4 id=1 name=ALEErrorSign
- " строка=1 id=1000001 имя=ALEErrorSign
- let pattern = 'id=\(\d\+\).*=ALE\(Warning\|Error\)Sign'
-
- redir => output
- silent exec 'sign place buffer=' . a:buffer
- redir END
-
- let id_list = []
-
- for line in split(output, "\n")
- let match = matchlist(line, pattern)
-
- if len(match) > 0
- call add(id_list, match[1] + 0)
- endif
- endfor
-
- return id_list
-endfunction
-
-" Given a loclist, combine the loclist into a list of signs such that only
-" one sign appears per line. Error lines will take precedence.
-" The loclist will have been previously sorted.
-function! ale#sign#CombineSigns(loclist)
- let signlist = []
-
- for obj in a:loclist
- let should_append = 1
-
- if obj.lnum < 1
- " Skip warnings and errors at line 0, etc.
- continue
- endif
-
- if len(signlist) > 0 && signlist[-1].lnum == obj.lnum
- " We can't add the same line twice, because signs must be
- " unique per line.
- let should_append = 0
-
- if signlist[-1].type ==# 'W' && obj.type ==# 'E'
- " If we had a warning previously, but now have an error,
- " we replace the object to set an error instead.
- let signlist[-1] = obj
- endif
- endif
-
- if should_append
- call add(signlist, obj)
- endif
- endfor
-
- return signlist
-endfunction
-
-" This function will set the signs which show up on the left.
-function! ale#sign#SetSigns(buffer, loclist)
- let signlist = ale#sign#CombineSigns(a:loclist)
-
- if len(signlist) > 0 || g:ale_sign_column_always
- if !get(g:ale_buffer_sign_dummy_map, a:buffer, 0)
- " Insert a dummy sign if one is missing.
- execute 'sign place ' . g:ale_sign_offset
- \ . ' line=1 name=ALEDummySign buffer='
- \ . a:buffer
-
- let g:ale_buffer_sign_dummy_map[a:buffer] = 1
- endif
- endif
-
- " Find the current signs with the markers we use.
- let current_id_list = ale#sign#FindCurrentSigns(a:buffer)
-
- " Remove those markers.
- for current_id in current_id_list
- exec 'sign unplace ' . current_id . ' buffer=' . a:buffer
- endfor
-
- " Now set all of the signs.
- for i in range(0, len(signlist) - 1)
- let obj = signlist[i]
- let name = obj['type'] ==# 'W' ? 'ALEWarningSign' : 'ALEErrorSign'
-
- let sign_line = 'sign place ' . (i + g:ale_sign_offset + 1)
- \. ' line=' . obj['lnum']
- \. ' name=' . name
- \. ' buffer=' . a:buffer
-
- exec sign_line
- endfor
-
- if !g:ale_sign_column_always && len(signlist) > 0
- if get(g:ale_buffer_sign_dummy_map, a:buffer, 0)
- execute 'sign unplace ' . g:ale_sign_offset . ' buffer=' . a:buffer
-
- let g:ale_buffer_sign_dummy_map[a:buffer] = 0
- endif
- endif
-endfunction
diff --git a/plugin/ale/statusline.vim b/plugin/ale/statusline.vim
deleted file mode 100644
index baef418a..00000000
--- a/plugin/ale/statusline.vim
+++ /dev/null
@@ -1,39 +0,0 @@
-" Author: KabbAmine <amine.kabb@gmail.com>
-" Description: Statusline related function(s)
-
-function! ALEGetStatusLine() abort
- " Returns a formatted string that can be integrated in the
- " statusline
-
- let buf = bufnr('%')
- let bufLoclist = g:ale_buffer_loclist_map
-
- if !has_key(bufLoclist, buf)
- return ''
- endif
-
- let errors = 0
- let warnings = 0
- for e in bufLoclist[buf]
- if e.type ==# 'E'
- let errors += 1
- else
- let warnings += 1
- endif
- endfor
-
- let errors = errors ? printf(g:ale_statusline_format[0], errors) : ''
- let warnings = warnings ? printf(g:ale_statusline_format[1], warnings) : ''
- let no_errors = g:ale_statusline_format[2]
-
- " Different formats if no errors or no warnings
- if empty(errors) && empty(warnings)
- let res = no_errors
- elseif !empty(errors) && !empty(warnings)
- let res = printf('%s %s', errors, warnings)
- else
- let res = empty(errors) ? warnings : errors
- endif
-
- return res
-endfunction
diff --git a/plugin/ale/util.vim b/plugin/ale/util.vim
deleted file mode 100644
index fd9bb356..00000000
--- a/plugin/ale/util.vim
+++ /dev/null
@@ -1,43 +0,0 @@
-" Author: w0rp <devw0rp@gmail.com>
-" Description: Contains miscellaneous functions
-
-if exists('g:loaded_ale_util')
- finish
-endif
-
-let g:loaded_ale_util = 1
-
-function! s:FindWrapperScript()
- for parent in split(&runtimepath, ',')
- " Expand the path to deal with ~ issues.
- let path = expand(parent . '/' . 'stdin-wrapper')
-
- if filereadable(path)
- if has('win32')
- return path . '.exe'
- endif
-
- return path
- endif
- endfor
-endfunction
-
-let g:ale#util#stdin_wrapper = s:FindWrapperScript()
-
-" Return the number of lines for a given buffer.
-function! ale#util#GetLineCount(buffer)
- return len(getbufline(a:buffer, 1, '$'))
-endfunction
-
-" Given a buffer and a filename, find the nearest file by searching upwards
-" through the paths relative to the given buffer.
-function! ale#util#FindNearestFile(buffer, filename)
- return findfile(a:filename, fnamemodify(bufname(a:buffer), ':p') . ';')
-endfunction
-
-" 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
diff --git a/plugin/ale/zmain.vim b/plugin/ale/zmain.vim
deleted file mode 100644
index 16b0a476..00000000
--- a/plugin/ale/zmain.vim
+++ /dev/null
@@ -1,437 +0,0 @@
-" Author: w0rp <devw0rp@gmail.com>
-" Description: Main entry point for this plugin
-" Loads linters and manages lint jobs
-
-if exists('g:loaded_ale_zmain')
- finish
-endif
-
-let g:loaded_ale_zmain = 1
-
-let s:lint_timer = -1
-let s:linters = {}
-
-if !exists('g:ale_linters')
- let g:ale_linters = {}
-endif
-
-" 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.
-let s:job_info_map = {}
-
-" Globals which each part of the plugin should use.
-let g:ale_buffer_loclist_map = {}
-let g:ale_buffer_should_reset_map = {}
-let g:ale_buffer_sign_dummy_map = {}
-
-function! s:GetFunction(string_or_ref)
- if type(a:string_or_ref) == type('')
- return function(a:string_or_ref)
- endif
-
- return a:string_or_ref
-endfunction
-
-function! s:ClearJob(job)
- let job_id = s:GetJobID(a:job)
- let linter = s:job_info_map[job_id].linter
-
- if has('nvim')
- call jobstop(a:job)
- else
- " 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(a:job)) ==# 'open'
- call ch_close_in(job_getchannel(a:job))
- endif
-
- call job_stop(a:job)
- endif
-
- call remove(s:job_info_map, job_id)
- call remove(linter, 'job')
-endfunction
-
-function! s:GatherOutput(job, data)
- let job_id = s:GetJobID(a:job)
-
- if !has_key(s:job_info_map, job_id)
- return
- endif
-
- call extend(s:job_info_map[job_id].output, a:data)
-endfunction
-
-function! s:GatherOutputNeoVim(job, data, event)
- call s:GatherOutput(a:job, a:data)
-endfunction
-
-function! s:GatherOutputVim(channel, data)
- call s:GatherOutput(ch_getjob(a:channel), [a:data])
-endfunction
-
-function! s:LocItemCompare(left, right)
- 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
-
-function! s:FixLoclist(buffer, 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 last_line_number = ale#util#GetLineCount(a:buffer)
-
- for item in a:loclist
- if item.lnum == 0
- " When errors appear at line 0, put them at line 1 instead.
- let item.lnum = 1
- elseif item.lnum > last_line_number
- let item.lnum = last_line_number
- endif
- endfor
-endfunction
-
-function! s:HandleExit(job)
- if a:job ==# 'no process'
- " Stop right away when the job is not valid in Vim 8.
- return
- endif
-
- let job_id = s:GetJobID(a:job)
-
- if !has_key(s:job_info_map, job_id)
- return
- endif
-
- let job_info = s:job_info_map[job_id]
-
- call s:ClearJob(a:job)
-
- let linter = job_info.linter
- let output = job_info.output
- let buffer = job_info.buffer
-
- let linter_loclist = s:GetFunction(linter.callback)(buffer, output)
-
- " Make some adjustments to the loclists to fix common problems.
- call s:FixLoclist(buffer, linter_loclist)
-
- " Remember which linter returned these items for later use.
- for obj in linter_loclist
- let obj.linter_name = linter.name
- endfor
-
- if g:ale_buffer_should_reset_map[buffer]
- let g:ale_buffer_should_reset_map[buffer] = 0
- let g:ale_buffer_loclist_map[buffer] = []
- endif
-
- " Add the loclist items from the linter.
- call extend(g:ale_buffer_loclist_map[buffer], 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(g:ale_buffer_loclist_map[buffer], 's:LocItemCompare')
-
- if g:ale_set_loclist
- call setloclist(0, g:ale_buffer_loclist_map[buffer])
- endif
-
- if g:ale_set_signs
- call ale#sign#SetSigns(buffer, g:ale_buffer_loclist_map[buffer])
- endif
-
- " Mark line 200, column 17 with a squiggly line or something
- " matchadd('ALEError', '\%200l\%17v')
-endfunction
-
-function! s:GetJobID(job)
- if has('nvim')
- "In NeoVim, job values are just IDs.
- return a:job
- endif
-
- " In Vim 8, the job is a special variable, and we open a channel for each
- " job. We'll use the ID of the channel instead as the job ID.
- return ch_info(job_getchannel(a:job)).id
-endfunction
-
-function! s:HandleExitNeoVim(job, data, event)
- call s:HandleExit(a:job)
-endfunction
-
-function! s:HandleExitVim(channel)
- call s:HandleExit(ch_getjob(a:channel))
-endfunction
-
-function! s:ApplyLinter(buffer, linter)
- if has_key(a:linter, 'job')
- " Stop previous jobs for the same linter.
- call s:ClearJob(a:linter.job)
- endif
-
- if has_key(a:linter, 'command_callback')
- " If there is a callback for generating a command, call that instead.
- let command = s:GetFunction(a:linter.command_callback)(a:buffer)
- else
- let command = a:linter.command
- endif
-
- if command =~# '%s'
- " If there is a '%s' in the command string, replace it with the name
- " of the file.
- let command = printf(command, shellescape(fnamemodify(bufname(a:buffer), ':p')))
- endif
-
- if has('nvim')
- if a:linter.output_stream ==# 'stderr'
- " Read from stderr instead of stdout.
- let job = jobstart(command, {
- \ 'on_stderr': 's:GatherOutputNeoVim',
- \ 'on_exit': 's:HandleExitNeoVim',
- \})
- elseif a:linter.output_stream ==# 'both'
- let job = jobstart(command, {
- \ 'on_stdout': 's:GatherOutputNeoVim',
- \ 'on_stderr': 's:GatherOutputNeoVim',
- \ 'on_exit': 's:HandleExitNeoVim',
- \})
- else
- let job = jobstart(command, {
- \ 'on_stdout': 's:GatherOutputNeoVim',
- \ 'on_exit': 's:HandleExitNeoVim',
- \})
- endif
- else
- let job_options = {
- \ 'in_mode': 'nl',
- \ 'out_mode': 'nl',
- \ 'err_mode': 'nl',
- \ 'close_cb': function('s:HandleExitVim'),
- \}
-
- if a:linter.output_stream ==# 'stderr'
- " Read from stderr instead of stdout.
- let job_options.err_cb = function('s:GatherOutputVim')
- elseif a:linter.output_stream ==# 'both'
- " Read from both streams.
- let job_options.out_cb = function('s:GatherOutputVim')
- let job_options.err_cb = function('s:GatherOutputVim')
- else
- let job_options.out_cb = function('s:GatherOutputVim')
- endif
-
- if has('win32')
- " job_start commands on Windows have to be run with cmd /c,
- " othwerwise %PATHTEXT% will not be used to programs ending int
- " .cmd, .bat, .exe, etc.
- let l:command = 'cmd /c ' . l:command
- else
- " On Unix machines, we can send the Vim buffer directly.
- " This is faster than reading the lines ourselves.
- let job_options.in_io = 'buffer'
- let job_options.in_buf = a:buffer
- endif
-
- " Vim 8 will read the stdin from the file's buffer.
- let job = job_start(l:command, l:job_options)
- endif
-
- " Only proceed if the job is being run.
- if has('nvim') || (job !=# 'no process' && job_status(job) ==# 'run')
- let a:linter.job = job
-
- " Store the ID for the job in the map to read back again.
- let s:job_info_map[s:GetJobID(job)] = {
- \ 'linter': a:linter,
- \ 'buffer': a:buffer,
- \ 'output': [],
- \}
-
- if has('nvim')
- " In NeoVim, we have to send the buffer lines ourselves.
- let input = join(getbufline(a:buffer, 1, '$'), "\n") . "\n"
-
- call jobsend(job, input)
- call jobclose(job, 'stdin')
- elseif has('win32')
- " On Windows, we have to send the buffer lines ourselves,
- " as there are issues with Windows and 'in_buf'
- let input = join(getbufline(a:buffer, 1, '$'), "\n") . "\n"
- let channel = job_getchannel(job)
-
- if ch_status(channel) ==# 'open'
- call ch_sendraw(channel, input)
- call ch_close_in(channel)
- endif
- endif
- endif
-endfunction
-
-function! s:TimerHandler(...)
- let filetype = &filetype
- let linters = ALEGetLinters(filetype)
-
- let buffer = bufnr('%')
-
- " Set a variable telling us to clear the loclist later.
- let g:ale_buffer_should_reset_map[buffer] = 1
-
- for linter in linters
- " Check if a given linter has a program which can be executed.
- if has_key(linter, 'executable_callback')
- let l:executable = s:GetFunction(linter.executable_callback)(buffer)
- else
- let l:executable = linter.executable
- endif
-
- if !executable(l:executable)
- " The linter's program cannot be executed, so skip it.
- continue
- endif
-
- call s:ApplyLinter(buffer, linter)
- endfor
-endfunction
-
-function s:BufferCleanup(buffer)
- if has_key(g:ale_buffer_should_reset_map, a:buffer)
- call remove(g:ale_buffer_should_reset_map, a:buffer)
- endif
-
- if has_key(g:ale_buffer_loclist_map, a:buffer)
- call remove(g:ale_buffer_loclist_map, a:buffer)
- endif
-
- if has_key(g:ale_buffer_sign_dummy_map, a:buffer)
- call remove(g:ale_buffer_sign_dummy_map, a:buffer)
- endif
-endfunction
-
-function! ALEAddLinter(filetype, linter)
- if !has_key(s:linters, a:filetype)
- let s:linters[a:filetype] = []
- endif
-
- let new_linter = {
- \ 'name': a:linter.name,
- \ 'callback': a:linter.callback,
- \}
-
- if has_key(a:linter, 'executable_callback')
- let new_linter.executable_callback = a:linter.executable_callback
- else
- let new_linter.executable = a:linter.executable
- endif
-
- if has_key(a:linter, 'command_callback')
- let new_linter.command_callback = a:linter.command_callback
- else
- let new_linter.command = a:linter.command
- endif
-
- if has_key(a:linter, 'output_stream')
- let new_linter.output_stream = a:linter.output_stream
- else
- let new_linter.output_stream = 'stdout'
- endif
-
- " TODO: Assert the value of the output_stream to be something sensible.
-
- call add(s:linters[a:filetype], new_linter)
-endfunction
-
-function! ALEGetLinters(filetype)
- if !has_key(s:linters, a:filetype)
- return []
- endif
-
- if has_key(g:ale_linters, a:filetype)
- let linters = []
- " Filter loaded linters according to list of linters specified in option
- for linter in s:linters[a:filetype]
- if index(g:ale_linters[a:filetype], linter.name) != -1
- call add(linters, linter)
- endif
- endfor
- return linters
- endif
-
- return s:linters[a:filetype]
-endfunction
-
-function! ALELint(delay)
- let filetype = &filetype
- let linters = ALEGetLinters(filetype)
-
- if s:lint_timer != -1
- call timer_stop(s:lint_timer)
- let s:lint_timer = -1
- endif
-
- if len(linters) == 0
- " There are no linters to lint with, so stop here.
- return
- endif
-
- if a:delay > 0
- let s:lint_timer = timer_start(a:delay, function('s:TimerHandler'))
- else
- call s:TimerHandler()
- endif
-endfunction
-
-" Load all of the linters for each filetype.
-runtime! ale_linters/*/*.vim
-
-if !g:ale_has_required_features
- echoerr 'ALE requires NeoVim >= 0.1.5 or Vim 8 with +timers +job +channel'
- echoerr 'Please update your editor appropriately.'
- finish
-endif
-
-if g:ale_lint_on_text_changed
- augroup ALERunOnTextChangedGroup
- autocmd!
- autocmd TextChanged,TextChangedI * call ALELint(g:ale_lint_delay)
- augroup END
-endif
-
-if g:ale_lint_on_enter
- augroup ALERunOnEnterGroup
- autocmd!
- autocmd BufEnter,BufRead * call ALELint(100)
- augroup END
-endif
-
-if g:ale_lint_on_save
- augroup ALERunOnSaveGroup
- autocmd!
- autocmd BufWrite * call ALELint(0)
- augroup END
-endif
-
-" Clean up buffers automatically when they are unloaded.
-augroup ALEBuffferCleanup
- autocmd!
- autocmd BufUnload * call s:BufferCleanup('<abuf>')
-augroup END