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

آیا تا به حال به تعریف تکمیل خود برای چیزهای خاصی مانند ایمیل ها، نام مخاطبین یا چیزهای پیچیده ای مانند کلاس های tailwind یا نام های کاربری github فکر کرده اید؟ خوب، هدف من در این پست این است که به شما نشان دهم چگونه این کار را به روشی ساده و مختصر انجام دهید!
ابتدا یک دمو
همانطور که در ویدیوی بالا می بینید، این یک مکانیسم کاملاً ساده برای تعریف شما است
تکمیل خود، ابتدا یک تابع ایجاد می کنید که آرایه ای از رشته ها و
سپس شما را به 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 را درک میکنید، بنابراین بیایید چیزها را تند کنیم و مثال پیچیدهتری ارائه دهیم.
- بیایید فرض کنیم فهرستی از ایمیلها را داریم
/tmp/emails
مثل این:
cherry@gmail.com
mel@gmail.com
morgana@outlook.com
yaya@heart.com
huelder@insiide.com.br
daniel@heart.com
- ما تابعی می نویسیم که محتوای این فایل را دریافت می کند و ایمیل ها را با استفاده از الگوریتم تطبیق فازی برمی گرداند، این کار را می توان با تابع زیر انجام داد:
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
- و voila! ببینیم کار می کند؟