я награвся різними колірними темами для vim: котрісь дуже сподобались, більшість — ні; переважно уникав тем «клоуна знудило» і пробував стримані, навіть однотонні. насамкінець спробував знайти мінімалістичну «прозору» тему, котра б просто покладалась на кольори терміналу, і додавала може один колірний акцент. точно такого, як хотів, не знайшлося, і захотілося розібратися, як швиденько змайструвати тему самотужки.
натхнення
найближче до того, що мені сподобалось наприкінці моїх пошуків:
- quiet (maxence weynans) — одна з нових стандартних тем vim, повністю однотонна з помірним контрастом і одним колірним акцентом; «прозора» — в тому сенсі, що уникає змін тла й покладається на базові 16 кольорів терміналу, а отже добре узгоджується з темою терміналу; недоліки: мені не подобається фуксиновий акцент і невиразність майже повністю одноманітного тексту;
- bruin (romain lafourcade) — контрастна й більше типографічна, ніж колірна тема: агресивно використовує атрибути тексту (жирний, нахилений, підкреслений) і яскравість, ніж кольори; «прозора»; з недоліків (як на мій смак) — місцями надмірна контрастність і брак консистентності у використанні кольорів;
- warlock (martin hardselius) — монохромна тема в тепло-сірих тонах і з помірним контрастом, що повністю уникає кольорів; з недоліків — брак акценту, ані кольором, ані текстовими атрибутами, «непрозорість» (вигляд відрізняється від терміналу під vim’ом), і мені не подобається використання різного тла.
можна було би взяти будь-яку з цих трьох тем і трішечки адаптувати для себе. проте мені було цікаво, як влаштовані теми vim і чи складно зробити щось «з нуля».
що я хочу?
хотілося б поєднати найкращі риси трьох перелічених тем:
- «прозорість» для палітри терміналу під vim’ом;
- монохромна основа: відтінки сірого;
- синтаксична підсвітка — стримана, за рахунок тонів
- один колірний акцент, як у quiet, але з іншим кольором;
- не надмірна контрастність (хоча це залежатиме від терміналу);
- помітно тьмяніший за основний відтінок для нумерації рядків та недрукованих символів.
робоча назва для першої спроби — embers, як у «ashes and embers» (попіл та жар), тому що тема буде переважно темна в тонах від чорного до білого, з червоним акцентом (і, можливо, трохи жовтого для окремих елементів інтерфейсу).
підготовка
підготовка робочої теки:
~> mkdir -p ~/projects/vim/vim-embers/colors
~> cd ~/projects/vim/vim-embers
# порожній файл майбутньої теми
…vim-embers> touch colors/embers.vim
# лінк на цей файл там, де vim шукає теми
…vim-embers> ln -s $HOME/projects/vim/vim-embers/colors/embers.vim $HOME/.vim/colors/embers.vim
# git, тому що без нього неправильно
…vim-embers> git init
за взірець варто брати стандартну тему: вони, як правило, дуже якісні, добре структуровані, і дотримуються вельми суворих обмежень; в мене quiet лежить тут:
…vim-embers> ls -l /usr/share/vim/vim*/colors/quiet.vim
-rw-r--r-- 1 root root 38959 січ 2 13:36 /usr/share/vim/vim91/colors/quiet.vim
…vim-embers> cp /usr/share/vim/vim91/colors/quiet.vim ~/projects/vim/vim-embers/colors
невелика функція (додати до .vimrc
) для визначення колірної групи слова/символа під курсором (:help highlight
):
" функція для визначення групи highlight слова під курсором
" використання: call SynGroup()
" або <Leader>h (зазвичай \h) в нормальному режимі
function! SynGroup()
let l:s = synID(line('.'), col('.'), 1)
echo synIDattr(l:s, 'name') . ' -> ' . synIDattr(synIDtrans(l:s), 'name')
endfun
nnoremap <Leader>h :call SynGroup()<CR>
скрипт colortest.vim
для відображення кольорів за назвами:
:source $VIMRUNTIME/syntax/colortest.vim
скрипт hitest.vim
для відображення всіх активних груп з використанням відповідних стилів:
:source $VIMRUNTIME/syntax/hitest.vim
анатомія колірної теми
опційний заголовок-коментар:
" Name: quiet
" Description: A mostly monochrome colorscheme, with a few niceties.
" ...
далі короткий блок для скидання поточної колірної теми й підсвітки синтаксису, якщо є:
hi clear
if exists("syntax_on")
syntax reset
endif
і назва теми:
let g:colors_name = 'quiet'
g:
в назві змінної визначає контекст (глобальний) змінної. далі в quiet йде блок, котрий зв’язує семантичні групи між собою:
hi! link Terminal Normal
загальний сенс рядка: для семантичної групи terminal
встановити такі ж атрибути, як у normal
. hi
— це highlight
(див. :help highlight
); знак оклику в hi! link...
потрібен, бо за замовчуванням зв’язування груп не працює, якщо перша група вже має якісь атрибути (кольори, атрибути тексту, — наприклад, встановлені іншою темою чи в .vimrc), тому треба примусово встановити прив’язку. тобто деінде в файлі теми має бути інший рядок, що фактично задає стиль групі normal
, або декілька:
hi Normal guifg=#dadada guibg=#000000 gui=NONE cterm=NONE
...
hi Normal ctermfg=253 ctermbg=16 cterm=NONE
...
hi Normal term=NONE
guifg
,guibg
,gui
— колір символа, тла, додаткові атрибути в графічному інтерфейсі;ctermfg
,ctermbg
,cterm
— те саме в кольоровому терміналі (cterm)term
— атрибути тексту для базового терміналу.
ці три рядки можна було би об’єднати, і деякі теми так і влаштовані:
hi Normal term=NONE ctermfg=253 ctermbg=16 cterm=NONE guifg=#dadada guibg=#000000 gui=NONE
…але найчастіше визначення стилів згруповано в умовний блок: окремо для графічного інтерфейсу, для кольорового терміналу і для базового терміналу. ось так у quiet (я не певен, що тут не наплутано трохи):
let s:t_Co = has('gui_running') ? -1 : (&t_Co ?? 0)
if (has('termguicolors') && &termguicolors) || has('gui_running')
... " gui (termguicolor)?
endif
if s:t_Co >= 256 " повноколірний термінал?
...
unlet s:t_Co
finish
endif
if s:t_Co >= 16 " кольоровий термінал 256 кольорів?
...
unlet s:t_Co
finish
endif
if s:t_Co >= 8 " кольоровий термінал 16 кольорів?
...
unlet s:t_Co
finish
if s:t_Co >= 0 " базовий термінал?
...
unlet s:t_Co
finish
endif
t_Co
— глобальна опція, містить кількість кольорів в терміналі (:help t_Co
, також:echo &t_Co
); наскільки я розумію, не має впливу на vim, якщо той в режиміtermguicolors
(тому треба перевіряти окремо);s:t_Co
— локальна змінна (локальна для скрипта/теми), в яку завантажується доступна кількість кольорів для терміналу (&t_Co
), або-1
для графічного інтерфейсу.
всередині кожного такого блоку — різні налаштування для темного і світлого тла; фактично тема quiet наче містить дві: темну й світлу.
if &background ==# 'dark' " темна тема
...
else " світла тема
...
endif
нарешті, групи highlight… (:help highlight-groups
) їх багато; частина з них — стандартні (документація каже, що повна тема має обов’язково призначати їм стилі); інші — стосуються синтаксичної підсвітки різних мов і є опційними.
попіл та жар
отже, почнімо. заголовок:
" Name: embers
" Description: монохромна тема в віддінках сірого з типографічним виділенням та єдиним колірним
" акцентом червого кольору (попіл та жар) і прозорим тлом; покладається на основні
" кольори (ansi) задля кращої інтеграції з темою термінального емулятора.
" Author: tivasyk <tivasyk@gmail.com>
" Website: https://blog.malynka.duckdns.org
" Last Updated: 2024-02-20
прибирання, і назва теми:
hi clear
if exists("syntax_on")
syntax reset
endif
let g:colors_name = 'embers'
далі буде блок з визначенням базових стилів; на відміну від того, як це зроблено в quiet та інших темах, я хочу визначити базові стилі взагалі окремо. отже…
let s:t_Co = has('gui_running') ? -1 : (&t_Co ?? 0)
if (has('termguicolors') && &termguicolors) || has('gui_running')
" графічний інтерфейс або повноколірний емулятор терміналу
unlet s:t_Co
finish
elseif s:t_Co >= 256
" багатоколірний термінал
unlet s:t_Co
finish
elseif s:t_Co >= 16
" термінал 256 кольорів
unlet s:t_Co
finish
elseif s:t_Co >= 8
" термінал 16 кольорів
unlet s:t_Co
finish
else
" ймовірно, простий термінал без підтримки кольороів
unlet s:t_Co
finish
endif
додаткові матеріяли
- making a vim colorscheme (emilie ma) — надихнуло спробувати самому;
- vim’s colorscheme incubator — офіційний репозиторій стандартних тем vim (також посилання на wiki проєкту).
далі буде…