إنتقل إلى المحتوى الرئيسي

مغامرة عبر vimrc الخاص بي (nvimrc)

· 12 دقائق قراءة
Ammar Najjar
Engineering Team Lead & Software Architect

في هذه المقالة، سآخذكم في مغامرة في ملفي vimrc السابق وملفي الحالي init.vim الذي جمعته خلال السنوات الأخيرة من استخدام vim ثم neovim. سأشرح الميزة أو الوظيفة، ثم أدرج التكوينات أو الكود الذي يجب إدراجه في ملف vimrc (init.vim) لتفعيل هذه الميزة.

)

قد لا يكون هذا محدّثاً دائماً، فأنا أغير هذه التكوينات عندما أشعر بالرغبة في ذلك.

التكوينات العامة (neovim)

القسم الأول يتعلق بالإعدادات العامة التي أعتقد أنها يجب أن تكون مضبوطة بشكل افتراضي في vim، مثل بعضها الموجود بالفعل في neovim، والتي تتضمن:

  • استخدام البحث التدريجي: هذه الميزة تتيح لـ vim تظليل نمط البحث أثناء كتابته.
set incsearch
  • استخدام اتصال سريع للطرفية، هذه الميزة تحسن سلاسة إعادة الرسم عندما تكون هناك نوافذ متعددة.
set ttyfast
  • عندما يتم اكتشاف أن ملفاً قد تغير خارج vim ولم يتم تغييره داخل vim، إعادة قراءته تلقائياً.
set autoread
  • تفعيل القائمة البرية لإكمال سطر الأوامر باستخدام مفتاح TAB.
set wildmenu
set wildmode=longest:list,full
  • تظليل جميع التطابقات لنمط البحث.
set hlsearch
  • يستخدم vim السجل لتذكر أوامر سطر الأوامر التي يدخلها المستخدم في أي من سطور الأوامر هذه:
    • أوامر :
    • نصوص البحث
    • التعبيرات
    • أسطر الإدخال، المكتوبة للدالة input().
    • أوامر وضع التنقيح أحب أن يتذكر vim الكثير (1000) من سجل أوامري.
set history=1000
  • جعل vim يتصرف بطريقة أكثر فائدة (هذا بالضبط ما هو مكتوب في توثيق vim). من الممكن اختيارياً تضمين هذا في ملف vimrc، لأن ملف vimrc أو gvimrc يُ_found عند بدء تشغيل vim، يتم تفعيل هذا الخيار.
set nocompatible
  • جعل مفتاح الرجوع يمسح الأحرف كما في المحررين الآخرين.
set backspace=2
  • عند إدراج حرف جدول باستخدام الضغط على مفتاح <TAB>، يتم استخدام مفتاح الرجوع لحذف ما تم إدخاله، ويعتمد على معلمات تكوين أخرى shiftwidth. tabstop و softtabstop.
set smarttab
  • عند بدء سطر جديد، استخدام نفس المسافة البادئة من السطر السابق. هذه ميزة مفيدة جداً عند البرمجة، خاصة في لغة حساسة للمسافة البادئة مثل python أو yaml.
set autoindent
  • الاستبدال المباشر (neovim فقط)، عند استبدال نمط.
set inccommand=nosplit
العودة للأعلى

التكوينات العامة (vim)

مجموعة أخرى من التكوينات العامة غير الموجودة افتراضياً في neovim. لا أزال أراها مفيدة جداً.

  • لا أحب استخدام الماوس أثناء التحرير، لكنني أحب تفعيلها.
set mouse=a
  • عرض الأمر (جزئي) في السطر الأخير من الشاشة. تشرح التوثيق هذا جيداً، لذا نسخت ذلك منها: في الوضع المرئي يتم عرض حجم المنطقة المحددة:
    • عند تحديد أحرف داخل سطر واحد، عدد الأحرف. إذا كان عدد البايتات مختلفاً يتم عرضه أيضاً: "2-6" يعني حرفين وستة بايتات.
    • عند تحديد أكثر من سطر واحد، عدد الأسطر.
    • عند تحديد كتلة، الحجم في أحرف الشاشة: {أسطر}x{أعمدة}.
set showcmd
  • عرض تطابق القوس عند إدراجه، يبدو هذا كما لو أن المؤشر انتقل إلى القوس المطابق لفترة قصيرة لظلاله. matchtime يتحكم في هذه الفترة الزمنية.
set showmatch
set matchtime=2
  • استخدام عدم الحساسية لحالة الأحرف عند البحث عن تطابق.
set ignorecase
  • إذا تضمّن نمط البحث أحرف كبيرة، تجاوز خيار ignorecase واستخدام البحث الحساس لحالة الأحرف.
set smartcase
  • الحفظ التلقائي قبل تنفيذ أوامر مثل :next و :make. أستخدم make كثيراً، لذا هذا فعال جداً.
set autowrite
  • إخفاء المخازن عند التخلي عنها، بالطبع إذا لم تظهر في نوافذ أخرى. هذا مفيد عندما أتعامل مع مخازن كثيرة في نفس الوقت، ولا أحتاج إلى القلق بشأن الحفظ قبل التبديل.
set hidden
  • أجد modeline مفيداً جداً، عندما أحصل على كود الآخرين، أو عندما أريد إعطاء كودي للآخرين، أضبط إعدادات محددة داخل modeline لتُضبط تلقائياً لأي مستخدم آخر يستخدم vim، والأهم هي tabstop و expandtab.
setglobal modeline
set modelines=3
  • أحب أن يكون لدي الحد الأدنى من أسطر الشاشة فوق المؤشر وتحته.
set scrolloff=3
  • عرض الوضع الذي أستخدمه كرسالة في السطر الأخير، سواء كان وضع insert أو visual أو replace.
set showmode
  • تفاف النص وعرض الأسطر الطويلة على عدة أسطر بدون إدراج فواصل أسطر.
set wrap
set linebreak
  • ضبط عنوان النافذة بقيمة 'titlestring'، وإذا كان فارغاً: اسم_الملف [+==] المسار - اسم_خادم_vim.
set title
  • عرض رقم السطر على الجانب الأيسر من المستند على السطر النشط، وتفعيل الأرقام النسبية على باقي الأسطر.
set number
set relativenumber
  • ضبط مسار الطرفية على 'bash'
set shell=/bin/bash
  • تجاهل الملفات المؤقتة والمُجمّعة لـ C++ وJava وPython وكذلك مجلدات تكوين أنظمة التحكم في الإصدارات التي قد أستخدمها.
set wildignore=*.o,*~,*.pyc,*.class
set wildignore+=*/.git/*,*/.hg/*,*/.svn/*
  • عند دمج الأسطر، عدم إدراج مسافتين بعد علامات الترقيم.
set nojoinspaces
  • عدم إعادة الرسم أثناء تنفيذ الأكواد النصية، هذه تكوين أداء جيد.
set lazyredraw
  • إيقاف النسخ الاحتياطي. بما أن معظم الأشياء موجودة في التحكم في الإصدارات، أجد أن ملفات النسخ الاحتياطي والتبديل هذه مزعجة فقط، لذا أوقفها جميعاً.
set nobackup
set nowritebackup
set noswapfile
  • ضبط الافتراضي 1 تاب == 4 مسافات
set shiftwidth=4
set tabstop=4
set softtabstop=4
set smartindent
  • إنشاء ملف تراجع للحفاظ على السجل بعد إغلاق الملف.
set undofile
set undolevels=100
set undodir=~/.vim/undo//
  • تذكّر معلومات حول المخازن المفتوحة عند الإغلاق.
set viminfo^=%
  • أحياناً أفقد تتبع السطر الذي أنا فيه، لذا تفعيل cursorline يجعل الأمور أسهل بكثير.
set cursorline
  • تفعيل الإكمال Omni.
set omnifunc=syntaxcomplete#Complete
  • تعطيل الجرس المرئي.
set t_vb=
  • ضبط عدد الألوان إلى 256، لأنني أحب ذلك هكذا.
set t_Co=256
  • يستخدم المسح لون الخلفية الحالي.
set t_ut=
  • ضبط مؤشر عمودي في وضع الإدراج.
set guicursor=n-v-c:block,i-ci-ve:ver25,r-cr:hor20,o:hor50
\,a:blinkwait700-blinkoff400-blinkon250-Cursor/lCursor
\,sm:block-blinkwait175-blinkoff150-blinkon175
العودة للأعلى

مدير الإضافات

للإضافات، جربت مديري إضافات كثيرة، كنت أستخدم vundle، و كان إعدادها في ملف vimrc يجب أن يبدو هكذا:

filetype off
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()

Plugin 'VundleVim/Vundle.vim'
" add other plugins here

call vundle#end()
filetype plugin indent on
syntax on

ثم انتقلت إلى مدير إضافات آخر يسمى vim-plug وهو أسرع ويقوم بتحديثات غير متزامنة للإضافات. الإعداد أبسط أيضاً، ويعمل جيداً مع vim/neovim:

call plug#begin(s:editor_root."/plugged/")

" add plugins here
" Plug 'dev-name/repo-name'

call plug#end()

لن أناقش إضافاتي المفضلة وتكويناتها هنا، لأنها تتغير من وقت لآخر، وتعتمد على استخدام vim وبيئة العمل. نقلت أيضاً كل ما يتعلق بالإضافات إلى ملف آخر plugs.vim، حتى لا أتشتت كثيراً معها وإعداداتها.

العودة للأعلى

تحديدات المفاتيح

  • تحديدات وضع طرفية Neovim، للتعامل مع مخزن الطرفية بشكل مشابه لمخزن vim العادي.
tnoremap <Esc> <C-\><C-n>
tnoremap <C-h> <C-\><C-n><C-w>h
tnoremap <C-j> <C-\><C-n><C-w>j
tnoremap <C-k> <C-\><C-n><C-w>k
tnoremap <C-l> <C-\><C-n><C-w>l
noremap <leader>s :split term://bash<CR><C-w><S-j><S-a>
noremap <leader>t :tabedit term://bash<CR><S-a>
  • كثيراً ما أريد البقاء في الوضع المرئي عندما أزحزح كتلة من الكود، لذا أعدت تحديد المفاتيح الأصلية لعمل الحيلة.
vnoremap < <gv
vnoremap > >gv
  • تحريك سطر من النص للأعلى وللأسفل باستخدام leader + [jk] في الوضع العادي والمرئي.
nmap <leader>j mz:m+<cr>'z
nmap <leader>k mz:m-2<cr>'z
vmap <leader>j :m'>+<cr>`<my`>mzgv`yo`z
vmap <leader>k :m'<-2<cr>`>my`<mzgv`yo`z
  • التبديل بين الأحرف المتجاورة باستخدام leader + [hl] لأنني أستخدمه كثيراً لإصلاح أخطاء الكتابة السريعة في الوضع العادي.
nmap <leader>l xp
nmap <leader>h xhhp
  • تعطيل التطابقات المظللة من البحث السابق عند الضغط على leader + ENTER.
map <silent> <leader><CR> :noh<CR>
  • أستخدم النوافذ بشكل متكرر، لذا هذه طريقة ذكية للتنقل بين النوافذ، باستخدام ctrl مع مفاتيح الحركة الأصلية لـ vim [hjkl].
map <C-j> <C-W>j
map <C-k> <C-W>k
map <C-h> <C-W>h
map <C-l> <C-W>l
  • فتح تبويب جديد بمسار المخزن الحالي. مفيد جداً عند تحرير ملفات في نفس الدليل
map <leader>te :tabedit <c-r>=expand("%:p:h")<CR>/
  • تغيير cwd إلى دليل المخزن المفتوح. مقترنة بالتحديد السابق، أحصل على سلوك ممتع جداً.
map <leader>cd :cd %:p:h<CR>:pwd<CR>
  • فتح ملف vimrc في تبويب جديد.
nmap <leader>ev :tabe $MYVIMRC<CR>
  • تبديل التدقيق الإملائي تشغيل/إيقاف، عندما أكتب ورقة.
map <leader>ss :setlocal spell!<cr>
العودة للأعلى

خط الحالة

لدي خط حالة جميل جداً، أنا فخور به، وأفضله على إضافات خط الحالة الراقية. يحتوي على بعض الدوال المساعدة وحالة الإضافات، لذا إذا لم تستخدم هذه الإضافات، فقط علّق الأسطر الخاصة بها، Fugitive و Syntastic.

set statusline=
set statusline=[%n]\ " buffer number
set statusline+=%<%.99f " File name, F for full path
set statusline+=%#warningmsg# " display a warning if
set statusline+=%{HasPaste()} " File name, F for full path
set statusline+=%* " tab chars
set statusline+=%m%r%h%w " status flags
set statusline+=%#question# " Display a warning if
set statusline+=%{(&fenc!='utf-8'&&&fenc!='')?'['.&fenc.']':''} " file encoding isnt
set statusline+=%* " utf-8
set statusline+=%#warningmsg# " display a warning if
set statusline+=%{StatuslineTabWarning()} " files contains
set statusline+=%* " tab chars
set statusline+=%#question# " Display a warning if
set statusline+=%{fugitive#statusline()} " Fugitive
set statusline+=%* " tab chars
set statusline+=%= " right align remainder
set statusline+=%{SyntasticStatuslineFlag()} " Syntastic
set statusline+=%y " buffer file type
set statusline+=%#directory# " display a warning if
set statusline+=%{&ff!='unix'?'['.&ff.']':''} " fileformat isnt
set statusline+=%* " unix
set statusline+=%c%V,%l/ " column and row Number
set statusline+=%L\ %P " total lines, position in file
set laststatus=2

أحب تغيير لون خط الحالة إلى الأزرق عندما أنتقل إلى وضع الإدراج، וזה يتم باستخدام الأسطر التالية:

autocmd InsertEnter * highlight StatusLine term=reverse ctermbg=Blue gui=bold guifg=White guibg=Blue
autocmd InsertLeave * highlight StatusLine term=reverse ctermfg=254 ctermbg=238 gui=bold guifg=White guibg=Black
العودة للأعلى

دوال مفيدة

  • حذف المسافات البيضاء في النهاية عند الحفظ، لكل أنواع الملفات باستثناء markdown، لأنني أحياناً أحتاج إلى ترك مسافتين في نهاية السطر لعمل فاصل سطر ناعم.
func! DeleteTrailingWS()
" Don't strip on these filetypes
if &ft =~ 'markdown'
return
endif
exe "normal mz"
%s/\s\+$//ge
exe "normal `z"
endfunc
autocmd BufWrite *.* :call DeleteTrailingWS()
  • أمر مريح لرؤية الفرق بين المخزن الحالي والملف الذي تم تحميله منه، أي التغييرات التي قمت بها.
if !exists(":Diff")
command DiffOrig vert new | set bt=nofile | r ++edit # | 0d_ | diffthis
\ | wincmd p | diffthis
endif
  • العودة إلى آخر موقع تحرير عند فتح الملفات (تريد هذا!)
autocmd BufReadPost *
\ if line("'\"") > 0 && line("'\"") <= line("$") |
\ exe "normal! g`\"" |
\ endif
  • في الوضع المرئي، الضغط على * أو # يبحث عن التحديد الحالي.
vnoremap <silent> * :call VisualSelection('f')<CR>
vnoremap <silent> # :call VisualSelection('b')<CR>

function! CmdLine(str)
exe "menu Foo.Bar :" . a:str
emenu Foo.Bar
unmenu Foo
endfunction

function! VisualSelection(direction) range
let l:saved_reg = @"
execute "normal! vgvy"

let l:pattern = escape(@", '\\/.*$^~[]')
let l:pattern = substitute(l:pattern, "\n$", "", "")

if a:direction == 'b'
execute "normal ?" . l:pattern . "^M"
elseif a:direction == 'gv'
call CmdLine("vimgrep " . '/'. l:pattern . '/' . ' **/*.')
elseif a:direction == 'replace'
call CmdLine("%s" . '/'. l:pattern . '/')
elseif a:direction == 'f'
execute "normal /" . l:pattern . "^M"
endif

let @/ = l:pattern
let @" = l:saved_reg
endfunction
  • تجميع Java باستخدام javac وتشغيلها باستخدام java مطبقة على المخزن الحالي. مفيد لبرامج Java الصغيرة التي تُشغّل على الفور.
function! CompileAndRunJava()
:w!
setlocal makeprg=javac\ %
setlocal errorformat=%A%f:%l:\ %m,%-Z%p^,%-C%.%#
:make
" split source filename by . and pass the first part to java
:!i=%; echo ${i//.*/}|xargs java
endfunction
  • في خط حالتني، أستخدم بعض الدوال. واحدة للحصول على حالة المخزن الحالي، إذا كان يستخدم تبويبات أو مسافات.
function! StatuslineTabWarning()
if !exists("b:statusline_tab_warning")
let tabs = search('^\t', 'nw') != 0
if tabs
let b:statusline_tab_warning = '[tabs]'
else
let b:statusline_tab_warning = ''
endif
endif
return b:statusline_tab_warning
endfunction
autocmd cursorhold,bufwritepost * unlet! b:statusline_tab_warning
  • هذا للتحقق مما إذا كان وضع اللصق مفعلاً، أحب أن أرى ذلك في خط حالتني أيضاً.
function! HasPaste()
if &paste
return '[PASTE]'
else
return ''
endif
endfunction
  • لا تغلق النافذة عند حذف مخزن.
command! Bclose call <SID>BufcloseCloseIt()
function! <SID>BufcloseCloseIt()
let l:currentBufNum = bufnr("%")
let l:alternateBufNum = bufnr("#")

if buflisted(l:alternateBufNum)
buffer #
else
bnext
endif

if bufnr("%") == l:currentBufNum
new
endif

if buflisted(l:currentBufNum)
execute("bdelete! ".l:currentBufNum)
endif
endfunction
  • بما أن لكل شخص معاييره الخاصة لاستخدام التبويبات أو المسافات، هذه الدالة تتيح التبديل بين التبويبات والمسافات، لتسهيل الأمر.
function! TabToggle()
if &expandtab
set noexpandtab
retab!
else
set expandtab
retab
endif
endfunction
  • عرض تظليل أحمر على عمود اللون 80.
function! g:ToggleColorColumn()
if &colorcolumn != ''
setlocal colorcolumn&
else
setlocal colorcolumn=80
endif
endfunction
nnoremap <silent> <leader>cc :call g:ToggleColorColumn()<CR>
  • كثيراً ما عندما أبحث عن تعبير نمطي، أردت نسخ جميع التطابقات الموجودة ولصقها في مكان آخر، ولهذا السبب أستخدم هذه الدالة.
    • :CopyMatches لنسخ جميع التطابقات إلى الحافظة.
    • :CopyMatches x حيث x هو أي سجل لحمل النتيجة.
    • اللصق من السجل x باستخدام "xp أو "xP.
function! CopyMatches(reg)
let hits = []
%s//\=len(add(hits, submatch(0))) ? submatch(0) : ''/ge
let reg = empty(a:reg) ? '+' : a:reg
execute 'let @'.reg.' = join(hits, "\n") . "\n"'
endfunction
command! -register CopyMatches call CopyMatches(<q-reg>)
  • إلحاق modeline بعد آخر سطر في المخزن.
function! AppendModeline()
let l:modeline = printf(" vim: set ft=%s ts=%d sw=%d %set %sai : ",
\ &filetype, &tabstop, &shiftwidth, &expandtab ? '' : 'no', &autoindent ? '' : 'no')
let l:modeline = substitute(&commentstring, "%s", l:modeline, "")
call append(line("$"), l:modeline)
endfunction
nnoremap <silent> <Leader>ml :call AppendModeline()<CR>
  • إعادة محاذاة المخازن عندما ينتقل iTerm إلى ملء الشاشة
augroup FixProportionsOnResize
au!
au VimResized * exe "normal! \<c-w>="
augroup END
  • تظليل جميع نسخ الكلمة تحت المؤشر، عندما يكون خاملاً. مفيد عند دراسة كود مصدر غريب. اكتب z/ لتبديل التظليل تشغيل/إيقاف.
nnoremap z/ :if AutoHighlightToggle()<Bar>set hls<Bar>endif<CR>
function! AutoHighlightToggle()
let @/ = ''
if exists('#auto_highlight')
au! auto_highlight
augroup! auto_highlight
setl updatetime=100
echo 'Highlight current word: off'
return 0
else
augroup auto_highlight
au!
au CursorHold * let @/ = '\V\<'.escape(expand('<cword>'), '\').'\>'
augroup end
setl updatetime=100
echo 'Highlight current word: ON'
return 1
endif
endfunction

يمكن العثور على جميع المعلومات حول أوامر vim باستخدام نظام المساعدة في vim عن طريق كتابة :help command أو النظر في التوثيق عبر الإنترنت، لأنه واضح ومباشر جداً. المجموعة الكاملة لـ vimrc الخاصة بي موجودة على GitHub. هناك أستخدم مستودع لجميع ملفات dotfiles الخاصة بي، وتكوينات bash وtmux.

لا تتردد في اقتراح تحسينات.

العودة للأعلى