Bạn có thể sử dụng maparg()
chức năng.
Để kiểm tra xem người dùng có ánh xạ thứ gì đó sang <C-c>
chế độ bình thường không, bạn sẽ viết:
if !empty(maparg('<C-c>', 'n'))
Nếu người dùng ánh xạ một cái gì đó, để lưu trữ {rhs}
trong một biến, bạn sẽ viết:
let rhs_save = maparg('<C-c>', 'n')
Nếu bạn muốn biết thêm thông tin về ánh xạ, như:
- Là im lặng (
<silent>
tranh luận)?
- nó là cục bộ của bộ đệm hiện tại (
<buffer>
đối số)?
- là sự
{rhs}
đánh giá của một biểu thức ( <expr>
đối số)?
- nó ánh xạ lại
{rhs}
( nnoremap
vs nmap
)?
- Nếu người dùng có một ánh xạ khác bắt đầu bằng
<C-c>
, Vim có chờ thêm ký tự để nhập ( <nowait>
đối số) không?
- ...
Sau đó, bạn có thể đưa ra một đối số thứ ba và thứ tư: 0
và 1
.
0
bởi vì bạn đang tìm kiếm một ánh xạ chứ không phải viết tắt và 1
vì bạn muốn một từ điển có tối đa thông tin và không chỉ {rhs}
giá trị:
let map_save = maparg('<C-c>', 'n', 0, 1)
Giả sử người dùng không sử dụng bất kỳ đối số đặc biệt nào trong ánh xạ của mình và rằng nó không ánh xạ lại {rhs}
, để khôi phục nó, bạn chỉ cần viết:
let rhs_save = maparg('<C-c>', 'n')
" do some stuff which changes the mapping
exe 'nnoremap <C-c> ' . rhs_save
Hoặc để chắc chắn và khôi phục tất cả các đối số có thể:
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
Chỉnh sửa: Xin lỗi, tôi vừa nhận ra rằng nó sẽ không hoạt động như mong đợi nếu người dùng gọi một hàm script-local trong {rhs}
ánh xạ.
Giả sử rằng người dùng có ánh xạ sau bên trong vimrc
:
nnoremap <C-c> :<C-U>call <SID>FuncA()<CR>
function! s:FuncA()
echo 'hello world!'
endfunction
Khi anh ta nhấn <C-c>
, nó sẽ hiển thị thông báo hello world!
.
Và trong plugin của bạn, bạn lưu một từ điển với tất cả thông tin, sau đó tạm thời thay đổi ánh xạ của mình như thế này:
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
Bây giờ, nó sẽ hiển thị bye all!
. Plugin của bạn thực hiện một số công việc và khi nó kết thúc, nó sẽ cố gắng khôi phục ánh xạ bằng lệnh trước đó.
Nó có thể sẽ thất bại với một tin nhắn trông như thế này:
E117: Unknown function: <SNR>61_FuncA
61
chỉ là định danh của tập lệnh trong đó lệnh ánh xạ của bạn sẽ được thực thi. Nó có thể là bất kỳ số nào khác. Nếu plugin của bạn là tệp thứ 42 có nguồn gốc trên hệ thống của người dùng, thì nó sẽ như vậy 42
.
Bên trong một tập lệnh, khi một lệnh ánh xạ được thực thi, Vim sẽ tự động dịch ký hiệu <SID>
thành mã khóa đặc biệt <SNR>
, theo sau là một số duy nhất cho tập lệnh và dấu gạch dưới. Nó phải làm điều này, bởi vì khi người dùng nhấn <C-c>
, ánh xạ sẽ được thực thi bên ngoài tập lệnh và do đó nó sẽ không biết tập lệnh nào FuncA()
được xác định.
Vấn đề là ánh xạ ban đầu có nguồn gốc từ một tập lệnh khác với plugin của bạn, vì vậy ở đây bản dịch tự động bị sai. Nó sử dụng định danh tập lệnh của bạn, trong khi nó nên sử dụng định danh của người dùng vimrc
.
Nhưng bạn có thể làm bản dịch thủ công. Từ điển map_save
chứa một khóa được gọi là 'sid'
có giá trị là định danh chính xác.
Vì vậy, để làm cho lệnh khôi phục trước đó mạnh mẽ hơn, bạn có thể thay thế map_save.rhs
bằng:
substitute(map_save.rhs, '<SID>', '<SNR>' . map_save.sid . '_', 'g')
Nếu {rhs}
ánh xạ gốc chứa <SID>
, nó cần được dịch đúng. Nếu không, không có gì phải thay đổi.
Và nếu bạn muốn rút ngắn mã một chút, bạn có thể thay thế 4 dòng chăm sóc các đối số đặc biệt bằng:
join(map(['buffer', 'expr', 'nowait', 'silent'], 'map_save[v:val] ? "<" . v:val . ">": ""'))
Các map()
chức năng nên chuyển đổi mỗi mục từ danh sách ['buffer', 'expr', 'nowait', 'silent']
vào lập luận bản đồ tương ứng nhưng chỉ khi bên chủ chốt của nó map_save
không phải là zero. Và join()
nên tham gia tất cả các mục vào một chuỗi.
Vì vậy, một cách mạnh mẽ hơn để lưu và khôi phục ánh xạ có thể là:
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')
Chỉnh sửa2:
Tôi đang đối mặt với cùng một vấn đề như bạn, cách lưu và khôi phục ánh xạ trong plugin vẽ. Và tôi nghĩ rằng tôi đã tìm thấy 2 vấn đề mà câu trả lời ban đầu không thấy vào lúc tôi viết nó, xin lỗi về điều đó.
Vấn đề đầu tiên, giả sử rằng người dùng sử dụng <C-c>
trong ánh xạ toàn cục mà còn trong ánh xạ cục bộ đệm. Thí dụ:
nnoremap <C-c> :echo 'global mapping'<CR>
nnoremap <buffer> <C-c> :echo 'local mapping'<CR>
Trong trường hợp này, maparg()
sẽ ưu tiên ánh xạ cục bộ:
: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}
Điều này được xác nhận trong :h maparg()
:
The mappings local to the current buffer are checked first,
then the global mappings.
Nhưng có thể bạn không quan tâm đến ánh xạ cục bộ đệm, có thể bạn muốn bản đồ toàn cầu.
Cách duy nhất mà tôi tìm thấy, đáng tin cậy, có được thông tin về ánh xạ toàn cầu, là cố gắng tạm thời hủy ánh xạ tiềm năng, tạo bóng, ánh xạ bộ đệm cục bộ bằng cách sử dụng cùng một khóa.
Nó có thể được thực hiện trong 4 bước:
- lưu một ánh xạ cục bộ (tiềm năng) bằng cách sử dụng khóa
<C-c>
- thực hiện
:silent! nunmap <buffer> <C-c>
để xóa ánh xạ cục bộ đệm (tiềm năng)
- lưu bản đồ toàn cầu (
maparg('<C-c>', 'n', 0, 1)
)
- khôi phục ánh xạ cục bộ
Vấn đề thứ hai là như sau. Giả sử rằng người dùng không ánh xạ bất cứ thứ gì vào <C-c>
thì đầu ra của maparg()
sẽ là một từ điển trống. Và trong trường hợp này, quá trình khôi phục không bao gồm việc cài đặt ánh xạ ( :nnoremap
), mà là phá hủy ánh xạ ( :nunmap
).
Để cố gắng giải quyết 2 vấn đề mới này, bạn có thể thử chức năng này để lưu ánh xạ:
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
... Và cái này để khôi phục chúng:
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
Các Save_mappings()
chức năng có thể được sử dụng để lưu ánh xạ.
Nó mong đợi 3 đối số:
- một danh sách các khóa; thí dụ:
['<C-a>', '<C-b>', '<C-c>']
- Một chế độ; ví dụ:
n
cho chế độ bình thường hoặc x
cho chế độ trực quan
- một lá cờ boolean; nếu có
1
, điều đó có nghĩa là bạn quan tâm đến ánh xạ toàn cầu và nếu nó 0
, ở địa phương
Với nó, bạn có thể tiết kiệm ánh xạ toàn cầu sử dụng các phím C-a
, C-b
và C-c
, trong chế độ bình thường, bên trong một cuốn từ điển:
let your_saved_mappings = Save_mappings(['<C-a>', '<C-b>', '<C-c>'], 'n', 1)
Sau đó, sau này, khi bạn muốn khôi phục ánh xạ, bạn có thể gọi Restore_mappings()
, chuyển từ điển chứa tất cả thông tin dưới dạng đối số:
call Restore_mappings(your_saved_mappings)
Có thể có vấn đề thứ 3, khi lưu / khôi phục ánh xạ bộ đệm cục bộ. Bởi vì, giữa thời điểm chúng ta lưu bản đồ và thời điểm chúng ta cố gắng khôi phục chúng, bộ đệm hiện tại có thể đã thay đổi.
Trong trường hợp này, có thể Save_mappings()
chức năng có thể được cải thiện bằng cách lưu số lượng bộ đệm hiện tại ( bufnr('%')
).
Và sau đó, Restore_mappings()
sẽ sử dụng thông tin này để khôi phục ánh xạ bộ đệm cục bộ trong bộ đệm bên phải. Có lẽ chúng ta có thể sử dụng :bufdo
lệnh, tiền tố sau với số đếm (khớp với số bộ đệm đã lưu trước đó) và hậu tố nó với lệnh ánh xạ.
Có lẽ một cái gì đó như:
:{original buffer number}bufdo {mapping command}
Chúng ta sẽ phải kiểm tra trước nếu bộ đệm vẫn còn tồn tại, sử dụng bufexists()
hàm, bởi vì nó có thể đã bị xóa trong thời gian đó.