🐲

自分のデストップに合うNeovimテーマがなかったので、作ってみた。

に公開

第1章:はじめに。

デスクトップテーマから始まった

落ち着いた緑を基調にした、自作のデスクトップテーマをこんな感じで整えていました。

ですが、同じ雰囲気のNeovimテーマがない。
既存テーマをカスタマイズしても微妙に理想に届かない。
そこで、自分の手で作るしかないと思い立ちました。
そして作ったのが yoda.nvim です。

この記事で学べること

この記事では、テーマ制作の流れを追いながら以下を学びます。

  • Neovimテーマの基本構造

最初は「Hello, Theme!」から始めましょう。


第2章:最初のテーマを作る

colorschemeコマンドの裏側

Neovimのテーマ切り替えは次の1行でできます。

:colorscheme tokyonight <--- 自分の好きなテーマ

Neovimは内部で以下の処理を行います。

  1. colors/mytheme.lua を探す
  2. ファイルを実行して色設定を反映する

つまり、テーマとは「色を設定したLuaファイル」なのです。


“Hello, Theme!”

次の3行だけでテーマが動きます。

-- ~/.config/nvim/colors/mytheme.lua
vim.cmd('highlight clear')
vim.o.background = 'dark'
vim.cmd('highlight Normal guibg=#1a1a1a guifg=#e0e0e0')

:colorscheme mytheme を実行すれば背景と文字色が切り替わります。


highlightの基本

highlight は「どの部分を何色で表示するか」を指定します。

vim.cmd('highlight Comment guifg=#608b4e') -- コメント
vim.cmd('highlight String guifg=#ce9178')  -- 文字列
vim.cmd('highlight Keyword guifg=#c586c0') -- キーワード

🧩 ハイライトグループとは「UI部品の名前」のこと。
Normal, Comment, Keyword, String などが代表例です。

カーソル位置のグループは :Inspect で確認できます。
これを知っておくだけで、テーマ制作が一気にスムーズになります。


Luaらしい書き方にする

vim.api.nvim_set_hl() を使うと、より整理された記法になります。

local colors = {
  bg = '#1a1a1a', fg = '#e0e0e0',
  comment = '#608b4e', string = '#ce9178',
  keyword = '#c586c0', func = '#dcdcaa',
}

local function hi(group, opts)
  vim.api.nvim_set_hl(0, group, opts)
end

hi('Normal', { bg = colors.bg, fg = colors.fg })
hi('Comment', { fg = colors.comment, italic = true })
hi('String', { fg = colors.string })
hi('Keyword', { fg = colors.keyword, bold = true })
hi('Function', { fg = colors.func })

読みやすく、再利用もしやすくなりました。


構造を整える

最終的なディレクトリ構成はこうなります。

mytheme/
├── colors/
│   └── mytheme.lua      # エントリーポイント
└── lua/
    └── mytheme/
        ├── init.lua     # メインロジック
        └── palette.lua  # 色定義

colors/mytheme.luarequire('mytheme').load() を呼び出すだけ。
本体の処理は lua/mytheme/init.lua にまとめましょう。


第3章:コアハイライト設計 - エディタに命を吹き込む

Normalを基準に考える

すべての配色は Normal から始まります。
この1行が全体の明暗バランスを決めます。

vim.api.nvim_set_hl(0, 'Normal', { bg = colors.bg, fg = colors.fg })

UI層の階層構造

NeovimのUIは階層的に整理できます。

hi('CursorLine', { bg = colors.bg_light })          -- レベル1
hi('Visual', { bg = colors.selection })              -- レベル2
hi('NormalFloat', { bg = colors.bg_lighter })        -- フロート
hi('CursorLineNr', { fg = colors.accent, bold = true }) -- 注目点

NormalCursorLineVisualFloat と段階をつけると、視線の流れが自然になります。


ステータスラインやサイドバー

hi('StatusLine', { bg = colors.bg_status, fg = colors.fg, bold = true })
hi('LineNr', { fg = colors.fg_dim })
hi('SignColumn', { bg = colors.bg })

最低限のUI整備で、もうプロフェッショナルな見た目に。


強調と診断表示

hi('ErrorMsg', { fg = colors.error, bold = true })
hi('WarningMsg', { fg = colors.warning })
hi('Search', { bg = colors.bg_search })
hi('IncSearch', { bg = colors.accent, fg = colors.bg })

⚡ 「常に目に入るが、邪魔しない」
これがテーマ設計の理想です。


第4章:TreeSitterでコードに命を吹き込む

Neovimでは今や TreeSitter が標準的な構文解析エンジン。
文脈を理解したハイライトが可能です。

local h = vim.api.nvim_set_hl
h(0, 'Comment', { fg = colors.comment, italic = true })
h(0, '@comment', { link = 'Comment' })

h(0, 'String', { fg = colors.string })
h(0, '@string', { link = 'String' })

h(0, 'Function', { fg = colors.func })
h(0, '@function', { link = 'Function' })

TreeSitterグループ(@stringなど)はより正確に構造を捉えます。
多色化しすぎず、関連要素を同系色でまとめるのがコツです。


第5章:Telescope対応 - プラグインとの調和

素晴らしいテーマでも、プラグインの色が合わないと台無しです。
代表例として、ファジーファインダー「Telescope」対応を見てみましょう。

-- lua/yoda/plugins/telescope.lua
local h = vim.api.nvim_set_hl
h(0, 'TelescopePromptNormal', { bg = colors.bg_search, fg = colors.fg })
h(0, 'TelescopePromptTitle',  { bg = colors.accent, fg = colors.bg })
h(0, 'TelescopeSelection',    { bg = colors.bg_highlight, bold = true })
h(0, 'TelescopeMatching',     { fg = colors.match, bold = true })

この4つの調整だけで、Telescopeウィンドウがテーマ全体と溶け込みます。

他の主要プラグインも同様の仕組みで対応可能です。

プラグイン 機能
Neo-tree ファイルツリー
nvim-cmp 補完メニュー
Gitsigns Git差分表示
Lualine ステータスライン

第6章:カスタマイズできるテーマ設計

ユーザーごとに「こうしたい」が違います。
背景の透明化、コメントの斜体、関数色の変更……
これらを可能にするのが setup() 関数です。

-- lua/yoda/init.lua
local M = {}

M.defaults = {
  transparent_background = false,
  italic_comments = true,
  colors = {},
  custom_highlights = {},
}

function M.setup(user_config)
  M.config = vim.tbl_deep_extend('force', M.defaults, user_config or {})
end

return M

カスタマイズ例

背景を透明に

require('yoda').setup({
  transparent_background = true,
})

独自ハイライトを追加

require('yoda').setup({
  custom_highlights = {
    Function = { fg = '#ff8800', bold = true },
    ['@string'] = { fg = '#99cc99' },
  }
})

これだけで“自分好みのテーマ”に変えられます。


第7章:公開しよう

完成したらGitHubで公開しましょう。(READMEにはインストール例を載せておくと親切です。)

ほとんどの方がLazyvimを使っているので、公開自体はこれだけで、完了です。
ここまで読んでくださり、ありがとうございました。
あなたのNvimテーマをGithubで見れることを楽しみにしています!

kuri-sun

Discussion