কীভাবে ম্যাপিং সংরক্ষণ এবং পুনরুদ্ধার করবেন?


12

আমি ভিমের জন্য একটি প্লাগইন বিকাশ করছি এবং আমি একটি ম্যাপিং সংজ্ঞায়িত করতে চাই যা কেবলমাত্র "প্লাগইনটির সম্পাদন" এর সময় পাওয়া যাবে।

এখনও পর্যন্ত প্লাগিনটির (সরলীকৃত) ওয়ার্কফ্লো নিম্নরূপ:

  1. ব্যবহারকারী প্লাগইনটির একটি কমান্ড কল করে
  2. কমান্ড প্রাক চিকিত্সা ফাংশন কল:

    function! s:PreTreatmentFunction(function, ...)
        " Do some pretreatment stuff
    
        " Create a mapping to call the TearDown
        nnoremap <C-c> :call TeardDown()<CR>
    
        " Call a function depending on the parameter passed to this one
        if function == "foo"
            call Foo()
        else
            call Bar()
        endif
    endfunction
    
  3. আরেকটি ফাংশন বলা হয় যা বাফারের অবস্থা পরিবর্তন করে ( Foo()বা Bar()পূর্ববর্তী ফাংশনের শেষ লাইনে)

  4. টিয়ারডাউন ফাংশনটি কল করতে ব্যবহারকারী ম্যাপিংটি ব্যবহার করে
  5. টিয়ার ডাউন ফাংশন তৈরি ম্যাপিংটি সরিয়ে দেয়:

    function! s:TearDown()
        " Do some tear down stuff
    
        " Remove the mapping
        unmap <C-c>
    endfunction
    

আমি আমার ম্যাপিং যেভাবে পরিচালনা করি তাতে আমি সন্তুষ্ট নই: যদি ব্যবহারকারী ইতিমধ্যে অন্য কোনও কিছুতে ম্যাপ করে তবে সে তার আসল ম্যাপিংটি looseিলা করবে।

সুতরাং আমার প্রশ্নটি: আমি কীভাবে <C-c>ম্যাপ করা আছে তা সংরক্ষণ করতে পারি (এটি ম্যাপ করা থাকলে) এবং টিয়ার ডাউন ফাংশনে এটি পুনরুদ্ধার করতে পারি? এটি করার জন্য কি কোনও অন্তর্নির্মিত বৈশিষ্ট্য রয়েছে? আমি grepফলাফলের ফলাফল সম্পর্কে যদিও :nmap <C-c>তবে এটি "পরিষ্কার" মনে হচ্ছে না।

কয়েকটি পক্ষের নোট:

  • আমি জানি যে শিখুনভিমস্ক্রিপ্টহার্ডওয়ের একটি বিভাগ আছে তবে তারা এখানে একটি ফ্যাটপ্লাগিন ব্যবহার করতে বলে যা এখানে সম্ভব নয়: প্লাগইন কোনও ফাইলের ধরণের উপর নির্ভর করে না
  • ব্যবহারকারী কী কী ব্যবহার করবেন তা বেছে নিতে আমি একটি পরিবর্তনশীল তৈরি করতে পারতাম: সম্ভবত আমি কী করব তবে আমি কীভাবে সংরক্ষণ এবং পুনরুদ্ধার করব সে সম্পর্কে প্রধানত আগ্রহী।
  • আমি একজন স্থানীয় নেতা ব্যবহার করতে পারি তবে আমি মনে করি এটি কিছুটা ওভারকিল এবং আমি এখনও সংরক্ষণ এবং পুনরুদ্ধার জিনিসটি সম্পর্কে মূলত আগ্রহী।

উত্তর:


24

আপনি maparg()ফাংশন ব্যবহার করতে পারে।

ব্যবহারকারী <C-c>সাধারণ মোডে কিছু ম্যাপ করেছেন কিনা তা পরীক্ষা করতে আপনি লিখবেন:

if !empty(maparg('<C-c>', 'n'))

{rhs}ভেরিয়েবলটিতে স্টোর সংরক্ষণ করতে যদি ব্যবহারকারী কোনও কিছু ম্যাপ করেন তবে আপনি লিখবেন:

let rhs_save = maparg('<C-c>', 'n')

আপনি যদি ম্যাপিং সম্পর্কিত আরও তথ্য চান তবে:

  • এটা কি নীরব ( <silent>যুক্তি)?
  • এটি কি বর্তমান বাফারের ( <buffer>যুক্তি) স্থানীয় ?
  • হয় {rhs}একটি অভিব্যক্তি (মূল্যায়ন <expr>যুক্তি)?
  • এটি {rhs}( nnoremapবনাম nmap) পুনর্নির্মাণ না ?
  • যদি ব্যবহারকারীটির সাথে আর একটি ম্যাপিং থাকে যা দিয়ে শুরু হয় <C-c>, তবে কি ভিম আরও অক্ষর টাইপ হওয়ার জন্য অপেক্ষা করবেন ( <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 ব্যবহারকারীর সিস্টেমে sourced ফাইল হয়, তাহলে এটি হতে হবে 42

একটি স্ক্রিপ্টের অভ্যন্তরে, যখন কোনও ম্যাপিং কমান্ড কার্যকর করা হয়, তখন ভিম স্বয়ংক্রিয়ভাবে স্বরলিপিটি <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 টি সমস্যা পেয়েছি যা প্রাথমিক উত্তরটি আমি লেখার সময় দেখিনি, সে সম্পর্কে দুঃখিত sorry

প্রথম ইস্যু, ধরুন যে ব্যবহারকারী <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 টি ধাপে করা যেতে পারে:

  1. কীটি ব্যবহার করে একটি (সম্ভাব্য) বাফার-লোকাল ম্যাপিং সংরক্ষণ করুন <C-c>
  2. :silent! nunmap <buffer> <C-c>একটি (সম্ভাব্য) বাফার-লোকাল ম্যাপিং মুছতে এক্সিকিউট করুন
  3. গ্লোবাল ম্যাপিং সংরক্ষণ করুন ( maparg('<C-c>', 'n', 0, 1))
  4. বাফার-লোকাল ম্যাপিং পুনরুদ্ধার করুন

দ্বিতীয় সংখ্যাটি নিম্নরূপ। মনে করুন যে ব্যবহারকারী কোনও মানচিত্র তৈরি করেনি <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 টি যুক্তি প্রত্যাশা করে:

  1. কীগুলির একটি তালিকা; উদাহরণ:['<C-a>', '<C-b>', '<C-c>']
  2. একটি মোড; উদাহরণ: nসাধারণ মোডের xজন্য বা ভিজ্যুয়াল মোডের জন্য
  3. একটি বুলিয়ান পতাকা; যদি এটি হয় তবে এর 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)

বাফার-লোকাল ম্যাপিংগুলি সংরক্ষণ / পুনরুদ্ধার করার সময় একটি তৃতীয় সমস্যা হতে পারে। কারণ, আমরা যখন ম্যাপিংগুলি সংরক্ষণ করেছি এবং সেই মুহুর্তের মধ্যে যখন আমরা সেগুলি পুনরুদ্ধার করার চেষ্টা করব তখনকার বর্তমান বাফারটি পরিবর্তিত হতে পারে।

এই ক্ষেত্রে, Save_mappings()বর্তমান বাফারের সংখ্যা সংরক্ষণ করে ফাংশনটি উন্নত হতে পারে ( bufnr('%'))।

এবং তারপরে, Restore_mappings()ডান বাফারে বাফার-লোকাল ম্যাপিংগুলি পুনরুদ্ধার করতে এই তথ্যটি ব্যবহার করবে। আমরা সম্ভবত :bufdoকমান্ডটি ব্যবহার করতে পারতাম , একটি গণনা দিয়ে পূর্বের উপসর্গটি ব্যবহার করতে পারি (পূর্বে সংরক্ষিত বাফার সংখ্যার সাথে মিল রেখে) এবং ম্যাপিং কমান্ডের সাথে এটি প্রত্যয় দিয়েছি ।

হতে পারে এরকম কিছু:

:{original buffer number}bufdo {mapping command}

bufexists()ফাংশনটি ব্যবহার করে বাফারটি এখনও বিদ্যমান আছে কিনা তা আমাদের প্রথমে পরীক্ষা করে দেখতে হবে, কারণ এর মধ্যে এটি মুছে ফেলা হতে পারে।


আশ্চর্যজনক যে আমার প্রয়োজন ঠিক কি। ধন্যবাদ!
স্ট্যাটক্স

2

আমার প্লাগিনগুলিতে, যখন আমার অস্থায়ী ম্যাপিং থাকে, সেগুলি সর্বদা স্থানীয় হয় - সুতরাং আমার lh#on#exit().restore_buffer_mapping()সহায়ক ফাংশন - lh-vim-lib থেকে

শেষ পর্যন্ত, যা ঘটে তা নিম্নলিখিত:

" excerpt from autoload/lh/on.vim
function! s:restore_buffer_mapping(key, mode) dict abort " {{{4
  let keybinding = maparg(a:key, a:mode, 0, 1)
  if get(keybinding, 'buffer', 0)
    let self.actions += [ 'silent! call lh#mapping#define('.string(keybinding).')']
  else
    let self.actions += [ 'silent! '.a:mode.'unmap <buffer> '.a:key ]
  endif
  return self
endfunction

" The action will be executed later on with:
" # finalizer methods {{{2
function! s:finalize() dict " {{{4
  " This function shall not fail!
  for l:Action in self.actions
    try
      if type(l:Action) == type(function('has'))
        call l:Action()
      elseif !empty(l:Action)
        exe l:Action
      endif
    catch /.*/
      call lh#log#this('Error occured when running action (%1)', l:Action)
      call lh#log#exception()
    finally
      unlet l:Action
    endtry
  endfor
endfunction


" excerpt from autoload/lh/mapping.vim
" Function: lh#mapping#_build_command(mapping_definition) {{{2
" @param mapping_definition is a dictionary witch the same keys than the ones
" filled by maparg()
function! lh#mapping#_build_command(mapping_definition)
  let cmd = a:mapping_definition.mode
  if has_key(a:mapping_definition, 'noremap') && a:mapping_definition.noremap
    let cmd .= 'nore'
  endif
  let cmd .= 'map'
  let specifiers = ['silent', 'expr', 'buffer']
  for specifier in specifiers
    if has_key(a:mapping_definition, specifier) && a:mapping_definition[specifier]
      let cmd .= ' <'.specifier.'>'
    endif
  endfor
  let cmd .= ' '.(a:mapping_definition.lhs)
  let rhs = substitute(a:mapping_definition.rhs, '<SID>', "\<SNR>".(a:mapping_definition.sid).'_', 'g')
  let cmd .= ' '.rhs
  return cmd
endfunction
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.