Skip to content

Commit

Permalink
Use the correct buffer when running in an autocmd
Browse files Browse the repository at this point in the history
In an autocmd (e.g., BufNew), `%` may not be the buffer being processed.
Use `<afile>` and `<abuf>` in those cases instead.
  • Loading branch information
cxw42 committed Aug 7, 2023
1 parent daa5573 commit 345a5a3
Showing 1 changed file with 99 additions and 64 deletions.
163 changes: 99 additions & 64 deletions plugin/editorconfig.vim
Original file line number Diff line number Diff line change
Expand Up @@ -91,23 +91,24 @@ let s:initialized = 0
" }}}1

" shellslash handling {{{1
function! s:DisableShellSlash() " {{{2
function! s:DisableShellSlash(bufnr) " {{{2
" disable shellslash for proper escaping of Windows paths

" In Windows, 'shellslash' also changes the behavior of 'shellescape'.
" It makes 'shellescape' behave like in UNIX environment. So ':setl
" noshellslash' before evaluating 'shellescape' and restore the
" settings afterwards when 'shell' does not contain 'sh' somewhere.
if has('win32') && empty(matchstr(&shell, 'sh'))
let s:old_shellslash = &l:shellslash
setlocal noshellslash
let l:shell = getbufvar(a:bufnr, '&shell')
if has('win32') && empty(matchstr(l:shell, 'sh'))
let s:old_shellslash = getbufvar(a:bufnr, '&shellslash')
setbufvar(a:bufnr, '&shellslash', 0)
endif
endfunction " }}}2

function! s:ResetShellSlash() " {{{2
function! s:ResetShellSlash(bufnr) " {{{2
" reset shellslash to the user-set value, if any
if exists('s:old_shellslash')
let &l:shellslash = s:old_shellslash
setbufvar(a:bufnr, '&shellslash', s:old_shellslash)
unlet! s:old_shellslash
endif
endfunction " }}}2
Expand Down Expand Up @@ -204,9 +205,20 @@ function! s:GetFilenames(path, filename) " {{{1
return l:path_list
endfunction " }}}1

function! s:UseConfigFiles() abort " Apply config to the current buffer {{{1
call setbufvar('%', 'editorconfig_tried', 1)
let l:buffer_name = expand('%:p')
function! s:UseConfigFiles(from_autocmd) abort " Apply config to the current buffer {{{1
" from_autocmd is truthy if called from an autocmd, falsy otherwise.

" Get the properties of the buffer we are working on
if a:from_autocmd
let l:bufnr = str2nr(expand('<abuf>'))
let l:buffer_name = expand('<afile>:p')
let l:buffer_path = expand('<afile>:p:h')
else
let l:bufnr = bufnr('%')
let l:buffer_name = expand('%:p')
let l:buffer_path = expand('%:p:h')
endif
call setbufvar(l:bufnr, 'editorconfig_tried', 1)

" Only process normal buffers (do not treat help files as '.txt' files)
" When starting Vim with a directory, the buftype might not yet be set:
Expand All @@ -226,7 +238,7 @@ function! s:UseConfigFiles() abort " Apply config to the current buffer {{{1
endif
endif

if getbufvar('%', 'EditorConfig_disable', 0)
if getbufvar(l:bufnr, 'EditorConfig_disable', 0)
if g:EditorConfig_verbose
echo 'EditorConfig disabled --- skipping buffer "' . l:buffer_name . '"'
endif
Expand All @@ -245,7 +257,7 @@ function! s:UseConfigFiles() abort " Apply config to the current buffer {{{1
endfor

" Check if any .editorconfig does exist
let l:conf_files = s:GetFilenames(expand('%:p:h'), '.editorconfig')
let l:conf_files = s:GetFilenames(l:buffer_path, '.editorconfig')
let l:conf_found = 0
for conf_file in conf_files
if filereadable(conf_file)
Expand All @@ -269,12 +281,12 @@ function! s:UseConfigFiles() abort " Apply config to the current buffer {{{1
endif

if s:editorconfig_core_mode ==? 'vim_core'
if s:UseConfigFiles_VimCore(l:buffer_name) == 0
call setbufvar('%', 'editorconfig_applied', 1)
if s:UseConfigFiles_VimCore(l:bufnr, l:buffer_name) == 0
call setbufvar(l:bufnr, 'editorconfig_applied', 1)
endif
elseif s:editorconfig_core_mode ==? 'external_command'
call s:UseConfigFiles_ExternalCommand(l:buffer_name)
call setbufvar('%', 'editorconfig_applied', 1)
call s:UseConfigFiles_ExternalCommand(l:bufnr, l:buffer_name)
call setbufvar(l:bufnr, 'editorconfig_applied', 1)
else
echohl Error |
\ echo "Unknown EditorConfig Core: " .
Expand All @@ -290,8 +302,8 @@ function! s:EditorConfigEnable(should_enable)
augroup editorconfig
autocmd!
if a:should_enable
autocmd BufNewFile,BufReadPost,BufFilePost * call s:UseConfigFiles()
autocmd VimEnter,BufNew * call s:UseConfigFiles()
autocmd BufNewFile,BufReadPost,BufFilePost * call s:UseConfigFiles(1)
autocmd VimEnter,BufNew * call s:UseConfigFiles(1)
endif
augroup END
endfunction
Expand All @@ -302,7 +314,7 @@ endfunction
command! EditorConfigEnable call s:EditorConfigEnable(1)
command! EditorConfigDisable call s:EditorConfigEnable(0)

command! EditorConfigReload call s:UseConfigFiles() " Reload EditorConfig files
command! EditorConfigReload call s:UseConfigFiles(0) " Reload EditorConfig files
" }}}2

" On startup, enable the autocommands
Expand All @@ -312,29 +324,29 @@ call s:EditorConfigEnable(1)

" UseConfigFiles function for different modes {{{1

function! s:UseConfigFiles_VimCore(target)
function! s:UseConfigFiles_VimCore(bufnr, target)
" Use the vimscript EditorConfig core
try
let l:config = editorconfig_core#handler#get_configurations(
\ { 'target': a:target } )
call s:ApplyConfig(l:config)
call s:ApplyConfig(a:bufnr, l:config)
return 0 " success
catch
return 1 " failure
endtry
endfunction

function! s:UseConfigFiles_ExternalCommand(target)
function! s:UseConfigFiles_ExternalCommand(bufnr, target)
" Use external EditorConfig core (e.g., the C core)

call s:DisableShellSlash()
call s:DisableShellSlash(a:bufnr)
let l:exec_path = shellescape(s:editorconfig_exec_path)
call s:ResetShellSlash()
call s:ResetShellSlash(a:bufnr)

call s:SpawnExternalParser(l:exec_path, a:target)
call s:SpawnExternalParser(a:bufnr, l:exec_path, a:target)
endfunction

function! s:SpawnExternalParser(cmd, target) " {{{2
function! s:SpawnExternalParser(bufnr, cmd, target) " {{{2
" Spawn external EditorConfig. Used by s:UseConfigFiles_ExternalCommand()

let l:cmd = a:cmd
Expand All @@ -345,9 +357,9 @@ function! s:SpawnExternalParser(cmd, target) " {{{2

let l:config = {}

call s:DisableShellSlash()
call s:DisableShellSlash(a:bufnr)
let l:cmd = l:cmd . ' ' . shellescape(a:target)
call s:ResetShellSlash()
call s:ResetShellSlash(a:bufnr)

let l:parsing_result = split(system(l:cmd), '\v[\r\n]+')

Expand Down Expand Up @@ -386,96 +398,102 @@ function! s:SpawnExternalParser(cmd, target) " {{{2
let l:config[l:eq_left] = l:eq_right
endfor

call s:ApplyConfig(l:config)
call s:ApplyConfig(a:bufnr, l:config)
endfunction " }}}2

" }}}1

function! s:ApplyConfig(config) abort " Set the buffer options {{{1
function! s:ApplyConfig(bufnr, config) abort " Set the buffer options {{{1
if g:EditorConfig_verbose
echo 'Options: ' . string(a:config)
endif

if s:IsRuleActive('indent_style', a:config)
if a:config["indent_style"] == "tab"
setl noexpandtab
call setbufvar(a:bufnr, '&expandtab', 0)
elseif a:config["indent_style"] == "space"
setl expandtab
call setbufvar(a:bufnr, '&expandtab', 1)
endif
endif

if s:IsRuleActive('tab_width', a:config)
let &l:tabstop = str2nr(a:config["tab_width"])
let l:tabstop = str2nr(a:config["tab_width"])
call setbufvar(a:bufnr, '&tabstop', l:tabstop)
else
" Grab the current ts so we can use it below
let l:tabstop = getbufvar(a:bufnr, '&tabstop')
endif

if s:IsRuleActive('indent_size', a:config)
" if indent_size is 'tab', set shiftwidth to tabstop;
" if indent_size is a positive integer, set shiftwidth to the integer
" value
if a:config["indent_size"] == "tab"
let &l:shiftwidth = &l:tabstop
call setbufvar(a:bufnr, '&shiftwidth', l:tabstop)
if type(g:EditorConfig_softtabstop_tab) != type([])
let &l:softtabstop = g:EditorConfig_softtabstop_tab > 0 ?
\ &l:shiftwidth : g:EditorConfig_softtabstop_tab
call setbufvar(a:bufnr, '&softtabstop',
\ g:EditorConfig_softtabstop_tab > 0 ?
\ l:tabstop : g:EditorConfig_softtabstop_tab)
endif
else
let l:indent_size = str2nr(a:config["indent_size"])
if l:indent_size > 0
let &l:shiftwidth = l:indent_size
call setbufvar(a:bufnr, '&shiftwidth', l:indent_size)
if type(g:EditorConfig_softtabstop_space) != type([])
let &l:softtabstop = g:EditorConfig_softtabstop_space > 0 ?
\ &l:shiftwidth : g:EditorConfig_softtabstop_space
call setbufvar(a:bufnr, '&softtabstop',
\ g:EditorConfig_softtabstop_space > 0 ?
\ l:indent_size : g:EditorConfig_softtabstop_space)
endif
endif
endif

endif

if s:IsRuleActive('end_of_line', a:config) &&
\ &l:modifiable
\ getbufvar(a:bufnr, '&modifiable')
if a:config["end_of_line"] == "lf"
setl fileformat=unix
call setbufvar(a:bufnr, '&fileformat', 'unix')
elseif a:config["end_of_line"] == "crlf"
setl fileformat=dos
call setbufvar(a:bufnr, '&fileformat', 'dos')
elseif a:config["end_of_line"] == "cr"
setl fileformat=mac
call setbufvar(a:bufnr, '&fileformat', 'mac')
endif
endif

if s:IsRuleActive('charset', a:config) &&
\ &l:modifiable
\ getbufvar(a:bufnr, '&modifiable')
if a:config["charset"] == "utf-8"
setl fileencoding=utf-8
setl nobomb
call setbufvar(a:bufnr, '&fileencoding', 'utf-8')
call setbufvar(a:bufnr, '&bomb', 0)
elseif a:config["charset"] == "utf-8-bom"
setl fileencoding=utf-8
setl bomb
call setbufvar(a:bufnr, '&fileencoding', 'utf-8')
call setbufvar(a:bufnr, '&bomb', 1)
elseif a:config["charset"] == "latin1"
setl fileencoding=latin1
setl nobomb
call setbufvar(a:bufnr, '&fileencoding', 'latin1')
call setbufvar(a:bufnr, '&bomb', 0)
elseif a:config["charset"] == "utf-16be"
setl fileencoding=utf-16be
setl bomb
call setbufvar(a:bufnr, '&fileencoding', 'utf-16be')
call setbufvar(a:bufnr, '&bomb', 1)
elseif a:config["charset"] == "utf-16le"
setl fileencoding=utf-16le
setl bomb
call setbufvar(a:bufnr, '&fileencoding', 'utf-16le')
call setbufvar(a:bufnr, '&bomb', 1)
endif
endif

augroup editorconfig_trim_trailing_whitespace
autocmd! BufWritePre <buffer>
if s:IsRuleActive('trim_trailing_whitespace', a:config) &&
\ get(a:config, 'trim_trailing_whitespace', 'false') ==# 'true'
autocmd BufWritePre <buffer> call s:TrimTrailingWhitespace()
execute 'autocmd BufWritePre <buffer=' . a:bufnr . '> call s:TrimTrailingWhitespace()'
endif
augroup END

if s:IsRuleActive('insert_final_newline', a:config)
if exists('+fixendofline')
if a:config["insert_final_newline"] == "false"
setl nofixendofline
call setbufvar(a:bufnr, '&fixendofline', 0)
else
setl fixendofline
call setbufvar(a:bufnr, '&fixendofline', 1)
endif
elseif exists(':SetNoEOL') == 2
if a:config["insert_final_newline"] == "false"
Expand All @@ -490,23 +508,39 @@ function! s:ApplyConfig(config) abort " Set the buffer options {{{1
let l:max_line_length = str2nr(a:config['max_line_length'])

if l:max_line_length >= 0
let &l:textwidth = l:max_line_length
call setbufvar(a:bufnr, '&textwidth', l:max_line_length)
if g:EditorConfig_preserve_formatoptions == 0
setlocal formatoptions+=tc
" setlocal formatoptions+=tc
let l:fo = getbufvar(a:bufnr, '&formatoptions')
if l:fo !~# 't'
let l:fo .= 't'
endif
if l:fo !~# 'c'
let l:fo .= 'c'
endif
call setbufvar(a:bufnr, '&formatoptions', l:fo)
endif
endif

if exists('+colorcolumn')
if l:max_line_length > 0
if g:EditorConfig_max_line_indicator == 'line'
setlocal colorcolumn+=+1
" setlocal colorcolumn+=+1
let l:cocol = getbufvar(a:bufnr, '&colorcolumn')
if !empty(l:cocol)
let l:cocol .= ','
endif
let l:cocol .= '+1'
call setbufvar(a:bufnr, '&colorcolumn', l:cocol)
elseif g:EditorConfig_max_line_indicator == 'fill' &&
\ l:max_line_length < &l:columns
\ l:max_line_length < getbufvar(a:bufnr, '&columns')
" Fill only if the columns of screen is large enough
let &l:colorcolumn = join(
\ range(l:max_line_length+1,&l:columns),',')
call setbufvar(a:bufnr, '&colorcolumn',
\ join(range(l:max_line_length+1,
\ getbufvar(a:bufnr, '&columns')),
\ ','))
elseif g:EditorConfig_max_line_indicator == 'exceeding'
let &l:colorcolumn = ''
call setbufvar(a:bufnr, '&colorcolumn', '')
for l:match in getmatches()
if get(l:match, 'group', '') == 'ColorColumn'
call matchdelete(get(l:match, 'id'))
Expand Down Expand Up @@ -534,7 +568,8 @@ endfunction
" }}}1

function! s:TrimTrailingWhitespace() " {{{1
if &l:modifiable
" Called from within a buffer-specific autocmd, so we can use '%'
if getbufvar('%', '&modifiable')
" don't lose user position when trimming trailing whitespace
let s:view = winsaveview()
try
Expand Down

0 comments on commit 345a5a3

Please sign in to comment.