คุณสามารถใช้maparg()
ฟังก์ชั่น
ในการทดสอบว่าผู้ใช้ทำการแมปบางอย่างเป็น<C-c>
ในโหมดปกติคุณจะต้องเขียน:
if !empty(maparg('<C-c>', 'n'))
หากผู้ใช้แมปบางสิ่งเพื่อเก็บไว้{rhs}
ในตัวแปรคุณจะเขียน:
let rhs_save = maparg('<C-c>', 'n')
หากคุณต้องการข้อมูลเพิ่มเติมเกี่ยวกับการทำแผนที่เช่น:
- มันเงียบ (
<silent>
โต้แย้ง)?
- มันอยู่ในท้องถิ่นเพื่อบัฟเฟอร์ปัจจุบัน (
<buffer>
โต้แย้ง)?
- คือ
{rhs}
การประเมินผลของการแสดงออก (คน<expr>
อาร์กิวเมนต์)?
- มันทำการแมปใหม่
{rhs}
( nnoremap
vs nmap
) หรือไม่
- หากผู้ใช้มีการแมปอื่นที่ขึ้นต้นด้วย
<C-c>
Vim จะรอให้พิมพ์อักขระเพิ่มเติม ( <nowait>
อาร์กิวเมนต์) หรือไม่?
- ...
จากนั้นคุณสามารถให้หนึ่งในสามและอาร์กิวเมนต์ที่สี่: และ0
เพราะคุณกำลังมองหาการทำแผนที่ไม่ใช่ตัวย่อและเพราะคุณต้องการพจนานุกรมที่มีข้อมูลสูงสุดไม่ใช่ค่า:1
0
1
{rhs}
let map_save = maparg('<C-c>', 'n', 0, 1)
สมมติว่าผู้ใช้ไม่ได้ใช้อาร์กิวเมนต์พิเศษใด ๆ ในการทำแผนที่ของเขาและมันไม่ได้ทำการแมป{rhs}
ใหม่เพื่อเรียกคืนคุณสามารถเขียน:
let rhs_save = maparg('<C-c>', 'n')
" do some stuff which changes the mapping
exe 'nnoremap <C-c> ' . rhs_save
หรือเพื่อให้แน่ใจและคืนค่าอาร์กิวเมนต์ที่เป็นไปได้ทั้งหมด:
let map_save = maparg('<C-c>', 'n', 0, 1)
" do some stuff which changes the mapping
exe (map_save.noremap ? 'nnoremap' : 'nmap') .
\ (map_save.buffer ? ' <buffer> ' : '') .
\ (map_save.expr ? ' <expr> ' : '') .
\ (map_save.nowait ? ' <nowait> ' : '') .
\ (map_save.silent ? ' <silent> ' : '') .
\ ' <C-c> ' .
\ map_save.rhs
แก้ไข: ขออภัยฉันเพิ่งรู้ว่ามันจะไม่ทำงานอย่างที่คาดไว้หากผู้ใช้เรียกใช้ฟังก์ชันสคริปต์ท้องถิ่นใน{rhs}
การทำแผนที่
สมมติว่าผู้ใช้มีการแมปต่อไปนี้ภายในvimrc
:
nnoremap <C-c> :<C-U>call <SID>FuncA()<CR>
function! s:FuncA()
echo 'hello world!'
endfunction
เมื่อเขาพบมันแสดงข้อความ<C-c>
hello world!
และในปลั๊กอินของคุณคุณบันทึกพจนานุกรมด้วยข้อมูลทั้งหมดจากนั้นเปลี่ยนการแมปของเขาเช่นนี้ชั่วคราว:
let map_save = maparg('<C-c>', 'n', 0, 1)
nnoremap <C-c> :<C-U>call <SID>FuncB()<CR>
function! s:FuncB()
echo 'bye all!'
endfunction
bye all!
ตอนนี้ก็จะแสดง ปลั๊กอินของคุณทำงานได้บางอย่างและเมื่อเสร็จสิ้นปลั๊กอินจะพยายามกู้คืนการแมปด้วยคำสั่งก่อนหน้า
มันอาจจะล้มเหลวด้วยข้อความที่มีลักษณะเช่นนี้:
E117: Unknown function: <SNR>61_FuncA
61
เป็นเพียงตัวระบุของสคริปต์ที่คำสั่งการจับคู่ของคุณจะถูกดำเนินการ อาจเป็นตัวเลขอื่นใดก็ได้ หากปลั๊กอินของคุณเป็นไฟล์ 42th 42
มาในระบบของผู้ใช้ก็จะเป็น
ภายในสคริปต์เมื่อคำสั่งการแมปถูกเรียกใช้งาน Vim จะแปลสัญลักษณ์<SID>
เป็นรหัสคีย์พิเศษโดยอัตโนมัติ<SNR>
ตามด้วยหมายเลขที่ไม่ซ้ำกันสำหรับสคริปต์และเครื่องหมายขีดล่าง จะต้องทำเช่นนี้เพราะเมื่อผู้ใช้จะเข้าชม<C-c>
การทำแผนที่จะดำเนินการนอกสคริปต์และดังนั้นจึงไม่ทราบว่าFuncA()
มีการกำหนดสคริปต์
ปัญหาคือว่าการแมปดั้งเดิมนั้นมีที่มาในสคริปต์ที่แตกต่างจากปลั๊กอินของคุณดังนั้นที่นี่การแปลอัตโนมัติผิด vimrc
จะใช้ตัวบ่งชี้ของสคริปต์ของคุณในขณะที่มันควรจะใช้ตัวบ่งชี้ของของผู้ใช้
แต่คุณสามารถทำการแปลด้วยตนเองได้ พจนานุกรมmap_save
มีรหัสที่เรียกว่า'sid'
มีค่าเป็นตัวระบุที่ถูกต้อง
ดังนั้นเพื่อให้คำสั่งการฟื้นฟูก่อนหน้านี้มีความสมบูรณ์มากขึ้นคุณสามารถแทนที่map_save.rhs
ด้วย:
substitute(map_save.rhs, '<SID>', '<SNR>' . map_save.sid . '_', 'g')
หากมี{rhs}
การแมปดั้งเดิมอยู่<SID>
ควรมีการแปลอย่างถูกต้อง มิฉะนั้นจะไม่มีอะไรเปลี่ยนแปลง
และถ้าคุณต้องการย่อโค้ดให้น้อยลงคุณสามารถแทนที่ 4 บรรทัดที่ดูแลอาร์กิวเมนต์พิเศษด้วย:
join(map(['buffer', 'expr', 'nowait', 'silent'], 'map_save[v:val] ? "<" . v:val . ">": ""'))
map()
ฟังก์ชั่นควรแปลงแต่ละรายการจากรายการ['buffer', 'expr', 'nowait', 'silent']
ลงในการโต้แย้งการทำแผนที่สอดคล้องกัน แต่ถ้าภายในที่สำคัญmap_save
เป็นที่ไม่ใช่ศูนย์ และjoin()
ควรเข้าร่วมรายการทั้งหมดเป็นสตริง
ดังนั้นวิธีที่ประหยัดกว่าในการบันทึกและกู้คืนการแมปอาจเป็นไปได้:
let map_save = maparg('<C-c>', 'n', 0, 1)
" do some stuff which changes the mapping
exe (map_save.noremap ? 'nnoremap' : 'nmap') .
\ join(map(['buffer', 'expr', 'nowait', 'silent'], 'map_save[v:val] ? "<" . v:val . ">": ""')) .
\ map_save.lhs . ' ' .
\ substitute(map_save.rhs, '<SID>', '<SNR>' . map_save.sid . '_', 'g')
Edit2:
ฉันกำลังเผชิญปัญหาเดียวกันกับคุณวิธีการบันทึกและคืนค่าการแมปในปลั๊กอินรูปวาด และฉันคิดว่าฉันพบ 2 ประเด็นที่คำตอบเริ่มต้นไม่เห็นในขณะที่ฉันเขียนขออภัยเกี่ยวกับเรื่องนั้น
ปัญหาแรกสมมติว่าผู้ใช้ใช้<C-c>
ในการแมปส่วนกลาง แต่ยังอยู่ในการแมปบัฟเฟอร์ภายใน ตัวอย่าง:
nnoremap <C-c> :echo 'global mapping'<CR>
nnoremap <buffer> <C-c> :echo 'local mapping'<CR>
ในกรณีนี้maparg()
จะให้ความสำคัญกับการแมปท้องถิ่น:
:echo maparg('<C-c>', 'n', 0, 1)
---> {'silent': 0, 'noremap': 1, 'lhs': '<C-C>', 'mode': 'n', 'nowait': 0, 'expr': 0, 'sid': 7, 'rhs': ':echo ''local mapping''<CR>', 'buffer': 1}
ซึ่งได้รับการยืนยันใน:h maparg()
:
The mappings local to the current buffer are checked first,
then the global mappings.
แต่บางทีคุณไม่ได้สนใจในการแมปบัฟเฟอร์ในตัวเครื่องบางทีคุณอาจต้องการแผนที่โลก
วิธีเดียวที่ฉันค้นพบได้รับข้อมูลเกี่ยวกับการแมปสากลอย่างน่าเชื่อถือคือการพยายามยกเลิกการแมปการแมปที่อาจเกิดขึ้นแบบเงาและบัฟเฟอร์ชั่วคราวโดยใช้คีย์เดียวกัน
สามารถทำได้ 4 ขั้นตอน:
- บันทึกการแมปบัฟเฟอร์ในพื้นที่โดยใช้คีย์
<C-c>
- ดำเนินการ
:silent! nunmap <buffer> <C-c>
เพื่อลบการแมปท้องถิ่น (ที่มีศักยภาพ)
- บันทึกการทำแผนที่โลก (
maparg('<C-c>', 'n', 0, 1)
)
- คืนค่าการแมปบัฟเฟอร์ท้องถิ่น
ปัญหาที่สองคือต่อไปนี้ สมมติว่าผู้ใช้ไม่ได้จับคู่สิ่งใดกับ<C-c>
ผลลัพธ์ของผลลัพธ์maparg()
จะเป็นพจนานุกรมว่างเปล่า และในกรณีนี้กระบวนการฟื้นฟูไม่ได้รวมอยู่ในการติดตั้งการแมป ( :nnoremap
) แต่ในการทำลายการทำแผนที่ ( :nunmap
)
ในการพยายามแก้ไขปัญหาใหม่ 2 ประเด็นนี้คุณสามารถลองใช้ฟังก์ชันนี้เพื่อบันทึกการแมป:
fu! Save_mappings(keys, mode, global) abort
let mappings = {}
if a:global
for l:key in a:keys
let buf_local_map = maparg(l:key, a:mode, 0, 1)
sil! exe a:mode.'unmap <buffer> '.l:key
let map_info = maparg(l:key, a:mode, 0, 1)
let mappings[l:key] = !empty(map_info)
\ ? map_info
\ : {
\ 'unmapped' : 1,
\ 'buffer' : 0,
\ 'lhs' : l:key,
\ 'mode' : a:mode,
\ }
call Restore_mappings({l:key : buf_local_map})
endfor
else
for l:key in a:keys
let map_info = maparg(l:key, a:mode, 0, 1)
let mappings[l:key] = !empty(map_info)
\ ? map_info
\ : {
\ 'unmapped' : 1,
\ 'buffer' : 1,
\ 'lhs' : l:key,
\ 'mode' : a:mode,
\ }
endfor
endif
return mappings
endfu
... และอันนี้เพื่อกู้คืน:
fu! Restore_mappings(mappings) abort
for mapping in values(a:mappings)
if !has_key(mapping, 'unmapped') && !empty(mapping)
exe mapping.mode
\ . (mapping.noremap ? 'noremap ' : 'map ')
\ . (mapping.buffer ? ' <buffer> ' : '')
\ . (mapping.expr ? ' <expr> ' : '')
\ . (mapping.nowait ? ' <nowait> ' : '')
\ . (mapping.silent ? ' <silent> ' : '')
\ . mapping.lhs
\ . ' '
\ . substitute(mapping.rhs, '<SID>', '<SNR>'.mapping.sid.'_', 'g')
elseif has_key(mapping, 'unmapped')
sil! exe mapping.mode.'unmap '
\ .(mapping.buffer ? ' <buffer> ' : '')
\ . mapping.lhs
endif
endfor
endfu
Save_mappings()
ฟังก์ชั่นสามารถใช้ในการบันทึกการแมป
คาดว่าจะมี 3 ข้อโต้แย้ง:
- รายการของกุญแจ; ตัวอย่าง:
['<C-a>', '<C-b>', '<C-c>']
- โหมด; ตัวอย่าง:
n
สำหรับโหมดปกติหรือx
โหมดภาพ
- ธงบูลีน; ถ้าเป็น
1
เช่นนั้นแสดงว่าคุณสนใจการทำแผนที่ทั่วโลกและในกรณีที่เป็น0
ท้องถิ่น
ด้วยคุณสามารถบันทึกการแมปทั่วโลกโดยใช้แป้นC-a
, C-b
และC-c
ในโหมดปกติภายในพจนานุกรม:
let your_saved_mappings = Save_mappings(['<C-a>', '<C-b>', '<C-c>'], 'n', 1)
จากนั้นในภายหลังเมื่อคุณต้องการคืนค่าการจับคู่คุณสามารถโทรRestore_mappings()
ผ่านพจนานุกรมที่มีข้อมูลทั้งหมดเป็นอาร์กิวเมนต์:
call Restore_mappings(your_saved_mappings)
อาจมีปัญหาที่ 3 เมื่อบันทึก / เรียกคืนการแมปบัฟเฟอร์ภายในเครื่อง เนื่องจากระหว่างช่วงเวลาที่เราบันทึกการแมปและช่วงเวลาที่เราพยายามกู้คืนบัฟเฟอร์ปัจจุบันอาจเปลี่ยนไป
ในกรณีนี้อาจปรับปรุงSave_mappings()
ฟังก์ชันได้โดยบันทึกจำนวนบัฟเฟอร์ปัจจุบัน ( bufnr('%')
)
จากนั้นRestore_mappings()
จะใช้ข้อมูลนี้เพื่อกู้คืนการแม็พบัฟเฟอร์ในบัฟเฟอร์ที่ถูกต้อง เราอาจใช้:bufdo
คำสั่งนำหน้าหลังด้วยการนับ (จับคู่หมายเลขบัฟเฟอร์ที่บันทึกไว้ก่อนหน้านี้) และต่อท้ายด้วยคำสั่งการจับคู่
อาจจะชอบ:
:{original buffer number}bufdo {mapping command}
เราจะต้องตรวจสอบก่อนว่าบัฟเฟอร์ยังคงมีอยู่โดยใช้bufexists()
ฟังก์ชั่นเพราะมันอาจถูกลบในเวลาเดียวกัน