1
0
mirror of https://github.com/amix/vimrc synced 2025-06-30 20:05:01 +08:00

Updated plugins

This commit is contained in:
Amir
2023-04-01 22:48:04 +02:00
parent 2b653aa950
commit b318c1d0e5
96 changed files with 2382 additions and 625 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2016-2020, w0rp <devw0rp@gmail.com>
Copyright (c) 2016-2023, Dense Analysis
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -25,7 +25,7 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, version, lines) abort
if '>=6.0.0' is# l:version_group
let l:error_codes = { 'blocker': 'E', 'critical': 'E', 'major': 'W', 'minor': 'W', 'info': 'I' }
let l:linter_issues = json_decode(join(a:lines, ''))
let l:linter_issues = ale#util#FuzzyJSONDecode(a:lines, [])
for l:issue in l:linter_issues
if ale#path#IsBufferPath(a:buffer, l:issue.location.path)

View File

@ -0,0 +1,37 @@
" Author: uidops <uidops@protonmail.com>
" Description: llvm-mc linter for asm files
call ale#Set('asm_llvm_mc_executable', 'llvm-mc')
call ale#Set('asm_llvm_mc_options', '')
function! ale_linters#asm#llvm_mc#GetCommand(buffer) abort
return '%e --assemble'
\ . ' --filetype=asm'
\ . ' -o ' . g:ale#util#nul_file
\ . ' ' . ale#Var(a:buffer, 'asm_llvm_mc_options')
endfunction
function! ale_linters#asm#llvm_mc#Handle(buffer, lines) abort
let l:pattern = '^.\+:\(\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,
\ 'type': l:match[3] =~? 'error' ? 'E' : 'W',
\ 'text': l:match[4],
\})
endfor
return l:output
endfunction
call ale#linter#Define('asm', {
\ 'name': 'llvm_mc',
\ 'output_stream': 'stderr',
\ 'executable': {b -> ale#Var(b, 'asm_llvm_mc_executable')},
\ 'command': function('ale_linters#asm#llvm_mc#GetCommand'),
\ 'callback': 'ale_linters#asm#llvm_mc#Handle',
\})

View File

@ -0,0 +1,12 @@
" Author: Victor Ananyev <vindex10@gmail.com>
" Description: eslint for js snippets in HTML files
call ale#linter#Define('html', {
\ 'name': 'eslint',
\ 'output_stream': 'both',
\ 'executable': function('ale#handlers#eslint#GetExecutable'),
\ 'cwd': function('ale#handlers#eslint#GetCwd'),
\ 'command': function('ale#handlers#eslint#GetCommand'),
\ 'callback': 'ale#handlers#eslint#HandleJSON',
\ })

View File

@ -0,0 +1,15 @@
" Author: w0rp <dev@w0rp.com>
" Description: lua-language-server integration (https://github.com/LuaLS/lua-language-server)
call ale#Set('lua_language_server_executable', 'lua-language-server')
call ale#Set('lua_language_server_config', {})
call ale#linter#Define('lua', {
\ 'name': 'lua_language_server',
\ 'aliases': ['lua-language-server'],
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'lua_language_server_executable')},
\ 'command': '%e',
\ 'project_root': function('ale#lua#FindProjectRoot'),
\ 'lsp_config': {b -> ale#Var(b, 'lua_language_server_config')},
\})

View File

@ -0,0 +1,13 @@
call ale#Set('nix_deadnix_executable', 'deadnix')
call ale#Set('nix_deadnix_options', '')
function! ale_linters#nix#deadnix#GetCommand(buffer) abort
return '%e -o json' . ale#Pad(ale#Var(a:buffer, 'nix_deadnix_options')) . ' -- %t'
endfunction
call ale#linter#Define('nix', {
\ 'name': 'deadnix',
\ 'executable': {b -> ale#Var(b, 'nix_deadnix_executable')},
\ 'command': function('ale_linters#nix#deadnix#GetCommand'),
\ 'callback': 'ale#handlers#deadnix#Handle',
\})

View File

@ -5,10 +5,10 @@
function! ale_linters#nix#nix#Command(buffer, output, meta) abort
let l:version = a:output[0][22:]
if l:version =~# '^\(2.[4-9]\|3\).*'
return 'nix-instantiate --log-format internal-json --parse -'
else
if l:version =~# '^\(1\|2.[0-3]\.\).*'
return 'nix-instantiate --parse -'
else
return 'nix-instantiate --log-format internal-json --parse -'
endif
endfunction

View File

@ -26,10 +26,8 @@ function! ale_linters#php#phpstan#GetCommand(buffer, version) abort
\ : ''
let l:level = ale#Var(a:buffer, 'php_phpstan_level')
let l:config_file_exists = ale#path#FindNearestFile(a:buffer, 'phpstan.neon')
let l:dist_config_file_exists = ale#path#FindNearestFile(a:buffer, 'phpstan.neon.dist')
if empty(l:level) && empty(l:config_file_exists) && empty(l:dist_config_file_exists)
if empty(l:level) && empty(ale_linters#php#phpstan#FindConfigFile(a:buffer))
" if no configuration file is found, then use 4 as a default level
let l:level = '4'
endif
@ -70,6 +68,22 @@ function! ale_linters#php#phpstan#Handle(buffer, lines) abort
return l:output
endfunction
function! ale_linters#php#phpstan#GetCwd(buffer) abort
let l:result = ale#path#Dirname(ale_linters#php#phpstan#FindConfigFile(a:buffer))
return empty(l:result) ? v:null : l:result
endfunction
function! ale_linters#php#phpstan#FindConfigFile(buffer) abort
let l:result = ale#path#FindNearestFile(a:buffer, 'phpstan.neon')
if empty(l:result)
let l:result = ale#path#FindNearestFile(a:buffer, 'phpstan.neon.dist')
endif
return l:result
endfunction
call ale#linter#Define('php', {
\ 'name': 'phpstan',
\ 'executable': {buffer -> ale#path#FindExecutable(buffer, 'php_phpstan', [
@ -86,4 +100,5 @@ call ale#linter#Define('php', {
\ function('ale_linters#php#phpstan#GetCommand'),
\ )},
\ 'callback': 'ale_linters#php#phpstan#Handle',
\ 'cwd': function('ale_linters#php#phpstan#GetCwd'),
\})

View File

@ -16,12 +16,16 @@ endfunction
function! ale_linters#python#jedils#GetCommand(buffer) abort
let l:executable = ale_linters#python#jedils#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run jedi-language-server'
\ : ''
let l:env_string = ''
return ale#Escape(l:executable) . l:exec_args
if ale#Var(a:buffer, 'python_auto_virtualenv')
let l:env_string = ale#python#AutoVirtualenvEnvString(a:buffer)
endif
return l:env_string . ale#Escape(l:executable) . l:exec_args
endfunction
call ale#linter#Define('python', {

View File

@ -0,0 +1,86 @@
" Author: Yining <zhang.yining@gmail.com>
" Description: pycln as linter for python files
call ale#Set('python_pycln_executable', 'pycln')
call ale#Set('python_pycln_options', '')
call ale#Set('python_pycln_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_pycln_change_directory', 1)
call ale#Set('python_pycln_auto_pipenv', 0)
call ale#Set('python_pycln_auto_poetry', 0)
call ale#Set('python_pycln_config_file', '')
function! ale_linters#python#pycln#GetExecutable(buffer) abort
if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pycln_auto_pipenv'))
\ && ale#python#PipenvPresent(a:buffer)
return 'pipenv'
endif
if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pycln_auto_poetry'))
\ && ale#python#PoetryPresent(a:buffer)
return 'poetry'
endif
return ale#python#FindExecutable(a:buffer, 'python_pycln', ['pycln'])
endfunction
function! ale_linters#python#pycln#GetCwd(buffer) abort
if ale#Var(a:buffer, 'python_pycln_change_directory')
" Run from project root if found, else from buffer dir.
let l:project_root = ale#python#FindProjectRoot(a:buffer)
return !empty(l:project_root) ? l:project_root : '%s:h'
endif
return ''
endfunction
function! ale_linters#python#pycln#GetCommand(buffer, version) abort
let l:executable = ale_linters#python#pycln#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv\|poetry$'
\ ? ' run pycln'
\ : ''
let l:options = ale#Var(a:buffer, 'python_pycln_options')
let l:config_file = ale#Var(a:buffer, 'python_pycln_config_file')
let l:config_file = l:options !~# '\v(^| )--config ' && !empty(l:config_file)
\ ? ale#Escape(ale#path#Simplify(l:config_file))
\ : ''
" NOTE: pycln version `1.3.0` supports liniting input from stdin
return ale#Escape(l:executable) . l:exec_args
\ . ale#Pad(ale#Var(a:buffer, 'python_pycln_options'))
\ . (empty(l:config_file) ? '' : ' --config ' . l:config_file)
\ . ' --check'
\ . (ale#semver#GTE(a:version, [1, 3, 0]) ? ' -' : ' %s')
endfunction
function! ale_linters#python#pycln#Handle(buffer, lines) abort
" Example: tmp/test.py:3:0 'import os' would be removed!
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],
\})
endfor
return l:output
endfunction
call ale#linter#Define('python', {
\ 'name': 'pycln',
\ 'executable': function('ale_linters#python#pycln#GetExecutable'),
\ 'cwd': function('ale_linters#python#pycln#GetCwd'),
\ 'command': {buffer -> ale#semver#RunWithVersionCheck(
\ buffer,
\ ale_linters#python#pycln#GetExecutable(buffer),
\ '%e --version',
\ function('ale_linters#python#pycln#GetCommand'),
\ )},
\ 'callback': 'ale_linters#python#pycln#Handle',
\ 'output_stream': 'both',
\ 'read_buffer': 1,
\})

View File

@ -22,20 +22,38 @@ function! ale_linters#python#pylsp#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'python_pylsp', ['pylsp'])
endfunction
" Force the cwd of the server to be the same as the project root to
" fix issues with treating local files matching first or third party library
" names being imported incorrectly.
function! ale_linters#python#pylsp#GetCwd(buffer) abort
let l:fake_linter = {
\ 'name': 'pylsp',
\ 'project_root': function('ale#python#FindProjectRoot'),
\}
let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, l:fake_linter)
return !empty(l:root) ? l:root : v:null
endfunction
function! ale_linters#python#pylsp#GetCommand(buffer) abort
let l:executable = ale_linters#python#pylsp#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv\|poetry$'
\ ? ' run pylsp'
\ : ''
let l:env_string = ''
return ale#Escape(l:executable) . l:exec_args . ale#Pad(ale#Var(a:buffer, 'python_pylsp_options'))
if ale#Var(a:buffer, 'python_auto_virtualenv')
let l:env_string = ale#python#AutoVirtualenvEnvString(a:buffer)
endif
return l:env_string . ale#Escape(l:executable) . l:exec_args . ale#Pad(ale#Var(a:buffer, 'python_pylsp_options'))
endfunction
call ale#linter#Define('python', {
\ 'name': 'pylsp',
\ 'lsp': 'stdio',
\ 'executable': function('ale_linters#python#pylsp#GetExecutable'),
\ 'cwd': function('ale_linters#python#pylsp#GetCwd'),
\ 'command': function('ale_linters#python#pylsp#GetCommand'),
\ 'project_root': function('ale#python#FindProjectRoot'),
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',

View File

@ -1,5 +1,21 @@
call ale#Set('python_pyright_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_pyright_executable', 'pyright-langserver')
call ale#Set('python_pyright_config', {})
call ale#Set('python_pyright_auto_pipenv', 0)
call ale#Set('python_pyright_auto_poetry', 0)
" Force the cwd of the server to be the same as the project root to
" fix issues with treating local files matching first or third party library
" names being imported incorrectly.
function! ale_linters#python#pyright#GetCwd(buffer) abort
let l:fake_linter = {
\ 'name': 'pyright',
\ 'project_root': function('ale#python#FindProjectRoot'),
\}
let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, l:fake_linter)
return !empty(l:root) ? l:root : v:null
endfunction
function! ale_linters#python#pyright#GetConfig(buffer) abort
let l:config = deepcopy(ale#Var(a:buffer, 'python_pyright_config'))
@ -32,11 +48,40 @@ function! ale_linters#python#pyright#GetConfig(buffer) abort
return l:config
endfunction
function! ale_linters#python#pyright#GetExecutable(buffer) abort
if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyright_auto_pipenv'))
\ && ale#python#PipenvPresent(a:buffer)
return 'pipenv'
endif
if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pyright_auto_poetry'))
\ && ale#python#PoetryPresent(a:buffer)
return 'poetry'
endif
return ale#python#FindExecutable(a:buffer, 'python_pyright', ['pyright-langserver'])
endfunction
function! ale_linters#python#pyright#GetCommand(buffer) abort
let l:executable = ale_linters#python#pyright#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv\|poetry$'
\ ? ' run pyright'
\ : ''
let l:env_string = ''
if ale#Var(a:buffer, 'python_auto_virtualenv')
let l:env_string = ale#python#AutoVirtualenvEnvString(a:buffer)
endif
return l:env_string . ale#Escape(l:executable) . l:exec_args . ' --stdio'
endfunction
call ale#linter#Define('python', {
\ 'name': 'pyright',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'python_pyright_executable')},
\ 'command': '%e --stdio',
\ 'cwd': function('ale_linters#python#pyright#GetCwd'),
\ 'executable': function('ale_linters#python#pyright#GetExecutable'),
\ 'command': function('ale_linters#python#pyright#GetCommand'),
\ 'project_root': function('ale#python#FindProjectRoot'),
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
\ 'lsp_config': function('ale_linters#python#pyright#GetConfig'),

View File

@ -0,0 +1,73 @@
" Author: Yining <zhang.yining@gmail.com>
" Description: refurb as linter for python files
call ale#Set('python_refurb_executable', 'refurb')
call ale#Set('python_refurb_options', '')
call ale#Set('python_refurb_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_refurb_change_directory', 1)
call ale#Set('python_refurb_auto_pipenv', 0)
call ale#Set('python_refurb_auto_poetry', 0)
function! ale_linters#python#refurb#GetExecutable(buffer) abort
if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_refurb_auto_pipenv'))
\ && ale#python#PipenvPresent(a:buffer)
return 'pipenv'
endif
if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_refurb_auto_poetry'))
\ && ale#python#PoetryPresent(a:buffer)
return 'poetry'
endif
return ale#python#FindExecutable(a:buffer, 'python_refurb', ['refurb'])
endfunction
function! ale_linters#python#refurb#GetCwd(buffer) abort
if ale#Var(a:buffer, 'python_refurb_change_directory')
" Run from project root if found, else from buffer dir.
let l:project_root = ale#python#FindProjectRoot(a:buffer)
return !empty(l:project_root) ? l:project_root : '%s:h'
endif
return ''
endfunction
function! ale_linters#python#refurb#GetCommand(buffer) abort
let l:executable = ale_linters#python#refurb#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv\|poetry$'
\ ? ' run refurb'
\ : ''
return ale#Escape(l:executable) . l:exec_args
\ . ale#Pad(ale#Var(a:buffer, 'python_refurb_options'))
\ . ' %s'
endfunction
function! ale_linters#python#refurb#Handle(buffer, lines) abort
"Example: path/to/file.py:3:17 [FURB109]: Replace `in [x, y, z]` with `in (x, y, z)`
let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+)?:?\s*\[FURB(\d+)\]:\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,
\ 'code': l:match[3] + 0,
\ 'text': l:match[4],
\ 'type': 'W',
\})
endfor
return l:output
endfunction
call ale#linter#Define('python', {
\ 'name': 'refurb',
\ 'executable': function('ale_linters#python#refurb#GetExecutable'),
\ 'cwd': function('ale_linters#python#refurb#GetCwd'),
\ 'command': function('ale_linters#python#refurb#GetCommand'),
\ 'callback': 'ale_linters#python#refurb#Handle',
\ 'output_stream': 'both',
\ 'read_buffer': 0,
\})

View File

@ -49,7 +49,7 @@ function! ale_linters#python#ruff#GetCommand(buffer, version) abort
return ale#Escape(l:executable) . l:exec_args
\ . ale#Pad(ale#Var(a:buffer, 'python_ruff_options'))
\ . ' --format text'
\ . (ale#semver#GTE(a:version, [0, 0, 69]) ? ' -' : ' %s')
\ . (ale#semver#GTE(a:version, [0, 0, 69]) ? ' --stdin-filename %s -' : ' %s')
endfunction
function! ale_linters#python#ruff#Handle(buffer, lines) abort

View File

@ -157,7 +157,7 @@ function! ale#Queue(delay, ...) abort
endif
endfunction
let s:current_ale_version = [3, 2, 0]
let s:current_ale_version = [3, 3, 0]
" A function used to check for ALE features in files outside of the project.
function! ale#Has(feature) abort
@ -254,6 +254,7 @@ function! ale#GetLocItemMessage(item, format_string) abort
" \=l:variable is used to avoid escaping issues.
let l:msg = substitute(l:msg, '\v\%([^\%]*)code([^\%]*)\%', l:code_repl, 'g')
let l:msg = substitute(l:msg, '\V%severity%', '\=l:severity', 'g')
let l:msg = substitute(l:msg, '\V%type%', '\=l:type', 'g')
let l:msg = substitute(l:msg, '\V%linter%', '\=l:linter_name', 'g')
" Replace %s with the text.
let l:msg = substitute(l:msg, '\V%s', '\=a:item.text', 'g')

View File

@ -55,6 +55,7 @@ let s:global_variable_list = [
\ 'ale_sign_highlight_linenrs',
\ 'ale_statusline_format',
\ 'ale_type_map',
\ 'ale_use_neovim_diagnostics_api',
\ 'ale_use_global_executables',
\ 'ale_virtualtext_cursor',
\ 'ale_warn_about_trailing_blank_lines',

View File

@ -184,9 +184,13 @@ endfunction
function! ale#engine#SetResults(buffer, loclist) abort
let l:linting_is_done = !ale#engine#IsCheckingBuffer(a:buffer)
if g:ale_use_neovim_diagnostics_api
call ale#engine#SendResultsToNeovimDiagnostics(a:buffer, a:loclist)
endif
" Set signs first. This could potentially fix some line numbers.
" The List could be sorted again here by SetSigns.
if g:ale_set_signs
if !g:ale_use_neovim_diagnostics_api && g:ale_set_signs
call ale#sign#SetSigns(a:buffer, a:loclist)
endif
@ -199,11 +203,12 @@ function! ale#engine#SetResults(buffer, loclist) abort
call ale#statusline#Update(a:buffer, a:loclist)
endif
if g:ale_set_highlights
if !g:ale_use_neovim_diagnostics_api && g:ale_set_highlights
call ale#highlight#SetHighlights(a:buffer, a:loclist)
endif
if g:ale_virtualtext_cursor == 2
if !g:ale_use_neovim_diagnostics_api
\&& (g:ale_virtualtext_cursor is# 'all' || g:ale_virtualtext_cursor == 2)
call ale#virtualtext#SetTexts(a:buffer, a:loclist)
endif
@ -214,7 +219,8 @@ function! ale#engine#SetResults(buffer, loclist) abort
call ale#cursor#EchoCursorWarning()
endif
if g:ale_virtualtext_cursor == 1
if !g:ale_use_neovim_diagnostics_api
\&& (g:ale_virtualtext_cursor is# 'current' || g:ale_virtualtext_cursor == 1)
" Try and show the warning now.
" This will only do something meaningful if we're in normal mode.
call ale#virtualtext#ShowCursorWarning()
@ -238,6 +244,19 @@ function! ale#engine#SetResults(buffer, loclist) abort
endif
endfunction
function! ale#engine#SendResultsToNeovimDiagnostics(buffer, loclist) abort
if !has('nvim-0.6')
" We will warn the user on startup as well if they try to set
" g:ale_use_neovim_diagnostics_api outside of a Neovim context.
return
endif
" Keep the Lua surface area really small in the VimL part of ALE,
" and just require the diagnostics.lua module on demand.
let l:SendDiagnostics = luaeval('require("diagnostics").sendAleResultsToDiagnostics')
call l:SendDiagnostics(a:buffer, a:loclist)
endfunction
function! s:RemapItemTypes(type_map, loclist) abort
for l:item in a:loclist
let l:key = l:item.type

View File

@ -139,7 +139,7 @@ function! ale#events#Init() abort
autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarning() | endif
endif
if g:ale_virtualtext_cursor == 1
if g:ale_virtualtext_cursor is# 'current' || g:ale_virtualtext_cursor is# 1 || g:ale_virtualtext_cursor is# '1'
autocmd CursorMoved,CursorHold * if exists('*ale#engine#Cleanup') | call ale#virtualtext#ShowCursorWarningWithDelay() | endif
" Look for a warning to echo as soon as we leave Insert mode.
" The script's position variable used when moving the cursor will

View File

@ -7,6 +7,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['python'],
\ 'description': 'Add blank lines before control statements.',
\ },
\ 'alejandra': {
\ 'function': 'ale#fixers#alejandra#Fix',
\ 'suggested_filetypes': ['nix'],
\ 'description': 'The Uncompromising Nix Code Formatter',
\ },
\ 'align_help_tags': {
\ 'function': 'ale#fixers#help#AlignTags',
\ 'suggested_filetypes': ['help'],
@ -301,6 +306,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['gomod'],
\ 'description': 'Fix Go module files with go mod edit -fmt.',
\ },
\ 'gopls': {
\ 'function': 'ale#fixers#gopls#Fix',
\ 'suggested_filetypes': ['go'],
\ 'description': 'Fix Go files with gopls.',
\ },
\ 'tslint': {
\ 'function': 'ale#fixers#tslint#Fix',
\ 'suggested_filetypes': ['typescript'],
@ -580,6 +590,21 @@ let s:default_registry = {
\ 'function': 'ale#fixers#raco_fmt#Fix',
\ 'suggested_filetypes': ['racket'],
\ 'description': 'Fix Racket files with raco fmt.',
\ },
\ 'ruff': {
\ 'function': 'ale#fixers#ruff#Fix',
\ 'suggested_filetypes': ['python'],
\ 'description': 'Fix python files with ruff.',
\ },
\ 'pycln': {
\ 'function': 'ale#fixers#pycln#Fix',
\ 'suggested_filetypes': ['python'],
\ 'description': 'remove unused python import statements',
\ },
\ 'rustywind': {
\ 'function': 'ale#fixers#rustywind#Fix',
\ 'suggested_filetypes': ['html'],
\ 'description': 'Sort Tailwind CSS classes',
\ }
\}

View File

@ -0,0 +1,13 @@
call ale#Set('nix_alejandra_executable', 'alejandra')
call ale#Set('nix_alejandra_options', '')
function! ale#fixers#alejandra#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'nix_alejandra_executable')
let l:options = ale#Var(a:buffer, 'nix_alejandra_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' -- -'
\}
endfunction

View File

@ -0,0 +1,23 @@
" Author: Sean Enck <enckse@voidedtech.com>
" Description: Integration of gopls format with ALE.
call ale#Set('go_gopls_fix_executable', 'gopls')
call ale#Set('go_gopls_fix_options', '')
function! ale#fixers#gopls#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'go_gopls_fix_executable')
let l:options = ale#Var(a:buffer, 'go_gopls_fix_options')
let l:env = ale#go#EnvString(a:buffer)
if !executable(l:executable)
return 0
endif
return {
\ 'command': l:env . ale#Escape(l:executable)
\ . ' format'
\ . ale#Pad(l:options)
\ . ' -l -w %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@ -0,0 +1,90 @@
" Author: Yining <zhang.yining@gmail.com>
" Description: pycln as ALE fixer for python files
call ale#Set('python_pycln_executable', 'pycln')
call ale#Set('python_pycln_options', '')
call ale#Set('python_pycln_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_pycln_change_directory', 1)
call ale#Set('python_pycln_auto_pipenv', 0)
call ale#Set('python_pycln_auto_poetry', 0)
call ale#Set('python_pycln_config_file', '')
function! ale#fixers#pycln#GetCwd(buffer) abort
if ale#Var(a:buffer, 'python_pycln_change_directory')
" Run from project root if found, else from buffer dir.
let l:project_root = ale#python#FindProjectRoot(a:buffer)
return !empty(l:project_root) ? l:project_root : '%s:h'
endif
return '%s:h'
endfunction
function! ale#fixers#pycln#GetExecutable(buffer) abort
if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pycln_auto_pipenv'))
\ && ale#python#PipenvPresent(a:buffer)
return 'pipenv'
endif
if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pycln_auto_poetry'))
\ && ale#python#PoetryPresent(a:buffer)
return 'poetry'
endif
return ale#python#FindExecutable(a:buffer, 'python_pycln', ['pycln'])
endfunction
function! ale#fixers#pycln#GetCommand(buffer) abort
let l:executable = ale#fixers#pycln#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv\|poetry$'
\ ? ' run pycln'
\ : ''
return ale#Escape(l:executable) . l:exec_args
endfunction
function! ale#fixers#pycln#FixForVersion(buffer, version) abort
let l:executable = ale#fixers#pycln#GetExecutable(a:buffer)
let l:cmd = [ale#Escape(l:executable)]
if l:executable =~? 'pipenv\|poetry$'
call extend(l:cmd, ['run', 'pycln'])
endif
let l:options = ale#Var(a:buffer, 'python_pycln_options')
if !empty(l:options)
call add(l:cmd, l:options)
endif
let l:config_file = ale#Var(a:buffer, 'python_pycln_config_file')
let l:config_file = l:options !~# '\v(^| )--config ' && !empty(l:config_file)
\ ? ale#Escape(ale#path#Simplify(l:config_file))
\ : ''
if !empty(l:config_file)
call add(l:cmd, '--config ' . l:config_file)
endif
call add(l:cmd, '--silence')
" NOTE: pycln version `1.3.0` support reading from stdin
call add(l:cmd, ale#semver#GTE(a:version, [1, 3, 0]) ? '-' : '%s')
return {
\ 'cwd': ale#fixers#pycln#GetCwd(a:buffer),
\ 'command': join(l:cmd, ' '),
\}
endfunction
function! ale#fixers#pycln#Fix(buffer) abort
let l:executable = ale#fixers#pycln#GetExecutable(a:buffer)
let l:command = ale#fixers#pycln#GetCommand(a:buffer) . ale#Pad('--version')
return ale#semver#RunWithVersionCheck(
\ a:buffer,
\ l:executable,
\ l:command,
\ function('ale#fixers#pycln#FixForVersion'),
\)
endfunction

View File

@ -1,6 +1,13 @@
" Author: Yining <zhang.yining@gmail.com>
" Description: ruff as ALE fixer for python files
call ale#Set('python_ruff_executable', 'ruff')
call ale#Set('python_ruff_options', '')
call ale#Set('python_ruff_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_ruff_change_directory', 1)
call ale#Set('python_ruff_auto_pipenv', 0)
call ale#Set('python_ruff_auto_poetry', 0)
function! ale#fixers#ruff#GetCwd(buffer) abort
if ale#Var(a:buffer, 'python_ruff_change_directory')
" Run from project root if found, else from buffer dir.
@ -9,7 +16,7 @@ function! ale#fixers#ruff#GetCwd(buffer) abort
return !empty(l:project_root) ? l:project_root : '%s:h'
endif
return ''
return '%s:h'
endfunction
function! ale#fixers#ruff#GetExecutable(buffer) abort
@ -26,29 +33,57 @@ function! ale#fixers#ruff#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'python_ruff', ['ruff'])
endfunction
function! ale#fixers#ruff#GetCommand(buffer, version) abort
let l:executable = ale_linters#python#ruff#GetExecutable(a:buffer)
function! ale#fixers#ruff#GetCommand(buffer) abort
let l:executable = ale#fixers#ruff#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv\|poetry$'
\ ? ' run ruff'
\ : ''
" NOTE: ruff version `0.0.72` implement `--fix` with stdin
return ale#Escape(l:executable) . l:exec_args
\ . ale#Pad(ale#Var(a:buffer, 'python_ruff_options'))
\ . ' --fix'
\ . (ale#semver#GTE(a:version, [0, 0, 72]) ? ' -' : ' %s')
endfunction
function! ale#fixers#ruff#FixForVersion(buffer, version) abort
let l:executable = ale#fixers#ruff#GetExecutable(a:buffer)
let l:cmd = [ale#Escape(l:executable)]
if l:executable =~? 'pipenv\|poetry$'
call extend(l:cmd, ['run', 'ruff'])
endif
let l:options = ale#Var(a:buffer, 'python_ruff_options')
if !empty(l:options)
call add(l:cmd, l:options)
endif
" when --stdin-filename present, ruff will use it for proj root resolution
" https://github.com/charliermarsh/ruff/pull/1281
let l:fname = expand('#' . a:buffer . '...')
call add(l:cmd, '--stdin-filename '.ale#Escape(ale#path#Simplify(l:fname)))
call add(l:cmd, '--fix')
" NOTE: ruff version `0.0.72` implements `--fix` with stdin
if ale#semver#GTE(a:version, [0, 0, 72])
call add(l:cmd, '-')
else
call add(l:cmd, '%s')
endif
return {
\ 'cwd': ale#fixers#ruff#GetCwd(a:buffer),
\ 'command': join(l:cmd, ' '),
\}
endfunction
function! ale#fixers#ruff#Fix(buffer) abort
let l:fix_cmd = {buffer -> ale#semver#RunWithVersionCheck(
\ buffer,
\ ale#fixers#ruff#GetExecutable(buffer),
\ '%e --version',
\ function('ale#fixers#ruff#GetCommand'),
\ )}(a:buffer)
let l:executable = ale#fixers#ruff#GetExecutable(a:buffer)
let l:command = ale#fixers#ruff#GetCommand(a:buffer) . ale#Pad('--version')
return {
\ 'cwd': ale#fixers#ruff#GetCwd(a:buffer),
\ 'command': l:fix_cmd,
\}
return ale#semver#RunWithVersionCheck(
\ a:buffer,
\ l:executable,
\ l:command,
\ function('ale#fixers#ruff#FixForVersion'),
\)
endfunction

View File

@ -0,0 +1,17 @@
scriptencoding utf-8
" Author: Guillermo Roig <groig@protonmail.com>
" Description: Sort TailwindCSS classes with rustywind
call ale#Set('html_rustywind_executable', 'rustywind')
call ale#Set('html_rustywind_options', '')
function! ale#fixers#rustywind#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'html_rustywind_executable')
let l:options = ale#Var(a:buffer, 'html_rustywind_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' --stdin'
\}
endfunction

View File

@ -52,9 +52,9 @@ function! s:NvimShow(lines, options) abort
autocmd!
if g:ale_close_preview_on_insert
autocmd CursorMoved,TabLeave,WinLeave,InsertEnter <buffer> ++once call s:NvimClose()
autocmd CursorMoved,TabLeave,WinLeave,BufWinLeave,WinScrolled,InsertEnter <buffer> ++once call s:NvimClose()
else
autocmd CursorMoved,TabLeave,WinLeave <buffer> ++once call s:NvimClose()
autocmd CursorMoved,TabLeave,WinLeave,BufWinLeave,WinScrolled <buffer> ++once call s:NvimClose()
endif
augroup END
@ -99,48 +99,30 @@ function! s:NvimPrepareWindowContent(lines) abort
let l:width = max(map(copy(a:lines), 'strdisplaywidth(v:val)'))
let l:height = min([len(a:lines), l:max_height])
if empty(g:ale_floating_window_border)
return [a:lines, l:width, l:height]
endif
" Add the size of borders
let l:width += 2
let l:height += 2
let l:left = get(g:ale_floating_window_border, 0, '|')
let l:top = get(g:ale_floating_window_border, 1, '-')
let l:top_left = get(g:ale_floating_window_border, 2, '+')
let l:top_right = get(g:ale_floating_window_border, 3, '+')
let l:bottom_right = get(g:ale_floating_window_border, 4, '+')
let l:bottom_left = get(g:ale_floating_window_border, 5, '+')
let l:right = get(g:ale_floating_window_border, 6, l:left)
let l:bottom = get(g:ale_floating_window_border, 7, l:top)
let l:lines = [l:top_left . repeat(l:top, l:width - 2) . l:top_right]
for l:line in a:lines
let l:line_width = strchars(l:line)
let l:lines = add(l:lines, l:left . l:line . repeat(' ', l:width - l:line_width - 2). l:right)
endfor
" Truncate the lines
if len(l:lines) > l:max_height + 1
let l:lines = l:lines[0:l:max_height]
endif
let l:lines = add(l:lines, l:bottom_left . repeat(l:bottom, l:width - 2) . l:bottom_right)
return [l:lines, l:width, l:height]
return [a:lines[0:l:height-1], l:width, l:height]
endfunction
function! s:NvimCreate(options) abort
let l:left = get(g:ale_floating_window_border, 0, '|')
let l:top = get(g:ale_floating_window_border, 1, '-')
let l:popup_opts = extend({
\ 'relative': 'cursor',
\ 'row': 1,
\ 'col': 0,
\ 'width': 42,
\ 'height': 4,
\ 'style': 'minimal'
\ 'style': 'minimal',
\ 'border': empty(g:ale_floating_window_border) ? 'none' : [
\ get(g:ale_floating_window_border, 2, '+'),
\ l:top,
\ get(g:ale_floating_window_border, 3, '+'),
\ get(g:ale_floating_window_border, 6, l:left),
\ get(g:ale_floating_window_border, 4, '+'),
\ get(g:ale_floating_window_border, 7, l:top),
\ get(g:ale_floating_window_border, 5, '+'),
\ l:left,
\ ],
\ }, s:GetPopupOpts())
let l:buffer = nvim_create_buf(v:false, v:false)

View File

@ -0,0 +1,33 @@
function! ale#handlers#deadnix#Handle(buffer, lines) abort
let l:output = []
for l:line in a:lines
try
let l:file = ale#util#FuzzyJSONDecode(l:line, v:null)
catch
continue
endtry
if type(l:file) isnot v:t_dict
continue
endif
for l:error in l:file['results']
try
let l:ale_error = {
\ 'lnum': l:error['line'],
\ 'col': l:error['column'],
\ 'end_col': l:error['endColumn'],
\ 'text': l:error['message'],
\ 'type': 'W',
\}
catch
continue
endtry
call add(l:output, l:ale_error)
endfor
endfor
return l:output
endfunction

View File

@ -22,26 +22,6 @@ if !hlexists('ALEInfo')
highlight link ALEInfo ALEWarning
endif
if !hlexists('ALEVirtualTextError')
highlight link ALEVirtualTextError ALEError
endif
if !hlexists('ALEVirtualTextStyleError')
highlight link ALEVirtualTextStyleError ALEVirtualTextError
endif
if !hlexists('ALEVirtualTextWarning')
highlight link ALEVirtualTextWarning ALEWarning
endif
if !hlexists('ALEVirtualTextStyleWarning')
highlight link ALEVirtualTextStyleWarning ALEVirtualTextWarning
endif
if !hlexists('ALEVirtualTextInfo')
highlight link ALEVirtualTextInfo ALEVirtualTextWarning
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)

View File

@ -51,7 +51,7 @@ let s:default_ale_linters = {
\ 'jsonc': [],
\ 'perl': ['perlcritic'],
\ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright'],
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright', 'ruff'],
\ 'rust': ['cargo', 'rls'],
\ 'spec': [],
\ 'text': [],

View File

@ -52,28 +52,24 @@ function! ale#lsp#message#Exit() abort
endfunction
function! ale#lsp#message#DidOpen(buffer, language_id) abort
let l:lines = getbufline(a:buffer, 1, '$')
return [1, 'textDocument/didOpen', {
\ 'textDocument': {
\ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')),
\ 'languageId': a:language_id,
\ 'version': ale#lsp#message#GetNextVersionID(),
\ 'text': join(l:lines, "\n") . "\n",
\ 'text': ale#util#GetBufferContents(a:buffer),
\ },
\}]
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#util#ToURI(expand('#' . a:buffer . ':p')),
\ 'version': ale#lsp#message#GetNextVersionID(),
\ },
\ 'contentChanges': [{'text': join(l:lines, "\n") . "\n"}]
\ 'contentChanges': [{'text': ale#util#GetBufferContents(a:buffer)}]
\}]
endfunction

View File

@ -0,0 +1,28 @@
" Author: w0rp <dev@w0rp.com>
" Description: Functions for integrating with Lua linters.
" Find project root for a Lua language server.
function! ale#lua#FindProjectRoot(buffer) abort
let l:possible_project_roots = [
\ '.git',
\ bufname(a:buffer),
\]
for l:possible_root in l:possible_project_roots
let l:project_root = ale#path#FindNearestFile(a:buffer, l:possible_root)
if empty(l:project_root)
let l:project_root = ale#path#FindNearestDirectory(a:buffer, l:possible_root)
endif
if !empty(l:project_root)
" dir:p expands to /full/path/to/dir/ whereas
" file:p expands to /full/path/to/file (no trailing slash)
" Appending '/' ensures that :h:h removes the path's last segment
" regardless of whether it is a directory or not.
return fnamemodify(l:project_root . '/', ':p:h:h')
endif
endfor
return ''
endfunction

View File

@ -1,4 +1,4 @@
" Author: w0rp <devw0rp@gmail.com>
" Author: w0rp <dev@w0rp.com>
" Description: Functions for integrating with Python linters.
call ale#Set('python_auto_pipenv', '0')
@ -96,6 +96,27 @@ function! ale#python#FindVirtualenv(buffer) abort
return $VIRTUAL_ENV
endfunction
" Automatically determine virtualenv environment variables and build
" a string of them to prefix linter commands with.
function! ale#python#AutoVirtualenvEnvString(buffer) abort
let l:venv_dir = ale#python#FindVirtualenv(a:buffer)
if !empty(l:venv_dir)
let l:strs = [ ]
" expand PATH correctly inside of the appropriate shell.
if has('win32')
call add(l:strs, 'set PATH=' . ale#Escape(l:venv_dir) . ';%PATH% && ')
else
call add(l:strs, 'PATH=' . ale#Escape(l:venv_dir) . '":$PATH" ')
endif
return join(l:strs, '')
endif
return ''
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

View File

@ -14,7 +14,7 @@ function! s:DisablePostamble() abort
call ale#highlight#UpdateHighlights()
endif
if g:ale_virtualtext_cursor == 1
if g:ale_virtualtext_cursor isnot# 'disabled' && g:ale_virtualtext_cursor != 0
call ale#virtualtext#Clear(bufnr(''))
endif
endfunction

View File

@ -542,7 +542,7 @@ function! ale#util#SetBufferContents(buffer, lines) abort
endfunction
function! ale#util#GetBufferContents(buffer) abort
return join(getbufline(a:buffer, 1, '$'), '\n') . '\n'
return join(getbufline(a:buffer, 1, '$'), "\n") . "\n"
endfunction
function! ale#util#ToURI(resource) abort

View File

@ -3,88 +3,58 @@ scriptencoding utf-8
" Author: Luan Santos <cfcluan@gmail.com>
" Description: Shows lint message for the current line as virtualtext, if any
" Controls the milliseconds delay before showing a message.
let g:ale_virtualtext_delay = get(g:, 'ale_virtualtext_delay', 10)
let s:cursor_timer = -1
let s:last_pos = [0, 0, 0]
let s:has_virt_text = 0
let s:emulate_virt = 0
if has('nvim-0.3.2')
let s:ns_id = nvim_create_namespace('ale')
let s:has_virt_text = 1
elseif has('textprop') && has('popupwin')
let s:has_virt_text = 1
let s:emulate_virt = !has('patch-9.0.0297')
let s:hl_list = []
if s:emulate_virt
call prop_type_add('ale', {})
let s:last_virt = -1
endif
if !hlexists('ALEVirtualTextError')
highlight link ALEVirtualTextError Comment
endif
function! ale#virtualtext#Clear(buf) abort
if !s:has_virt_text
return
endif
if !hlexists('ALEVirtualTextStyleError')
highlight link ALEVirtualTextStyleError ALEVirtualTextError
endif
if has('nvim')
call nvim_buf_clear_namespace(a:buf, s:ns_id, 0, -1)
else
if s:emulate_virt && s:last_virt != -1
call prop_remove({'type': 'ale'})
call popup_close(s:last_virt)
let s:last_virt = -1
elseif !empty(s:hl_list)
call prop_remove({
\ 'types': s:hl_list,
\ 'all': 1,
\ 'bufnr': a:buf})
if !hlexists('ALEVirtualTextWarning')
highlight link ALEVirtualTextWarning Comment
endif
if !hlexists('ALEVirtualTextStyleWarning')
highlight link ALEVirtualTextStyleWarning ALEVirtualTextWarning
endif
if !hlexists('ALEVirtualTextInfo')
highlight link ALEVirtualTextInfo ALEVirtualTextWarning
endif
let g:ale_virtualtext_prefix =
\ get(g:, 'ale_virtualtext_prefix', '%comment% %type%: ')
" Controls the milliseconds delay before showing a message.
let g:ale_virtualtext_delay = get(g:, 'ale_virtualtext_delay', 10)
" Controls the positioning of virtualtext
let g:ale_virtualtext_column = get(g:, 'ale_virtualtext_column', 0)
let g:ale_virtualtext_maxcolumn = get(g:, 'ale_virtualtext_maxcolumn', 0)
let g:ale_virtualtext_single = get(g:,'ale_virtualtext_single',0)
let s:cursor_timer = get(s:, 'cursor_timer', -1)
let s:last_pos = get(s:, 'last_pos', [0, 0, 0])
let s:hl_list = get(s:, 'hl_list', [])
let s:last_message = ''
if !has_key(s:, 'has_virt_text')
let s:has_virt_text = 0
let s:emulate_virt = 0
let s:last_virt = -1
if has('nvim-0.3.2')
let s:ns_id = nvim_create_namespace('ale')
let s:has_virt_text = 1
elseif has('textprop') && has('popupwin')
let s:has_virt_text = 1
let s:emulate_virt = !has('patch-9.0.0297')
if s:emulate_virt
call prop_type_add('ale', {})
endif
endif
endfunction
function! ale#virtualtext#ShowMessage(message, hl_group, buf, line) abort
if !s:has_virt_text || !bufexists(str2nr(a:buf))
return
endif
let l:prefix = get(g:, 'ale_virtualtext_prefix', '> ')
let l:msg = l:prefix.trim(substitute(a:message, '\n', ' ', 'g'))
if has('nvim')
call nvim_buf_set_virtual_text(a:buf, s:ns_id, a:line-1, [[l:msg, a:hl_group]], {})
elseif s:emulate_virt
let l:left_pad = col('$')
call prop_add(a:line, l:left_pad, {
\ 'type': 'ale',
\})
let s:last_virt = popup_create(l:msg, {
\ 'line': -1,
\ 'padding': [0, 0, 0, 1],
\ 'mask': [[1, 1, 1, 1]],
\ 'textprop': 'ale',
\ 'highlight': a:hl_group,
\ 'fixed': 1,
\ 'wrap': 0,
\ 'zindex': 2
\})
else
let type = prop_type_get(a:hl_group)
if type == {}
call add(s:hl_list, a:hl_group)
call prop_type_add(a:hl_group, {'highlight': a:hl_group})
endif
call prop_add(a:line, 0, {
\ 'type': a:hl_group,
\ 'text': ' ' . l:msg,
\ 'bufnr': a:buf
\})
endif
endfunction
endif
function! s:StopCursorTimer() abort
if s:cursor_timer != -1
@ -93,65 +63,199 @@ function! s:StopCursorTimer() abort
endif
endfunction
function! ale#virtualtext#GetHlGroup(type, style) abort
if a:type is# 'E'
if a:style is# 'style'
return 'ALEVirtualTextStyleError'
else
return 'ALEVirtualTextError'
endif
elseif a:type is# 'W'
if a:style is# 'style'
return 'ALEVirtualTextStyleWarning'
else
return 'ALEVirtualTextWarning'
endif
function! ale#virtualtext#ResetDataForTests() abort
let s:last_pos = [0, 0, 0]
let s:last_message = ''
endfunction
function! ale#virtualtext#GetLastMessageForTests() abort
return s:last_message
endfunction
function! ale#virtualtext#GetComment(buffer) abort
let l:filetype = getbufvar(a:buffer, '&filetype')
let l:split = split(getbufvar(a:buffer, '&commentstring'), '%s')
return !empty(l:split) ? trim(l:split[0]) : '#'
endfunction
function! ale#virtualtext#Clear(buffer) abort
if !s:has_virt_text || !bufexists(str2nr(a:buffer))
return
endif
if has('nvim')
call nvim_buf_clear_namespace(a:buffer, s:ns_id, 0, -1)
else
return 'ALEVirtualTextInfo'
if s:emulate_virt && s:last_virt != -1
call prop_remove({'type': 'ale'})
call popup_close(s:last_virt)
let s:last_virt = -1
elseif !empty(s:hl_list)
call prop_remove({
\ 'types': s:hl_list,
\ 'all': 1,
\ 'bufnr': a:buffer,
\})
endif
endif
endfunction
function! ale#virtualtext#GetGroup(item) abort
let l:type = get(a:item, 'type', 'E')
let l:sub_type = get(a:item, 'sub_type', '')
if l:type is# 'E'
if l:sub_type is# 'style'
return 'ALEVirtualTextStyleError'
endif
return 'ALEVirtualTextError'
endif
if l:type is# 'W'
if l:sub_type is# 'style'
return 'ALEVirtualTextStyleWarning'
endif
return 'ALEVirtualTextWarning'
endif
return 'ALEVirtualTextInfo'
endfunction
function! ale#virtualtext#GetColumnPadding(buffer, line) abort
let l:mincol = ale#Var(a:buffer, 'virtualtext_column')
let l:maxcol = ale#Var(a:buffer, 'virtualtext_maxcolumn')
let l:win = bufwinnr(a:buffer)
if l:mincol[len(l:mincol)-1] is# '%'
let l:mincol = (winwidth(l:win) * l:mincol) / 100
endif
if l:maxcol[len(l:maxcol)-1] is# '%'
let l:maxcol = (winwidth(l:win) * l:maxcol) / 100
endif
" Calculate padding for virtualtext alignment
if l:mincol > 0 || l:maxcol > 0
let l:line_width = strdisplaywidth(getline(a:line))
if l:line_width < l:mincol
return l:mincol - l:line_width
elseif l:maxcol > 0 && l:line_width >= l:maxcol
" Stop processing if virtualtext would start beyond maxcol
return -1
endif
endif
" no padding.
return 0
endfunction
function! ale#virtualtext#ShowMessage(buffer, item) abort
if !s:has_virt_text || !bufexists(str2nr(a:buffer))
return
endif
let l:line = max([1, a:item.lnum])
let l:hl_group = ale#virtualtext#GetGroup(a:item)
" Get a language-appropriate comment character, or default to '#'.
let l:comment = ale#virtualtext#GetComment(a:buffer)
let l:prefix = ale#Var(a:buffer, 'virtualtext_prefix')
let l:prefix = ale#GetLocItemMessage(a:item, l:prefix)
let l:prefix = substitute(l:prefix, '\V%comment%', '\=l:comment', 'g')
let l:msg = l:prefix . substitute(a:item.text, '\n', ' ', 'g')
let l:col_pad = ale#virtualtext#GetColumnPadding(a:buffer, l:line)
" Store the last message we're going to set so we can read it in tests.
let s:last_message = l:msg
" Discard virtualtext if padding is negative.
if l:col_pad < 0
return
endif
if has('nvim')
call nvim_buf_set_virtual_text(
\ a:buffer,
\ s:ns_id, l:line - 1,
\ [[l:msg, l:hl_group]],
\ {}
\)
elseif s:emulate_virt
let l:left_pad = col('$')
call prop_add(l:line, l:left_pad, {'type': 'ale'})
let s:last_virt = popup_create(l:msg, {
\ 'line': -1,
\ 'padding': [0, 0, 0, 1],
\ 'mask': [[1, 1, 1, 1]],
\ 'textprop': 'ale',
\ 'highlight': l:hl_group,
\ 'fixed': 1,
\ 'wrap': 0,
\ 'zindex': 2
\})
else
let l:type = prop_type_get(l:hl_group)
if l:type == {}
call prop_type_add(l:hl_group, {'highlight': l:hl_group})
endif
" Add highlight groups to the list so we can clear them later.
if index(s:hl_list, l:hl_group) == -1
call add(s:hl_list, l:hl_group)
endif
" We ignore all errors from prop_add.
silent! call prop_add(l:line, 0, {
\ 'type': l:hl_group,
\ 'text': ' ' . l:msg,
\ 'bufnr': a:buffer,
\ 'text_padding_left': l:col_pad,
\})
endif
endfunction
function! ale#virtualtext#ShowCursorWarning(...) abort
if g:ale_virtualtext_cursor != 1
if g:ale_virtualtext_cursor isnot# 'current'
\&& g:ale_virtualtext_cursor != 1
return
endif
let l:buffer = bufnr('')
if mode(1) isnot# 'n'
\|| g:ale_use_neovim_diagnostics_api
\|| ale#ShouldDoNothing(l:buffer)
return
endif
if ale#ShouldDoNothing(l:buffer)
return
endif
let [l:info, l:loc] = ale#util#FindItemAtCursor(l:buffer)
let [l:info, l:item] = ale#util#FindItemAtCursor(l:buffer)
call ale#virtualtext#Clear(l:buffer)
if !empty(l:loc)
let l:msg = l:loc.text
let l:type = get(l:loc, 'type', 'E')
let l:style = get(l:loc, 'sub_type', '')
let l:hl_group = ale#virtualtext#GetHlGroup(l:type, l:style)
call ale#virtualtext#ShowMessage(l:msg, l:hl_group, l:buffer, line('.'))
if !empty(l:item)
call ale#virtualtext#ShowMessage(l:buffer, l:item)
endif
endfunction
function! ale#virtualtext#ShowCursorWarningWithDelay() abort
let l:buffer = bufnr('')
if g:ale_virtualtext_cursor != 1
return
endif
if mode(1) isnot# 'n'
if g:ale_virtualtext_cursor isnot# 'current'
\&& g:ale_virtualtext_cursor != 1
return
endif
call s:StopCursorTimer()
if mode(1) isnot# 'n'
\|| g:ale_use_neovim_diagnostics_api
return
endif
let l:pos = getpos('.')[0:2]
" Check the current buffer, line, and column number against the last
@ -169,19 +273,24 @@ function! ale#virtualtext#ShowCursorWarningWithDelay() abort
endif
endfunction
function! ale#virtualtext#SetTexts(buf, loclist) abort
function! ale#virtualtext#SetTexts(buffer, loclist) abort
if !has('nvim') && s:emulate_virt
return
endif
call ale#virtualtext#Clear(a:buf)
call ale#virtualtext#Clear(a:buffer)
for l in a:loclist
if l['bufnr'] != a:buf
continue
let l:filter = ale#Var(a:buffer,'virtualtext_single')
let l:seen = {}
for l:item in a:loclist
if l:item.bufnr == a:buffer
let l:line = max([1, l:item.lnum])
if !has_key(l:seen,l:line) || l:filter == 0
call ale#virtualtext#ShowMessage(a:buffer, l:item)
let l:seen[l:line] = 1
endif
endif
let hl = ale#virtualtext#GetHlGroup(l['type'], get(l, 'sub_type', ''))
call ale#virtualtext#ShowMessage(l['text'], hl, a:buf, l['lnum'])
endfor
endfunction

View File

@ -21,5 +21,24 @@ g:ale_asm_gcc_options *g:ale_asm_gcc_options*
This variable can be set to pass additional options to gcc.
===============================================================================
llvm_mc *ale-asm-llvm_mc*
g:ale_asm_clang_executable *g:ale_asm_llvm_mc_executable*
*b:ale_asm_llvm_mc_executable*
Type: |String|
Default: `'llvm-mc'`
This variable can be changed to use a different executable for llvm-mc.
g:ale_asm_clang_options *g:ale_asm_llvm_mc_options*
*b:ale_asm_llvm_mc_options*
Type: |String|
Default: `''`
This variable can be set to pass additional options to llvm-mc.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@ -168,7 +168,7 @@ g:ale_c_cc_header_exts *g:ale_c_cc_header_exts*
considered as header files.
This variable is only used when `'-x c-header'` is used instead of `'-x c'`,
see |ale_c_cc_use_header_lang_flag|.
see |g:ale_c_cc_use_header_lang_flag|.
===============================================================================

View File

@ -97,7 +97,7 @@ g:ale_cpp_cc_header_exts *g:ale_cpp_cc_header_exts*
considered as header files.
This variable is only used when `'-x c++-header'` is used instead of `'-x c++'`,
see |ale_cpp_cc_use_header_lang_flag|.
see |g:ale_cpp_cc_use_header_lang_flag|.
===============================================================================

View File

@ -15,6 +15,7 @@ CONTENTS *ale-development-contents*
4.2. Writing Fixer Tests..............|ale-development-fixer-tests|
4.3. Running Tests in a Windows VM....|ale-development-windows-tests|
5. Contributing.........................|ale-development-contributing|
5.1. Preparing a Release..............|ale-development-release|
===============================================================================
1. Introduction *ale-development-introduction*
@ -154,7 +155,7 @@ ALE runs tests with the following versions of Vim in the following
environments.
1. Vim 8.0.0027 on Linux via GitHub Actions.
2. Vim 9.0.0133 on Linux via GitHub Actions.
2. Vim 9.0.0297 on Linux via GitHub Actions.
3. NeoVim 0.2.0 on Linux via GitHub Actions.
4. NeoVim 0.8.0 on Linux via GitHub Actions.
6. Vim 8 (stable builds) on Windows via AppVeyor.
@ -325,7 +326,6 @@ given the above setup are as follows.
`AssertLSPProject project_root` - Check the root given to an LSP server.
`AssertLSPAddress address` - Check the address to an LSP server.
===============================================================================
4.2 Writing Fixer Tests *ale-development-fixer-tests*
@ -367,7 +367,6 @@ given the above setup are as follows.
`AssertFixer results` - Check the fixer results
`AssertFixerNotExecuted` - Check that fixers will not be executed.
===============================================================================
4.3 Running Tests in a Windows VM *ale-development-windows-tests*
@ -462,5 +461,76 @@ and profile settings. See: https://docs.github.com/en/account-and-profile/
Unless configuring GitHub to expose contact details, commits will be rewritten
to appear by `USERNAME <RANDOM_NUMBER+USERNAME@users.noreply.github.com>` .
===============================================================================
5.1 Preparing a Release *ale-development-release*
ALE offers release packages through GitHub, for two reasons:
1. Some users like to target specific release versions rather than simply
installing the plugin from `master`. This includes users who create Linux
distribution specific packages from GitHub releases.
2. The releases provide a nice way to get an overview of what has changed in
ALE over time.
ALE has no fixed release schedule. Release versions are created whenever the
ALE developers feel the need to create one. ALE release versions follow the
typical Semantic Versioning scheme. See: https://semver.org/
Minor version releases for ALE should be the most common, followed by patch
releases. Every minor version release should be followed by a `vA.B.x` branch
such as `v2.0.x` for version `2.0.0` and every following patch version before
`2.1.0`. The `git` branch strategy for patches is to first merge a bug fix to
`master`, and then `git cherry-pick` a patch to a branch for a specific
version. ALE developers do not generally support anything but `master` or the
last minor version.
Generally ALE releases hit a major version only when there are breaking
changes to a public ALE setting or function. A "public" setting or function is
defined as any setting or function documented in the `:help` |ale| text file.
Major ALE versions ought to be so rare that they only come once a year at
most. ALE should not typically introduce any breaking changes.
If there are ever to be any breaking changes made for ALE, there should first
come a minor version release for ALE documenting all of the coming breaking
changes to ALE. It should be described how users can prepare for a breaking
change that is coming before it is done.
To create a release for ALE, you will need sufficient permissions in GitHub.
Once you do, follow these steps.
1. Create a new release draft, or edit an existing one. It helps to craft
drafts ahead of time and write the last commit ID checked for release notes
on the last update to a draft.
See the releases page: https://github.com/dense-analysis/ale/releases
2. Examine `git log` and read changes made between the last ID checked, or the
git tag of the previous release, and the current commit in `master`.
3. Write updates in separate sections (except where empty) for:
3.a. Breaking Changes
3.b. Deprecated Features
3.c. New Features
3.d. New Linters
3.e. New Fixers
3.f. Linter Enhancements
3.g. Fixer Enhancements
3.h. Bugs Fixed
4. Once you've finished writing the draft for the release, bump
`s:current_ale_version` in `autoload/ale.vim` to the current version, and
add a line to `test/test_ale_has.vader` to test for the version. See
|ale#Has()| documentation for more information.
5. Commit the changes after `./run-tests --fast -q` passes.
6. Tag the release with `git tag vA.B.C`, replacing `A`, `B`, and `C` with the
version numbers. See `git tag --list` for examples.
7. Run `git push` and `git push --tags` to push the commit and the tag.
8. Edit the release draft in GitHub, select the tag you just pushed, and
publish the draft.
9. If you're creating a new major or minor version: `git checkout -b vA.B.x`,
replacing `A` and `B` with the major and minor versions. `git push` the new
branch, and the GitHub branch protection settings should automatically
apply to the new release branch.
10. You have already completed the last step.
Have fun creating ALE releases. Drink responsibly, or not at all, which is the
preference of w0rp.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@ -269,6 +269,21 @@ g:ale_go_gopls_options *g:ale_go_gopls_options*
Command-line options passed to the gopls executable. See `gopls -h`.
g:ale_go_gopls_fix_executable *g:ale_go_gopls_fix_executable*
*b:ale_go_gopls_fix_executable*
Type: |String|
Default: `'gopls'`
Executable to run to use as the gopls fixer.
g:ale_go_gopls_fix_options *g:ale_go_gopls_fix_options*
*b:ale_go_gopls_fix_options*
Type: |String|
Default: `''`
Options to pass to the gopls fixer.
g:ale_go_gopls_init_options *g:ale_go_gopls_init_options*
*b:ale_go_gopls_init_options*
Type: |Dictionary|

View File

@ -102,6 +102,25 @@ prettier *ale-html-prettier*
See |ale-javascript-prettier| for information about the available options.
===============================================================================
rustywind *ale-html-rustywind*
g:ale_html_rustywind_executable *g:ale_html_rustywind_executable*
*b:ale_html_rustywind_executable*
Type: |String|
Default: `'rustywind'`
See |ale-integrations-local-executables|
g:ale_html_rustywind_options *g:ale_html_rustywind_options*
*b:ale_html_rustywind_options*
Type: |String|
Default: `''`
This variable can be changed to modify flags given to rustywind.
===============================================================================
stylelint *ale-html-stylelint*

View File

@ -27,6 +27,30 @@ g:ale_lua_lua_format_options *g:ale_lua_lua_format_options*
This variable can be set to pass additional options to lua-format.
===============================================================================
lua-language-server *ale-lua-lua-language-server*
*ale-lua-language-server*
g:ale_lua_language_server_executable *g:ale_lua_language_server_executable*
*b:ale_lua_language_server_executable*
Type: |String|
Default: `'lua-language-server'`
This variable can be changed to set the path to lua-language-server.
If you have compiled the language server yourself in `/some/path`, the path
will be `'/some/path/bin/lua-language-server'`.
g:ale_lua_lua_language_server_config *g:ale_lua_lua_language_server_config*
*b:ale_lua_lua_language_server_config*
Type: |Dictionary|
Default: `{}`
Dictionary containing configuration settings that will be passed to the
language server.
===============================================================================
luac *ale-lua-luac*

View File

@ -17,13 +17,13 @@ See |ale-dprint-options| and https://dprint.dev/plugins/markdown
===============================================================================
markdownlint *ale-markdown-markdownlint*
g:ale_markdown_markdown_executable *g:ale_markdown_markdownlint_executable*
g:ale_markdown_markdownlint_executable *g:ale_markdown_markdownlint_executable*
*b:ale_markdown_markdownlint_executable*
Type: |String|
Default: `'markdownlint'`
Override the invoked markdownlint binary. You can use other binaries such as
markdownlint-cli2.
Override the invoked `markdownlint` binary. You can use other binaries such as
`markdownlint-cli2`.
g:ale_markdown_markdownlint_options *g:ale_markdown_markdownlint_options*

View File

@ -2,6 +2,24 @@
ALE Nix Integration *ale-nix-options*
===============================================================================
alejandra *ale-nix-alejandra*
g:ale_nix_alejandra_executable *g:ale_nix_alejandra_executable*
*b:ale_nix_alejandra_executable*
Type: |String|
Default: `'alejandra'`
This variable sets the executable used for alejandra.
g:ale_nix_alejandra_options *g:ale_nix_alejandra_options*
*b:ale_nix_alejandra_options*
Type: |String|
Default: `''`
This variable can be set to pass additional options to the alejandra fixer.
===============================================================================
nixfmt *ale-nix-nixfmt*
@ -75,5 +93,23 @@ g:ale_nix_statix_fix_options *g:ale_nix_statix_fix_options*
it as a fixer.
===============================================================================
deadnix *ale-nix-deadnix*
g:ale_nix_deadnix_executable *g:ale_nix_deadnix_executable*
*b:ale_nix_deadnix_executable*
Type: |String|
Default: `'deadnix'`
This variable sets the executable used for deadnix.
g:ale_nix_deadnix_options *g:ale_nix_deadnix_options*
*b:ale_nix_deadnix_options*
Type: |String|
Default: `''`
This variable can be used to pass additional options to deadnix.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@ -20,6 +20,17 @@ g:ale_python_auto_poetry *g:ale_python_auto_poetry*
if true. This is overridden by a manually-set executable.
g:ale_python_auto_virtualenv *g:ale_python_auto_virtualenv*
*b:ale_python_auto_virtualenv*
Type: |Number|
Default: `0`
If set to `1`, ALE will automatically set environment variables for commands
such as `PATH` to attempt to make the experience of running Python linters
via virtualenv easier, without the need for another plugin or some
specialised setup.
===============================================================================
ALE Python Project Root Behavior *ale-python-root*
@ -88,24 +99,24 @@ g:ale_python_autoflake_use_global *g:ale_python_autoflake_use_global*
===============================================================================
autoimport *ale-python-autoimport*
g:ale_python_autoimport_executable *g:ale_python_autoimport_executable*
*b:ale_python_autoimport_executable*
g:ale_python_autoimport_executable *g:ale_python_autoimport_executable*
*b:ale_python_autoimport_executable*
Type: |String|
Default: `'autoimport'`
See |ale-integrations-local-executables|
g:ale_python_autoimport_options *g:ale_python_autoimport_options*
*b:ale_python_autoimport_options*
g:ale_python_autoimport_options *g:ale_python_autoimport_options*
*b:ale_python_autoimport_options*
Type: |String|
Default: `''`
This variable can be set to pass extra options to autoimport.
g:ale_python_autoimport_use_global *g:ale_python_autoimport_use_global*
*b:ale_python_autoimport_use_global*
g:ale_python_autoimport_use_global *g:ale_python_autoimport_use_global*
*b:ale_python_autoimport_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
@ -338,7 +349,7 @@ g:ale_python_flake8_auto_poetry *g:ale_python_flake8_auto_poetry*
flakehell *ale-python-flakehell*
g:ale_python_flakehell_change_directory*g:ale_python_flakehell_change_directory*
*b:ale_python_flakehell_change_directory*
*b:ale_python_flakehell_change_directory*
Type: |String|
Default: `project`
@ -349,8 +360,8 @@ g:ale_python_flakehell_change_directory*g:ale_python_flakehell_change_directory*
Python is executed from yourself.
g:ale_python_flakehell_executable *g:ale_python_flakehell_executable*
*b:ale_python_flakehell_executable*
g:ale_python_flakehell_executable *g:ale_python_flakehell_executable*
*b:ale_python_flakehell_executable*
Type: |String|
Default: `'flakehell'`
@ -360,8 +371,8 @@ g:ale_python_flakehell_executable *g:ale_python_flakehell_executable*
invoke `'python` `-m` `flakehell'`.
g:ale_python_flakehell_options *g:ale_python_flakehell_options*
*b:ale_python_flakehell_options*
g:ale_python_flakehell_options *g:ale_python_flakehell_options*
*b:ale_python_flakehell_options*
Type: |String|
Default: `''`
@ -369,8 +380,8 @@ g:ale_python_flakehell_options *g:ale_python_flakehell_options*
lint invocation.
g:ale_python_flakehell_use_global *g:ale_python_flakehell_use_global*
*b:ale_python_flakehell_use_global*
g:ale_python_flakehell_use_global *g:ale_python_flakehell_use_global*
*b:ale_python_flakehell_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
@ -381,8 +392,8 @@ g:ale_python_flakehell_use_global *g:ale_python_flakehell_use_global*
Both variables can be set with `b:` buffer variables instead.
g:ale_python_flakehell_auto_pipenv *g:ale_python_flakehell_auto_pipenv*
*b:ale_python_flakehell_auto_pipenv*
g:ale_python_flakehell_auto_pipenv *g:ale_python_flakehell_auto_pipenv*
*b:ale_python_flakehell_auto_pipenv*
Type: |Number|
Default: `0`
@ -580,6 +591,78 @@ g:ale_python_prospector_auto_poetry *g:ale_python_prospector_auto_poetry*
if true. This is overridden by a manually-set executable.
===============================================================================
pycln *ale-python-pycln*
g:ale_python_pycln_change_directory *g:ale_python_pycln_change_directory*
*b:ale_python_pycln_change_directory*
Type: |Number|
Default: `1`
If set to `1`, `pycln` will be run from a detected project root, per
|ale-python-root|. if set to `0` or no project root detected,
`pycln` will be run from the buffer's directory.
g:ale_python_pycln_executable *g:ale_python_pycln_executable*
*b:ale_python_pycln_executable*
Type: |String|
Default: `'pycln'`
See |ale-integrations-local-executables|
Set this to `'pipenv'` to invoke `'pipenv` `run` `pycln'`.
Set this to `'poetry'` to invoke `'poetry` `run` `pycln'`.
g:ale_python_pycln_options *g:ale_python_pycln_options*
*b:ale_python_pycln_options*
Type: |String|
Default: `''`
This variable can be changed to add command-line arguments to the pycln
invocation.
For example, to select/enable and/or disable some error codes,
you may want to set >
let g:ale_python_pycln_options = '--expand-stars'
g:ale_python_pycln_config_file *g:ale_python_pycln_config_file*
*b:ale_python_pycln_config_file*
Type: |String|
Default: `''`
Use this variable to set the configuration file.
If `'--config' ` is found in the |g:ale_python_pycln_options|, then that
option value will override the value in this variable.
g:ale_python_pycln_use_global *g:ale_python_pycln_use_global*
*b:ale_python_pycln_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
g:ale_python_pycln_auto_pipenv *g:ale_python_pycln_auto_pipenv*
*b:ale_python_pycln_auto_pipenv*
Type: |Number|
Default: `0`
Detect whether the file is inside a pipenv, and set the executable to `pipenv`
if true. This is overridden by a manually-set executable.
g:ale_python_pycln_auto_poetry *g:ale_python_pycln_auto_poetry*
*b:ale_python_pycln_auto_poetry*
Type: |Number|
Default: `0`
Detect whether the file is inside a poetry, and set the executable to `poetry`
if true. This is overridden by a manually-set executable.
===============================================================================
pycodestyle *ale-python-pycodestyle*
@ -903,13 +986,13 @@ g:ale_python_pylint_use_msg_id *g:ale_python_pylint_use_msg_id*
===============================================================================
pylsp *ale-python-pylsp*
pylsp *ale-python-pylsp*
`pylsp` will be run from a detected project root, per |ale-python-root|.
g:ale_python_pylsp_executable *g:ale_python_pylsp_executable*
*b:ale_python_pylsp_executable*
g:ale_python_pylsp_executable *g:ale_python_pylsp_executable*
*b:ale_python_pylsp_executable*
Type: |String|
Default: `'pylsp'`
@ -919,16 +1002,16 @@ g:ale_python_pylsp_executable *g:ale_python_pylsp_executable
Set this to `'poetry'` to invoke `'poetry` `run` `pyls'`.
g:ale_python_pylsp_use_global *g:ale_python_pylsp_use_global*
*b:ale_python_pylsp_use_global*
g:ale_python_pylsp_use_global *g:ale_python_pylsp_use_global*
*b:ale_python_pylsp_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
g:ale_python_pylsp_auto_pipenv *g:ale_python_pylsp_auto_pipenv*
*b:ale_python_pylsp_auto_pipenv*
g:ale_python_pylsp_auto_pipenv *g:ale_python_pylsp_auto_pipenv*
*b:ale_python_pylsp_auto_pipenv*
Type: |Number|
Default: `0`
@ -936,8 +1019,8 @@ g:ale_python_pylsp_auto_pipenv *g:ale_python_pylsp_auto_pipenv
if true. This is overridden by a manually-set executable.
g:ale_python_pylsp_auto_poetry *g:ale_python_pylsp_auto_poetry*
*b:ale_python_pylsp_auto_poetry*
g:ale_python_pylsp_auto_poetry *g:ale_python_pylsp_auto_poetry*
*b:ale_python_pylsp_auto_poetry*
Type: |Number|
Default: `0`
@ -945,8 +1028,8 @@ g:ale_python_pylsp_auto_poetry *g:ale_python_pylsp_auto_poetry
if true. This is overridden by a manually-set executable.
g:ale_python_pylsp_config *g:ale_python_pylsp_config*
*b:ale_python_pylsp_config*
g:ale_python_pylsp_config *g:ale_python_pylsp_config*
*b:ale_python_pylsp_config*
Type: |Dictionary|
Default: `{}`
@ -963,8 +1046,8 @@ g:ale_python_pylsp_config *g:ale_python_pylsp_config
\ }
<
g:ale_python_pylsp_options *g:ale_python_pylsp_options*
*b:ale_python_pylsp_options*
g:ale_python_pylsp_options *g:ale_python_pylsp_options*
*b:ale_python_pylsp_options*
Type: |String|
Default: `''`
@ -1085,6 +1168,67 @@ g:ale_python_pyright_config *g:ale_python_pyright_config*
\}
<
===============================================================================
refurb *ale-python-refurb*
g:ale_python_refurb_change_directory *g:ale_python_refurb_change_directory*
*b:ale_python_refurb_change_directory*
Type: |Number|
Default: `1`
If set to `1`, `refurb` will be run from a detected project root, per
|ale-python-root|. if set to `0` or no project root detected,
`refurb` will be run from the buffer's directory.
g:ale_python_refurb_executable *g:ale_python_refurb_executable*
*b:ale_python_refurb_executable*
Type: |String|
Default: `'refurb'`
See |ale-integrations-local-executables|
Set this to `'pipenv'` to invoke `'pipenv` `run` `refurb'`.
Set this to `'poetry'` to invoke `'poetry` `run` `refurb'`.
g:ale_python_refurb_options *g:ale_python_refurb_options*
*b:ale_python_refurb_options*
Type: |String|
Default: `''`
This variable can be changed to add command-line arguments to the refurb
invocation.
For example, to select/enable and/or disable some error codes,
you may want to set >
let g:ale_python_refurb_options = '--ignore 100'
g:ale_python_refurb_use_global *g:ale_python_refurb_use_global*
*b:ale_python_refurb_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
g:ale_python_refurb_auto_pipenv *g:ale_python_refurb_auto_pipenv*
*b:ale_python_refurb_auto_pipenv*
Type: |Number|
Default: `0`
Detect whether the file is inside a pipenv, and set the executable to `pipenv`
if true. This is overridden by a manually-set executable.
g:ale_python_refurb_auto_poetry *g:ale_python_refurb_auto_poetry*
*b:ale_python_refurb_auto_poetry*
Type: |Number|
Default: `0`
Detect whether the file is inside a poetry, and set the executable to `poetry`
if true. This is overridden by a manually-set executable.
===============================================================================
reorder-python-imports *ale-python-reorder_python_imports*
@ -1202,8 +1346,8 @@ g:ale_python_unimport_auto_poetry *g:ale_python_unimport_auto_poetry*
if true. This is overridden by a manually-set executable.
g:ale_python_unimport_executable *g:ale_python_unimport_executable*
*b:ale_python_unimport_executable*
g:ale_python_unimport_executable *g:ale_python_unimport_executable*
*b:ale_python_unimport_executable*
Type: |String|
Default: `'unimport'`
@ -1213,8 +1357,8 @@ g:ale_python_unimport_executable *g:ale_python_unimport_executable*
Set this to `'poetry'` to invoke `'poetry` `run` `unimport'`.
g:ale_python_unimport_options *g:ale_python_unimport_options*
*b:ale_python_unimport_options*
g:ale_python_unimport_options *g:ale_python_unimport_options*
*b:ale_python_unimport_options*
Type: |String|
Default: `''`
@ -1222,8 +1366,8 @@ g:ale_python_unimport_options *g:ale_python_unimport_options*
invocation.
g:ale_python_unimport_use_global *g:ale_python_unimport_use_global*
*b:ale_python_unimport_use_global*
g:ale_python_unimport_use_global *g:ale_python_unimport_use_global*
*b:ale_python_unimport_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`

View File

@ -0,0 +1,41 @@
===============================================================================
ALE Racket Integration *ale-racket-options*
===============================================================================
racket_langserver *ale-racket-langserver*
1. Install racket-langserver as described here:
https://github.com/jeapostrophe/racket-langserver
2. Have `racket` available in the `$PATH` environment variable, currently there
is no way to specify path to custom location of `racket`.
3. set `racket_langserver` as a linter for `racket` like: >
let g:ale_linters['racket'] += ['racket_langserver']
You should be able to see linter results and use LSP features of `ALE` like
`ALEGoToDefinition` with `racket-langserver`.
===============================================================================
raco_fmt *ale-racket-raco-fmt*
g:ale_racket_raco_fmt_executable *g:ale_racket_raco_fmt_executable*
*b:ale_racket_raco_fmt_executable*
Type: |String|
Default: `'raco'`
If the `raco` excutable is not in the `$PATH` environment variable, or you
prefer to use one installed in a custom location, set this option to the
path to the specific `raco` executable.
g:ale_racket_raco_fmt_options *g:ale_racket_raco_fmt_options*
*b:ale_racket_raco_fmt_options*
Type: |String|
Default: `''`
Use this variable to pass command-line flags/parameters to `raco_fmt`
For example, set the page width limit to 40 >
let g:ale_racket_raco_fmt_options = '--width 40'
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@ -36,6 +36,7 @@ Notes:
* `write-good`
* ASM
* `gcc`
* `llvm-mc`
* AVRA
* `avra`
* Awk
@ -255,11 +256,13 @@ Notes:
* `alex`
* `angular`
* `cspell`
* `eslint`
* `fecs`
* `html-beautify`
* `htmlhint`
* `prettier`
* `proselint`
* `rustywind`
* `tidy`
* `write-good`
* Idris
@ -340,6 +343,7 @@ Notes:
* Lua
* `cspell`
* `lua-format`
* `lua-language-server`
* `luac`
* `luacheck`
* `luafmt`
@ -377,6 +381,7 @@ Notes:
* `nimlsp`
* `nimpretty`
* nix
* `alejandra`
* `nix-instantiate`
* `nixfmt`
* `nixpkgs-fmt`
@ -481,6 +486,7 @@ Notes:
* `isort`
* `mypy`
* `prospector`!!
* `pycln`
* `pycodestyle`
* `pydocstyle`
* `pyflakes`
@ -490,6 +496,7 @@ Notes:
* `pylsp`
* `pyre`
* `pyright`
* `refurb`
* `reorder-python-imports`
* ruff
* `unimport`

View File

@ -17,7 +17,7 @@ CONTENTS *ale-contents*
5.1 Completion........................|ale-completion|
5.2 Go To Definition..................|ale-go-to-definition|
5.3 Go To Type Definition.............|ale-go-to-type-definition|
5.4 Go To Implementation..............|ale-go-to-type-implementation|
5.4 Go To Implementation..............|ale-go-to-implementation|
5.5 Find References...................|ale-find-references|
5.6 Hovering..........................|ale-hover|
5.7 Symbol Search.....................|ale-symbol-search|
@ -121,6 +121,7 @@ circumstances.
ALE will report problems with your code in the following ways, listed with
their relevant options.
* Via the Neovim diagnostics API (Off by default) - |g:ale_use_neovim_diagnostics_api|
* By updating loclist. (On by default) - |g:ale_set_loclist|
* By updating quickfix. (Off by default) - |g:ale_set_quickfix|
* By setting error highlights. - |g:ale_set_highlights|
@ -1063,7 +1064,8 @@ g:ale_echo_msg_format *g:ale_echo_msg_format*
`%s` - replaced with the text for the problem
`%...code...% `- replaced with the error code
`%linter%` - replaced with the name of the linter
`%severity%` - replaced with the severity of the problem
`%severity%` - replaced with the severity of the problem (e.g. `Error`)
`%type%` - replaced with the type of the problem (e.g. `E`)
The strings for `%severity%` can be configured with the following options.
@ -1234,7 +1236,7 @@ g:ale_floating_preview *g:ale_floating_preview*
|g:ale_detail_to_floating_preview| to `1`.
g:ale_floating_preview_popup_opts *g:ale_floating_preview_popup_opts*
g:ale_floating_preview_popup_opts *g:ale_floating_preview_popup_opts*
Type: |String| or |Dictionary|
Default: `''`
@ -1250,14 +1252,16 @@ g:ale_floating_preview_popup_opts *g:ale_floating_preview_popup_opts
For example, to enhance popups with a title: >
function! CustomOpts() abort {
function! CustomOpts() abort
let [l:info, l:loc] = ale#util#FindItemAtCursor(bufnr(''))
return {'title': ' ALE: ' . (l:loc.linter_name) . ' '}
endfunction
let g:ale_floating_preview_popup_opts = 'g:CustomOpts'
<
g:ale_floating_window_border *g:ale_floating_window_border*
g:ale_floating_window_border *g:ale_floating_window_border*
Type: |List|
Default: `['|', '-', '+', '+', '+', '+', '|', '-']`
@ -1647,7 +1651,7 @@ g:ale_linters *g:ale_linters*
\ 'jsonc': [],
\ 'perl': ['perlcritic'],
\ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright'],
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright', 'ruff'],
\ 'rust': ['cargo', 'rls'],
\ 'spec': [],
\ 'text': [],
@ -2287,23 +2291,41 @@ g:ale_use_global_executables *g:ale_use_global_executables*
options.
g:ale_virtualtext_cursor *g:ale_virtualtext_cursor*
g:ale_use_neovim_diagnostics_api *g:ale_use_neovim_diagnostics_api*
Type: |Number|
Default: `0`
When this option is set to `1`, a message will be shown when a cursor is
near a warning or error. ALE will attempt to find the warning or error at a
column nearest to the cursor when the cursor is resting on a line which
contains a warning or error. This option can be set to `0` to disable this
behavior.
When this option is set to `2`, then all warnings will be shown for the
whole buffer, regardless of if the cursor is currently positioned in that
line.
If enabled, this option will disable ALE's standard UI, and instead send
all linter output to Neovim's diagnostics API. This allows you to collect
errors from nvim-lsp, ALE, and anything else that uses diagnostics all in
one place. The following options are ignored when using the diagnostics API:
- |g:ale_set_highlights|
- |g:ale_set_signs|
- |g:ale_virtualtext_cursor|
To enable this option, set the value to `1`.
This option requires Neovim 0.6+, as that version introduces the diagnostics
API.
g:ale_virtualtext_cursor *g:ale_virtualtext_cursor*
Type: |Number|
Default: `'all'` (if supported, otherwise `'disabled'`)
This option controls how ALE will display problems using |virtual-text|.
The following values can be used.
`'all'`, `'2'`, or `2` - Show problems for all lines.
`'current'`, `'1'`, or `1` - Show problems for the current line.
`'disabled'`, `'0'`, or `0` - Do not show problems with virtual-text.
Messages are only displayed after a short delay. See |g:ale_virtualtext_delay|.
Messages can be prefixed prefixed with a string. See |g:ale_virtualtext_prefix|.
Messages can be prefixed with a string. See |g:ale_virtualtext_prefix|.
ALE will use the following highlight groups for problems:
@ -2316,7 +2338,6 @@ g:ale_virtualtext_cursor *g:ale_virtualtext_cursor*
g:ale_virtualtext_delay *g:ale_virtualtext_delay*
*b:ale_virtualtext_delay*
Type: |Number|
Default: `10`
@ -2328,12 +2349,58 @@ g:ale_virtualtext_delay *g:ale_virtualtext_delay*
g:ale_virtualtext_prefix *g:ale_virtualtext_prefix*
*b:ale_virtualtext_prefix*
Type: |String|
Default: `'> '`
Default: `'%comment% %type%: '`
Prefix to be used with |g:ale_virtualtext_cursor|.
This setting can be changed in each buffer with `b:ale_virtualtext_prefix`.
All of the same format markers used for |g:ale_echo_msg_format| can be used
for defining the prefix, including some additional sequences of characters.
`%comment%` - replaced with comment characters in the current language
ALE will read the comment characters from |&commentstring|, reading only the
part before `%s`, with whitespace trimmed. If comment syntax cannot be
pulled from |&commentstring|, ALE will default to `'#'`.
g:ale_virtualtext_column *g:ale_virtualtext_column*
*b:ale_virtualtext_column*
g:ale_virtualtext_maxcolumn *g:ale_virtualtext_maxcolumn*
*b:ale_virtualtext_maxcolumn*
Type: |String| or |Number|
Default: `0`
Virtualtext column range, from `column` to `maxcolumn`. If a line is
`column` or less characters long, the virtualtext message is shifted right
to `column`.
Where the line is greater than `column` characters long, but less than
`maxcolumn`, the virtualtext message is placed at the end of the line.
Where the line is greater than `maxcolumn` the virtualtext message is
omitted.
A |Number| greater than `0` is used as the fixed column position, however
a |String| ending in `%` represents a percentage of the window width.
When `column` is set to zero, column positioning is disabled, when `maxcolumn`
is set to zero, no maximum line length is enforced.
g:ale_virtualtext_single *g:ale_virtualtext_single*
*b:ale_virtualtext_single*
Type: |Number|
Default: `0`
Enable or disable concatenation of multiple virtualtext messages on a single
line. By default, if a line has multiple errors or warnings, each will be
appended in turn.
With `single` set to a non-zero value, only the first message appears.
(No attempt is made to prefer message types such as errors over warnings)
g:ale_virtualenv_dir_names *g:ale_virtualenv_dir_names*
*b:ale_virtualenv_dir_names*
@ -2510,7 +2577,7 @@ ALEStyleWarningSignLineNr *ALEStyleWarningSignLineNr*
ALEVirtualTextError *ALEVirtualTextError*
Default: `highlight link ALEVirtualTextError ALEError`
Default: `highlight link ALEVirtualTextError Comment`
The highlight for virtualtext errors. See |g:ale_virtualtext_cursor|.
@ -2538,7 +2605,7 @@ ALEVirtualTextStyleWarning *ALEVirtualTextStyleWarning*
ALEVirtualTextWarning *ALEVirtualTextWarning*
Default: `highlight link ALEVirtualTextWarning ALEWarning`
Default: `highlight link ALEVirtualTextWarning Comment`
The highlight for virtualtext errors. See |g:ale_virtualtext_cursor|.
@ -2778,6 +2845,7 @@ documented in additional help files.
textlint..............................|ale-asciidoc-textlint|
asm.....................................|ale-asm-options|
gcc...................................|ale-asm-gcc|
llvm_mc...............................|ale-asm-llvm_mc|
avra....................................|ale-avra-options|
avra..................................|ale-avra-avra|
awk.....................................|ale-awk-options|
@ -2962,6 +3030,7 @@ documented in additional help files.
html-beautify.........................|ale-html-beautify|
htmlhint..............................|ale-html-htmlhint|
prettier..............................|ale-html-prettier|
rustywind.............................|ale-html-rustywind|
stylelint.............................|ale-html-stylelint|
tidy..................................|ale-html-tidy|
vscodehtml............................|ale-html-vscode|
@ -3037,6 +3106,7 @@ documented in additional help files.
lua.....................................|ale-lua-options|
cspell................................|ale-lua-cspell|
lua-format............................|ale-lua-lua-format|
lua-language-server...................|ale-lua-lua-language-server|
luac..................................|ale-lua-luac|
luacheck..............................|ale-lua-luacheck|
luafmt................................|ale-lua-luafmt|
@ -3063,9 +3133,11 @@ documented in additional help files.
nimlsp................................|ale-nim-nimlsp|
nimpretty.............................|ale-nim-nimpretty|
nix.....................................|ale-nix-options|
alejandra.............................|ale-nix-alejandra|
nixfmt................................|ale-nix-nixfmt|
nixpkgs-fmt...........................|ale-nix-nixpkgs-fmt|
statix................................|ale-nix-statix|
deadnix...............................|ale-nix-deadnix|
nroff...................................|ale-nroff-options|
write-good............................|ale-nroff-write-good|
objc....................................|ale-objc-options|
@ -3159,6 +3231,7 @@ documented in additional help files.
isort.................................|ale-python-isort|
mypy..................................|ale-python-mypy|
prospector............................|ale-python-prospector|
pycln.................................|ale-python-pycln|
pycodestyle...........................|ale-python-pycodestyle|
pydocstyle............................|ale-python-pydocstyle|
pyflakes..............................|ale-python-pyflakes|
@ -3168,6 +3241,7 @@ documented in additional help files.
pylsp.................................|ale-python-pylsp|
pyre..................................|ale-python-pyre|
pyright...............................|ale-python-pyright|
refurb................................|ale-python-refurb|
reorder-python-imports................|ale-python-reorder_python_imports|
ruff..................................|ale-python-ruff|
unimport..............................|ale-python-unimport|
@ -3179,6 +3253,9 @@ documented in additional help files.
languageserver........................|ale-r-languageserver|
lintr.................................|ale-r-lintr|
styler................................|ale-r-styler|
racket..................................|ale-racket-options|
racket_langserver.....................|ale-racket-langserver|
raco_fmt..............................|ale-racket-raco-fmt|
reasonml................................|ale-reasonml-options|
merlin................................|ale-reasonml-merlin|
ols...................................|ale-reasonml-ols|

View File

@ -0,0 +1,49 @@
local module = {}
local ale_type_to_diagnostic_severity = {
E = vim.diagnostic.severity.ERROR,
W = vim.diagnostic.severity.WARN,
I = vim.diagnostic.severity.INFO
}
module.sendAleResultsToDiagnostics = function(buffer, loclist)
local diagnostics = {}
-- Convert all the ALE loclist items to the shape that Neovim's diagnostic
-- API is expecting.
for _, location in ipairs(loclist) do
table.insert(
diagnostics,
-- All line numbers from ALE are 1-indexed, but all line numbers
-- in the diagnostics API are 0-indexed, so we have to subtract 1
-- to make this work.
{
lnum = location.lnum - 1,
-- Ending line number, or if we don't have one, just make it the same
-- as the starting line number
end_lnum = (location.end_lnum or location.lnum) - 1,
-- Which column does the error start on?
col = math.max((location.col or 1) - 1, 0),
-- end_col does *not* appear to need 1 subtracted, so we don't.
end_col = location.end_col,
-- Which severity: error, warning, or info?
severity = ale_type_to_diagnostic_severity[location.type] or "E",
-- The error message
message = location.text,
-- e.g. "rubocop"
source = location.linter_name,
}
)
end
local virtualtext_enabled_set = {['all'] = true, ['2'] = true, [2] = true, ['current'] = true, ['1'] = true, [1] = true}
vim.diagnostic.set(
vim.api.nvim_create_namespace('ale'),
buffer,
diagnostics,
{ virtual_text = virtualtext_enabled_set[vim.g.ale_virtualtext_cursor] ~= nil}
)
end
return module

View File

@ -127,8 +127,8 @@ let g:ale_echo_cursor = get(g:, 'ale_echo_cursor', 1)
" This flag can be set to 1 to automatically show errors in the preview window.
let g:ale_cursor_detail = get(g:, 'ale_cursor_detail', 0)
" This flag can be set to 1 to enable virtual text when the cursor moves.
let g:ale_virtualtext_cursor = get(g:, 'ale_virtualtext_cursor', 0)
" This flag can be changed to disable/enable virtual text.
let g:ale_virtualtext_cursor = get(g:, 'ale_virtualtext_cursor', (has('nvim-0.3.2') || has('patch-9.0.0297') && has('textprop') && has('popupwin')) ? 'all' : 'disabled')
" This flag can be set to 1 to enable LSP hover messages at the cursor.
let g:ale_hover_cursor = get(g:, 'ale_hover_cursor', 1)
@ -178,6 +178,10 @@ let g:ale_python_auto_pipenv = get(g:, 'ale_python_auto_pipenv', 0)
" Enable automatic detection of poetry for Python linters.
let g:ale_python_auto_poetry = get(g:, 'ale_python_auto_poetry', 0)
" Enable automatic adjustment of environment variables for Python linters.
" The variables are set based on ALE's virtualenv detection.
let g:ale_python_auto_virtualenv = get(g:, 'ale_python_auto_virtualenv', 0)
" This variable can be overridden to set the GO111MODULE environment variable.
let g:ale_go_go111module = get(g:, 'ale_go_go111module', '')
@ -187,6 +191,15 @@ let g:ale_deno_executable = get(g:, 'ale_deno_executable', 'deno')
" If 1, enable a popup menu for commands.
let g:ale_popup_menu_enabled = get(g:, 'ale_popup_menu_enabled', has('gui_running'))
" If 1, disables ALE's built in error display. Instead, all errors are piped
" to the diagnostics API.
let g:ale_use_neovim_diagnostics_api = get(g:, 'ale_use_neovim_diagnostics_api', 0)
if g:ale_use_neovim_diagnostics_api && !has('nvim-0.6')
" no-custom-checks
echoerr('Setting g:ale_use_neovim_diagnostics_api to 1 requires Neovim 0.6+.')
endif
if g:ale_set_balloons is 1 || g:ale_set_balloons is# 'hover'
call ale#balloon#Enable()
endif

View File

@ -45,6 +45,7 @@ formatting.
* [write-good](https://github.com/btford/write-good)
* ASM
* [gcc](https://gcc.gnu.org)
* [llvm-mc](https://llvm.org)
* AVRA
* [avra](https://github.com/Ro5bert/avra)
* Awk
@ -264,11 +265,13 @@ formatting.
* [alex](https://github.com/get-alex/alex)
* [angular](https://www.npmjs.com/package/@angular/language-server)
* [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell)
* [eslint](https://github.com/BenoitZugmeyer/eslint-plugin-html)
* [fecs](http://fecs.baidu.com/)
* [html-beautify](https://beautifier.io/)
* [htmlhint](http://htmlhint.com/)
* [prettier](https://github.com/prettier/prettier)
* [proselint](http://proselint.com/)
* [rustywind](https://github.com/avencera/rustywind)
* [tidy](http://www.html-tidy.org/)
* [write-good](https://github.com/btford/write-good)
* Idris
@ -349,6 +352,7 @@ formatting.
* Lua
* [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell)
* [lua-format](https://github.com/Koihik/LuaFormatter)
* [lua-language-server](https://github.com/LuaLS/lua-language-server)
* [luac](https://www.lua.org/manual/5.1/luac.html)
* [luacheck](https://github.com/mpeterv/luacheck)
* [luafmt](https://github.com/trixnz/lua-fmt)
@ -386,6 +390,7 @@ formatting.
* [nimlsp](https://github.com/PMunch/nimlsp)
* nimpretty
* nix
* [alejandra](https://github.com/kamadorueda/alejandra)
* [nix-instantiate](http://nixos.org/nix/manual/#sec-nix-instantiate)
* [nixfmt](https://github.com/serokell/nixfmt)
* [nixpkgs-fmt](https://github.com/nix-community/nixpkgs-fmt)
@ -490,6 +495,7 @@ formatting.
* [isort](https://github.com/timothycrosley/isort)
* [mypy](http://mypy-lang.org/)
* [prospector](https://github.com/PyCQA/prospector) :warning: :floppy_disk:
* [pycln](https://github.com/hadialqattan/pycln)
* [pycodestyle](https://github.com/PyCQA/pycodestyle) :warning:
* [pydocstyle](https://www.pydocstyle.org/) :warning:
* [pyflakes](https://github.com/PyCQA/pyflakes)
@ -499,6 +505,7 @@ formatting.
* [pylsp](https://github.com/python-lsp/python-lsp-server) :warning:
* [pyre](https://github.com/facebook/pyre-check) :warning:
* [pyright](https://github.com/microsoft/pyright)
* [refurb](https://github.com/dosisod/refurb) :floppy_disk:
* [reorder-python-imports](https://github.com/asottile/reorder_python_imports)
* [ruff](https://github.com/charliermarsh/ruff)
* [unimport](https://github.com/hakancelik96/unimport)