Tuesday, December 09, 2008

"vi" & vim" - Programmers view #2

به نام دوست

vi برای برنامه نویسان امکانات گوناگونی فراهم میکند که بیشک رافع مشکلات برنامه نویس در هنگام نوشتن برنامه میباشند. در این نوشته طریقه استفاده از tagها به عنوان یک راه حال مناسب جهت دستیابی سریع به تعارف فانکشنها و کلا شناسه ها بیان خواهد شد. همچنین مواردی جهت جابه جایی در کد نیز در ادامه خواهد آمد.

1- Tag چیست؟
معمولا از پردردسرترین موضوعات در هنگام کار با سورس کرنل یافتن تعریف فانکشنهای مورد استفاده است. جستجو در درون فایلها راه حل اول است:
find /path/to/kernel | xargs grep yourfunction_name

اما تکرار این موضوع خسته کننده است. استفاده از tagها مناسبترین راه حل است.
Tag مشخص کننده جایگاه تعریف یک شناسه (identifier) است. به عنوان مثال تعریف یک فانکشن در c را میتوان در نظر گرفت. Tagها در درون فایلی با نام tags نگهداری میشوند و در درون vi با استفاده از محتویات آن برنامه نویس میتواند مستقیما به محل تعریف شناسه پرش کند. این روش سریعترین و مناسبترین روش برای دستیابی به تعاریف فانکشنها و یا متغیرها است.
تولید tags فایل توسط برنامه ای با نام ctags انجام میشود که در تمام linuxها نسخه ای از آن وجود دارد. طریقه استفاده از آن نیز به این شکل است:
ctags *.c *.h
که در درون تمام فایلهای c. و h. به دنبال تعاریف خواهد گشت و فایلی به نام tags را به صورت پیش فرض ایجاد خواهد کرد.. چنانچه سورس برنامه دارای شاخه ها و زیرشاخه هایی باشد به دوصورت میتوان فایل tags را تولید کرد:
  • برای هر شاخه یک فایل tag مجزا تعریف شود که این امر مستلزم اجرای دستور ctags در هر شاخه به صورت مجزا میباشد. معمولا این امر هنگامی که سورس برنامه از Makefile ها برای ساخت استفاده میکند، به صورت بازگشتی دستور ctags برای تمام زیرشاخه ها اجرا میشود.
  • البته روش سریعتر این است که برای تمام زیرشاخه ها یک فایل ctags ساخته شود. برای این کار میتوان از دستور زیر استفاده کرد:
    ctags -R
برای رجوع(پرش) به تعاریف شناسه ها میتوان از دستور tag در حالت خط فرمان استفاده کرد:
:tag identifier
و یا اینکه اگر نام فانکشن در زیر مکان نما قرار دارد از ترکیب [+ctrl استفاده کرد. برای بازگشت به عقب نیز میتوان از ترکیب ctrl+T استفاده کرد.
دستور tags: لیست تمامی تگهایی که مرور شده است را با ترتب LIFO نشان خواهد داد. دستور tag: موجب پرش به تگ ابتدای لیست خواهد شد و همچنین 2tag: موجب پرش به عنصر دوم از بالای لیست خواهد شد.

1-1: تقسیم(split) پنجره:
استفاده از دستور tag: و یا [+ctrl باعث جایگزینی پنجره فعلی میشود. برای نمایش تگ همزمان با نمایش کد فعلی که در حال فعالیت بر روی آن هستید باید پنجره به دو تیکه تقسیم(split) شود. برای اینکار میتوان از دستور split: و به دنبال آن دستور tag: استفاده کرد.
دستور مناسبتر برای این منظور دستور stag است:
:stag identifier_name
در صورتیکه نام شناسه در زیر مکان نما باشد میتوان از ترکیب کلیدهای زیر استفاده کرد:
ctrl+w ]

1-2: استفاده از فایلهای tags گوناگون:
در حالت معمول vi در شاخه جاری به دنبال فایل tags میگردد. در صورتیکه tags فایلهای گوناگونی داشته باشید میبایست همه آنها را مشخص کنید. برای اینکار میبایست پارامتر tags را مقدار دهی کرد. به عنوان مثال:
:set tags=./tags,./../tags,./*/tags
این دستور باعث میشود که tags فایل موجود در مسیر جاری، یک شاخه بالاتر و همچنین تمام زیرشاخه های موجود در شاخه جاری مورد نظر قرار گیرند.
همچنین ارجاع به تمام زیرشاخه ها در یک شاخه میتواند به این صورت انجام شود:
:set tags=~/projs/**/tags
که باعث میشود تمام فایلهای تگ با نام tags در ساختار درختی زیر مجموعه projs (که در شاخه home کاربر قرار دارد)، مورد استفاده قرار گیرد.
البته همانطور که در قبل آمد میتوان یک فایل تگ برای یک شاخه و زیرشاخه های آن ساخت که به این طریق دسترسی به تگها سریعتر خواهد شد(دستور ctags -R ).

3-1: تطابقهای گوناگون:
در صورتیکه شناسه در مکانهای مختلف تعریف شده باشد هنگام استفاده از دستور tag: به اولین تطابق پرش خواهد شد. برای رفتن به تطابق بعدی میبایست از دستور:
:tnext
استفاده کرد. همچنین
:2tnext
باعث پرش دوگام به جلو در لیست تطابقها میشود.
همچنین دستور
:tselect identifier
لیست تمامی تطابقها را نشان خواهد داد که با زدن شماره آن میتوان به آن تطابق پرش کرد. دیگر کامندها برای جابه جایی بین تطابقها به این شرح هستند:
:tfirst پرش به اولین تطابق
:tlast پرش به آخرین تطابق
:tprevious پرش به قبل شبیه به دستور tnext

1-4: حدس نام تگ:
استفاده از کلید tab در پوسته لینوکس امری رایج است. جالب اینجاست که در هنگام استفاده از دستورات tag (که در قبل آمد) به هنگام تایپ شناسه میتوان از tab استفاده کرد.
در حالت معمول میتوان قسمتی از آن را تایپ کرد و به دنبال آن کلید tab را زد:
:tag iden
همچنین در صورتیکه به دنبال تگی میگردید که شامل کلمه ای مانند block باشد میتوان به اینصورت عمل کرد:
:tag /block
استفاده از / بدان معنی است که دنباله دستور tag یک شناسه نیست بلکه یک الگو (pattern) است. بنابراین جستجو در تگهایی که شامل عبارت block است باید انجام شود.
همچنین استفاده از «^» در ابتدای عبارت بدان معنی است که الگو در ابتدای تگ باشد و همچنین استفاده از «$» در انتهای الگو بدان معنی است که الگو در انتهای تگ باشد. برای آگاهی از طریقه مشخص کردن الگو از دستور help pattern استفاده کنید.

1-5: پنجره پیش نمایش:
در پاره ای از مواقع خواستار نمایش تعاریف بدون ترک پنجره فعلی هستیم. به عنوان مثال شما میخواهید تعریف فانکشن را ببینید تا از کاربرد پارامترها مطمئن شوید. برای این منظور میتوان از دستور ptag استفاده کرد:
:ptag identifier
همچنین اگر نام شناسه در زیر مکان نما باشد میتوان از ترکیب کلیدهای
ctrl+w }
استفاده کرد.
جهت بستن پنجره پیش نمایش باید از دستور pclose: استفاده کرد.
برای ویرایش یک فایل در پنجره پیش نمایش میتوان از دستور pedit استفاده کرد:
pedit yourfile.h
همچنین جهت جستجوی یک کلمه در فایل جاری و تمام فایلهای includeشده و نمایش در پنجره پیش نمایش میبایست از
:psearch word
استفاده کرد.

2: جابه جایی در یک برنامه
در هنگام برنامه نویسی خیلی اوقات اتفاق می افتد که برنامه نویس نیاز به پرش به ابتدای بلاک، پرانتز متناظر و ... جهت اطمینان از صحت برنامه پیدا میکند.
استفاده از «%» در حالت فرمان، باعث جابه جایی بین براکتهای متناظر میشود. به عنوان اگر بر روی یکی از کاراکترهای {}و ()و [] قرار گرفته و % را بزنید مکان نما به مکان کاراکتر متناظر خواهد رفت. استفاده جالبتر آن برای بلاکهای ifdef# در ماکروها هست که باعث جابه جایی بین ابتدا و انتهای بلاک if و همچنین در صورت وجود else باعث حرکت به صورت منظم بین آنها خواهد شد.
در صورتیکه در بین کد نوشته شده برای یک ماکرو هستید و نیازمند به پرش به ابتدای تعریف ماکرو هستید میتوانید از ترکیب #] بار پرش به ابتدا و همچنین برای پرش به انتها از #[ استفاده کنید.

2-1: حرکت در بلاکی از کد
با توجه به اینکه بلاکهای c در بین {} قرار دارند برای جابه جایی بین ابتدا و انتهای بلاکی که در آن قرار داریم میتوانیم از ترکیب }] برای پرش به ابتدای بلاک جاری و همچنین }[ برای پرش به انتهای بلاک جاری استفاده کنیم.
همچنین ترکیب )] و ([ رفتاری مشابه ترکیب کلمات قبلی برای جابه جایی در ابتدا و انتهای عبارت محصور شده با () دارد. ترکیب /] و /[ برای جابه جایی در ابتدا و انتهای توضیحات (comment) استفاده میشود.
m] و m[ برای جابه جایی به ابتدا و انتهای یک فانکشن استفاده میشود.

2-2: یافتن شناسه عمومی (Global):
در صورت نیاز به دیدن تعریف یک شناسه ای که به صورت global تعریف شده از ترکیب I] میتوان استفاده کرد. فشردن این کلیدها لیست تمامی تطابقها با جستجو در فایل جاری و فایلهای include شده را نمایش خواهد شد.

2-3: تعیین مکان فایلهای include شده:
فایلهای include شده در مسیرهایی که توسط متغیر path تعیین شده اند جتسجو خواهند شد که طریقه تنظیم آن در قسمت قبلی توضیح داده شد.
استفاده از دستور
:checkpath
فایلهای include را که در مسیرهای مشخص شده توسط path پیدا نشده اند را لیست خواهد کرد. همچنین استفاده از دستور
:checkpath!
لیست فایلهای include که قابل دستیابی در مسیرهای path هستند مشخص خواهند شد.
تنظیم پارامتر path میتواند به اینصورت نیز انجام شود:
:set path+=/projs/**/include
که باعث خواهد شد تمام شاخه های include در تمام زیرشاخه های projs به path اضافه شوند.

2-4: پرش به یک تطابق:
استفاده از I] لیست تمام تطابق را نشان خواهد داد. استفاده از ترکیب:
[tab
باعث پرش به اولین تطابق میشود(منظور از tab فشردن کلید tab است). در لیست نشان داده شده توسط I] هر عنصر لیست با یک شماره مشخص میشود. از آن شماره میتوان جهت پرش به تطابق مرود نظر استفاده کرد. به عنوان مثال:
3[tab
باعث پرش به تطابق با شماره 3 میشود. به جای کلید tab میتوان از ترکیب ctrl+I نیز استفاده کرد. در تمام موارد برای بازگشت به مکانی که از آنجا پرش به تطابق را آغاز کرده اید از ترکیب ctrl+o باید استفاده کرد.
همچنین ترکیبات زیر نیز مفید هستند:
[i تنها اولین تطابق را لیست میکند
]I آیتمهایی را که در زیر مکان نما هستند را نمایش خواهد داد
]i اولین تطابق در زیر مکان نما را لیست خواهد کرد.

2-5: یافتن شناسه ای که به صورت ماکرو تعریف شده است:
استفاه از I] تمام شناسه هایی را که به هر طریق تعریف شده است نمایش خواهد داد. در صورتیکه به دنبال تعریف شناسه ای هستید که به صورت ماکرو تعریف شده است باید از ترکیب D] استفاده کنید. پارامتر «defined» مشخص میکند که کدام خطوط مربوط به تعریف ماکرو هستند که میتواند برای زبانهای گوناگون تنظیم شود(البته به صورت پیش فرض برای c تعرف شده است).
ترکیبات زیر نیز مفید هستند:
[d اولین تطابق را لیست خواهد کرد
]D تنها آیتمهای زیر مکان نما را لیست خواهد کرد
]d تنها اولین تطابق زیر مکان نما را لیست خواهد کرد

2-6: یافتن شناسه های محلی
جهت جستجوی شناسه تنها در فایل جاری میتوان از ترکیب gD استفاده کرد. همچنین برای جستجو در فانکشن جاری از ترکیب gd استفاده میشود.


منبع: اینجا

No comments: