Vim 駅伝 2025/06/11 の投稿です。前回の記事は、あべべさんの vim マクロで楽する!実践例あり でした。
背景
久しぶりに Neovim に入門しています。今回は設定ファイルを Org ファイルにしてみようと思います。
- 設定ファイル:
init.org
README のような雰囲気のみご覧ください。
注意:
lazy.nvim
の設定に失敗しました。
Neovim の設定としては致命的な失敗があることをご了承お願いします。
Org とは
Org は主に Emacs で活躍するマークアップ言語です。 Org の処理系は文芸的プログラミングの機能を備えている場合があります。 Neovim の nvim-orgmode/orgmode
にも tangle が実装されており、これを使えば init.lua
を init.org
の中に埋め込むことができます。
Tangle とは
具体的には、以下の init.org
に対し org-babel-tangle
コマンドを実行すると、全ての Lua ブロックを連結した init.lua
が生成されます:
#+TITLE Neovim Configuration
#+STARTUP: nofold
#+PROPERTY: header-args:lua :tangle ./init.lua
* Bootstrapping
:PROPERTIES:
:VISIBILITY: folded
:END:
#+BEGIN_SRC lua
print("Hello, A!") -- 1
#+END_SRC
* Packages
#+BEGIN_SRC lua
print("Hello, B!") -- 2
#+END_SRC
生成結果は以下です:
print("Hello, A!")
print("Hello, B!")
このように init.lua
全体を init.org
に埋め込むことで、構造化ドキュメントとしての利便性を享受して設定ファイルを編集できます。
Cons
org-mode
のコードブロック中では、補間や言語サーバ等が動作しないかもしれません。この欠点は文芸的プログラミングに付き物だと思います。
- Neovim の場合
nvim-orgmode/orgmode
は言語サーバをサポートしていません。- Emacs の場合
lsp-bridge
だと簡単に動くかもしれません。lsp-mode
ではlsp-org
が動くはずですが、僕の環境では失敗しました。
どうしても言語サーバが必要な時は、 init.lua
の方を見に行くことにします。
環境構築
init.org
事始め
始めから init.org
を書きたいので、 Emacs で tangle する環境を作ります。 Emacs に不慣れな人も、コマンドラインツールとしての Emacs には抵抗が少ないのではないでしょうか。
Emacs の バッチモード (--batch
) で org-bable-tangle-file
を実行できます:
$ emacs --batch --eval "(require 'org)" --eval '(org-babel-tangle-file "init.org")'
Loading /nix/store/52b391v99j92cx9dka8py47cr8hx167b-emacs-unstable-30.1.90/share/emacs/site-lisp/site-start...
Tangled 1 code block from init.org
$ ls # init.lua が生成されました:
init.lua init.org
これを tangle
コマンドにしておけば、 emacs
の使い方を忘れても安心です:
#!/usr/bin/env bash
cd "$(dirname "$0")"
emacs --batch --eval "(require 'org)" --eval '(org-babel-tangle-file "init.org")'
(Nix ユーザ向け) 上記の tangle
コマンドを nix run .#tangle
から実行できるようにします:
flake.nix
一応動きます:
{
description = "A basic flake for generating `init.lua`";
inputs = {
flake-utils.url = "github:numtide/flake-utils";
};
outputs =
{ nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs { inherit system; };
tangleCommand = pkgs.writeShellApplication {
name = "run-tangle";
runtimeInputs = with pkgs; [emacs];
text = ''
./tangle;
'';
};
in
{
apps.tangle = flake-utils.lib.mkApp {
drv = tangleCommand;
};
}
);
}
$ nix run .#tangle
Tangled 2 code blocks from init.
これで init.org
から init.lua
を生成できるようになったので、 Neovim の設定が始められます。
Package Manager
packer.nvim
が流行ったのも今は昔、現在は lazy.nvim
と dpp.vim
の二強の時代のようです。今回は観光目的なので、簡単な lazy.nvim
の方を使います。
Not Structuring Your Plugins
lazy.nvim
のドキュメントでは、以下のファイル構成が 勧められています:
~/.config/nvim
├── lua
│ ├── config
│ │ └── lazy.lua
│ └── plugins
│ ├── spec1.lua
│ ├── **
│ └── spec2.lua
└── init.lua
これに沿って tangle
の出力先ファイルを切り替えても良いのですが、今回はファイル分割しない簡単な構成とします。これはこれでハマり所がありそうですが……:
~/.config/nvim
├── init.lua
└── init.org
Neovim 入門 + Tangle の設定
mattn/vim-tanakh
まずは lazy.nvim
の動作確認を兼ねて、 vim-tanakh
をゲットします:
#+BEGIN_SRC lua
{
"mattn/vim-tanakh"
},
#+END_SRC
tangle
してから Neovim を起動すると、ダッシュボードが起動し、プラグインをインストールできました:

lazy.nvim
のダッシュボード (格好いい!)
config
を設定すると、カーソル移動に応じてステータスバーが更新されるようになりました:
{
"mattn/vim-tanakh",
config = function()
vim.opt.statusline = vim.fn["tanakh#face"]()
vim.api.nvim_create_autocmd({"CursorMoved", "CursorMovedI"}, {
callback = function()
vim.opt.statusline = vim.fn["tanakh#face"]()
end
})
end,
},

普段は lazy = true
を設定して封印します。
nvim-orgmode/orgmode
lazy.nvim
の使い方が分かったところで、 Neovim から tangle できるように nvim-orgmode/orgmode をインストールしてみました。起動時にドキュメントが折り畳まれています:

init.org
Emacs から見るとこうで、 #+STARTUP: nofold
が反映されています。この動きが正しいです:

init.org
いきなり未実装機能 (nvim-orgmode/orgmode#394) を引いてしまいました。どうしても欲しい機能にはコントリビュートする必要がありそうです。
畳み込みの初期値
README に沿って最低限の設定をしてみます:
{
'nvim-orgmode/orgmode',
event = 'VeryLazy',
ft = { 'org' },
config = function()
require('orgmode').setup({
org_startup_folded = 'showeverything', -- 1
-- org_startup_indented = true,
org_agenda_files = '~/org/**/*',
org_default_notes_file = '~/org/refile.org',
})
end,
}
- 1 起動時に全ての畳み込みを開く設定にしました。
org-babel-tangle
nvim-orgmode/orgmode
を使って init.lua
を生成できるのか試してみます。一直線に DeepWiki に聞いてみると <Leader>obt
に org-babel-tangle
がマップされています。これを実行すると:
[orgmode] Tangled 0 blocks from init.org
何も起こらない! ファイル全体の #+PROPERTY
が実装されていません。
現状の対策としては、見出しの header-args
を設定するか:
* 見出し
:PROPERTIES:
:header-args:lua :tangle ./init.lua
:END:
コードブロック毎に :tangle
を書く必要があります:
#+BEGIN_SRC lua :tangle ./init.lua
print('hello')
#+END_SRC
僕は #+PROPERTY
で :tangle
の設定がしたかったので、 Emacs 依存の tangle
コマンドを使い続けることにしました。
Neovim から tangle
コマンドを実行する
SourceConfig
で tangle
を実行できるようにします:
vim.api.nvim_create_user_command("SourceConfig", function()
-- Run the `tangle` command
local config = vim.fn.stdpath("config")
local tangle = vim.fs.joinpath(config, "tangle")
vim.fn.system(tangle, config)
-- Reload the buffer in case it's `init.lua`
vim.cmd("edit!")
end, {})
また :s
が :SourceConfig
に展開されるようにしました。 Vimscript で恐縮ですが:
-- Abbreviate function:
-- https://stackoverflow.com/a/3879737
vim.cmd([[
function! Abbreviate(from, to)
exec 'cnoreabbrev <expr> '.a:from
\ .' ((getcmdtype() ==# ":" && getcmdline() ==# "'.a:from.'")'
\ .'? ("'.a:to.'") : ("'.a:from.'"))'
endfunction
call Abbreviate('s', 'SourceConfig')
call Abbreviate('ed', 'edit ~/.config/nvim/init.org')
call Abbreviate('h', 'tab help')
call Abbreviate('hs', 'split')
]])
本来は :SourceConfig
実行時に init.lua
を読み込む予定でしたが、 lazy.nvim
では init.lua
の再読み込みが禁止されていました:
Re-sourcing your config is not supported with lazy.nvim
派手に失敗していて申し訳ないですが、設定ファイルの変更内容をエディタに反映する方法は未検討です。
まとめ
久しぶりに Neovim に入門しました。 init.org
で Neovim の設定を書くのは結構アリだと感じています。 Org は Emacs 以外のエディタでガンガン使っても良いですし、 emacs
を CLI ツールとして使うのもポピュラーになったら良いなと思います。
Neovim は Telescope を始め各種プラグインの完成度が素晴らしく、また Lua が設定ファイルの記述に驚くほど適していると感じました。もっと変な Lua を読み書きしたいとすら思いました。 5 年遅れぐらいで熱が伝わってきたのかもしれません。イケています。
そんなわけで、 Neovim の入門記事にお付き合い頂きありがとうございました!
.| / ! / .l __/_ ! / / \ ! /. / _ノ \ .l │. /(● )(●) ありがとう! .| │ / (__人__) ! │. / ` ⌒´ノ ! │ / } | ノ./ヾ.ヘ } ..=ィ゙ニ| /、;i;i;ヾヘ _ノ . : :イ/{ / ̄ヾ}l!;i;i;iLc、> . / '/,ム{ ∧ }ー-,-、《;i〈 . !:.,'〃´ハ{/ ハ::〃,=ヾミ;i . :.:{/' 〃゙ヽ__ノヽi/´ }\ . :.:|!、/ ヽ::Y::/{ r、/ム .\ . !:.!ム ヽj::ノ{ | ,';i;iム ヽ. . Ⅵマ\ _ ヽ';i乂__.ソ;i;i;i;i| 丶 . トj0l|Y´\{ } Y;i;i;i;i;i;i;i;i;i;iト, \ . `!0j;iト、 ヾ__.人;i;i;i;i;i;i;i;i;i;i;{ \ . 〈ソ,∧ \ 「 ! Y;i;i;i;i;i;i;i;i;iム . j、;i;i;、 \___丿;i;i;i;i;i;i;i;i;i;iム . /.:::∨;i;i`i.、___ノ;i\;i;i;i;i;i;i;i;i;i;i;iム . ::::::::.∨;i;i|:;i;i;i;i;i;i;i;i;\;i;i;i;i;i;i;i;i;i;ム . 、_:::::::∨;i|:;i;i;i;i;i;i;i;i;i;i;i;丶:;i;i;i;i;i;i;i;ム . ::ーニ=イ};i:!:;i;i;i;i;i;i;i;i;i;i;i;i;i;i\:;i;i;i;i;i;i;i〉 . ヽ:::::::::ノ;i:!:;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i\:;i;i;/ . ヽ/;i;i:|:;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i\:〉 . ../;i;i;i;i;i:|:;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;\ . ,ゝ;i;i;i;i;i;i:|:;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i/ 丶 . i;i;i;i;i;i;i;i;i:|:;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;/ \ . i;i;i;i;i;i;i;i;i:!:;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i∧ . i;i;i;i;i;i;i;i;i:!:;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i/. ム . i;i;i;i;i;i;i;i;i:l:;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i//マ___ . 、i;i;i;i;i;i;i;i:|:;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;}/イ;;;;;;;;;`! . ';i;i;i;i;i;i;i;i:l:;i;i;i;i;i;i;i;i;i;i;i;i;i;i;i;iム.;;;;;;;;;;;;;;;;;〉