Ctags, Completion
1 юни 2023
Преговор
- Структура на един плъгин, документация
- (Идея за use/abuse на doc таговете за бележки)
Преговор
- Структура на един плъгин, документация
- (Идея за use/abuse на doc таговете за бележки)
- Организация на код и данни в "обекти"
Преговор
- Структура на един плъгин, документация
- (Идея за use/abuse на doc таговете за бележки)
- Организация на код и данни в "обекти"
- Quickfix, makeprg, compiler
Преговор
- Структура на един плъгин, документация
- (Идея за use/abuse на doc таговете за бележки)
- Организация на код и данни в "обекти"
- Quickfix, makeprg, compiler
- Още навигация -- "намери ми символ"
Довършващи неща: Дефиниране на функции за навигация
Вариант 1: глобални команди в локален файл
" Check if editing a directory
autocmd VimEnter * call s:MaybeEnterDirectory(expand("<amatch>"))
function! s:MaybeEnterDirectory(file)
if a:file == '' || !isdirectory(a:file)
return
endif
let dir = a:file
exe "cd ".fnameescape(dir)
if filereadable('_project.vim')
edit _project.vim
setfiletype vim
source _project.vim
endif
endfunction
Оттам мога да извикам примерно runtime! projects/rails.vim
: Vimfiles/projects/
Довършващи неща: Дефиниране на функции за навигация
- Потенциално може да пробвате
:help 'exrc'
Довършващи неща: Дефиниране на функции за навигация
- Потенциално може да пробвате
:help 'exrc'
- Или този ужасяващо стар плъгин: Proj
Довършващи неща: Дефиниране на функции за навигация
- Потенциално може да пробвате
:help 'exrc'
- Или този ужасяващо стар плъгин: Proj
- Впрочем: "организация на проекти" не е лоша идея за проект
Довършващи неща: Дефиниране на функции за навигация
Вариант 2: буфер-локални променливи (the Tim Pope way)
autocmd FileType * if RailsDetect() | call rails#buffer_setup() | endif
И една купчина други аутокоманди
Detection-a се свежда до "има ли Gemfile.lock" в родителска директория (:help findfile()
). И командите се дефинират само в този буфер и така във всеки следващ.
Довършващи неща: Ctags
Ако минем твърде бързо, или ви се чете, две стари статии:
Ctags: История
Оригиналния ctags е само за C, hence the name. После излиза Exuberant ctags, което започва да се използва мега много, и наскоро Universal ctags, което е поддържаната версия.
Съществуват разни language-specific алтернативи за haskell, за rust, за ruby, със смесен успех.
Ctags: Генериране
ctags -R .
Ако искате да индексирате и пакетите, освен вашия код, трябва да намерите директориите им. Аз имам bundle-tags за руби и cargo-tags за Rust (което използва cargo-local)
Ctags: Употреба
<C-]>
на символ (:help CTRL-]
)
Ctags: Употреба
<C-]>
на символ (:help CTRL-]
):tselect <tag>
Ctags: Употреба
<C-]>
на символ (:help CTRL-]
):tselect <tag>
- И една купчина други:
:help tags-and-searches
Ctags: Употреба
<C-]>
на символ (:help CTRL-]
):tselect <tag>
- И една купчина други:
:help tags-and-searches
- Вкарване в quickfix прозореца: https://github.com/AndrewRadev/tagfinder.vim
Ctags: Употреба
<C-]>
на символ (:help CTRL-]
):tselect <tag>
- И една купчина други:
:help tags-and-searches
- Вкарване в quickfix прозореца: https://github.com/AndrewRadev/tagfinder.vim
- Completion:
<C-X><C-]>
(:help CTRL-X_CTRL-]
)- Имате и
getcompletion
, примерноecho getcompletion('Hash', 'tag')
ще ви даде HashMap, HashSet, Hasher…
- Имате и
Ctags: Сериозна употреба
:help taglist()
-- намира тагове по регекс. Много добра идея е винаги регекса да започва със^
, защото Vim може да намери match-овете с binary search.:help tag-regexp
Ctags: Сериозна употреба
:help taglist()
-- намира тагове по регекс. Много добра идея е винаги регекса да започва със^
, защото Vim може да намери match-овете с binary search.:help tag-regexp
- Таговете могат да съдържат метаданни, които да ви дадат информация това клас ли е, trait ли е, enum ли е?
Ctags: Сериозна употреба
:help taglist()
-- намира тагове по регекс. Много добра идея е винаги регекса да започва със^
, защото Vim може да намери match-овете с binary search.:help tag-regexp
- Таговете могат да съдържат метаданни, които да ви дадат информация това клас ли е, trait ли е, enum ли е?
- Примерно: rustbucket
Ctags: Сериозна употреба
:help taglist()
-- намира тагове по регекс. Много добра идея е винаги регекса да започва със^
, защото Vim може да намери match-овете с binary search.:help tag-regexp
- Таговете могат да съдържат метаданни, които да ви дадат информация това клас ли е, trait ли е, enum ли е?
- Примерно: rustbucket
:help tagfunc
, и пример за употреба във моите Vimfiles
Ctags: Сериозно генериране
- autotag -- иска python
Ctags: Сериозно генериране
Ctags: Сериозно генериране
- autotag -- иска python
- gutentags -- едно време ми беше бъгав, но преди много време
- Git hooks? https://tbaggery.com/2011/08/08/effortless-ctags-with-git.html
Ctags: Сериозно генериране
- autotag -- иска python
- gutentags -- едно време ми беше бъгав, но преди много време
- Git hooks? https://tbaggery.com/2011/08/08/effortless-ctags-with-git.html
- Ако нещо не сработи, просто регенерирам 🤷
:RebuildTags
отнема по-малко от секунда на доста голям проект
Ctags: Има ли смисъл?
- Накратко: да
Ctags: Има ли смисъл?
- Накратко: да
- Ctags не е перфектно, но много рядко ви трябва "перфектно". "Намери символ" работи супер почти винаги. В ситуациите, в които не работи (примерно функция, която се казва "call" или "new"), обикновено ще имате други начини за навигация
Ctags: Има ли смисъл?
- Накратко: да
- Ctags не е перфектно, но много рядко ви трябва "перфектно". "Намери символ" работи супер почти винаги. В ситуациите, в които не работи (примерно функция, която се казва "call" или "new"), обикновено ще имате други начини за навигация
- LSP сървър може да ви даде много по-прецизна информация (ако ви се чака), но
- Има много по-малко покритие на езици и технологии
- Има си своите бъгове (кой както го е имплементирал)
- Доста по-тежко е
Ctags: Има ли смисъл?
- Накратко: да
- Ctags не е перфектно, но много рядко ви трябва "перфектно". "Намери символ" работи супер почти винаги. В ситуациите, в които не работи (примерно функция, която се казва "call" или "new"), обикновено ще имате други начини за навигация
- LSP сървър може да ви даде много по-прецизна информация (ако ви се чака), но
- Има много по-малко покритие на езици и технологии
- Има си своите бъгове (кой както го е имплементирал)
- Доста по-тежко е
- Тагове могат да се генерират с регекси, но могат и да се генерират с истински парсър като syn. Формата е ужасно прост.
Ctags: Има ли смисъл?
- Накратко: да
- Ctags не е перфектно, но много рядко ви трябва "перфектно". "Намери символ" работи супер почти винаги. В ситуациите, в които не работи (примерно функция, която се казва "call" или "new"), обикновено ще имате други начини за навигация
- LSP сървър може да ви даде много по-прецизна информация (ако ви се чака), но
- Има много по-малко покритие на езици и технологии
- Има си своите бъгове (кой както го е имплементирал)
- Доста по-тежко е
- Тагове могат да се генерират с регекси, но могат и да се генерират с истински парсър като syn. Формата е ужасно прост.
- Както винаги, напомням че не е нужно да имате само един начин да навигирате и манипулирате код.
Ctags: Идеи за проекти
- Gutentags/Autotag клонинг, защо не?
Ctags: Идеи за проекти
- Gutentags/Autotag клонинг, защо не?
- LSP сървър, който използва ctags?
Ctags: Идеи за проекти
- Gutentags/Autotag клонинг, защо не?
- LSP сървър, който използва ctags?
- Генератор на тагове за любим език? (интеграция с Vim в случая ще рече -- използва метаданните в таговете за нещо интересно, умен completion, линкове към документация…).
Ctags: Идеи за проекти
- Gutentags/Autotag клонинг, защо не?
- LSP сървър, който използва ctags?
- Генератор на тагове за любим език? (интеграция с Vim в случая ще рече -- използва метаданните в таговете за нещо интересно, умен completion, линкове към документация…).
- Просто може да използвате каквото имате от ctags като метаданни като част от друг проект
Insert-mode Completion
:help ins-completion
:help CTRL-X_CTRL-N
-- completion на думи в буфера
Insert-mode Completion
:help ins-completion
:help CTRL-X_CTRL-N
-- completion на думи в буфера:help CTRL-X_CTRL-L
-- completion на цели редове
Insert-mode Completion
:help ins-completion
:help CTRL-X_CTRL-N
-- completion на думи в буфера:help CTRL-X_CTRL-L
-- completion на цели редове:help CTRL-X_CTRL-F
-- completion на файлове
Insert-mode Completion
:help ins-completion
:help CTRL-X_CTRL-N
-- completion на думи в буфера:help CTRL-X_CTRL-L
-- completion на цели редове:help CTRL-X_CTRL-F
-- completion на файлове:help CTRL-X_CTRL-]
-- completion на тагове
Insert-mode Completion
:help ins-completion
:help CTRL-X_CTRL-N
-- completion на думи в буфера:help CTRL-X_CTRL-L
-- completion на цели редове:help CTRL-X_CTRL-F
-- completion на файлове:help CTRL-X_CTRL-]
-- completion на тагове:help CTRL-X_CTRL-V
-- completion на vim команди
Insert-mode Completion
:help complete-functions
:help CTRL-X_CTRL-U
-- user completion със&completefunc
- Интересна default-на стойност:
set completefunc=syntaxcomplete#Complete
- Интересна default-на стойност:
:help CTRL-X_CTRL-O
-- user completion със&omnifunc
Insert-mode Completion
Пример: strftime completion: strftime.vim
Функцията се вика два пъти, веднъж със findstart
истина, веднъж лъжа. При първото викане, искаме да върнем на коя колона започва completion-а. При второто, връщаме списък с думи, които complete-ват:
function! strftime#Complete(findstart, base)
if a:findstart
" Намери началото и върни номер на колона или отрицателно число, за да спреш completion-а
else
" Върни списък от думи, или `{ word: ..., menu: ..., ... }`
endif
endfunction
Rust импорти
- Регекси, регекси, регекси
Rust импорти
- Регекси, регекси, регекси
- Как да проверим, че символите са usable? Може да пробваме
taglist('^', item, filename)
Готин трик
inoremap <expr> <Plug>StrftimeComplete <SID>CompleteOnce()
function s:CompleteOnce()
let b:saved_completefunc = &completefunc
set completefunc=strftime#Completefunc
autocmd CompleteDone * ++once let &completefunc = b:saved_completefunc
autocmd CompleteDone * ++once unlet b:saved_completefunc
return "\<c-x>\<c-u>"
endfunction
Можем да си изберем наша клавишна комбинация примерно със:
imap <c-x><c-d> <Plug>StrftimeComplete
Какво е <SID>
?
Това би дало грешка:
inoremap <expr> <Plug>StrftimeComplete s:CompleteOnce()
E120: Using <SID> not in a script context: s:CompleteOnce
Функцията s:CompleteOnce
е script-local… Но когато изпълняваме мапинга, той все едно бива "написан" в командния ред, което е различен контекст.
Конкретно при мапинги, скрипт-локални функции и променливи могат да се реферират със <SID>
. :help <SID>
Completion
Има много повече за четене, но не го ползвам често. Ако решите да пишете completion script за проект, започнете от това да прочетете цялата документация във
:help complete-functions
, и може би също така::help 'completeopt'
:help CompleteChanged
:help pumvisible()
Completion: примери
- Всички "complete" функции във
$VIMRUNTIME
: runtime/autoload/
Completion: примери
- Всички "complete" функции във
$VIMRUNTIME
: runtime/autoload/ - Perl completion-а, който писахме със Стефан в някакъв изблик и той не е използвал оттогава: ftplugin/perl.vim
Completion: примери
- Всички "complete" функции във
$VIMRUNTIME
: runtime/autoload/ - Perl completion-а, който писахме със Стефан в някакъв изблик и той не е използвал оттогава: ftplugin/perl.vim
- Интересна функция, която е по-умен line completion: https://www.reddit.com/r/vim/comments/13v0mz2/line_suffix_completion/ (писана на vim9script, но за това следващата лекция)
Completion: примери
- Всички "complete" функции във
$VIMRUNTIME
: runtime/autoload/ - Perl completion-а, който писахме със Стефан в някакъв изблик и той не е използвал оттогава: ftplugin/perl.vim
- Интересна функция, която е по-умен line completion: https://www.reddit.com/r/vim/comments/13v0mz2/line_suffix_completion/ (писана на vim9script, но за това следващата лекция)
- Rust нещата ще ги кача някъде в някакъв момент
Автоматичен completion
- Acp -- мега стар плъгин
Автоматичен completion
- Acp -- мега стар плъгин
- … който аз използвам с ей тези настройки: acp.vim
- mucomplete -- вероятно по-добра идея и доволно популярен
Автоматичен completion
- Acp -- мега стар плъгин
- … който аз използвам с ей тези настройки: acp.vim
- mucomplete -- вероятно по-добра идея и доволно популярен
- Може би asyncomplete, макар че целта му изглежда малко различна
Асорти
Асорти
- Tim Pope има плъгин за писане на плъгини: https://github.com/tpope/vim-scriptease
- Undo (
:help undo-tree
, mundo, Gundo) - Сесии (
:help mksession
) - Vimdiff (
:help vimdiff
,:help 'diffopt'
) :help <Leader>
,:help <Localleader>