การใช้ <buffer> นี้ถูกต้องหรือไม่
ฉันคิดว่ามันถูกต้อง แต่คุณเพียงแค่ใส่มันไว้ในกลุ่มและเคลียร์หลังเพื่อให้แน่ใจว่า autocmd จะไม่ซ้ำกันทุกครั้งที่คุณรันคำสั่งที่โหลดบัฟเฟอร์เดียวกัน
ในขณะที่คุณอธิบายรูปแบบพิเศษที่<buffer>ช่วยให้คุณสามารถที่จะพึ่งพาในตัวกลไกการตรวจสอบ filetype $VIMRUNTIME/filetype.vimดำเนินการภายในแฟ้ม
ในไฟล์นี้คุณสามารถค้นหา autocmds ในตัวของ Vim ซึ่งมีหน้าที่รับผิดชอบในการตั้งค่าประเภทไฟล์ที่ถูกต้องสำหรับบัฟเฟอร์ที่กำหนด ตัวอย่างเช่นสำหรับ markdown:
" Markdown
au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md  setf markdown
ภายในปลั๊กอินชนิดไฟล์ของคุณคุณสามารถคัดลอกรูปแบบเดียวกันสำหรับทุก ๆ autocmd ที่คุณติดตั้ง ตัวอย่างเช่นหากต้องการบันทึกบัฟเฟอร์โดยอัตโนมัติเมื่อเคอร์เซอร์ของคุณไม่ได้ถูกย้ายในช่วงสองสามวินาที:
au CursorHold *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md  update
แต่<buffer>ทาง verbose น้อยกว่า:
au CursorHold <buffer> update
นอกจากนี้หากบางวันมีส่วนขยายอื่นที่ถูกต้องและ$VIMRUNTIME/filetype.vimได้รับการอัปเดตเพื่อรวมส่วนเติมเงินอัตโนมัติของคุณจะไม่ได้รับแจ้ง และคุณจะต้องอัปเดตรูปแบบทั้งหมดภายในปลั๊กอินชนิดไฟล์ของคุณ
  สิ่งต่าง ๆ จะยุ่งถ้าฉันลบบัฟเฟอร์และเปิดอีกครั้ง (หวังว่าตัวเลขจะไม่ชนกัน แต่…)
ฉันไม่แน่ใจ แต่ฉันไม่คิดว่า Vim สามารถใช้หมายเลขบัฟเฟอร์ของบัฟเฟอร์ที่ลบแล้วได้อีก ฉันไม่พบหัวข้อที่เกี่ยวข้องจากความช่วยเหลือ แต่ฉันพบย่อหน้านี้จากvim.wikia.com :
  ไม่ Vim จะไม่ใช้หมายเลขบัฟเฟอร์ของบัฟเฟอร์ที่ถูกลบอีกครั้งสำหรับบัฟเฟอร์ใหม่ Vim จะกำหนดหมายเลขลำดับถัดไปสำหรับบัฟเฟอร์ใหม่เสมอ
นอกจากนี้ตามที่@ Tumbler41อธิบายเมื่อคุณล้างบัฟเฟอร์ autocmds ของมันจะถูกลบออก จาก:h autocmd-buflocal:
  เมื่อบัฟเฟอร์ถูกลบออกออโต้คำสั่งบัฟเฟอร์ท้องถิ่นจะหายไปเช่นกัน
หากคุณต้องการตรวจสอบตัวเองคุณสามารถทำได้โดยเพิ่มระดับ verbosity ของ Vim เป็น 6 คุณสามารถทำได้ชั่วคราวเพียงแค่หนึ่งคำสั่งโดยใช้:verboseตัวปรับแต่ง ดังนั้นภายในบัฟเฟอร์มาร์คดาวน์ของคุณคุณสามารถดำเนินการได้:
:6verbose bwipe
จากนั้นถ้าคุณตรวจสอบข้อความของ Vim:
:messages
คุณควรเห็นบรรทัดที่มีลักษณะดังนี้:
auto-removing autocommand: CursorHold <buffer=42>
42จำนวน markdown buffer ของคุณอยู่ที่ไหน
  มีข้อผิดพลาดอะไรบ้างที่ฉันควรระวัง?
มี 3 <buffer>สถานการณ์ที่ผมจะพิจารณาเป็นข้อผิดพลาดและที่เกี่ยวข้องกับรูปแบบพิเศษ ในสองของพวกเขา<buffer>อาจมีปัญหาในอื่น ๆ มันเป็นทางออก
หลุมพราง 1
ก่อนอื่นคุณควรระวังด้วยวิธีที่คุณล้างข้อมูลกลุ่มของ autocmds บัฟเฟอร์ในเครื่องของคุณ คุณต้องคุ้นเคยกับตัวอย่างนี้:
augroup your_group_name
    autocmd!
    autocmd Event pattern command
augroup END
ดังนั้นคุณอาจถูกล่อลวงให้ใช้มันสำหรับ autocmds บัฟเฟอร์ท้องถิ่นของคุณไม่มีการแก้ไขเช่นนี้:
augroup my_markdown
    autocmd!
    autocmd CursorHold <buffer> update
augroup END
แต่สิ่งนี้จะมีผลกระทบที่ไม่พึงประสงค์ ครั้งแรกที่คุณโหลดบัฟเฟอร์ markdown มาเรียกมันว่าAautocmd นั้นจะถูกติดตั้งอย่างถูกต้อง จากนั้นเมื่อคุณโหลดใหม่Aautocmd จะถูกลบ (เนื่องจากautocmd!) และติดตั้งใหม่ ดังนั้นกลุ่มจะถูกต้องจะป้องกันการทำซ้ำของ autocmd อย่างถูกต้อง
ทีนี้สมมติว่าคุณโหลดบัฟเฟอร์ markdown ครั้งที่สองเรียกมันว่าBในหน้าต่างที่ 2 autocmds ทั้งหมดของ augroup จะถูกล้าง: นั่นคือ autocmd ของAและหนึ่งในBนั้น จากนั้น autocmd SINGLE Bจะติดตั้งสำหรับ
ดังนั้นเมื่อคุณทำการเปลี่ยนแปลงBและรอสักครู่เพื่อCursorHoldให้ถูกไล่ออกมันจะถูกบันทึกโดยอัตโนมัติ แต่ถ้าคุณกลับไปAทำสิ่งเดียวกันบัฟเฟอร์จะไม่ถูกบันทึก นี่เป็นเพราะครั้งสุดท้ายที่คุณโหลดบัฟเฟอร์ markdown มีความไม่สมดุลระหว่างสิ่งที่คุณลบกับสิ่งที่คุณเพิ่ม คุณลบมากกว่าสิ่งที่คุณเพิ่ม
วิธีแก้ไขคือไม่ลบ autocmds ทั้งหมด แต่เฉพาะบัฟเฟอร์ปัจจุบันโดยส่งผ่านรูปแบบพิเศษ<buffer>ไปที่:autocmd!:
augroup my_markdown
    autocmd! CursorHold <buffer>
    autocmd CursorHold <buffer> update
augroup END
โปรดทราบว่าคุณสามารถแทนที่CursorHoldด้วยดาวเพื่อจับคู่เหตุการณ์ใด ๆ ในบรรทัดที่ลบ autocmds:
augroup my_markdown
    autocmd! * <buffer>
    autocmd CursorHold <buffer> update
augroup END
ด้วยวิธีนี้คุณไม่จำเป็นต้องระบุเหตุการณ์ทั้งหมดที่ autocmds ของคุณกำลังฟังอยู่เมื่อคุณต้องการล้าง augroup
หลุมพราง 2
มีข้อผิดพลาดอีกอย่างหนึ่ง แต่คราว<buffer>นี้ไม่ใช่ปัญหามันคือทางออก
เมื่อคุณรวมตัวเลือกโลคัลในปลั๊กอินชนิดไฟล์คุณอาจทำดังนี้:
setlocal option1=value
setlocal option2
สิ่งนี้จะทำงานได้ตามที่คาดไว้สำหรับตัวเลือกบัฟเฟอร์ในเครื่อง แต่ไม่จำเป็นสำหรับตัวเลือกในหน้าต่าง เพื่อแสดงปัญหาคุณสามารถลองการทดสอบต่อไปนี้ สร้างไฟล์~/.vim/after/ftdetect/potion.vimและข้างในเขียน:
autocmd BufNewFile,BufRead *.pn setfiletype potion
ไฟล์นี้จะตั้ง filetype โดยอัตโนมัติpotionสำหรับไฟล์ใด ๆ .pnที่มีนามสกุลเป็น คุณไม่จำเป็นต้องห่อไว้ในกลุ่มเพราะสำหรับไฟล์ประเภทนี้ Vim จะทำมันโดยอัตโนมัติ (ดู:h ftdetect)
หากไม่มีไดเรกทอรีกลางในระบบของคุณคุณสามารถสร้างได้
ถัดไปสร้างปลั๊กอินประเภทไฟล์~/.vim/after/ftplugin/potion.vimและข้างในเขียน:
setlocal list
ตามค่าเริ่มต้นในpotionไฟล์การตั้งค่านี้จะทำให้อักขระแท็บแสดงเป็น^Iและสิ้นสุดบรรทัด$ดังนี้
ตอนนี้สร้างน้อยที่สุดvimrc; ภายใน/tmp/vimrcเขียน:
filetype plugin on
... เพื่อเปิดใช้งานปลั๊กอินประเภทไฟล์
นอกจากนี้ยังสร้างแฟ้มยา, และไฟล์แบบสุ่ม/tmp/pn.pn /tmp/fileในไฟล์ potion เขียนบางสิ่ง:
foo
bar
baz
ในไฟล์สุ่มเขียนพา ธ ไปยังไฟล์ potion /tmp/pn.pn:
/tmp/pn.pn
ตอนนี้เริ่ม Vim ด้วยการเริ่มต้นขั้นต่ำเพียงแค่จัดหาvimrcและเปิดไฟล์ทั้งสองในวิวพอร์ตแนวตั้ง:
$ vim -Nu /tmp/vimrc -O /tmp/pn.pn /tmp/file
คุณควรเห็นวิวพอร์ตแนวตั้ง 2 ตำแหน่ง ไฟล์ potion ทางด้านซ้ายแสดงจุดสิ้นสุดของบรรทัดที่มีเครื่องหมายดอลลาร์ไฟล์สุ่มทางด้านขวาจะไม่แสดงผลเลย
ให้ความสำคัญกับไฟล์แบบสุ่มและกดgfเพื่อแสดงไฟล์ potion ที่มีพา ธ อยู่ใต้เคอร์เซอร์ ตอนนี้คุณเห็นบัฟเฟอร์ potion เดียวกันในวิวพอร์ตด้านขวา แต่ในตอนนี้จุดสิ้นสุดของบรรทัดจะไม่แสดงด้วยเครื่องหมายดอลลาร์ และถ้าคุณพิมพ์:setlocal list?เสียงเรียกเข้าควรตอบด้วยnolist:

ห่วงโซ่ของเหตุการณ์ทั้งหมด:
BufRead event → set 'filetype' option → load filetype plugins
... ไม่ได้เกิดขึ้นเพราะเป็นครั้งแรกของพวกเขาไม่ได้เกิดขึ้นเมื่อคุณกดBufRead gfโหลดบัฟเฟอร์แล้ว
อาจดูเหมือนไม่คาดคิดเพราะเมื่อคุณเพิ่มsetlocal listในปลั๊กอินประเภทไฟล์ potion คุณอาจคิดว่ามันจะเปิดใช้งาน'list'ตัวเลือกในหน้าต่างใด ๆ ที่แสดงบัฟเฟอร์ potion
ปัญหาไม่ได้เฉพาะเจาะจงกับpotionไฟล์ประเภทใหม่นี้ คุณสามารถสัมผัสกับmarkdownไฟล์ได้เช่นกัน
ไม่เฉพาะเจาะจงกับ'list'ตัวเลือกเช่นกัน คุณจะได้พบกับการตั้งค่าหน้าต่างท้องถิ่นอื่น ๆ เช่น'conceallevel', 'foldmethod', 'foldexpr', 'foldtitle'...
ไม่เฉพาะเจาะจงกับgfคำสั่งเช่นกัน คุณสามารถสัมผัสกับมันด้วยคำสั่งอื่น ๆ ซึ่งอาจเปลี่ยนบัฟเฟอร์ที่แสดงในหน้าต่างปัจจุบัน: เครื่องหมายสากลC-o(เลื่อนไปด้านหลังใน jumplist แบบโลคัลหน้าต่าง) :b {buffer_number},, ...
ในการสรุปตัวเลือกในหน้าต่างจะถูกตั้งค่าอย่างถูกต้องถ้าหาก:
- ไฟล์ที่ยังไม่ได้อ่านในช่วง Vim ปัจจุบัน (เพราะBufReadจะต้องถูกไล่ออก)
- ไฟล์กำลังแสดงอยู่ในหน้าต่างที่มีการตั้งค่าตัวเลือกภายในหน้าต่างไว้อย่างถูกต้อง
- หน้าต่างใหม่ถูกสร้างขึ้นด้วยคำสั่งเช่น:split(ในกรณีนี้มันควรสืบทอดตัวเลือกหน้าต่างท้องถิ่นจากหน้าต่างที่คำสั่งถูกดำเนินการ)
มิฉะนั้นการตั้งค่าตัวเลือกในหน้าต่างอาจไม่ถูกต้อง
วิธีการแก้ปัญหาที่เป็นไปได้ที่จะตั้งพวกเขาไม่ได้โดยตรงจากปลั๊กอิน filetype แต่จาก autocmd BufWinEnterติดตั้งในภายหลังซึ่งจะฟัง เหตุการณ์นี้ควรเริ่มทำงานทุกครั้งที่มีการแสดงบัฟเฟอร์ในหน้าต่าง
ตัวอย่างเช่นแทนที่จะเขียนสิ่งนี้:
setlocal list
คุณจะเขียนสิ่งนี้:
augroup my_potion
    au! * <buffer>
    au BufWinEnter <buffer> setlocal list
augroup END
<buffer>และที่นี่คุณจะพบอีกครั้งในรูปแบบพิเศษ

หลุมพราง 3
หากคุณเปลี่ยนประเภทไฟล์ของบัฟเฟอร์ของคุณ autocmds จะยังคงอยู่ หากคุณต้องการลบพวกเขาคุณจะต้องกำหนดค่าb:undo_ftplugin(ดู:h undo_ftplugin) และรวมคำสั่งนี้ไว้ในนั้น:
exe 'au! my_markdown * <buffer>'
อย่างไรก็ตามอย่าพยายามลบกลุ่มตัวเองออกเพราะอาจมีบัฟเฟอร์มาร์กอัปที่มี autocmds อยู่ด้านใน
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 รายการเท่านั้น (คุณอาจพบมากขึ้นหรือน้อยลงฉันใช้ Vim เวอร์ชัน 8.0 พร้อมแพตช์ไม่เกิน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 ซึ่งหมายความว่าทุกครั้งที่คุณโหลดบัฟเฟอร์ที่มี filetype คือ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('.')
ทีนี้โหลดบัฟเฟอร์ใหม่แล้วถามอีกครั้งว่าบัฟเฟอร์อัตโนมัติในพื้นที่สำหรับบัฟเฟอร์ปัจจุบันคืออะไร:
: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 คุณสามารถสร้างปลั๊กอินไวยากรณ์ของคุณเองสำหรับไฟล์โดยใช้ไฟล์dircolors ~/.vim/syntax/dircolors.vimภายในนั้นคุณจะต้องนำเข้าเนื้อหาของปลั๊กอินไวยากรณ์ดั้งเดิม:
$ vim ~/.vim/syntax/dircolors.vim
:r $VIMRUNTIME/syntax/dircolors.vim
จากนั้นในตอนท้ายคุณก็แค่ใส่ค่า autocmds ภายในกลุ่มที่คุณจะเคลียร์ ดังนั้นคุณจะแทนที่บรรทัดเหล่านี้:
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
โปรดทราบว่าถ้าคุณสร้างdircolorsปลั๊กอินไวยากรณ์ของคุณด้วยไฟล์~/.vim/after/syntax/dircolors.vimมันจะไม่ทำงานเพราะปลั๊กอินไวยากรณ์เริ่มต้นจะต้องมีที่มาก่อน โดยการใช้~/.vim/syntax/dircolors.vimปลั๊กอินไวยากรณ์ของคุณจะได้รับก่อนที่จะเริ่มต้นและมันจะตั้งค่าตัวแปรบัฟเฟอร์ท้องถิ่นb:current_syntaxซึ่งจะป้องกันไม่ให้ปลั๊กอินไวยากรณ์เริ่มต้นจากแหล่งที่มาเพราะมันมียามนี้:
if exists("b:current_syntax")
    finish
endif
กฎทั่วไปดูเหมือนว่า: ใช้~/.vim/ftpluginและ~/.vim/syntaxไดเรกทอรีเพื่อสร้างปลั๊กอินประเภทไฟล์ / ไวยากรณ์ที่กำหนดเองและป้องกันปลั๊กอินถัดไป (สำหรับไฟล์ประเภทเดียวกัน) ในพา ธ รันไทม์ที่จะได้รับแหล่งที่มา และการใช้งาน~/.vim/after/ftplugin, ~/.vim/after/syntaxไม่ได้ที่จะป้องกันไม่ให้ปลั๊กอินอื่น ๆ ที่มาจากการถูก แต่เพียงแค่มีคำสุดท้ายเกี่ยวกับคุณค่าของการตั้งค่าบางอย่าง