*vimpack.txt*   Install Neovim plugins from archives on an artifact registry

==============================================================================
CONTENTS                                                    *vimpack-contents*

  1. Introduction ............................. |vimpack-introduction|
  2. Setup .................................... |vimpack-setup|
  3. Plugin spec .............................. |vimpack-spec|
  4. Registries ............................... |vimpack-registries|
  5. Auth ..................................... |vimpack-auth|
  6. Commands ................................. |vimpack-commands|
  7. Layout ................................... |vimpack-layout|
  8. Lua API .................................. |vimpack-api|

==============================================================================
1. INTRODUCTION                                         *vimpack-introduction*

vimpack installs Neovim plugins from tarballs or zips served by an artifact
registry, at an explicit version, rather than by cloning git repositories.
Downloads are checksum-verified and swapped into place atomically, so a failed
install never leaves a half-written plugin behind.

Requirements: Neovim 0.10+, `curl`, and `tar` (plus `unzip` for .zip
archives).

==============================================================================
2. SETUP                                                       *vimpack-setup*

>lua
    require('vimpack').setup({
      registry = {
        kind = 'artifactapi',
        base_url = 'https://artifactapi.k8s.syd1.au.unkin.net',
        repo = 'nvim-plugins',
        auth = { env = 'ARTIFACTAPI_TOKEN' },
      },
      plugins = {
        { name = 'telescope.nvim', version = '0.1.8' },
        { name = 'vim-fugitive', version = '3.7', opt = true },
      },
      concurrency = 4,
      timeout = 120000,
    })
<
`setup()` validates the spec and returns the normalised config, or nil plus an
error message. Nothing is downloaded until |:VimpackInstall|.

Top-level options ~

  registry     default registry for every plugin        (table, optional)
  plugins      list of plugin specs                     (list, default {})
  concurrency  maximum simultaneous downloads           (number, default 4)
  timeout      per-download timeout in milliseconds     (number, default 120000)

==============================================================================
3. PLUGIN SPEC                                                  *vimpack-spec*

  name       Plugin name. Required. Also the directory name under
             pack/vimpack/{start,opt}/ unless dir_name overrides it.
  version    Required unless `url` is given. Passed to the resolver.
  sha256     Expected digest of the archive. A mismatch aborts the install
             and reports both the expected and the actual digest.
  opt        When true the plugin lands in opt/ for |:packadd|.
  url        Fully explicit archive URL; registry resolution is skipped.
  ext        Archive extension, default "tar.gz".
  registry   Per-plugin registry, overriding the top-level one.
  dir_name   On-disk directory name.

==============================================================================
4. REGISTRIES                                             *vimpack-registries*

A registry maps (name, version) to a download URL. `kind` selects the
resolver; the default kind is "template".

template ~

Substitutes ${name}, ${version}, ${ext}, ${slug}, ${repo} and ${base_url} into
`url_template`. An unrecognised placeholder is reported as an error.
`filename_template` optionally names the cached archive.
>lua
    registry = {
      kind = 'template',
      url_template = 'https://artifactory.example.com/artifactory/nvim-generic/'
        .. '${name}/${version}/${name}-${version}.${ext}',
    }
<
artifactapi ~

Builds ${base_url}/api/v2/remotes/${repo}/files/${path}. `path_template`
defaults to "${name}/${name}-${version}.${ext}".
>lua
    registry = {
      kind = 'artifactapi',
      base_url = 'https://artifactapi.k8s.syd1.au.unkin.net',
      repo = 'nvim-plugins',
    }
<
custom ~

A resolver is `(spec, registry) -> resolved | nil, err`, where `resolved` is
`{ url, headers, filename, sha256? }`.
>lua
    require('vimpack').register_resolver('mine', function(spec, registry)
      return { url = registry.base_url .. '/' .. spec.name .. '-'
        .. spec.version .. '.tar.gz', headers = {} }
    end)
<
==============================================================================
5. AUTH                                                         *vimpack-auth*

Tokens are never stored in the config. `registry.auth` accepts:

  env        name of an environment variable holding the token
  token_cmd  command (list or shell string) that prints the token
  header     header name, default "Authorization"
  prefix     value prefix, default "Bearer " for Authorization

A literal `token` key is rejected at |vimpack-setup| time.
>lua
    auth = { header = 'X-JFrog-Art-Api', prefix = '',
             token_cmd = { 'pass', 'show', 'artifactory/api-key' } }
<
==============================================================================
6. COMMANDS                                                 *vimpack-commands*

                                                            *:VimpackInstall*
:VimpackInstall [{name}...]
    Install plugins that are missing or whose installed version, digest or
    start/opt placement has drifted from the spec. Up-to-date plugins are
    skipped. With names, restrict the work to those plugins.

                                                             *:VimpackUpdate*
:VimpackUpdate [{name}...]
    Re-fetch plugins whether or not the manifest says they are current.

                                                              *:VimpackClean*
:VimpackClean
    Remove installed plugins and manifest entries that are no longer in the
    spec.

                                                             *:VimpackStatus*
:VimpackStatus
    Print wanted versus installed version per plugin, with a state of "ok",
    "missing", "drift" or "orphan".

==============================================================================
7. LAYOUT                                                     *vimpack-layout*

  stdpath('cache')/vimpack/archives/    downloaded archives
  stdpath('cache')/vimpack/stage/       extraction staging area
  stdpath('data')/vimpack/manifest.json installed name/version/sha256
  stdpath('data')/site/pack/vimpack/start/<name>
  stdpath('data')/site/pack/vimpack/opt/<name>

An install extracts to the staging area, hoists a single wrapper directory if
the archive has one, then renames into place after parking any previous tree
aside. If the rename fails the previous tree is restored.

Lazy loading is out of scope: `opt = true` only chooses the opt/ bucket.

==============================================================================
8. LUA API                                                       *vimpack-api*

  require('vimpack').setup(opts)              configure; returns cfg or nil,err
  require('vimpack').install(names?)          same as |:VimpackInstall|
  require('vimpack').update(names?)           same as |:VimpackUpdate|
  require('vimpack').clean()                  same as |:VimpackClean|
  require('vimpack').status()                 same as |:VimpackStatus|
  require('vimpack').status_rows()            status as a list of tables
  require('vimpack').register_resolver(n, fn) add a registry resolver

vim:tw=78:ts=8:ft=help:norl:
