English | 日本語
Shows the license of every dependency inline at the end of the line, with the license itself colored so it stands out at a glance.
// package.json { "dependencies": { "lodash": "^4.17.21", // MIT "@babel/core": "^7.0.0", // MIT "left-pad": "1.3.0", // WTFPL "axios": "^1.1.1" // MIT (Node: >=20) }, "devDependencies": { "typescript": "^5.7.2" // Apache-2.0 } }
Hover an annotation to see the resolved version, where the information came from, and a link to the package homepage.
| Language | Support | Version | Package managers | First contributor | Notes |
|---|---|---|---|---|---|
| JavaScript / TypeScript | ✅ | ✅ | npm, pnpm, yarn (classic & berry), bun | @otnc | package.json, plus deno.json/jsr.json/import_map.json and pnpm workspace catalogs |
| Deno / JSR | ✅ | ✅ | jsr, npm: specifiers |
@otnc | Same manifests as above — jsr: and npm: specifiers are both resolved |
| Go | ✅ | ✅ | go mod | @otnc | go.mod requirements, with replace applied, resolved against deps.dev; no local Go install needed, and modules matching GOPRIVATE are never looked up |
| Rust | ✅ | ✅ | Cargo | @bem130 | Cargo.toml declarations resolved against crates.io / Cargo.lock; no local Cargo install needed |
| MoonBit | ✅ | ❌ | moon | @Allianaab2m | moon.mod / moon.mod.json resolved against .mooncakes, the local registry index and mooncakes.io; no local moon install needed |
| Ruby | ✅ | ✅ | bundler, gem | @muse-chan | Gemfile and *.gemspec declarations resolved against rubygems.org / Gemfile.lock; no local Ruby install needed |
| PHP | ✅ | ✅ | Composer | @v420v | composer.json requirements resolved against vendor/ / composer.lock / Packagist; no local PHP or Composer install needed |
| Python | ❌ | ❌ | pip, uv, poetry | Planned — Issue #14 | |
| Your language? | Not listed here? Support for other languages is welcome — open an issue or a pull request (see CONTRIBUTING.md) |
See docs/resolution-details.md for exactly how each language resolves a license, per-package-manager notes, and known metadata gaps (e.g. JSR).
| Editor | Support | Notes |
|---|---|---|
| VS Code | ✅ | The full feature set: inline annotations, hover, and every packageLicenseViewer.* setting. |
| Neovim | ✅ (experimental) | Inline annotations, hover, and setting sync, via a bundled Node language server plus a Lua layer (vim.lsp.start(), nvim_buf_set_extmark()). The server is built with npm automatically on first use — see :help package_license_viewer. |
| Vim | ✅ (experimental) | Same as Neovim, through the plugin's own VimScript LSP client (job/channel + prop_add/popup_atcursor). Needs Vim 9.0+ with +job, +channel and +textprop — see :help package_license_viewer. |
The Vim/Neovim plugin lives at the repository root, so every plugin manager installs it from just otnc/package-license-viewer, with no rtp option or build hook:
| Plugin manager | Editor | Install |
|---|---|---|
| lazy.nvim | Neovim | { "otnc/package-license-viewer" } |
| vim.pack | Neovim 0.12+ | vim.pack.add({ "https://github.com/otnc/package-license-viewer" }) |
| mini.deps | Neovim | MiniDeps.add("otnc/package-license-viewer") |
| packer.nvim | Neovim | use("otnc/package-license-viewer") |
| paq-nvim | Neovim | "otnc/package-license-viewer", |
| vim-plug | Vim / Neovim | Plug 'otnc/package-license-viewer' |
| dein.vim | Vim / Neovim | call dein#add('otnc/package-license-viewer') |
| vim-jetpack | Vim / Neovim | Jetpack 'otnc/package-license-viewer' |
Native packages (:help packages) |
Vim / Neovim | git clone into ~/.vim/pack/plugins/start/ |
It needs Node.js 22+ and npm on $PATH; the language server is built in the background the first time a supported file is opened, and again after an update. See :help package_license_viewer for every manager and for configuration.
| Command | Description |
|---|---|
Package License Viewer: Refresh License Annotations |
Re-read local metadata, lockfiles and Cargo workspace declarations, then redraw. Use after dependency changes. |
Package License Viewer: Clear License Cache |
Drop everything cached from the registries. |
Package License Viewer: Toggle Inline License Annotations |
Turn the annotations on or off. |
| Setting | Default | Description |
|---|---|---|
packageLicenseViewer.enabled |
true |
Show inline license annotations. |
packageLicenseViewer.format |
${license} |
Annotation template. Placeholders: ${license}, ${version}, ${name}, ${source}, ${nodeEngine}, ${rubyVersion}, ${rustVersion}, ${goVersion}, ${phpVersion}. |
packageLicenseViewer.showResolvedVersion |
false |
Append the resolved version, e.g. MIT · 4.17.21. |
packageLicenseViewer.showNodeEngine |
true |
Append the package's engines.node range, when it has one, e.g. MIT (Node: >=20). |
packageLicenseViewer.showRubyVersion |
true |
Append a gem's required_ruby_version range, when it has one, e.g. MIT (Ruby: >=3.0). |
packageLicenseViewer.showRustVersion |
true |
Append a crate's rust-version (MSRV), when it has one, e.g. MIT (Rust: >=1.56). |
packageLicenseViewer.showGoVersion |
true |
Append a module version's go directive, when it has one, e.g. MIT (Go: >=1.21). |
packageLicenseViewer.showPhpVersion |
true |
Append a package's require.php constraint, when it has one, e.g. MIT (PHP: >=8.1). |
packageLicenseViewer.unknownText |
"" |
Text shown when the license is unknown. Empty means show nothing. |
packageLicenseViewer.annotationColor |
editorCodeLens.foreground |
Theme color id, or a CSS color such as #88888899, for everything except the license itself. |
packageLicenseViewer.licenseColor |
charts.green |
Theme color id, or a CSS color, used for just the license part of the annotation. |
packageLicenseViewer.margin |
0 0 0 1.5em |
CSS margin before the annotation. |
packageLicenseViewer.cacheTtlHours |
168 |
Lifetime of cached registry results. 0 disables the on-disk cache. |
packageLicenseViewer.requestTimeoutMs |
8000 |
Timeout of a single registry request. |
packageLicenseViewer.maxConcurrentRequests |
8 |
Parallel registry requests. |
packageLicenseViewer.npm.enabled |
true |
Enable annotations for package.json. |
packageLicenseViewer.npm.registry |
https://registry.npmjs.org |
Registry base URL. |
packageLicenseViewer.npm.useRegistry |
true |
Allow registry lookups. Set to false to stay fully offline. |
packageLicenseViewer.npm.useLockfiles |
true |
Read lockfiles for exact pinned versions. |
packageLicenseViewer.npm.sections |
4 standard sections | Sections that are always annotated. |
packageLicenseViewer.npm.autoDetectSections |
true |
Also annotate other top-level objects whose key ends with dependencies. |
packageLicenseViewer.npm.pnpmWorkspaceCatalogs |
true |
Also annotate the catalog: and catalogs: sections of pnpm-workspace.yaml. |
packageLicenseViewer.jsr.enabled |
true |
Enable annotations for Deno / import map manifests. |
packageLicenseViewer.jsr.registry |
https://jsr.io |
JSR registry base URL. |
packageLicenseViewer.jsr.apiUrl |
https://api.jsr.io |
JSR API base URL, where the license lives. |
packageLicenseViewer.crates.enabled |
true |
Annotate dependency declarations in Cargo.toml. |
packageLicenseViewer.crates.useRegistry |
true |
Allow crates.io requests. When disabled, existing cached public metadata can still be used. |
packageLicenseViewer.crates.useLockfiles |
true |
Prefer a uniquely matching crates.io version in the applicable Cargo.lock. |
packageLicenseViewer.moonbit.enabled |
true |
Annotate dependency declarations in moon.mod / moon.mod.json. |
packageLicenseViewer.moonbit.useRegistry |
true |
Allow mooncakes.io requests. When disabled, installed modules, the local registry index and existing cached metadata are still used. |
packageLicenseViewer.moonbit.useRegistryIndex |
true |
Read the registry index moon update keeps in $MOON_HOME/registry/index, so an installed toolchain resolves without any request. |
packageLicenseViewer.go.enabled |
true |
Annotate the requirements in go.mod. |
packageLicenseViewer.go.useRegistry |
true |
Allow deps.dev requests, and reads of a version's go.mod from the Go module proxy for its go directive. Modules matching GOPRIVATE, GONOPROXY or GONOSUMDB are never looked up either way. When disabled, existing cached metadata is still used. |
packageLicenseViewer.rubygems.enabled |
true |
Annotate dependency declarations in Gemfile and *.gemspec. |
packageLicenseViewer.rubygems.useRegistry |
true |
Allow rubygems.org requests. When disabled, existing cached metadata can still be used. |
packageLicenseViewer.rubygems.useLockfiles |
true |
Prefer a uniquely matching rubygems.org version in Gemfile.lock. |
packageLicenseViewer.composer.enabled |
true |
Annotate the require and require-dev sections of composer.json. |
packageLicenseViewer.composer.useLockfiles |
true |
Read composer.lock for the locked version and its license when nothing is installed under vendor/. |
packageLicenseViewer.composer.useRegistry |
true |
Allow Packagist requests. When disabled, installed packages, composer.lock and existing cached metadata are still used. |
Use the plv CLI to report dependency licenses or check them against an allowlist or denylist. See the CLI guide for build instructions, JSON output, and an efm-langserver configuration example.
Adding a new ecosystem is one interface: LicenseProvider. See CONTRIBUTING.md for the architecture and contribution workflow.
otoneko. https://github.com/otnc