Anda bisa menggunakan maparg()
fungsinya.
Untuk menguji apakah pengguna memetakan sesuatu ke <C-c>
dalam mode normal, Anda akan menulis:
if !empty(maparg('<C-c>', 'n'))
Jika pengguna memetakan sesuatu, untuk menyimpan {rhs}
dalam variabel, Anda akan menulis:
let rhs_save = maparg('<C-c>', 'n')
Jika Anda ingin informasi lebih lanjut tentang pemetaan, seperti:
- apakah itu diam (
<silent>
argumen)?
- apakah ini bersifat lokal untuk buffer (
<buffer>
argumen) saat ini?
- adalah
{rhs}
evaluasi ekspresi ( <expr>
argumen)?
- apakah itu memetakan kembali
{rhs}
( nnoremap
vs nmap
)?
- jika pengguna memiliki pemetaan lain yang dimulai dengan
<C-c>
, apakah Vim menunggu lebih banyak karakter untuk diketik ( <nowait>
argumen)?
- ...
Lalu, Anda bisa memberikan argumen ketiga dan keempat: 0
dan 1
.
0
karena Anda mencari pemetaan dan bukan singkatan, dan 1
karena Anda menginginkan kamus dengan informasi maksimal dan bukan hanya {rhs}
nilainya:
let map_save = maparg('<C-c>', 'n', 0, 1)
Dengan asumsi pengguna tidak menggunakan argumen khusus dalam pemetaannya, dan itu tidak memetakan kembali {rhs}
, untuk mengembalikannya, Anda cukup menulis:
let rhs_save = maparg('<C-c>', 'n')
" do some stuff which changes the mapping
exe 'nnoremap <C-c> ' . rhs_save
Atau untuk memastikan dan mengembalikan semua argumen yang mungkin:
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
Sunting: Maaf, saya baru menyadari itu tidak akan berfungsi seperti yang diharapkan jika pengguna memanggil fungsi skrip-lokal di {rhs}
pemetaan.
Misalkan pengguna memiliki pemetaan berikut di dalam miliknya vimrc
:
nnoremap <C-c> :<C-U>call <SID>FuncA()<CR>
function! s:FuncA()
echo 'hello world!'
endfunction
Ketika dia memukul <C-c>
, itu menampilkan pesan hello world!
.
Dan di plugin Anda, Anda menyimpan kamus dengan semua informasi, lalu untuk sementara mengubah pemetaannya seperti ini:
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
Sekarang, itu akan ditampilkan bye all!
. Plugin Anda berfungsi, dan ketika selesai, ia mencoba mengembalikan pemetaan dengan perintah sebelumnya.
Mungkin akan gagal dengan pesan yang tampak seperti ini:
E117: Unknown function: <SNR>61_FuncA
61
hanyalah pengidentifikasi dari skrip di mana perintah pemetaan Anda akan dieksekusi. Bisa jadi nomor lainnya. Jika plugin Anda adalah file ke-42 yang bersumber pada sistem pengguna, itu akan menjadi 42
.
Di dalam skrip, ketika perintah pemetaan dijalankan, Vim secara otomatis menerjemahkan notasi <SID>
ke kode kunci khusus <SNR>
, diikuti oleh angka yang unik untuk skrip, dan garis bawah. Itu harus melakukan ini, karena ketika pengguna akan menekan <C-c>
, pemetaan akan dieksekusi di luar skrip, dan dengan demikian ia tidak akan tahu di mana skrip FuncA()
didefinisikan.
Masalahnya adalah pemetaan asli bersumber dalam skrip yang berbeda dari plugin Anda, jadi di sini terjemahan otomatisnya salah. Ini menggunakan pengidentifikasi skrip Anda, sementara itu harus menggunakan pengidentifikasi pengguna vimrc
.
Tetapi Anda bisa melakukan terjemahan secara manual. Kamus map_save
berisi kunci yang disebut 'sid'
nilainya sebagai pengidentifikasi yang benar.
Jadi, untuk membuat perintah restorasi sebelumnya lebih kuat, Anda bisa menggantinya map_save.rhs
dengan:
substitute(map_save.rhs, '<SID>', '<SNR>' . map_save.sid . '_', 'g')
Jika {rhs}
pemetaan asli berisi <SID>
, itu harus diterjemahkan dengan benar. Kalau tidak, tidak ada yang harus diubah.
Dan jika Anda ingin mempersingkat kodenya sedikit, Anda bisa mengganti 4 baris yang menangani argumen khusus dengan:
join(map(['buffer', 'expr', 'nowait', 'silent'], 'map_save[v:val] ? "<" . v:val . ">": ""'))
The map()
Fungsi harus mengkonversi setiap item dari daftar ['buffer', 'expr', 'nowait', 'silent']
ke argumen pemetaan yang sesuai tetapi hanya jika dalam kuncinya map_save
adalah non-nol. Dan join()
harus menggabungkan semua item menjadi string.
Jadi, cara yang lebih kuat untuk menyimpan dan memulihkan pemetaan bisa menjadi:
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')
Sunting2:
Saya menghadapi masalah yang sama seperti Anda, bagaimana cara menyimpan dan mengembalikan pemetaan dalam plugin menggambar. Dan saya pikir saya menemukan 2 masalah yang tidak dilihat oleh jawaban awal pada saat saya menulisnya, maaf soal itu.
Masalah pertama, anggaplah bahwa pengguna menggunakan <C-c>
pemetaan global tetapi juga dalam pemetaan buffer-lokal. Contoh:
nnoremap <C-c> :echo 'global mapping'<CR>
nnoremap <buffer> <C-c> :echo 'local mapping'<CR>
Dalam hal ini, maparg()
akan memberikan prioritas pada pemetaan lokal:
: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}
Yang dikonfirmasi di :h maparg()
:
The mappings local to the current buffer are checked first,
then the global mappings.
Tapi mungkin Anda tidak tertarik pada pemetaan buffer-lokal, mungkin Anda ingin yang global.
Satu-satunya cara yang saya temukan untuk, secara andal, mendapatkan informasi tentang pemetaan global, adalah mencoba untuk sementara waktu memetakan pemetaan potensi, bayangan, buffer-lokal menggunakan kunci yang sama.
Itu bisa dilakukan dalam 4 langkah:
- menyimpan (potensi) pemetaan buffer-lokal menggunakan kunci
<C-c>
- mengeksekusi
:silent! nunmap <buffer> <C-c>
untuk menghapus (potensi) pemetaan buffer-lokal
- simpan pemetaan global (
maparg('<C-c>', 'n', 0, 1)
)
- pulihkan pemetaan buffer-local
Masalah kedua adalah sebagai berikut. Misalkan pengguna tidak memetakan apa pun untuk <C-c>
, maka output dari maparg()
akan menjadi kamus kosong. Dan dalam hal ini, proses restorasi tidak terdiri dari pemasangan pemetaan ( :nnoremap
), tetapi dalam penghancuran pemetaan ( :nunmap
).
Untuk mencoba menyelesaikan 2 masalah baru ini, Anda dapat mencoba fungsi ini untuk menyimpan pemetaan:
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
... dan yang ini untuk mengembalikannya:
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
The Save_mappings()
Fungsi dapat digunakan untuk menyimpan pemetaan.
Ia mengharapkan 3 argumen:
- daftar kunci; contoh:
['<C-a>', '<C-b>', '<C-c>']
- sebuah mode; contoh:
n
untuk mode normal atau x
untuk mode visual
- sebuah bendera boolean; jika itu
1
, itu berarti Anda tertarik pada pemetaan global, dan jika itu 0
, dalam pemetaan lokal
Dengannya, Anda bisa menyimpan pemetaan global menggunakan tombol C-a
, C-b
dan C-c
, dalam mode normal, di dalam kamus:
let your_saved_mappings = Save_mappings(['<C-a>', '<C-b>', '<C-c>'], 'n', 1)
Kemudian, nanti, ketika Anda ingin mengembalikan pemetaan, Anda bisa menelepon Restore_mappings()
, melewati kamus berisi semua info sebagai argumen:
call Restore_mappings(your_saved_mappings)
Mungkin ada masalah ke-3, saat menyimpan / mengembalikan pemetaan penyangga-lokal. Karena, antara saat ketika kami menyimpan pemetaan, dan saat ketika kami mencoba mengembalikannya, buffer saat ini mungkin telah berubah.
Dalam hal ini, mungkin Save_mappings()
fungsinya dapat ditingkatkan dengan menyimpan jumlah buffer saat ini ( bufnr('%')
).
Dan kemudian, Restore_mappings()
akan menggunakan info ini untuk mengembalikan pemetaan buffer-lokal di buffer yang tepat. Kita mungkin bisa menggunakan :bufdo
perintah, awali yang terakhir dengan hitungan (cocok dengan nomor buffer yang disimpan sebelumnya), dan sufikskan dengan perintah pemetaan.
Mungkin sesuatu seperti:
:{original buffer number}bufdo {mapping command}
Kami harus memeriksa dulu apakah buffer masih ada, menggunakan bufexists()
fungsi, karena itu bisa saja dihapus sementara itu.