Skip to main content
Home
It is unknown whether this package works with Cloudflare Workers, Node.js, Deno, Bun, Browsers
It is unknown whether this package works with Cloudflare Workers
It is unknown whether this package works with Node.js
It is unknown whether this package works with Deno
It is unknown whether this package works with Bun
It is unknown whether this package works with Browsers
JSR Score
35%
Published
2 months ago (7.0.3)

dvpm - Denops Vim/Neovim Plugin Manager !

DeepWiki

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 type { Denops, Entrypoint } from "jsr:@denops/std";
import * as fn from "jsr:@denops/std/function";
import * as mapping from "jsr:@denops/std/mapping";
import * as vars from "jsr:@denops/std/variable";
import { ensure, is } from "jsr:@core/unknownutil";
import { execute } from "jsr:@denops/std/helper";

import { Dvpm } from "jsr:@yukimemi/dvpm";

export const main: Entrypoint = async (denops: Denops) => {
  const base_path = (await fn.has(denops, "nvim")) ? "~/.cache/nvim/dvpm" : "~/.cache/vim/dvpm";
  const base = ensure(await fn.expand(denops, base_path), is.String);

  // 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/autocursor.vim" });
  // 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 }) => {
      if (!info.isUpdate || !info.isLoad) {
        // build option is called after git pull, even if there are no changes
        // so you need to check for changes
        return;
      }
      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));
    },
  });
  // shalow clone.
  await dvpm.add({ url: "yukimemi/chronicle.vim", depth: 1 });
  // before setting.
  await dvpm.add({
    url: "yukimemi/silentsaver.vim",
    before: async ({ denops }) => {
      await vars.g.set(
        denops,
        "silentsaver_dir",
        ensure(await fn.expand(denops, "~/.cache/nvim/silentsaver"), is.String),
      );
    },
  });
  // 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/spectrism.vim",
    dst: "~/src/github.com/yukimemi/spectrism.vim",
    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/hitori.vim",
    enabled: false,
  });
  // Disable with function.
  await dvpm.add({
    url: "editorconfig/editorconfig-vim",
    enabled: async ({ denops }) => !(await fn.has(denops, "nvim")),
  });
  // With dependencies. dependencies plugin must be added.
  await dvpm.add({ url: "lambdalisue/askpass.vim" });
  await dvpm.add({ url: "lambdalisue/guise.vim" });
  await dvpm.add({
    url: "lambdalisue/gin.vim",
    dependencies: [
      "lambdalisue/askpass.vim",
      "lambdalisue/guise.vim",
    ],
  });
  // Load from file. ( `.lua` or `.vim` )
  await dvpm.add({
    url: "rcarriga/nvim-notify",
    beforeFile: "~/.config/nvim/rc/before/nvim-notify.lua",
    afterFile: "~/.config/nvim/rc/after/nvim-notify.lua",
  });

  // 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;
  // Cache file path. See `Cache setting`.
  cache?: string;
  // debug print. Default is false.
  debug?: boolean;
  // If specified in profiles, only plugins that match the profiles specified in `Plug` will be loaded
  // See `Profile setting`
  profiles?: string[];
  // Number of concurrent processes. Default is 8.
  // This is used plugin install, update, source.
  concurrency?: number;
  // 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>

Add plugin to runtimepath and source plugin/.vim and plugin/.lua.

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 or revision name. (Option)
  rev?: string;
  // clone depth. (Option)
  depth?: number;
  // enable or disable. Default is true.
  enabled?: Bool;
  // If profiles are specified in DvpmOption, the plugin will be enabled only if the profiles specified here are included in the profiles of DvpmOption.
  profiles: string[];
  // Processing to be performed before source plugin/*.vim and plugin/*.lua. (Option)
  before?: ({
    denops,
    info,
  }: {
    denops: Denops;
    info: PlugInfo;
  }) => Promise<void>;
  // Processing to be performed after source plugin/*.vim and plugin/*.lua. (Option)
  after?: ({
    denops,
    info,
  }: {
    denops: Denops;
    info: PlugInfo;
  }) => Promise<void>;
  // File path of processing to be performed before source plugin/*.vim and plugin/*.lua. (Option)
  beforeFile?: string;
  // File path of processing to be performed after source plugin/*.vim and plugin/*.lua. (Option)
  afterFile?: string;
  // build option. Execute after install or update. (Option)
  // Executed even if there are no changes in the update
  // Therefore, conditionally branch on `info.isLoad` and `info.isUpdate` as necessary
  build?: ({
    denops,
    info,
  }: {
    denops: Denops;
    info: PlugInfo;
  }) => Promise<void>;
  // Cache settings. See `Cache setting`.
  cache?: {
    enabled?: Bool;
    before?: string;
    after?: string;
    beforeFile?: string;
    afterFile?: string;
  };
  // Whether to git clone and update. Default is true. (Option)
  // If this option is set to false, then `enabled` is also set to false.
  clone?: Bool;
  // dependencies. (Option)
  dependencies?: string[];
};
export type Bool =
  | boolean
  | (({
    denops,
    info,
  }: {
    denops: Denops;
    info: PlugInfo;
  }) => Promise<boolean>);

PlugInfo type is almost same as Plug. Contains the calculated results for each variable, such as enabled.

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.

Cache setting

If you want some plugins to be loaded before VimEnter, enable the cache setting. A sample configuration is shown below.

export const main: Entrypoint = async (denops: Denops) => {
  const base_path = (await fn.has(denops, "nvim")) ? "~/.cache/nvim/dvpm" : "~/.cache/vim/dvpm";
  const base = ensure(await fn.expand(denops, base_path), is.String);
  const cache_path = (await fn.has(denops, "nvim"))
    ? "~/.config/nvim/plugin/dvpm_plugin_cache.vim"
    : "~/.config/vim/plugin/dvpm_plugin_cache.vim";
  // This cache path must be pre-appended to the runtimepath.
  // Add it in vimrc or init.lua by yourself, or specify the path originally added to
  // runtimepath of Vim / Neovim.
  const cache = ensure(await fn.expand(denops, cache_path), is.String);

  // Specify `cache` to Dvpm.begin.
  const dvpm = await Dvpm.begin(denops, { base, cache });

  await dvpm.add({
    url: "tani/vim-artemis",
    // Just set `cache.enabled` to true if you don't need plugin settings.
    cache: { enabled: true },
  });
  await dvpm.add({
    url: "nvim-lua/plenary.nvim",
    cache: { enabled: true },
    enabled: async ({ denops }) => await fn.has(denops, "nvim"),
  });

  await dvpm.add({
    url: "startup-nvim/startup.nvim",
    // deno-lint-ignore require-await
    enabled: async ({ denops }) => denops.meta.host === "nvim",
    // Specify `before` or `after` if you need to configure the plugin.
    // `before` is executed before the plugin is added to the runtimepath.
    // `after` runs after the plugin is added to the runtimepath.
    cache: {
      before: `echomsg "Load startup !"`,
      after: `
        lua require("startup").setup({ theme = "startify" })
      `,
    },
  });

  await dvpm.add({
    url: "rcarriga/nvim-notify",
    enabled: async ({ denops }) => await fn.has(denops, "nvim"),
    cache: {
      // `before` and `after` can be set independently.
      after: `
        lua << EOB
          require("notify").setup({
            stages = "slide",
          })
          vim.notify = require("notify")
        EOB
      `,
      // If you want to read it in a separate file, specify as follows. (.lua and .vim can be specified)
      // afterFile: "~/.config/nvim/rc/after/notify.lua",
    },
  });

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

After performing the above settings, when you start Vim / Neovim, the following should be output to the file specified as cache in Dvpm.begin. And the next time Vim / Neovim starts, the plugin will be enabled before VimEnter.

  • ~/.config/nvim/plugin/dvpm_plugin_cache.vim (for Neovim)
" This file is generated by dvpm.
set runtimepath+=/Users/yukimemi/.cache/nvim/dvpm/github.com/tani/vim-artemis
set runtimepath+=/Users/yukimemi/.cache/nvim/dvpm/github.com/nvim-lua/plenary.nvim
echomsg "Load startup !"
set runtimepath+=/Users/yukimemi/.cache/nvim/dvpm/github.com/startup-nvim/startup.nvim
lua require("startup").setup({theme = "startify"})
set runtimepath+=/Users/yukimemi/.cache/nvim/dvpm/github.com/rcarriga/nvim-notify
lua << EOB
require("notify").setup({
stages = "slide",
})
vim.notify = require("notify")
EOB

Autocmd

  • DvpmCacheUpdated

Fires after updating the cache.

e.g.

import * as autocmd from "jsr:@denops/std/autocmd";

~~~

await autocmd.define(denops, "User", "DvpmCacheUpdated", "echo 'dvpm cache updated !'");

Profile setting

If profiles is specified in DvpmOption, the plugins to be enabled can be restricted by the specified profile.

e.g.

~~~
export const main: Entrypoint = async (denops: Denops) => {
  const base_path = (await fn.has(denops, "nvim")) ? "~/.cache/nvim/dvpm" : "~/.cache/vim/dvpm";
  const base = ensure(await fn.expand(denops, base_path), is.String);

  const dvpm = await Dvpm.begin(denops, {
    base,
    // Use only minimal plugins
    profiles: ["minimal"],
  });

  await dvpm.add({
    url: "yukimemi/chronicle.vim",
    profiles: ["minimal"],
  });
  await dvpm.add({
    url: "yukimemi/silentsaver.vim",
    profiles: ["default"],
  });
  await dvpm.add({
    url: "yukimemi/autocursor.vim",
    profiles: ["full"],
  });

  await dvpm.end();
};

In this case, only yukimemi/chronicle.vim is enabled.

e.g.

~~~
export const main: Entrypoint = async (denops: Denops) => {
  const base_path = (await fn.has(denops, "nvim")) ? "~/.cache/nvim/dvpm" : "~/.cache/vim/dvpm";
  const base = ensure(await fn.expand(denops, base_path), is.String);

  const dvpm = await Dvpm.begin(denops, {
    base,
    // Use only minimal and default plugins
    profiles: ["minimal", "default"],
  });

  await dvpm.add({
    url: "yukimemi/chronicle.vim",
    profiles: ["minimal"],
  });
  await dvpm.add({
    url: "yukimemi/silentsaver.vim",
    profiles: ["default"],
  });
  await dvpm.add({
    url: "yukimemi/autocursor.vim",
    profiles: ["full"],
  });

  await dvpm.end();
};

In this case, yukimemi/chronicle.vim and yukimemi/silentsaver.vim are enabled.

If you specify ["minimal", "default", "full"] in DvpmOption.profiles, all three plugins will be enabled.

New Ticket: Report package

Please provide a reason for reporting this package. We will review your report and take appropriate action.

Please review the JSR usage policy before submitting a report.

Add Package

deno add jsr:@yukimemi/dvpm

Import symbol

import * as dvpm from "@yukimemi/dvpm";
or

Import directly with a jsr specifier

import * as dvpm from "jsr:@yukimemi/dvpm";

Add Package

pnpm i jsr:@yukimemi/dvpm
or (using pnpm 10.8 or older)
pnpm dlx jsr add @yukimemi/dvpm

Import symbol

import * as dvpm from "@yukimemi/dvpm";

Add Package

yarn add jsr:@yukimemi/dvpm
or (using Yarn 4.8 or older)
yarn dlx jsr add @yukimemi/dvpm

Import symbol

import * as dvpm from "@yukimemi/dvpm";

Add Package

vlt install jsr:@yukimemi/dvpm

Import symbol

import * as dvpm from "@yukimemi/dvpm";

Add Package

npx jsr add @yukimemi/dvpm

Import symbol

import * as dvpm from "@yukimemi/dvpm";

Add Package

bunx jsr add @yukimemi/dvpm

Import symbol

import * as dvpm from "@yukimemi/dvpm";