Skip to main content

dvpm - Denops Vim/Neovim Plugin Manager

dvpm is a plugin manager for Vim and Neovim, powered by denops.vim.

  • Vim / Neovim starts up very fast !

…but plugins are not loaded yet at startup \(^o^)/

All plugins are loaded lazily.

  • You can write all Vim / Neovim settings in typescript

Requirement

Sample configuration

Neovim

  • ~/.config/nvim/init.lua (Mac / Linux)
  • ~/AppData/Local/nvim/init.lua (Windows)
local denops = vim.fn.expand("~/.cache/nvim/dvpm/github.com/vim-denops/denops.vim")
if not vim.loop.fs_stat(denops) then
  vim.fn.system({ "git", "clone", "https://github.com/vim-denops/denops.vim", denops })
end
vim.opt.runtimepath:prepend(denops)

Vim

  • ~/.vimrc (Mac / Linux)
  • ~/_vimrc (Windows)
let s:denops = expand("~/.cache/vim/dvpm/github.com/vim-denops/denops.vim")
if !isdirectory(s:denops)
  execute 'silent! !git clone https://github.com/vim-denops/denops.vim ' .. s:denops
endif
execute 'set runtimepath^=' . substitute(fnamemodify(s:denops, ':p') , '[/\\]$', '', '')

Neovim

  • ~/.config/nvim/denops/config/main.ts (Mac / Linux)
  • ~/AppData/Local/nvim/denops/config/main.ts (Windows)

Vim

  • ~/.vim/denops/config/main.ts (Mac / Linux)
  • ~/vimfiles/denops/config/main.ts (Windows)
import * as fn from "https://deno.land/x/denops_std@v5.0.0/function/mod.ts";
import * as mapping from "https://deno.land/x/denops_std@v5.0.0/mapping/mod.ts";
import { Denops } from "https://deno.land/x/denops_std@v5.0.0/mod.ts";
import { ensureString } from "https://deno.land/x/unknownutil@v2.1.1/mod.ts";
import { execute } from "https://deno.land/x/denops_std@v5.0.0/helper/mod.ts";
import { globals } from "https://deno.land/x/denops_std@v5.0.0/variable/mod.ts";

import { Dvpm } from "https://deno.land/x/dvpm@1.3.0/mod.ts";

export async function main(denops: Denops): Promise<void> {
  const base_path = (await fn.has(denops, "nvim"))
    ? "~/.cache/nvim/dvpm"
    : "~/.cache/vim/dvpm";
  const base = ensureString(await fn.expand(denops, base_path));

  // First, call Dvpm.begin with denops object and base path.
  const dvpm = await Dvpm.begin(denops, { base });

  // URL only (GitHub).
  await dvpm.add({ url: "yukimemi/dps-autocursor" });
  // URL only (not GitHub).
  await dvpm.add({ url: "https://notgithub.com/some/other/plugin" });
  // With branch.
  // await dvpm.add({ url: "neoclide/coc.nvim", branch: "release" });
  // build option. Execute after install or update.
  await dvpm.add({
    url: "neoclide/coc.nvim",
    branch: "master",
    build: async ({ info }) => {
      const args = ["install", "--frozen-lockfile"];
      const cmd = new Deno.Command("yarn", { args, cwd: info?.dst });
      const output = await cmd.output();
      console.log(new TextDecoder().decode(output.stdout));
    },
  });
  // before setting.
  await dvpm.add({
    url: "yukimemi/dps-autobackup",
    before: async ({ denops }) => {
      await globals.set(
        denops,
        "autobackup_dir",
        ensureString(await fn.expand(denops, "~/.cache/nvim/autobackup")),
      );
    },
  });
  // after setting.
  await dvpm.add({
    url: "folke/which-key.nvim",
    after: async ({ denops }) => {
      await execute(denops, `lua require("which-key").setup()`);
    },
  });
  // dst setting. (for develop)
  await dvpm.add({
    url: "yukimemi/dps-randomcolorscheme",
    dst: "~/src/github.com/yukimemi/dps-randomcolorscheme",
    before: async ({ denops }) => {
      await mapping.map(denops, "<space>ro", "<cmd>ChangeColorscheme<cr>", {
        mode: "n",
      });
      await mapping.map(
        denops,
        "<space>rd",
        "<cmd>DisableThisColorscheme<cr>",
        { mode: "n" },
      );
      await mapping.map(denops, "<space>rl", "<cmd>LikeThisColorscheme<cr>", {
        mode: "n",
      });
      await mapping.map(denops, "<space>rh", "<cmd>HateThisColorscheme<cr>", {
        mode: "n",
      });
    },
  });
  // Disable setting.
  await dvpm.add({
    url: "yukimemi/dps-hitori",
    enabled: false,
  });
  // Disable with function.
  await dvpm.add({
    url: "editorconfig/editorconfig-vim",
    enabled: async ({ denops }) => !(await fn.has(denops, "nvim")),
  });
  // With dependencies.
  await dvpm.add({
    url: "lambdalisue/gin.vim",
    dependencies: [
      { url: "lambdalisue/askpass.vim" },
      { url: "lambdalisue/guise.vim" },
    ],
  });

  // Finally, call Dvpm.end.
  await dvpm.end();

  console.log("Load completed !");
}

See my dotfiles for more complex examples.

dotfiles/.config/nvim at main · yukimemi/dotfiles · GitHub

API

Dvpm.begin

public static async begin(denops: Denops, dvpmOption: DvpmOption): Promise<Dvpm>
export type DvpmOption = {
  // Base path for git clone.
  base: string;
  // debug print. Default is false.
  debug?: boolean;
  // Number of concurrent processes. Default is 8.
  // This is used plugin install, update, source.
  concurrency?: number;
  // When this option is set, the time taken to source each plugin is output to dvpm://profile buffer after Vim is launched.
  // `before` and `after` execution times are not included. Default is false.
  profile?: boolean;
  // Use `vim.notify` for Install and Update log. Default is false. (Neovim only)
  notify?: boolean;
  // git log arg. Used for :DvpmUpdate command output. Default is [].
  logarg?: string[];
};

Dvpm.end

public async end(): Promise<void>

source after/*.(vim|lua) files.

Dvpm.add

public async add(plug: Plug): Promise<void>
export type Plug = {
  // Github `username/repository` or URL that can be cloned with git.
  url: string;
  // The path to git clone. (Option)
  dst?: string;
  // Git branch name. (Option)
  branch?: string;
  // enable or disable. Default is true.
  enabled?:
    | boolean
    | ((
      { denops, info }: { denops: Denops; info: PlugInfo },
    ) => Promise<boolean>);
  // Processing to be performed before adding runtimepath. (Option)
  before?: (
    { denops, info }: { denops: Denops; info: PlugInfo },
  ) => Promise<void>;
  // Processing to be performed after adding runtimepath. (Option)
  after?: (
    { denops, info }: { denops: Denops; info: PlugInfo },
  ) => Promise<void>;
  // build option. Execute after install or update. (Option)
  build?: (
    { denops, info }: { denops: Denops; info: PlugInfo },
  ) => Promise<void>;
  // dependencies. (Option)
  dependencies?: Plug[];
};
export type PlugInfo = Plug & {
  // `true` if added to runtimepath.
  isLoad: boolean;
  // `true` if install or update.
  isUpdate: boolean;
  // plugin load time. Need to set DvpmOption.profile.
  elaps: number;
};

Dvpm.cache

public async cache(arg: { script: string; path: string }): Promise<void>

Cache the script to path.

e.g.

await dvpm.cache({
  script: `
    if !v:vim_did_enter && has('reltime')
      let s:startuptime = reltime()
      au VimEnter * ++once let s:startuptime = reltime(s:startuptime) | redraw
            \\ | echomsg 'startuptime: ' .. reltimestr(s:startuptime)
    endif
  `,
  path: "~/.config/nvim/plugin/dvpm_cache.vim",
});

await dvpm.cache({
  script: `
    vim.g.loaded_2html_plugin = 1
    vim.g.loaded_gzip = 1
    vim.g.loaded_man = 1
    vim.g.loaded_matchit = 1
    vim.g.loaded_matchparen = 1
    vim.g.loaded_netrwPlugin = 1
    vim.g.loaded_tarPlugin = 1
    vim.g.loaded_tutor_mode_plugin = 1
    vim.g.loaded_zipPlugin = 1
  `,
  path: "~/.config/nvim/plugin/dvpm_cache.lua",
});

Dvpm.list

public list(): Plugin[]

If you want a list of plugin information, you can get it with the dvpm.list() function. The return value is Plugin[]. See the doc for type information.

Command

:DvpmUpdate [url]

Update installed plugins.

If url is specified, update only target plugins, if not specified, update all plugins.

:DvpmList

It outputs the list of plugins to the dvpm://list buffer.