Compare commits

..
2 Commits
Author SHA1 Message Date
Ben YounesandJordan Harband a8bb497400 [New] nvm ls-remote: annotate versions with the node alias and local aliases
Tests: installation_node / installation_node (bash) (push) Canceled after 0s
Tests: installation_node / installation_node (bash, without curl) (push) Canceled after 0s
Tests: installation_node / installation_node (dash) (push) Canceled after 0s
Tests: installation_node / installation_node (dash, without curl) (push) Canceled after 0s
Tests: installation_node / installation_node (sh) (push) Canceled after 0s
Tests: installation_node / installation_node (sh, without curl) (push) Canceled after 0s
Tests: installation_node / installation_node (zsh, without curl) (push) Canceled after 0s
Tests: xenial / xenial (bash) (push) Canceled after 0s
Tests: xenial / xenial (dash) (push) Canceled after 0s
Tests: xenial / xenial (sh) (push) Canceled after 0s
Tests: xenial / xenial (zsh) (push) Canceled after 0s
Tests: linting / dockerfile_lint (push) Canceled after 0s
Tests: linting / doctoc (push) Canceled after 0s
Tests: linting / test_naming (push) Canceled after 0s
Tests: linting / check_exec (push) Canceled after 0s
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3, zsh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3, bash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3, dash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3, sh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.15, dash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.15, sh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.15, zsh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.15, bash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.15, dash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.15, sh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.15, zsh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.19, bash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.19, dash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.19, zsh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.19, bash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.19, dash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.19, sh) (push) Canceled after 0s
Tests: installation_node / installation_node (zsh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3, zsh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.15, bash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.19, sh) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian-13) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.19, zsh) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine-3.17) (push) Canceled after 0s
Code scanning - action / CodeQL-Build (push) Canceled after 0s
Tests: `nvm install-latest-npm` / matrix (push) Canceled after 0s
Tests: linting / eclint (push) Canceled after 0s
Tests: nvm install with set -e / matrix (push) Canceled after 0s
Tests: release process / release (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3, bash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Canceled after 0s
Tests: alpine / musl-binary arm64 (alpine 3, node v22.21.1) (push) Canceled after 0s
Tests: alpine / musl-binary arm64 (alpine 3, node v24.9.0) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3, node v22.12.0) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.10, node v10.24.1) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.10, node v8.17.0) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.12, node v12.22.12) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.16, node v16.20.2) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.18, node v18.20.4) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-24.04) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3, dash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3, sh) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.15, node v14.21.3) (push) Canceled after 0s
Tests: fast / fast (bash, gawk) (push) Canceled after 0s
Tests: fast / fast (sh, gawk) (push) Canceled after 0s
Tests: fast / fast (zsh, gawk) (push) Canceled after 0s
Tests: fast / fast (bash, mawk) (push) Canceled after 0s
Tests: fast / fast (dash, mawk) (push) Canceled after 0s
Tests: fast / fast (sh, mawk) (push) Canceled after 0s
Tests: fast / fast (zsh, mawk) (push) Canceled after 0s
Tests: installation_iojs / installation_iojs without curl (bash) (push) Canceled after 0s
Tests: installation_iojs / installation_iojs without curl (dash) (push) Canceled after 0s
Tests: installation_iojs / installation_iojs without curl (sh) (push) Canceled after 0s
Tests: alpine / musl-binary arm64 (alpine 3.20, node v20.20.1) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.20, node v20.18.1) (push) Canceled after 0s
Tests: installation_iojs / actually compile io.js from source (gcc 4.9 container) (push) Canceled after 0s
Tests: fast / fast (dash, gawk) (push) Canceled after 0s
urchin tests / tests (dash, installation_iojs) (push) Canceled after 0s
urchin tests / tests (dash, slow) (push) Canceled after 0s
urchin tests / tests (dash, sourcing) (push) Canceled after 0s
urchin tests / tests (sh, installation_iojs) (push) Canceled after 0s
urchin tests / tests (sh, slow) (push) Canceled after 0s
urchin tests / tests (sh, sourcing) (push) Canceled after 0s
urchin tests / tests (zsh, installation_iojs) (push) Canceled after 0s
urchin tests / tests (zsh, slow) (push) Canceled after 0s
urchin tests / tests (zsh, sourcing) (push) Canceled after 0s
update readme TOC / update readme TOC (push) Canceled after 0s
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Canceled after 0s
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Canceled after 0s
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Canceled after 0s
Tests on Windows: `nvm install` / Cygwin nvm install (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine-3.17) (push) Canceled after 0s
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Canceled after 0s
urchin tests / tests (bash, install_script) (push) Canceled after 0s
urchin tests / tests (bash, installation_iojs) (push) Canceled after 0s
urchin tests / tests (bash, slow) (push) Canceled after 0s
urchin tests / tests (bash, sourcing) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine-3.23) (push) Canceled after 0s
Tests: fast / all fast tests (push) Canceled after 0s
latest-npm.yml / nvm install-latest-npm (${{ fromJson(needs.matrix.outputs.latest) }}) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (21) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (9.0) (push) Canceled after 0s
nvm-install-test.yml / test (nvmrc, ${{ fromJson(needs.matrix.outputs.matrix) }}, 2 shlvls) (push) Canceled after 0s
Tests: nvm install with set -e / finisher (push) Canceled after 0s
Tests: shellcheck / shellcheck (push) Canceled after 0s
Tests: alpine / all alpine tests (push) Canceled after 0s
urchin tests / all test suites, all shells (push) Canceled after 0s
Tests on Windows: `nvm install` / tests, on windows (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine-3.23) (push) Canceled after 0s
Tests: installation_iojs / all installation_iojs tests (push) Canceled after 0s
Tests: installation_node / all installation_node tests (push) Canceled after 0s
Tests: xenial / all xenial tests (push) Canceled after 0s
Tests: linting / all linting (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (0.10) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (0.12) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (14.16) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (14.17) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (20.4) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (20.5) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (4.4) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (4.5) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (4.6) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (5.9) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (6.1) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (9.1) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (9.2) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Canceled after 0s
nvm-install-test.yml / test (no nvmrc, ${{ fromJson(needs.matrix.outputs.matrix) }}, 1 shlvl) (push) Canceled after 0s
nvm-install-test.yml / test (no nvmrc, ${{ fromJson(needs.matrix.outputs.matrix) }}, 2 shlvls) (push) Canceled after 0s
nvm-install-test.yml / test (nvmrc, ${{ fromJson(needs.matrix.outputs.matrix) }}, 1 shlvl) (push) Canceled after 0s
Fixes #2786.

Ben Younes added the alias annotations to bare `nvm ls-remote`, with their regression tests;
Jordan Harband moved `(Latest: node)` onto the newest node release, gave each kind of annotation a fixed column so the output can be sliced with `cut`, matched aliases to versions in one pass, and kept local aliases out of the mocks and tests.

Co-authored-by: Ben Younes <2910651+ousamabenyounes@users.noreply.github.com>
Co-authored-by: Jordan Harband <ljharb@gmail.com>
2026-09-23 21:35:43 +00:00
Jordan Harband 04fbd9570c [New] add nvm_has_italics, to detect terminal italics support via terminfo 2026-09-29 17:08:36 +09:00
7 changed files with 412 additions and 15 deletions
+9
View File
@@ -401,6 +401,15 @@ You can list available versions using `ls-remote`:
nvm ls-remote
```
When no version or `--lts` filter is given, the list also marks the version the `node` alias would install, and every version that one of your own aliases would resolve to. Each kind of annotation always starts in the same column, so the output can be sliced with `cut -c` or similar tools:
```
v20.9.0 (Latest LTS: Iron) (Aliases: work)
v21.0.0
v21.1.0
v21.2.0 (Latest: node) (Aliases: default)
```
And then in any new shell just use the installed version:
```sh
+182 -13
View File
@@ -101,6 +101,11 @@ nvm_has_colors() {
[ -t 1 ] && [ "${NVM_NUM_COLORS:--1}" -ge 8 ] && [ "${NVM_NO_COLORS-}" != '--no-colors' ]
}
# terminals without italics may render the italic escape as reverse video instead, so check terminfo's `sitm` capability
nvm_has_italics() {
nvm_has_colors && command tput -T "${TERM:-vt100}" sitm >/dev/null 2>&1
}
nvm_curl_libz_support() {
command curl -V 2>/dev/null | nvm_grep "^Features:" | nvm_grep -q "libz"
}
@@ -2156,10 +2161,53 @@ nvm_get_checksum() {
nvm_download -L -s "${SHASUMS_URL}" -o - | command awk -v tarball="${4}.${5}" '{ if (tarball == $2) print $1 }'
}
nvm_get_remote_aliases() {
local NVM_ALIAS_DIR
NVM_ALIAS_DIR="$(nvm_alias_path)"
if [ ! -d "${NVM_ALIAS_DIR}" ]; then
return 0
fi
local NVM_NODE_PREFIX
NVM_NODE_PREFIX="$(nvm_node_prefix)"
local NVM_IOJS_PREFIX
NVM_IOJS_PREFIX="$(nvm_iojs_prefix)"
local NVM_ALIAS_PATH
local NVM_ALIAS_NAME
local NVM_ALIAS_TARGET
nvm_is_zsh && setopt local_options nonomatch
# the same glob as `nvm_list_aliases`, so this never shows an alias that `nvm alias` omits
for NVM_ALIAS_PATH in "${NVM_ALIAS_DIR}/"*; do
if [ ! -f "${NVM_ALIAS_PATH}" ]; then
continue
fi
NVM_ALIAS_NAME="${NVM_ALIAS_PATH##*/}"
case "${NVM_ALIAS_NAME}" in
"${NVM_NODE_PREFIX}" | "${NVM_IOJS_PREFIX}" | stable | unstable) continue ;;
# control characters would corrupt the terminal, or the tab-separated output
*[[:cntrl:]]*) continue ;;
esac
NVM_ALIAS_TARGET="$(nvm_resolve_alias "${NVM_ALIAS_NAME}" 2>/dev/null)" || continue
case "${NVM_ALIAS_TARGET}" in
'' | *[[:cntrl:]]*) continue ;;
esac
command printf '%s\t%s\n' "${NVM_ALIAS_TARGET}" "${NVM_ALIAS_NAME}"
done
}
nvm_print_versions() {
local NVM_CURRENT
NVM_CURRENT=$(nvm_ls_current)
local NVM_LATEST_ALIAS
NVM_LATEST_ALIAS="${2-}"
local NVM_NAMED_ALIASES
NVM_NAMED_ALIASES="${3-}"
local INSTALLED_COLOR
local SYSTEM_COLOR
local CURRENT_COLOR
@@ -2180,20 +2228,36 @@ nvm_print_versions() {
NVM_HAS_COLORS=1
fi
local NVM_HAS_ITALICS
NVM_HAS_ITALICS=0
if [ "${NVM_HAS_COLORS}" = 1 ] && [ -n "${NVM_LATEST_ALIAS}${NVM_NAMED_ALIASES}" ] && nvm_has_italics; then
NVM_HAS_ITALICS=1
fi
NVM_NAMED_ALIASES="${NVM_NAMED_ALIASES}" \
command awk \
-v remote_versions="$(printf '%s' "${1-}" | tr '\n' '|')" \
-v latest_alias="${NVM_LATEST_ALIAS}" \
-v node_prefix="$(nvm_node_prefix)" -v iojs_prefix="$(nvm_iojs_prefix)" \
-v installed_versions="$(nvm_ls | tr '\n' '|')" -v current="$NVM_CURRENT" \
-v installed_color="$INSTALLED_COLOR" -v system_color="$SYSTEM_COLOR" \
-v current_color="$CURRENT_COLOR" -v default_color="$DEFAULT_COLOR" \
-v old_lts_color="$DEFAULT_COLOR" -v has_colors="$NVM_HAS_COLORS" '
-v old_lts_color="$DEFAULT_COLOR" -v has_colors="$NVM_HAS_COLORS" \
-v has_italics="$NVM_HAS_ITALICS" '
function alen(arr, i, len) { len=0; for(i in arr) len++; return len; }
function paint(color, text) { return (has_colors && color) ? ("\033[" color text "\033[0m") : text; }
function spaces(count, result) { result = ""; while (count-- > 0) result = result " "; return result; }
function italicize(text) { return has_italics ? ("\033[3m" text "\033[23m") : text; }
BEGIN {
named_alias_list = ENVIRON["NVM_NAMED_ALIASES"];
fmt_installed = has_colors ? (installed_color ? "\033[" installed_color "%15s\033[0m" : "%15s") : "%15s *";
fmt_system = has_colors ? (system_color ? "\033[" system_color "%15s\033[0m" : "%15s") : "%15s *";
fmt_current = has_colors ? (current_color ? "\033[" current_color "->%13s\033[0m" : "%15s") : "->%13s *";
latest_lts_color = current_color;
sub(/0;/, "1;", latest_lts_color);
alias_color = current_color;
sub(/^1;/, "0;", alias_color);
fmt_latest_lts = has_colors && latest_lts_color ? ("\033[" latest_lts_color " (Latest LTS: %s)\033[0m") : " (Latest LTS: %s)";
fmt_old_lts = has_colors && old_lts_color ? ("\033[" old_lts_color " (LTS: %s)\033[0m") : " (LTS: %s)";
@@ -2203,6 +2267,57 @@ BEGIN {
split(installed_versions, installed, "|");
rows = alen(lines);
for (n = 1; n <= rows; n++) {
split(lines[n], fields, "[[:blank:]]+");
if (index(fields[1], iojs_prefix "-") == 1) {
latest_iojs = fields[1];
} else if (fields[1] ~ /^v0\.[0-9]*[13579]\./) {
latest_unstable = fields[1];
} else if (fields[1] ~ /^v[0-9]/) {
latest_stable = fields[1];
}
}
named_alias_rows = split(named_alias_list, named_alias_lines, "\n");
for (a = 1; a <= named_alias_rows; a++) {
tab_position = index(named_alias_lines[a], "\t");
if (tab_position < 2) {
continue;
}
alias_target = substr(named_alias_lines[a], 1, tab_position - 1);
alias_name = substr(named_alias_lines[a], tab_position + 1);
if (alias_name == "") {
continue;
}
alias_version = "";
if (alias_target == node_prefix || alias_target == "stable") {
alias_version = latest_stable;
} else if (alias_target == "unstable") {
alias_version = latest_unstable;
} else if (alias_target == iojs_prefix || alias_target == (iojs_prefix "-")) {
alias_version = latest_iojs;
} else {
for (n = 1; n <= rows; n++) {
split(lines[n], fields, "[[:blank:]]+");
if (fields[1] == alias_target || index(fields[1], alias_target ".") == 1) {
alias_version = fields[1];
}
}
}
if (alias_version != "") {
# mawk creates the assigned element before evaluating the right side, so `in` must be checked first
if (alias_version in named_aliases) {
named_aliases[alias_version] = named_aliases[alias_version] ", " alias_name;
italic_aliases[alias_version] = italic_aliases[alias_version] ", " italicize(alias_name);
} else {
named_aliases[alias_version] = alias_name;
italic_aliases[alias_version] = italicize(alias_name);
}
}
}
for (n = 1; n <= rows; n++) {
split(lines[n], fields, "[[:blank:]]+");
cols = alen(fields);
@@ -2225,23 +2340,69 @@ BEGIN {
fmt_version = fmt_installed;
}
padding = (!has_colors && is_installed) ? "" : " ";
padding[n] = (!has_colors && is_installed) ? "" : " ";
if (cols == 1) {
formatted = sprintf(fmt_version, version);
} else if (version == "system" && cols >= 2) {
formatted = sprintf((fmt_version fmt_system_target), version, fields[2]);
output[n] = sprintf(fmt_version, version);
version_width[n] = output[n] padding[n];
gsub(/\033\[[0-9;]*m/, "", version_width[n]);
version_width[n] = length(version_width[n]);
if (version_width[n] > max_version_width) {
max_version_width = version_width[n];
}
for (c = 1; c <= 3; c++) {
text[n, c] = "";
cell[n, c] = "";
}
if (version == "system" && cols >= 2) {
output[n] = output[n] sprintf(fmt_system_target, fields[2]);
} else if (cols == 2) {
formatted = sprintf((fmt_version padding fmt_old_lts), version, fields[2]);
text[n, 1] = sprintf(" (LTS: %s)", fields[2]);
cell[n, 1] = sprintf(fmt_old_lts, fields[2]);
} else if (cols == 3 && fields[3] == "*") {
formatted = sprintf((fmt_version padding fmt_latest_lts), version, fields[2]);
text[n, 1] = sprintf(" (Latest LTS: %s)", fields[2]);
cell[n, 1] = sprintf(fmt_latest_lts, fields[2]);
}
output[n] = formatted;
if (latest_alias != "" && version == latest_stable) {
text[n, 2] = " (Latest: " latest_alias ")";
cell[n, 2] = paint(alias_color, " (Latest: " italicize(latest_alias) ")");
}
if (version in named_aliases) {
text[n, 3] = " (Aliases: " named_aliases[version] ")";
cell[n, 3] = paint(alias_color, " (Aliases: " italic_aliases[version] ")");
}
for (c = 1; c <= 3; c++) {
if (length(text[n, c]) > width[c]) {
width[c] = length(text[n, c]);
}
}
}
# each kind of annotation starts in the same column on every row, so the output stays `cut`-able
for (n = 1; n <= rows; n++) {
print output[n]
last = 0;
for (c = 1; c <= 3; c++) {
if (text[n, c] != "") {
last = c;
}
}
formatted = output[n];
if (last) {
formatted = formatted padding[n];
if (width[2] || width[3]) {
formatted = formatted spaces(max_version_width - version_width[n]);
}
gap = "";
for (c = 1; c <= last; c++) {
if (width[c]) {
formatted = formatted gap cell[n, c];
gap = spaces(width[c] - length(text[n, c])) " ";
}
}
}
print formatted
}
exit
@@ -4746,7 +4907,15 @@ nvm() {
NVM_OUTPUT="$(NVM_LTS="${NVM_LTS-}" nvm_remote_versions "${PATTERN-}" &&:)"
EXIT_CODE=$?
if [ -n "${NVM_OUTPUT}" ]; then
NVM_NO_COLORS="${NVM_NO_COLORS-}" nvm_print_versions "${NVM_OUTPUT}"
local NVM_REMOTE_LATEST_ALIAS
NVM_REMOTE_LATEST_ALIAS=''
local NVM_REMOTE_NAMED_ALIASES
NVM_REMOTE_NAMED_ALIASES=''
if [ "${EXIT_CODE}" -eq 0 ] && [ -z "${NVM_LTS-}" ] && [ -z "${PATTERN-}" ]; then
NVM_REMOTE_LATEST_ALIAS="$(nvm_node_prefix)"
NVM_REMOTE_NAMED_ALIASES="$(nvm_get_remote_aliases)"
fi
NVM_NO_COLORS="${NVM_NO_COLORS-}" nvm_print_versions "${NVM_OUTPUT}" "${NVM_REMOTE_LATEST_ALIAS}" "${NVM_REMOTE_NAMED_ALIASES}"
return $EXIT_CODE
fi
NVM_NO_COLORS="${NVM_NO_COLORS-}" nvm_print_versions "N/A"
@@ -5030,7 +5199,7 @@ nvm() {
nvm_iojs_prefix nvm_node_prefix \
nvm_add_iojs_prefix nvm_strip_iojs_prefix \
nvm_is_iojs_version nvm_is_alias nvm_has_non_aliased \
nvm_ls_remote nvm_ls_remote_iojs nvm_ls_remote_index_tab \
nvm_ls_remote nvm_ls_remote_iojs nvm_ls_remote_index_tab nvm_get_remote_aliases \
nvm_ls nvm_remote_version nvm_remote_versions \
nvm_install_binary nvm_install_source nvm_clang_version \
nvm_get_mirror nvm_get_download_slug nvm_download_artifact \
@@ -5061,7 +5230,7 @@ nvm() {
nvm_install_lock_name nvm_acquire_install_lock nvm_release_install_lock \
nvm_list_aliases nvm_make_alias nvm_print_alias_file nvm_print_alias_path \
nvm_print_default_alias nvm_print_formatted_alias nvm_resolve_local_alias \
nvm_sanitize_path nvm_has_colors nvm_process_parameters \
nvm_sanitize_path nvm_has_colors nvm_has_italics nvm_process_parameters \
nvm_node_version_has_solaris_binary nvm_iojs_version_has_solaris_binary \
nvm_curl_libz_support nvm_command_info nvm_is_zsh nvm_stdout_is_terminal \
nvm_npmrc_bad_news_bears nvm_sanitize_auth_header \
+1 -1
View File
@@ -797,4 +797,4 @@
v22.10.0
v22.11.0  (Latest LTS: Jod)
v23.0.0
v23.1.0
v23.1.0  (Latest: node)
+4 -1
View File
@@ -3,7 +3,7 @@
die () { echo "$@" ; cleanup ; exit 1; }
cleanup() {
unset -f nvm_download nvm_ls_remote nvm_ls_remote_iojs
unset -f nvm_download nvm_ls_remote nvm_ls_remote_iojs nvm_get_remote_aliases nvm_has_italics
if [ -n "${TEMP_NVM_COLORS-}" ]; then
export NVM_COLORS=TEMP_NVM_COLORS
fi
@@ -87,6 +87,9 @@ REMOTE_IOJS="${PWD}/mocks/nvm_ls_remote_iojs.txt"
nvm_ls_remote_iojs() {
cat "${REMOTE_IOJS}"
}
# the mock must not depend on whatever local aliases exist in $NVM_DIR
nvm_get_remote_aliases() { :; }
nvm_has_italics() { return 0; }
EXPECTED_OUTPUT_PATH="${MOCKS_DIR}/nvm ls-remote.txt"
OUTPUT="$(nvm ls-remote | sed 's/[ \t]*$//')"
+126
View File
@@ -0,0 +1,126 @@
#!/bin/sh
WORK="${PWD}/nvm-ls-remote-aliases-work.$$"
export HOME="${WORK}/home"
export NVM_DIR="${HOME}/.nvm"
cleanup() {
command rm -rf "${WORK}"
unset -f cleanup die nvm_has_colors nvm_has_italics nvm_remote_versions expected_row
}
die () { echo "$@" ; cleanup ; exit 1; }
command mkdir -p "${NVM_DIR}/alias/lts" "${NVM_DIR}/versions/node/v1.5.0"
: nvm.sh
\. ../../../nvm.sh
nvm_has_colors() { return 1; }
nvm_remote_versions() {
if [ -n "${NVM_LTS-}" ] || [ -n "${1-}" ]; then
command printf '%s\n' 'v2.0.0'
else
# io.js sorts last here, so the latest node release is not the last row
command printf '%s\n' 'v0.11.16' 'v0.12.18' 'v1.0.0 Argon' 'v1.5.0' 'v2.0.0 Iron *' 'iojs-v3.3.1'
fi
return "${NVM_REMOTE_STATUS-0}"
}
nvm_make_alias 'project' '1' >/dev/null
nvm_make_alias 'argon-project' '1.0' >/dev/null
nvm_make_alias 'lts/iron' 'v2.0.0' >/dev/null
nvm_make_alias 'iron-project' 'lts/iron' >/dev/null
nvm_make_alias 'latest-project' 'node' >/dev/null
nvm_make_alias 'stable-project' 'stable' >/dev/null
nvm_make_alias 'unstable-project' 'unstable' >/dev/null
nvm_make_alias 'io-project' 'iojs' >/dev/null
nvm_make_alias '.hidden-project' '1' >/dev/null
command printf '%s\n' '[' > "${NVM_DIR}/alias/invalid-pattern"
command printf '%s\n' '1' > "${NVM_DIR}/alias/$(command printf 'control\rname')"
# the version cell is 17 wide (`%15s` plus the ` *` installed marker or two spaces), then LTS, Latest, and Aliases columns
expected_row() {
command printf '%-17s%-19s %-15s %s\n' "$1" "$2" "$3" "$4" | command sed 's/[[:space:]]*$//'
}
EXPECTED_OUTPUT="$(
expected_row ' v0.11.16' '' '' ' (Aliases: unstable-project)'
expected_row ' v0.12.18'
expected_row ' v1.0.0' ' (LTS: Argon)' '' ' (Aliases: argon-project)'
expected_row ' v1.5.0 *' '' '' ' (Aliases: project)'
expected_row ' v2.0.0' ' (Latest LTS: Iron)' ' (Latest: node)' ' (Aliases: iron-project, latest-project, stable-project)'
expected_row ' iojs-v3.3.1' '' '' ' (Aliases: io-project)'
)"
REMOTE_ERROR="${WORK}/remote-error"
OUTPUT="$(NVM_REMOTE_LATEST_ALIAS='injected' NVM_REMOTE_NAMED_ALIASES="$(command printf 'v0.12.18\tinjected')" nvm ls-remote --no-colors 2>"${REMOTE_ERROR}")"
[ ! -s "${REMOTE_ERROR}" ] \
|| die "bare nvm ls-remote emitted an error; got >$(command cat "${REMOTE_ERROR}")<"
[ "_${OUTPUT}" = "_${EXPECTED_OUTPUT}" ] \
|| die "bare nvm ls-remote did not annotate aliases in stable columns; got >${OUTPUT}< expected >${EXPECTED_OUTPUT}<"
ALIASES_COLUMN="$(command printf '%s\n' "${OUTPUT}" | command cut -c56-65 | command sort -u)"
[ "_${ALIASES_COLUMN}" = "_$(command printf '\n (Aliases:')" ] \
|| die "bare nvm ls-remote did not start every Aliases annotation in the same column; got >${ALIASES_COLUMN}<"
case "${OUTPUT}" in
*'node, stable'* | *unstable,* | *hidden* | *invalid* | *control* | *injected*)
die "bare nvm ls-remote showed an alias it should omit; got >${OUTPUT}<"
;;
esac
EXPECTED_FILTERED_OUTPUT='v2.0.0'
OUTPUT="$(nvm ls-remote 2 --no-colors | command sed 's/^[[:space:]]*//')"
[ "_${OUTPUT}" = "_${EXPECTED_FILTERED_OUTPUT}" ] \
|| die "filtered nvm ls-remote annotated aliases; got >${OUTPUT}< expected >${EXPECTED_FILTERED_OUTPUT}<"
OUTPUT="$(nvm ls-remote --lts --no-colors | command sed 's/^[[:space:]]*//')"
[ "_${OUTPUT}" = "_${EXPECTED_FILTERED_OUTPUT}" ] \
|| die "LTS nvm ls-remote annotated aliases; got >${OUTPUT}< expected >${EXPECTED_FILTERED_OUTPUT}<"
NVM_REMOTE_STATUS=1
OUTPUT="$(nvm ls-remote --no-colors 2>/dev/null)"
COMMAND_STATUS=$?
NVM_REMOTE_STATUS=0
[ "${COMMAND_STATUS}" -eq 1 ] \
|| die "failed nvm ls-remote returned ${COMMAND_STATUS}; expected 1"
case "${OUTPUT}" in
*Latest:* | *Aliases:*) die "failed nvm ls-remote annotated aliases; got >${OUTPUT}<" ;;
esac
nvm_has_colors() { return 0; }
nvm_has_italics() { return 0; }
ESC="$(command printf '\033')"
OUTPUT="$(nvm ls-remote)"
EXPECTED_LATEST_ROW="$(command printf ' v2.0.0 \033[1;32m (Latest LTS: Iron)\033[0m \033[0;32m (Latest: \033[3mnode\033[23m)\033[0m \033[0;32m (Aliases: \033[3miron-project\033[23m, \033[3mlatest-project\033[23m, \033[3mstable-project\033[23m)\033[0m')"
case "${OUTPUT}" in
*"${EXPECTED_LATEST_ROW}"*) ;;
*) die "colored nvm ls-remote did not use an unbolded color and italic names for aliases; got >${OUTPUT}<" ;;
esac
nvm_has_italics() { return 1; }
NO_ITALICS_OUTPUT="$(nvm ls-remote)"
nvm_has_italics() { return 0; }
EXPECTED_LATEST_ROW="$(command printf ' v2.0.0 \033[1;32m (Latest LTS: Iron)\033[0m \033[0;32m (Latest: node)\033[0m \033[0;32m (Aliases: iron-project, latest-project, stable-project)\033[0m')"
case "${NO_ITALICS_OUTPUT}" in
*"${EXPECTED_LATEST_ROW}"*) ;;
*) die "colored nvm ls-remote used italics on a terminal without italics support; got >${NO_ITALICS_OUTPUT}<" ;;
esac
OUTPUT="$(command printf '%s\n' "${OUTPUT}" | command sed "s/${ESC}\[[0-9;]*m//g")"
EXPECTED_OUTPUT="$(command printf '%s\n' "${EXPECTED_OUTPUT}" | command sed 's/^\( v1\.5\.0\) \*/\1 /')"
[ "_${OUTPUT}" = "_${EXPECTED_OUTPUT}" ] \
|| die "colored nvm ls-remote did not keep annotation columns aligned; got >${OUTPUT}< expected >${EXPECTED_OUTPUT}<"
nvm_has_colors() { return 1; }
nvm_remote_versions() {
command printf '%s\n' 'v2.0.0-nightly20240101abcdef0123 Iron *' 'v3.0.0-nightly2024020201234567890abc'
}
nvm_make_alias 'nightly-project' 'v2.0.0-nightly20240101abcdef0123' >/dev/null
OUTPUT="$(nvm ls-remote --no-colors)"
ALIASES_COLUMNS="$(command printf '%s\n' "${OUTPUT}" | command awk 'index($0, "(Aliases:") { print index($0, "(Aliases:") }' | command sort -u)"
[ "$(command printf '%s\n' "${ALIASES_COLUMNS}" | command wc -l | command tr -d ' ')" = 1 ] \
|| die "versions wider than the version column did not keep Aliases annotations in one column; got >${OUTPUT}<"
cleanup
+80
View File
@@ -0,0 +1,80 @@
#!/bin/sh
WORK="${PWD}/nvm-has-italics-work.$$"
FAKE_BIN="${WORK}/bin"
TPUT_LOG="${WORK}/tput.log"
cleanup() {
command rm -rf "${WORK}"
unset -f cleanup die nvm_has_colors
}
die () { echo "$@" ; cleanup ; exit 1; }
: nvm.sh
\. ../../../nvm.sh
nvm_has_colors() { return 0; }
command mkdir -p "${FAKE_BIN}"
command cat > "${FAKE_BIN}/tput" <<EOF
#!/bin/sh
echo "\$*" > "${TPUT_LOG}"
command printf '\033[3m'
exit "\${FAKE_TPUT_STATUS-0}"
EOF
command chmod +x "${FAKE_BIN}/tput"
(
export PATH="${FAKE_BIN}:${PATH}" TERM=xterm-256color
nvm_has_italics
) || die 'nvm_has_italics should be true when terminfo has the sitm capability'
[ "$(command cat "${TPUT_LOG}")" = '-T xterm-256color sitm' ] \
|| die "nvm_has_italics should query sitm for the current TERM; got >$(command cat "${TPUT_LOG}")<"
OUTPUT="$(
export PATH="${FAKE_BIN}:${PATH}" TERM=xterm-256color
nvm_has_italics
)"
[ -z "${OUTPUT}" ] \
|| die "nvm_has_italics should not print the escape sequence; got >${OUTPUT}<"
(
export PATH="${FAKE_BIN}:${PATH}" TERM=screen FAKE_TPUT_STATUS=1
! nvm_has_italics
) || die 'nvm_has_italics should be false when terminfo lacks the sitm capability'
(
export PATH="${FAKE_BIN}:${PATH}" TERM=not-a-terminal FAKE_TPUT_STATUS=3
! nvm_has_italics
) || die 'nvm_has_italics should be false when the terminal is unknown'
(
export PATH="${FAKE_BIN}:${PATH}"
unset TERM
nvm_has_italics
) || die 'nvm_has_italics should query vt100 when TERM is unset'
[ "$(command cat "${TPUT_LOG}")" = '-T vt100 sitm' ] \
|| die "nvm_has_italics should fall back to vt100 when TERM is unset; got >$(command cat "${TPUT_LOG}")<"
(
PATH="${WORK}"
! nvm_has_italics
) || die 'nvm_has_italics should be false when tput is unavailable'
command rm -f "${TPUT_LOG}"
(
export PATH="${FAKE_BIN}:${PATH}" TERM=xterm-256color
nvm_has_colors() { return 1; }
! nvm_has_italics
) || die 'nvm_has_italics should be false when colors are disabled'
[ ! -f "${TPUT_LOG}" ] \
|| die 'nvm_has_italics should not query terminfo when colors are disabled'
if nvm_has tput; then
(
export TERM=dumb
! nvm_has_italics
) || die 'nvm_has_italics should be false for the dumb terminal'
fi
cleanup
+10
View File
@@ -20,6 +20,16 @@ nvm_make_alias() {
return 0
}
nvm_get_remote_aliases() {
# prevent local aliases from leaking into `nvm ls-remote` mocks
return 0
}
nvm_has_italics() {
# keep mocks independent of the local terminal's italics support
return 0
}
nvm_ls_remote > "$MOCKS_DIR/nvm_ls_remote.txt"
nvm_ls_remote_iojs > "$MOCKS_DIR/nvm_ls_remote_iojs.txt"
NVM_LTS=* nvm_ls_remote > "$MOCKS_DIR/nvm_ls_remote LTS.txt"