কোনও প্রতিনিধি ব্যবহার করা বা ভিমস্ক্রিপ্টে যুক্তি হিসাবে কোনও ফাংশন পাস করা সম্ভব?


11

আমি উইমস্ক্রিপ্ট শিখতে একটি ছোট প্লাগইন তৈরি করার চেষ্টা করছি, আমার লক্ষ্যটি একটি নির্বাচিত পাঠ্য প্রক্রিয়াজাতকরণ এবং ফলাফলের সাথে এটি প্রতিস্থাপন করে কিছু ফাংশন তৈরি করা। স্ক্রিপ্টটিতে নিম্নলিখিত আইটেম রয়েছে:

  • দুটি ফাংশন পাঠ্য প্রক্রিয়াজাতকরণ: তারা প্যারামিটার হিসাবে একটি স্ট্রিং নেয় একটি রিটার্ন রিটার্ন দেয় যা মূল পাঠ্যটি প্রতিস্থাপন করতে ব্যবহার করা উচিত। আপাতত আমার কাছে কেবল দুটি আছে তবে অল্প সময়ের মধ্যে আরও অনেক কিছু রয়েছে।

  • নির্বাচিত পাঠ্য প্রাপ্ত একটি ফাংশন: যা কেবল সর্বশেষ নির্বাচনকে ইয়েঙ্ক করে ফিরে আসে।

  • একটি মোড়ক ফাংশন: যা একটি প্রক্রিয়াজাতকরণ ফাংশন কল করে, তার ফলাফল পেয়েছে এবং পুরানো নির্বাচনটিকে এই ফলাফলের সাথে প্রতিস্থাপন করে।

আপাতত আমার মোড়ক ফাংশনটি দেখতে এমন দেখাচ্ছে:

function! Wrapper()
    " Get the string to insert
    let @x = Type1ProcessString(GetSelectedText())

    " remove the old selection
    normal gvd

    " insert the new string
    normal "xp
endfunction

এবং আমাকে একটি দ্বিতীয় র‌্যাপার তৈরি করতে হবে যার সাথে 3 লাইনটি প্রতিস্থাপন করা হবে

let @x = Type2ProcessString(GetSelectedText())

আমি আমার র‍্যাপার ফাংশনটিতে প্রসেস ফাংশন সম্বলিত একটি প্যারামিটারটি লাইনে 3 লাইনে জেনেরিক কল কার্যকর করতে এবং ব্যবহার callকরতে চাই, এখনকার জন্য আমি বিভিন্নভাবে যেমন চেষ্টা করেছি , উদাহরণস্বরূপ:

let @x = call('a:functionToExecute', GetSelectedText()) 

তবে আমি সত্যিই সফল :h callহইনি এবং প্রতিনিধিদের বিষয়ে সত্যই সহায়ক হইনি।

এখানে সংক্ষেপে আমার প্রশ্নগুলি হল:

  • সমস্ত প্রক্রিয়াজাতকরণের জন্য আমি কীভাবে কেবল একটি মোড়কের কাজ করতে পারি?
  • ভাইসস্ক্রিপ্টে প্রতিনিধি হিসাবে কাজ করে এমন কিছু আছে কি?
  • যদি প্রতিনিধিদের অস্তিত্ব না থাকে তবে আমি যা চাই তা করার একটি "ভাল" উপায় কী হবে?

উত্তর:


16

আপনার প্রশ্নের উত্তর দেওয়ার জন্য: call()ম্যানুয়ালটিতে প্রোটোটাইপটি রয়েছে call({func}, {arglist} [, {dict}]); {arglist}যুক্তি আক্ষরিক একটি তালিকা বস্তু, না আর্গুমেন্ট এর একটি তালিকায় থাকতে হবে। এটি হ'ল, আপনাকে এটি লিখতে হবে:

let @x = call(a:functionToExecute, [GetSelectedText()])

এটি ধরে নেওয়া a:functionToExecuteহয় হয় ফানক্রাইফ (দেখুন :help Funcref), বা কোনও ফাংশনের নাম (যেমন একটি স্ট্রিং, যেমন 'Type1ProcessString')।

এখন, এটি একটি শক্তিশালী বৈশিষ্ট্য যা ভিমকে এক ধরণের এলআইএসপি-জাতীয় মানের দেয়, তবে আপনি সম্ভবত এটি উপরের মতো ব্যবহার করবেন d যদি a:functionToExecuteকোনও স্ট্রিং, কোনও ফাংশনের নাম হয় তবে আপনি এটি করতে পারেন:

function! Wrapper(functionToExecute)
    " ...
    let s:processing = function(a:functionToExecute)
    let @x = s:processing(GetSelectedText())
    " ...
endfunction

এবং আপনি ফাংশনটির নাম দিয়ে র‍্যাপারটি কল করবেন:

call Wrapper('Type1ProcessString')

অন্যদিকে a:functionToExecuteযদি ফানক্রাইফ হয় তবে আপনি সরাসরি এটিকে কল করতে পারেন:

function! Wrapper(functionToExecute)
    " ...
    let @x = a:functionToExecute(GetSelectedText())
    " ...
endfunction

তবে আপনার এইভাবে র‍্যাপারটি কল করতে হবে:

call Wrapper(function('Type1ProcessString'))

আপনি সাথে ফাংশনগুলির অস্তিত্বের জন্য পরীক্ষা করতে পারেন exists('*name')। এটি নিম্নলিখিত ছোট কৌশলটি সম্ভব করে তোলে:

let s:width = function(exists('*strwidth') ? 'strwidth' : 'strlen')

অর্থাত্ একটি ফাংশন যা বিল্ট-ইন ব্যবহার করে strwidth()যদি ভিম এটির জন্য যথেষ্ট নতুন থাকে এবং strlen()অন্যথায় ফিরে যায় (আমি যুক্তি দিচ্ছি না যে এই জাতীয় ফলব্যাকটি বোধগম্য; আমি কেবল বলছিলাম এটি সম্পন্ন করা যেতে পারে)। :)

অভিধানের ফাংশনগুলির সাথে (দেখুন :help Dictionary-function) শ্রেণীর অনুরূপ কিছু সংজ্ঞা দিতে পারেন:

let g:MyClass = {}

function! g:MyClass.New(...)
    let newObj = copy(self)

    if a:0 && type(a:1) == type({})
        let newObj._attributes = deepcopy(a:1)
    endif
    if exists('*MyClassProcess')
        let newObj._process = function('MyClassProcess')
    else
        let newObj._process = function('s:_process_default')
    endif

    return newObj
endfunction

function! g:MyClass.getFoo() dict
    return get(get(self, '_attributes', {}), 'foo')
endfunction

function! g:MyClass.setFoo(val) dict
    if !has_key(self, '_attributes')
        let self._attributes = {}
    endif
    let self._attributes['foo'] = a:val
endfunction

function! g:MyClass.process() dict
    call self._process()
endfunction

function! s:_process_default()
    echomsg 'nothing to see here, define MyClassProcess() to make me interesting'
endfunction

তারপরে আপনি এই জাতীয় বস্তুগুলি ইনস্ট্যান্ট করবেন:

let little_object = g:MyClass.New({'foo': 'bar'})

এবং এর পদ্ধতিগুলি কল করুন:

call little_object.setFoo('baz')
echomsg little_object.getFoo()
call little_object.process()

আপনি শ্রেণি বৈশিষ্ট্য এবং পদ্ধতি থাকতে পারে:

let g:MyClass.__meaning_of_life = 42

function g:MyClass.GetMeaningOfLife()
    return get(g:MyClass, '__meaning_of_life')
endfunction

( dictএখানে কোন প্রয়োজন বিজ্ঞপ্তি )।

সম্পাদনা: সাবক্লাসিং হ'ল এইরকম কিছু:

let g:MySubclass = copy(g:MyClass)
call extend(g:MySubclass, subclass_attributes)

এখানে সূক্ষ্ম বিন্দু copy()পরিবর্তে এর ব্যবহার deepcopy()। এর কারণটি হল পিতাম শ্রেণীর বৈশিষ্ট্যগুলি রেফারেন্সের মাধ্যমে অ্যাক্সেস করতে সক্ষম হওয়া। এটি অর্জন করা যেতে পারে তবে এটি অত্যন্ত ভঙ্গুর এবং সঠিকভাবে পাওয়া তুচ্ছ থেকে অনেক দূরে। আর একটি সম্ভাব্য সমস্যা হ'ল এই ধরণের সাবক্লাসের সাথে is-aমিল রয়েছে has-a। এই কারণে শ্রেণিক বৈশিষ্ট্যগুলি সাধারণত ব্যথার পক্ষে মূল্যবান হয় না।

ঠিক আছে, ভাবনার জন্য আপনাকে কিছু খাবার দেওয়ার জন্য এটি যথেষ্ট হওয়া উচিত।

আপনার প্রাথমিক কোড স্নিপেটে ফিরে আসুন, এর সাথে দুটি বিবরণ রয়েছে যা উন্নত করা যেতে পারে:

  • আপনার normal gvdপুরানো নির্বাচন মুছে ফেলার দরকার নেই , normal "xpআপনি প্রথমে এটি হত্যা না করলেও এটি প্রতিস্থাপন করবেন
  • call setreg('x', [lines], type)পরিবর্তে ব্যবহার করুন let @x = [lines]। এটি স্পষ্টভাবে নিবন্ধের ধরণ নির্ধারণ করে x। অন্যথায় আপনি xইতিমধ্যে সঠিক টাইপ (যেমন চরিত্রের দিক, লাইনওয়াইজ বা ব্লকওয়াইস) এর উপর নির্ভর করছেন ।

আপনি যখন সরাসরি অভিধানে ফাংশন তৈরি করেন (অর্থাত্ একটি "সংখ্যাযুক্ত ফাংশন"), আপনার dictকীওয়ার্ডের প্রয়োজন হবে না । এটি আপনার "শ্রেণি পদ্ধতিতে" প্রযোজ্য। দেখুন :h numbered-function
কার্ল ইংভে লেভের্গ

@ কার্লইংভেলেভের্গ প্রযুক্তিগতভাবে এটি শ্রেণি এবং অবজেক্ট উভয় পদ্ধতির ক্ষেত্রেই প্রযোজ্য (অর্থাত কোনও কার্যকারণের dictজন্য প্রয়োজন নেই MyClass)। তবে আমি এটি বিভ্রান্তিকর মনে করি, তাই আমি dictস্পষ্টভাবে যুক্ত করার প্রবণতা রাখি ।
lcd047

আমি দেখি. সুতরাং আপনি dictনিজের উদ্দেশ্যটি স্পষ্ট করতে সহায়তা করার জন্য ক্লাসের পদ্ধতিগুলির জন্য না, তবে বস্তু পদ্ধতিগুলির জন্য যুক্ত করছেন?
কার্ল ইংভে লেরভেগ

@ lcd047 এই আশ্চর্যজনক উত্তরের জন্য অনেক ধন্যবাদ! আমি এটিতে কাজ করতে হবে কিন্তু আমি ঠিক এটিই খুঁজছিলাম!
স্টাটক্স

1
@ কার্লইংভেলেভের্গ এখানে একটি সূক্ষ্মতা রয়েছে, selfশ্রেণি পদ্ধতি এবং অবজেক্ট পদ্ধতিগুলির অর্থ পৃথক। এটি পূর্ববর্তী ক্ষেত্রে শ্রেণি নিজেই এবং পরবর্তীকালের বর্তমান অবজেক্টের উদাহরণ। এই কারণে আমি সর্বদা ক্লাসটি নিজেই হিসাবে g:MyClassব্যবহার selfকরি না, কখনও ব্যবহার করি না এবং আমি বেশিরভাগই dictমনে করিয়ে দিচ্ছি যে এটি ব্যবহার করা ঠিক আছে self(এটি একটি ফাংশন যা dictসর্বদা কোনও বস্তুর উদাহরণে কাজ করে)। আবার আমি ক্লাসের পদ্ধতিগুলি খুব বেশি ব্যবহার করি না এবং যখন আমি এটি করি তখন আমি dictসর্বত্র বাদ দিতে চাই । হ্যাঁ, স্ব-ধারাবাহিকতা আমার মধ্য নাম। ;)
lcd047

1

কমান্ডটি একটি স্ট্রিংয়ে তৈরি করুন এবং :exeএটি চালানোর জন্য ব্যবহার করুন । দেখুন :help executeআরো বিস্তারিত জানার জন্য।

এই ক্ষেত্রে, executeফাংশনটিতে কল করতে এবং ফলাফলটি রেজিস্টারে রাখার জন্য ব্যবহৃত হয়, কমান্ডের বিভিন্ন উপাদানগুলি .নিয়মিত স্ট্রিং হিসাবে অপারেটরের সাথে সংহত হওয়া আবশ্যক । এর পরে 3 লাইনটি হওয়া উচিত:

execute "let @x = " . a:functionToExecute . "(GetSelectedText())"
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.