برنامه نویسی

چگونه تکمیل خود را برای vim ایجاد کنید

آیا تا به حال به تعریف تکمیل خود برای چیزهای خاصی مانند ایمیل ها، نام مخاطبین یا چیزهای پیچیده ای مانند کلاس های tailwind یا نام های کاربری github فکر کرده اید؟ خوب، هدف من در این پست این است که به شما نشان دهم چگونه این کار را به روشی ساده و مختصر انجام دهید!

ابتدا یک دمو

چگونه تکمیل خود را برای vim ایجاد کنید.svg

همانطور که در ویدیوی بالا می بینید، این یک مکانیسم کاملاً ساده برای تعریف شما است
تکمیل خود، ابتدا یک تابع ایجاد می کنید که آرایه ای از رشته ها و
سپس شما را به completefunc گزینه ای که مرجع تابع و
پس از آن می توانید با فشار دادن، تکمیل را فعال کنید Ctrl+x Ctrl+u وقتی روشن است
حالت درج حالا بیایید ساختار این تابع را بفهمیم و a بنویسیم
یکی هیجان انگیز تر!

درک ساختار تابع تکمیل

برای مثال در اینجا تابع استفاده شده در ویدیوی بالا آمده است:

function! MyCompletion(findstart, base) abort
  return ['something', 'to', 'complete', 'devto']
endfunction
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

استدلال اول findstart این یک آرگومان عددی است و vim آن را با مقدار فراخوانی می کند 1 در اولین اجرای تکمیل برای یافتن موقعیت ستون کلمه فعلی (به عنوان مثال برای قرار دادن پنجره تکمیل)، سپس در لحظه دوم vim این تابع را دوباره با یک مقدار فراخوانی کنید. 0 جایی که انتظار دارد یک لیست واقعی از آیتم ها وجود داشته باشد.

به همین دلیل است که در ویدیو با این خطا مواجه شدم E745: Using a List as a Number، زیرا vim منتظر شماره ستون در آن نقطه از چرخه تکمیل بود.

استدلال دوم base رشته‌ای است که تمام موارد تکمیل قبلی را با هم گروه‌بندی می‌کند، البته در اولین اجرا خالی است و اگر کاربر دکمه تکمیل را فشار دهد به تدریج افزایش می‌یابد.

نوشتن نسخه ساده با فیلتر

اکنون که ساختار اصلی یک تابع تکمیل را فهمیدیم، بیایید
با یک فیلتر کمی آن را بهتر کنید! اساسا ما رشته فرعی را شناسایی خواهیم کرد
که کاربر ابتدا گزینه صحیح را تایپ کرده و برگرداند تا انتخاب آن آسان باشد
آی تی.

به عنوان مثال:

function! MyCompletion(findstart, base) abort
  if a:findstart
    return 0
  endif

  let s:matches = ['something', 'to', 'complete', 'devto']

  if a:base->len() == 0
    return s:matches
  endif

  return s:matches->matchfuzzy(a:base)
endfunction
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را matchfuzzy در این زمینه یک تابع پیش‌فرض از vimscript است و به ما کمک می‌کند تا یک الگوریتم تطبیق فازی بدست آوریم که تابع تکمیل ساده ما را یک مقدار زیادی قدرت، همانطور که در زیر نشان داده شده است:

ویدئوی آزمایشی در مورد تکمیل با فازی

آخرین پیشرفت در مثال اصلی

اگر در تنظیمات خود با این عملکرد اشتباه کنید، متوجه می شوید که یک اشکال وجود دارد، برای روشن شدن و نگه داشتن ما در همان صفحه، اشکال زیر را نشان می دهم:

ویدئوی آزمایشی در مورد اشکال تکمیل

همانطور که در ویدیو می بینید، ما فقط می توانیم کلمه اول را کامل کنیم و سپس همه چیز کار نمی کند، به این دلیل است که ما یک مقدار صحیح مناسب برای findstart برنگردانیم! به این ترتیب vim نمی تواند شروع کلمه فعلی را پیدا کند و درست ارائه کند base مقدار، حل آن بسیار ساده است و می‌توانیم آن را به صورت زیر افزایش دهیم:

function! MyCompletion(findstart, base) abort
  if a:findstart
    let s:startcol = col('.') - 1
    while s:startcol > 0 && getline('.')[s:startcol - 1] =~ '\a'
      let s:startcol -= 1
    endwhile
    return s:startcol
  endif

  let s:matches = ['something', 'to', 'complete', 'devto']

  if a:base->len() == 0
    return s:matches
  endif

  return s:matches->matchfuzzy(a:base)
endfunction
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این نسخه، ما در حال عبور از خط و به روز رسانی آن هستیم startcol متغیر بر این اساس، به این ترتیب vim همیشه کلمه ناقص فعلی ما را پیدا می کند و آرگومان های صحیح را ارائه می دهد.

نوشتن یک تابع تکمیل هیجان انگیزتر

خوب در این مرحله، فکر می‌کنم ساختار و قدرت یک تابع تکمیل سفارشی در vim را درک می‌کنید، بنابراین بیایید چیزها را تند کنیم و مثال پیچیده‌تری ارائه دهیم.

  1. بیایید فرض کنیم فهرستی از ایمیل‌ها را داریم /tmp/emails مثل این:
cherry@gmail.com
mel@gmail.com
morgana@outlook.com
yaya@heart.com
huelder@insiide.com.br
daniel@heart.com
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  1. ما تابعی می نویسیم که محتوای این فایل را دریافت می کند و ایمیل ها را با استفاده از الگوریتم تطبیق فازی برمی گرداند، این کار را می توان با تابع زیر انجام داد:
function! EmailCompletion(findstart, base) abort
  if a:findstart
    let s:startcol = col('.') - 1
    while s:startcol > 0 && getline('.')[s:startcol - 1] =~ '\a'
      let s:startcol -= 1
    endwhile
    return s:startcol
  endif

  let s:emails = expand('/tmp/emails')->readfile()

  if a:base->len() == 0
    return s:emails
  endif

  return s:emails->matchfuzzy(a:base)
endfunction
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  1. و voila! ببینیم کار می کند؟

نسخه ی نمایشی نهایی با تکمیل ایمیل

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا