スキップしてメイン コンテンツに移動

dpp.vimの設定でハマったアホな話

dpp.vimの設定でハマったアホな話

本記事はVim駅伝 2024年11月13日の記事です。

気がつけば11月も折り返しが近づいてきていて「2024年もあと1ヶ月半か~時間の流れが早すぎるってばよ……」と思っているArcCosineです。皆様いかがお過ごしでしょうか。

今日の記事は、dpp.vimの設定をしていてハマったアホな話になります。

忙しい人のための要約

  • インストールパスを間違えない
  • 便利な自動設定コードを活用
  • dpp.vimの導入をスムーズに

もう少し詳しく知りたいと思った方は、続きをお読みください。

dpp.vimとは

dpp.vimとは

Dark Powered Plugin manager for Vim/NeoVim

の事で、俗に言うshougowareにおける最新のVimプラグインマネージャーです。 この一つ前は、dein.vimと呼ばれるプラグインマネージャーが活用さていました。dein.vimは中々画期的なプラグインマネージャーでした。dein.tomlやdein_lazy.tomlといったTOMLファイルを活用してプラグインの管理が色々出来るという事で、飛びついたのもありますし、何よりも高速化という言葉に弱い私にとっては大変魅力的なツールでした。しかし、dein.vimにも弱点が無かった訳ではありません。その辺の歴史に関しては、プラグインマネージャーの歴史と新世代のプラグインマネージャー dpp.vimという記事が大変詳しいです。

この記事は実は非常に重要な二次情報で(一次情報はgithubに挙げられているソースコード。プログラマは黙ってソースコード読みなさいというストロングスタイル)、ここに書いてある設定を読み込むならば、誰でも(誰でもとは言っていない)dpp.vimを導入することが出来るようになっています。 記事の前段部分があまりにもボリューミーなため、本当に必要な設定に関しては一番最後の方に書いてある上に、これはどういう事をしますという説明が省かれているため、初見さんにはかなり厳しい内容となっています。

とは言え、そういう思想のプラグインなので、楽に導入したいという人は、もっと楽に導入出来るプラグインマネージャーを採用すれば良いのです。無理して苦労して導入している人たちは、ごく一部の好事家と言えますね。

設定のハードルを下げる記事

さて、一部の好事家がこのdpp.vimの導入記事を書いてくれました。一番詳しいのはこもまかさんが書かれたNeovimでdpp.vimをセットアップするです。 今回、自分がNeovimにdpp.vimをインストールするにあたり、この記事を一番参考にしました。 この記事の通りに設定すれば、誰でも(誰でもとは言っていない)簡単にdpp.vimを導入出来ます。やったね!

はい。ここで罠にハマりました。と言っても、これは僕がアホなので、ハマっただけで、普通の人はハマりません。

こもまかさんの記事を見ますと、

mkdir -p ~/.cache/dpp/repos/github.com/
cd ~/.cache/dpp/repos/github.com/

mkdir Shougo
mkdir vim-denops

cd ./Shougo
git clone https://github.com/Shougo/dpp.vim

git clone https://github.com/Shougo/dpp-ext-installer
git clone https://github.com/Shougo/dpp-protocol-git
git clone https://github.com/Shougo/dpp-ext-lazy
git clone https://github.com/Shougo/dpp-ext-toml

cd ../vim-denops
git clone https://github.com/vim-denops/denops.vim

一番最初にこの環境設定のコードが出てきて、これの通りにやっていけば、問題なく物事は進みます。 が、何を思ったのか、僕はinit.luaの中で、

~/.cache

とされている部分を

vim.fn.stdpath("cache")

として、パス設定してしまったのです。その結果どうなったのでしょうか。

環境構築の想定インストール先は

~/.cache/dpp/repos/github.com/

だったのに、実際には

~/.cache/nvim/dpp/repos/github.com/

にインストールされているとinit.luaの中で、設定してしまったのです。 その結果、git cloneされているはずの、dpp.vimやdenops.vimが読み込まれないという状況に陥ってしまいました。 こんな初歩的なミスをして、数日間「動かね~~~」をやっていました。アホですねぇ。 余計なことをしたばっかりにこんな苦労をしています。皆様気をつけましょうね。

そうして結局こうなった

この違いに気がついてから、修正を一気に終わらせることが出来ました。dpp.vimを完全に理解しました

という事で、設定めんどうくせ~~~という方向けに、dpp.vimを導入するコードを公開します。 このコードを導入すると、dpp.vimやdenops.vimなどの環境構築処理をすっ飛ばす事が出来ます

init.luaに下記を記載するか、あるいは適当なluaファイルに貼り付けて読み込ませてください。 問題なく動作するはずです。

local cache_path = vim.fn.stdpath("cache") .. "/dpp/repos/github.com"
local dppSrc = cache_path .. "/Shougo/dpp.vim"
local denopsSrc = cache_path .. "/vim-denops/denops.vim"

-- Add path to runtimepath
vim.opt.runtimepath:prepend(dppSrc)

-- check repository exists.
local function ensure_repo_exists(repo_url, dest_path)
	if not vim.loop.fs_stat(dest_path) then
		vim.fn.system({ "git", "clone", "https://github.com/" .. repo_url, dest_path })
	end
end

ensure_repo_exists("vim-denops/denops.vim.git", denopsSrc)
ensure_repo_exists("Shougo/dpp.vim.git", dppSrc)

local dpp = require("dpp")

local dppBase = vim.fn.stdpath("cache") .. "/dpp"
local dppConfig = vim.fn.stdpath("config") .. "/config.ts"

-- option.
local extension_urls = {
	"Shougo/dpp-ext-installer.git",
	"Shougo/dpp-ext-toml.git",
	"Shougo/dpp-protocol-git.git",
	"Shougo/dpp-ext-lazy.git",
	"Shougo/dpp-ext-local.git",
}

-- Ensure each extension is installed and add to runtimepath
for _, url in ipairs(extension_urls) do
	local ext_path = cache_path .. "/" .. string.gsub(url, ".git", "")
	ensure_repo_exists(url, ext_path)
	vim.opt.runtimepath:append(ext_path)
end

-- vim.g.denops_server_addr = "127.0.0.1:41979"
-- vim.g["denops#debug"] = 1

if dpp.load_state(dppBase) then
	vim.opt.runtimepath:prepend(denopsSrc)
	vim.api.nvim_create_augroup("ddp", {})

	vim.api.nvim_create_autocmd("User", {
		pattern = "DenopsReady",
		callback = function()
			dpp.make_state(dppBase, dppConfig)
		end,
	})
end

vim.api.nvim_create_autocmd("User", {
	pattern = "Dpp:makeStatePost",
	callback = function()
		vim.notify("dpp make_state() is done")
	end,
})

if vim.fn["dpp#min#load_state"](dppBase) then
	vim.opt.runtimepath:prepend(denopsSrc)

	vim.api.nvim_create_autocmd("User", {
		pattern = "DenopsReady",
		callback = function()
			dpp.make_state(dppBase, dppConfig)
		end,
	})
end

vim.cmd("filetype indent plugin on")
vim.cmd("syntax on")

-- install
vim.api.nvim_create_user_command("DppInstall", "call dpp#async_ext_action('installer', 'install')", {})

-- update
vim.api.nvim_create_user_command("DppUpdate", function(opts)
	local args = opts.fargs
	vim.fn["dpp#async_ext_action"]("installer", "update", { names = args })
end, { nargs = "*" })

色々やっている事

  • denops.vimとdpp.vimがgit cloneされていなかったら、勝手にgit cloneする=こもまかさんの記事にある最初の環境設定をスキップできる
  • dpp-ext系も、勝手にgit cloneする。=変数化しているので、欲しくない機能はコメントアウトすればok。
  • プラグインのインストールやアップデート様に、DppInstallやDppUpdateコマンドを追加する。

最後のコマンド追加に関しては、dpp.vim(dpp-ext-installer)のinstallとupdateを少し使いやすくするをそのままコピペして使っています。

皆様も、コピペして使ってください。

もう一つの設定

dpp.vimには忘れてはならない設定として、config.tsの設定があります。僕は、config.tsを

~/.config/nvim/config.ts

に配置しています。 内容は

import {
    BaseConfig,
    ContextBuilder,
    Dpp,
    Plugin,
} from "https://deno.land/x/dpp_vim@v1.0.0/types.ts";
import { Denops, fn } from "https://deno.land/x/dpp_vim@v1.0.0/deps.ts";

type Toml = {
    hooks_file?: string;
    ftplugins?: Record<string, string>;
    plugins?: Plugin[];
};

type LazyMakeStateResult = {
    plugins: Plugin[];
    stateLines: string[];
};

export class Config extends BaseConfig {
    override async config(args: {
        denops: Denops;
        contextBuilder: ContextBuilder;
        basePath: string;
        dpp: Dpp;
    }): Promise<{
        plugins: Plugin[];
        stateLines: string[];
    }> {
        args.contextBuilder.setGlobal({
            protocols: ["git"],
        });

        const [context, options] = await args.contextBuilder.get(args.denops);
        const dotfilesDir = "~/.config/nvim/toml/";

        // use toml
        const tomls: Toml[] = [];
        const toml = (await args.dpp.extAction(
            args.denops,
            context,
            options,
            "toml",
            "load",
            {
                path: await fn.expand(args.denops, dotfilesDir + "/dein.toml"),
                //path: `${dotfilesDir}/dein.toml`,
                options: {
                    lazy: false,
                },
            }
        )) as Toml | undefined;
        if (toml) {
            tomls.push(toml);
        }

        const lazyToml = (await args.dpp.extAction(
            args.denops,
            context,
            options,
            "toml",
            "load",
            {
                path: await fn.expand(
                    args.denops,
                    dotfilesDir + "/dein_lazy.toml"
                ),
                //path: `${dotfilesDir}/dein_lazy.toml`,
                options: {
                    lazy: true,
                },
            }
        )) as Toml | undefined;
        if (lazyToml) {
            tomls.push(lazyToml);
        }

        const recordPlugins: Record<string, Plugin> = {};
        const ftplugins: Record<string, string> = {};
        const hooksFiles: string[] = [];

        tomls.forEach((toml) => {
            for (const plugin of toml.plugins) {
                recordPlugins[plugin.name] = plugin;
            }

            if (toml.ftplugins) {
                for (const filetype of Object.keys(toml.ftplugins)) {
                    if (ftplugins[filetype]) {
                        ftplugins[filetype] += `\n${toml.ftplugins[filetype]}`;
                    } else {
                        ftplugins[filetype] = toml.ftplugins[filetype];
                    }
                }
            }

            if (toml.hooks_file) {
                hooksFiles.push(toml.hooks_file);
            }
        });

        // use local
        const localPlugins = (await args.dpp.extAction(
            args.denops,
            context,
            options,
            "local",
            "local",
            {
                directory: "~/work",
                options: {
                    frozen: true,
                    merged: false,
                },
            }
        )) as Plugin[] | undefined;

        if (localPlugins) {
            // Merge localPlugins
            for (const plugin of localPlugins) {
                if (plugin.name in recordPlugins) {
                    recordPlugins[plugin.name] = Object.assign(
                        recordPlugins[plugin.name],
                        plugin
                    );
                } else {
                    recordPlugins[plugin.name] = plugin;
                }
            }
        }

        // use lazy
        const lazyResult = (await args.dpp.extAction(
            args.denops,
            context,
            options,
            "lazy",
            "makeState",
            {
                plugins: Object.values(recordPlugins),
            }
        )) as LazyMakeStateResult | undefined;

        //console.log(lazyResult);

        return {
            ftplugins,
            hooksFiles,
            plugins: lazyResult?.plugins ?? [],
            stateLines: lazyResult?.stateLines ?? [],
        };
    }
}

こんな感じです。 実は、こもまかさんの記事のconifg.tsは古くなっていて、returnのパラメータが足りない状態です。 しかし、Shougoさんの記事を見ると、ちゃんと書いてありますので、こちらをコピペすればオッケーです。 これも、地味にハマった罠でした。

僕がやっている設定

基本的に、この2箇所を設定すれば、dpp.vimは稼働できますが、それ以外の設定も見てみたいなと思われた方は

https://github.com/ArcCosine/ac-neovim-config

に設定ファイルを公開していますので、こちらを参考にしてみてください。 git cloneして、~/.config/nvim以下に中身を配置すれば動くと思います。 Windowsではもしかしたら、色々調整しなければならないかもしれませんので、その点は各自の環境に合わせて修正してください。 LinuxやMaxOS環境下、WSL2上のUbuntuでは特に調整しなくても勝手に動いてくれました。

導入した最初は、色々とgit cloneするので、画面が固まってそのままのNeovimが立ち上がります。そうなったら、一旦終了させて、またNeovimを立ち上げます。そこで

:DppInstall

を実行すると、各種プラグインのインストール(dein.tomlに書かれているファイル類)がされます。 そのインストールが終わった状態で、もう一度Neovimを終了させて再起動すれば、新しいNeovimに出会うことが出来るに違いありません。

,uj

とタイピングすると、Fernが立ち上がるようになっています。

最後に

ここまで、記事を読んでくださりありがとうございました。ハマりポイントを集約しますと

  • 設定用のPathを間違っていた
  • config.tsの返り値を間違っていた

この2点に集約されます。ノリと勢いで動かないdpp.vimは信用できるプログラムですね。 これをいい感じに解釈して動かされるとさらに困惑していたに違いありません。 dpp.vimの導入を考えておられる方の一助になればと考え、この記事を作成しました。 それでは皆様、良いdpp.vimライフを!

コメント

このブログの人気の投稿

EFIブートローダを移動した話

EFIブートローダを移動した HX90に環境を整え終わってから、アホな事をしたので、その記録を残す。 SSD: Cドライブ SSD: Dドライブ(データストレージ用) + ESP※ SSD: Eドライブ(データストレージ用) ※ESP(EFI System Partition) インストールした時、こんな構成だった。 ESPがDドライブにあるのが気持ち悪かったので、これを削除した。 そしたら、BIOS画面が出るだけになり、Windowsが起動しなくなった。 移動手順 この時の自分はMBRをふっ飛ばした時と同じ現象だと思ったので、MBRというキーワードで検索したが、今はEFIブートローダーと呼んでいるらしい。 【Win10】任意のディスクにEFIブートローダをインストールする 色々検索した結果この記事が参考になった。 Diskpartを使って、パーティションを新たに分割し、bcdbootを実行して、無事に事なきを得た。 パーティションの分割はこんな感じ Diskpart Select volume 0 shrink desired = 200 Select disk 0 Create partition EFI size=200 Format quick fs=fat32 label="ESP" Assign letter=P exit EFIブートローダーのインストールはこんな感じ bcdboot C:\Windows /s P: /f UEFI ちなみに、自分の環境だけの問題なのだが、コマンドラインで、「\」を入力するのができなかった。我が家のキーボードはHHKBだけなので、日本語配列を無理やり適用されると、バックスラッシュが入力できないという不具合が生じる。 結局、コマンドプロンプトからマウスで範囲選択してコピーして貼り付けるという荒業でクリアした。 普通の人は、何も考えずに、\を入力すれば良い。 最終的に SSD: Cドライブ + ESP※ SSD: Dドライブ(データストレージ用) SSD: Eドライブ(データストレージ用) ※ESP(EFI System Partition) という構成に切り替えることができた。

Windows版gVimをアンインストールした日

Windows 版 gVim をアンインストールした話 以前に、 Windows11 on WSL2 + wezterm + Neovim = 最強開発環境 という痛々しい記事を書いたのだが、その続きの記事と言っても過言ではない。 この記事は Vim 駅伝 の 3 月 1 日の記事である。 前回はぺりーさんの netrw を使うために という記事だった。 次回は kuuote さんの Vim 側の組み込みプラグインを無効化するハック という記事である。 gVim との付き合い 思い返してみると、gVim との付き合いは大分長くなった。エディタとしては 自分の人生の中で最も長く付き合ってきたエディタ と言える。Vim のインターフェースとして gVim を何度も使ってきた。自分の手持ちのマシンは Windows なので、必然的に gVim を選択肢として選ぶ必要があった。 gVim の良さは何か。それは、Windows とのシームレスな関係であり、Windows OS の機能をそのまま使いたい場合に有用である。かつての自分にとってこの部分は非常に重要であった。具体的には、印刷機能と画面半透明化機能であり、これが無いとやってられないという認識であった。 しかし、時代が進み、自分の技術力の向上や考え方の変化、さらに Vim 周りのプラグインの更新が進むと gVim で運用していく事がだんだんと億劫になっていったというのが事実である。故に、 WSL2 上で動く Neovim の快適さに心が打ち震えた のである。 技術力の向上に伴う考え方の変化 かつての自分は 何でも gVim で処理したいな と考えていた。メールを見たり天気を見たり、Twitter を見たりするのに、gVim を活用していた。かつての Emacs 使いの guru のような立ち位置を目指していたというのがある。2000 年代初頭にインターネットに多少なりとも触れていた人ならば、「それ Pla」という古の単語を思い浮かべるかもしれない。この概念を持ち出すのはあまりにも古すぎるが、結局言いたいのは、 1 つの手法で全部をこなす という考え方だ。ネットを見るのにわざわざブラウザに切り替えるのはもったいないという今となっては情熱に似た何かを当時は多くの人が持っていた。 しかし、自分自身の技術力...

javascriptは外部ファイルにした方がいいの?それとも、インラインの方が良いの?

事の発端 os0xさんのブログコメント で、javascriptの書き方について、面白いやり取りがありましたので、それについての私見を書きたいと思います。 結論から言いますと、プログラマ的な立場から言わせて頂くと、外部ファイル管理が望ましく、コーダ的な立場から言わせていただくとインラインが望ましいです。 なぜそのような結論に至ったのか、まずは経緯を御覧ください。 コメント欄でのやり取り os0xさんのブログコメント欄を引用しています