ftplugin의 autocmd의 경우 패턴 일치 또는 <buffer>를 사용해야합니까?


14

파일을 자동으로 저장하는 TeX 및 Markdown 파일에 대한 autocmd가 있습니다. 특이한 것은 없습니다 :

autocmd CursorHold *.tex,*.md w

이러한 파일에 대한 사용자 지정 설정이 증가하지만, 난으로 그들을 분할 ftplugin/tex.vimftplugin/markdown.vim:

" ftplugin/tex.vim
autocmd CursorHold *.tex w
" ftplugin/markdown.vim
autocmd CursorHold *.md w

이제 이러한 파일은 해당 파일에 대해서만 소스되므로 패턴 일치가 중복됩니다. 분명히 autocmds는 버퍼 로컬 일 수 있습니다. 보낸 사람 :h autocmd-buffer-local:

Buffer-local autocommands are attached to a specific buffer.  They are useful
if the buffer does not have a name and when the name does not match a specific
pattern.  But it also means they must be explicitly added to each buffer.

Instead of a pattern buffer-local autocommands use one of these forms:
        <buffer>        current buffer
        <buffer=99>     buffer number 99
        <buffer=abuf>   using <abuf> (only when executing autocommands)
                        <abuf>

그것은 그러한 사용법을위한 것 같습니다. 이제, 모두 ftplugin/tex.vimftplugin/markdown.vim할 수 있습니다 :

autocmd CursorHold <buffer> w

이에 대해 걱정할 필요에서 저를 절약 할 수 있도록 나는 정말, 파일 타입이 올바른지 같이만큼 실제 확장에 대해 우려하고 있지 않다 *.md*.markdown다른 어떤 확장 마크 다운 유효합니다.

이 사용법이 <buffer>맞습니까? 내가 알아야 할 함정이 있습니까? 버퍼를 지우고 다른 버퍼를 열면 문제가 발생합니까 (숫자가 충돌하지는 않지만 ...)?


1
버퍼를 지우면 버퍼 로컬 autocmd도 지워집니다.
텀블러 41

실제로 @ Tumbler41. 그것은 도움으로 몇 단락 아래에 있다고 말합니다.
muru

1
정확히 요청한 것은 아니지만 up(의 약어 :update)가 wautocmd 보다 빠릅니다 (불필요한 쓰기는 피함).
mMontu 2016 년

@mMontu 니스. 심지어 git history에서 검사중인 파일에 대해 autocmd가 활성화되었을 때 발생하는 문제를 해결합니다. 버퍼가 읽기 전용이며 w실패했습니다. 자꾸. :up이 경우에는 아무것도하지 않습니다. :)
muru

우연히도 :) 우연히도, 'autowrite'옵션이 유용하다는 것을 알 수 있습니다 (동기 부여에 따라 autocmds를 삭제할 수 있음).
mMontu 2016 년

답변:


11

이 <buffer> 사용법이 맞습니까?

나는 그것이 옳다고 생각하지만, 당신은 그것을 augroup 안에 감싸고 후자를 지워서 동일한 버퍼를 다시로드하는 명령을 실행할 때마다 autocmd가 복제되지 않도록해야합니다.

설명했듯이 특수 패턴을 <buffer>사용하면 파일 내부에 구현 된 내장 파일 유형 감지 메커니즘에 의존 할 수 있습니다 $VIMRUNTIME/filetype.vim.

이 파일에서 주어진 버퍼에 대해 올바른 파일 유형을 설정하는 Vim의 내장 autocmd를 찾을 수 있습니다. 예를 들어, 마크 다운의 경우 :

" Markdown
au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md  setf markdown

파일 유형 플러그인 내에서 설치하는 모든 autocmd에 대해 동일한 패턴을 복사 할 수 있습니다. 예를 들어, 몇 초 동안 커서가 움직이지 않을 때 버퍼를 자동으로 저장하려면 다음을 수행하십시오.

au CursorHold *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md  update

그러나 <buffer>덜 장황한 방법입니다.

au CursorHold <buffer> update

또한 언젠가 다른 확장이 유효하고 $VIMRUNTIME/filetype.vim이를 포함하도록 업데이트 된 경우 autocmd에 정보가 표시되지 않습니다. 그리고 파일 유형 플러그인 내에서 모든 패턴을 업데이트해야합니다.


버퍼를 지우고 다른 버퍼를 열면 문제가 발생합니까 (숫자가 충돌하지는 않지만 ...)?

확실하지 않지만 Vim이 와이 핑 된 버퍼의 버퍼 번호를 재사용 할 수 있다고 생각하지 않습니다. 도움말에서 관련 섹션을 찾을 수 없지만 vim.wikia.com 에서이 단락을 찾았습니다 .

Vim은 삭제 된 버퍼의 버퍼 번호를 새로운 버퍼에 재사용하지 않습니다. Vim은 항상 새 버퍼에 대해 다음 일련 번호를 할당합니다.

또한 @ Tumbler41이 설명했듯이 버퍼를 지우면 autocmd 가 제거됩니다. 보낸 사람 :h autocmd-buflocal:

버퍼가 지워지면 버퍼 로컬 자동 명령도 사라집니다.

직접 확인하려면 Vim의 상세 수준을 6으로 늘려서 확인할 수 있습니다 :verbose. 수정자를 사용하여 한 명령만으로 임시로 수행 할 수 있습니다 . 따라서 마크 다운 버퍼 내부에서 다음을 실행할 수 있습니다.

:6verbose bwipe

그런 다음 Vim의 메시지를 확인하면 :

:messages

다음과 같은 줄이 나타납니다.

auto-removing autocommand: CursorHold <buffer=42>

42마크 다운 버퍼의 수는 어디에 있었 습니까 ?


내가 알아야 할 함정이 있습니까?

내가 함정으로 생각하고 특별한 패턴을 포함하는 세 가지 상황이 있습니다 <buffer>. 그중 두 가지는 <buffer>문제가 될 수 있으며 다른 하나는 해결책입니다.

함정 1

먼저, 버퍼 로컬 autocmds의 augroup을 지우는 방법에주의해야합니다. 이 스 니펫에 익숙해야합니다.

augroup your_group_name
    autocmd!
    autocmd Event pattern command
augroup END

따라서 다음과 같이 수정하지 않은 버퍼 로컬 autocmd에 사용하도록 유혹 할 수 있습니다.

augroup my_markdown
    autocmd!
    autocmd CursorHold <buffer> update
augroup END

그러나 이것은 바람직하지 않은 영향을 미칩니다. 마크 다운 버퍼를 처음로드 할 때이를 호출하면 Aautocmd가 올바르게 설치됩니다. 그런 다음을 다시로드 할 때 Aautocmd가 (로 인해 autocmd!) 삭제 되고 다시 설치됩니다. 따라서 augroup은 autocmd의 복제를 올바르게 방지합니다.

이제 두 번째 마크 다운 버퍼를로드하고 두 B번째 창에 이를 호출한다고 가정 해 봅시다 . augroup의 모든 autocmd가 지워집니다. 즉 autocmd와의 A하나입니다 B. 그런 다음 SINGLE autocmd가 설치됩니다 B.

따라서을 (를) 변경 B하고 몇 초 동안 CursorHold해고 될 때까지 자동으로 저장됩니다. 그러나 돌아가서 A같은 일을하면 버퍼가 저장되지 않습니다. 마크 다운 버퍼를 마지막으로로드했을 때 제거한 것과 추가 한 것 사이에 불균형이 있었기 때문입니다. 추가 한 것보다 더 많이 제거했습니다.

해결책은 특수 패턴 <buffer>:autocmd!다음 에 전달하여 모든 autocmd를 제거하지 않고 현재 버퍼 중 하나만 제거하는 것입니다 .

augroup my_markdown
    autocmd! CursorHold <buffer>
    autocmd CursorHold <buffer> update
augroup END

CursorHoldautocmds를 제거하는 행의 모든 ​​이벤트와 일치하도록 별표로 바꿀 수 있습니다 .

augroup my_markdown
    autocmd! * <buffer>
    autocmd CursorHold <buffer> update
augroup END

이런 방식으로, 오 그룹을 지우고 싶을 때 autocmds가 듣고있는 모든 이벤트를 지정할 필요는 없습니다.


함정 2

또 다른 함정이 있지만 이번에 <buffer>는 문제가 아니며 해결책입니다.

파일 유형 플러그인에 로컬 옵션을 포함하면 다음과 같이 할 수 있습니다.

setlocal option1=value
setlocal option2

이것은 버퍼 로컬 옵션에서 예상대로 작동하지만 항상 창 로컬 옵션에서는 작동하지 않습니다. 문제를 설명하기 위해 다음 실험을 시도 할 수 있습니다. 파일을 작성하고 그 ~/.vim/after/ftdetect/potion.vim안에 작성하십시오.

autocmd BufNewFile,BufRead *.pn setfiletype potion

이 파일은 potion확장자가 인 파일의 파일 형식 을 자동으로 설정합니다 .pn. 이 특정 종류의 파일의 경우 Vim이 자동으로 수행하므로 (u 참조 :h ftdetect) augroup 안에 래핑 할 필요가 없습니다 .

시스템에 중간 디렉토리가 없으면 작성할 수 있습니다.

다음으로 파일 유형 플러그인을 작성하고 그 ~/.vim/after/ftplugin/potion.vim안에 작성하십시오.

setlocal list

기본적으로 potion파일에서이 설정을 사용하면 탭 문자가로 표시되고 ^I줄 끝이 로 표시됩니다 $.

이제 최소한을 만드십시오 vimrc. 내부 /tmp/vimrc쓰기 :

filetype plugin on

... 파일 유형 플러그인을 활성화합니다.

또한 물약 파일 /tmp/pn.pn및 무작위 파일을 만드십시오 /tmp/file. 물약 파일에서 다음과 같이 작성하십시오.

foo
bar
baz

무작위 파일에서 물약 파일의 경로를 작성하십시오 /tmp/pn.pn.

/tmp/pn.pn

이제 최소한의 초기화로 Vim을 시작하고을 소싱하고 vimrc세로 뷰포트에서 두 파일을 모두 엽니 다.

$ vim -Nu /tmp/vimrc -O /tmp/pn.pn /tmp/file

2 개의 수직 뷰포트가 나타납니다. 왼쪽의 물약 파일은 달러 기호와 함께 줄의 끝을 표시하고 오른쪽의 임의 파일은 전혀 표시하지 않습니다.

임의의 파일에 초점을 gf두고을 눌러 경로가 커서 아래에있는 물약 파일을 표시하십시오. 이제 오른쪽 뷰포트에 동일한 물약 버퍼가 표시되지만 이번에는 줄 끝이 달러 기호로 표시되지 않습니다. 그리고를 입력 :setlocal list?하면 Vim은 다음과 nolist같이 대답해야합니다 .

여기에 이미지 설명을 입력하십시오

전체 이벤트 체인 :

BufRead event → set 'filetype' option → load filetype plugins

...을 ( BufRead를) 누를 때 첫 번째가 발생하지 않았기 때문에 발생하지 않았습니다 gf. 버퍼가 이미로드되었습니다.

setlocal list묘약 파일 유형 플러그인 내부에 추가 'list'하면 묘약 버퍼를 표시하는 모든 창 에서 옵션을 사용할 수 있다고 생각 했을 수 있기 때문에 예기치 않은 것처럼 보일 수 있습니다 .

이 문제는이 새로운 potion파일 형식 에만 국한되지 않습니다 . markdown파일로도 경험할 수 있습니다 .

'list'옵션 에만 국한되지는 않습니다 . 당신은 다른 윈도우 지역 설정을 체험 할 수있는, 같은 'conceallevel', 'foldmethod', 'foldexpr', 'foldtitle', ...

gf명령 에만 국한되지 않습니다 . 현재 창에 표시된 버퍼를 변경할 수있는 다른 명령을 사용하여이를 경험할 수 있습니다 : 전역 표시, C-o(창 로컬 점프 목록에서 뒤로 이동) :b {buffer_number},, ...

요약하면 다음과 같은 경우에만 창 로컬 옵션이 올바르게 설정됩니다.

  • 현재 Vim 세션 중에 파일을 읽지 못했습니다 ( BufRead실행해야 하므로 )
  • 파일이 창 ​​로컬 옵션이 이미 올바르게 설정된 창에 표시되고 있습니다
  • 새 창은 다음과 같은 명령으로 작성됩니다 :split(이 경우 명령이 실행 된 창에서 창 로컬 옵션을 상속해야 함).

그렇지 않으면 창 로컬 옵션이 올바르게 설정되지 않을 수 있습니다.

가능한 해결책은 파일 유형 플러그인에서 직접 설정하는 것이 아니라 후자에 설치된 autocmd에서 설정하는 것 BufWinEnter입니다. 이 이벤트는 버퍼가 창에 표시 될 때마다 발생해야합니다.

예를 들어 이것을 쓰는 대신

setlocal list

당신은 이것을 쓸 것입니다 :

augroup my_potion
    au! * <buffer>
    au BufWinEnter <buffer> setlocal list
augroup END

그리고 여기에서 특별한 패턴을 다시 찾을 수 <buffer>있습니다.

여기에 이미지 설명을 입력하십시오


함정 3

버퍼의 파일 형식을 변경하면 autocmd가 유지됩니다. 이를 제거하려면 구성 b:undo_ftplugin(참조 :h undo_ftplugin)하고이 명령을 포함시켜야합니다.

exe 'au! my_markdown * <buffer>'

그러나 autocmds가 포함 된 마크 다운 버퍼가 여전히있을 수 있으므로 augroup 자체를 제거하지 마십시오.

FWIW, 이것은 내가 설정하는 데 사용하는 UltiSnips 스 니펫입니다 b:undo_ftplugin.

snippet undo "undo ftplugin settings" bm
" teardown {{{1

let b:undo_ftplugin =         get(b:, 'undo_ftplugin', '')
\                     .(empty(get(b:, 'undo_ftplugin', '')) ? '' : '|')
\                     ."${1:
\                          setl ${2:option}<}${3:
\                        | exe '${4:n}unmap <buffer> ${5:lhs}'}${6:
\                        | exe 'au! ${7:group_name} * <buffer>'}${8:
\                        | unlet! b:${9:variable}}${10:
\                        | delcommand ${11:Cmd}}
\                      "
$0
endsnippet

그리고 여기 내가 가진 가치의 예가 있습니다 ~/.vim/after/ftplugin/awk.vim.

let b:undo_ftplugin =         get(b:, 'undo_ftplugin', '')
                    \ .(empty(get(b:, 'undo_ftplugin', '')) ? '' : '|')
                    \ ."
                    \   setl cms< cocu< cole< fdm< fdt< tw<
                    \|  exe 'nunmap <buffer> K'
                    \|  exe 'au! my_awk * <buffer>'
                    \|  exe 'au! my_awk_format * <buffer>'
                    \  "

부수적으로, 나는 당신이 질문을 한 이유를 이해합니다. 왜냐하면 <buffer>Vim의 기본 파일에서 특수 패턴 이 사용 된 모든 줄을 찾을 때 :

:vim /au\%[tocmd!].\{-}<buffer>/ $VIMRUNTIME/**/*

나는 단지 9 개의 일치하는 것을 발견했다 134. 그리고 9 개의 일치 항목 중 7 개가 문서에 있으며 실제로 2 개만 제공됩니다. $ VIMRUNTIME / syntax / dircolors.vim 에서 찾을 수 있습니다 :

autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI   <buffer> call s:reset_colors()

이 문제를 일으킬 수 있을지는 모르겠지만, 그들은 당신이 파일 형식 인 버퍼를 다시로드 할 때마다 의미 augroup, 내부되지 않습니다 dircolors(라는 이름의 파일을 편집 할 경우 발생을 .dircolors, .dir_colors또는 그 경로 끝 /etc/DIR_COLORS) 구문 플러그인은 새로운 버퍼 로컬 autocmd를 추가합니다.

다음과 같이 확인할 수 있습니다.

$ vim ~/.dir_colors
:au * <buffer>

마지막 명령은 다음을 표시해야합니다.

CursorHold
    <buffer=1>
              call s:reset_colors()
CursorHoldI
    <buffer=1>
              call s:reset_colors()
CursorMoved
    <buffer=1>
              call s:preview_color('.')
CursorMovedI
    <buffer=1>
              call s:preview_color('.')

이제 버퍼를 다시로드하고 현재 버퍼에 대한 버퍼 로컬 autocmd가 무엇인지 다시 질문하십시오.

:e
:au * <buffer>

이번에는 다음을 볼 수 있습니다 :

CursorHold
    <buffer=1>
              call s:reset_colors()
              call s:reset_colors()
CursorHoldI
    <buffer=1>
              call s:reset_colors()
              call s:reset_colors()
CursorMoved
    <buffer=1>
              call s:preview_color('.')
              call s:preview_color('.')
CursorMovedI
    <buffer=1>
              call s:preview_color('.')
              call s:preview_color('.')

모든 파일의 다시로드, 후 s:reset_colors()s:preview_color('.')하나의 추가 시간을 호출됩니다, 이벤트의 때마다 하나 CursorHold, CursorHoldI, CursorMoved, CursorMovedI발생합니다.

dircolors파일을 여러 번 다시로드 한 후에도 Vim에서 눈에 띄게 느려지거나 예기치 않은 동작이 발생하지 않았기 때문에 큰 문제 는 아닙니다.

문제가있는 경우 구문 플러그인의 관리자에게 문의 할 수 있지만 그 동안 autocmds의 복제를 방지하려면 dircolorsfile을 사용하여 파일에 대한 고유 구문 플러그인을 만들 수 있습니다 ~/.vim/syntax/dircolors.vim. 그 안에 원래 구문 플러그인의 내용을 가져옵니다.

$ vim ~/.vim/syntax/dircolors.vim
:r $VIMRUNTIME/syntax/dircolors.vim

그런 다음 후자의 경우 autocmds를 augroup 안에 래핑하여 지우십시오. 따라서 다음 줄을 바꾸십시오.

autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI   <buffer> call s:reset_colors()

... 이것들과 함께 :

augroup my_dircolors_syntax
    autocmd! * <buffer>
    autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
    autocmd CursorHold,CursorHoldI   <buffer> call s:reset_colors()
augroup END

dircolorsfile을 사용 하여 구문 플러그인 을 만든 경우 ~/.vim/after/syntax/dircolors.vim기본 구문 플러그인이 이전에 제공되었으므로 작동하지 않습니다. 를 사용 ~/.vim/syntax/dircolors.vim하면 구문 플러그인이 기본 플러그인보다 먼저 소스 화되고 buffer-local 변수가 설정 b:current_syntax되어 기본 가드 플러그인에이 가드가 포함되어 있기 때문에 소스 화되지 않습니다.

if exists("b:current_syntax")
    finish
endif

일반적인 규칙은 다음 ~/.vim/ftplugin과 같습니다. 및 ~/.vim/syntax디렉토리를 사용하여 사용자 정의 파일 유형 / 구문 플러그인을 작성하고 런타임 경로의 다음 플러그인 (동일한 파일 유형에 대한)이 소스 소스 (기본 플러그인 포함)가되는 것을 방지하십시오. 그리고 사용은 ~/.vim/after/ftplugin, ~/.vim/after/syntax, 공급되는 다른 플러그인을 방지하기 위해,하지만 그냥 몇 가지 설정 값의 마지막 단어를 가지고 있지.


1
나는 이것을 더 열심히지지 할 수 있으면 좋겠다.
Rich

3
@Rich 나는 당신을 위해 이것을 열심히지지했다. 내 유일한 불만은 요약 "tl; dr"이 없다는 것입니다. 그러나 텍스트로 표현 된 세부 사항을 이해하는 데 중요한 페이지는 노화하는 영혼이 고통을 겪는 고통입니다. autocmd!with autocmd! CursorHold <buffer>in을 교체 augroup하는 것은 특히 중요한 문제이며, 미리 강조 표시해야합니다. 그럼에도 불구하고 ... 이것은 시간, 노력, 피의 눈물에 대한 놀랍도록 놀라운 투자입니다.
Cecil Curry
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.