diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..6041c46 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,14 @@ +{ + "permissions": { + "allow": [ + "Bash(fish_indent:*)", + "Bash(find:*)", + "Bash(make lint-fish:*)", + "Bash(make lint-json:*)", + "Bash(make lint-markdown:*)", + "Bash(make lint-fix:*)", + "Bash(make lint:*)" + ], + "deny": [] + } +} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index 869f880..864816a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,17 +3,9 @@ root = true [*] charset = utf-8 end_of_line = lf -indent_size = 2 -indent_style = space insert_final_newline = true -max_line_length = 160 -tab_width = 2 trim_trailing_whitespace = true -[{*.json}] +[*.fish] indent_size = 4 -tab_width = 4 - -[{*.markdown,*.md}] -indent_size = 4 -tab_width = 4 +indent_style = space diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..4a267e1 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,47 @@ +name: Lint + +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + +jobs: + lint: + runs-on: ubuntu-latest + name: Lint codebase + + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Setup Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '18' + cache: 'npm' + + - name: Setup Fish shell + run: | + sudo apt-add-repository ppa:fish-shell/release-3 + sudo apt-get update + sudo apt-get install -y fish + + - name: Install linting tools + run: make install-tools + + - name: Lint Fish files + run: make lint-fish + + - name: Lint Markdown files + run: make lint-markdown + + - name: Lint JSON files + run: make lint-json + + - name: Test plugin installation + shell: fish {0} + run: | + curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher + fisher --version + make test diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml index 193995c..2167179 100644 --- a/.github/workflows/pr-lint.yml +++ b/.github/workflows/pr-lint.yml @@ -15,4 +15,4 @@ permissions: jobs: SuperLinter: - uses: ivuorinen/actions/pr-lint@main + uses: ivuorinen/actions/pr-lint@625c37446b1c7e219755a40807f825c9283f6e05 # 25.7.7 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 2055b92..58f6e3c 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -16,4 +16,4 @@ jobs: issues: write pull-requests: write steps: - - uses: ivuorinen/actions/stale@main + - uses: ivuorinen/actions/stale@625c37446b1c7e219755a40807f825c9283f6e05 # 25.7.7 diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml index e5e2001..c5c6856 100644 --- a/.github/workflows/sync-labels.yml +++ b/.github/workflows/sync-labels.yml @@ -20,4 +20,4 @@ jobs: issues: write runs-on: ubuntu-latest steps: - - uses: ivuorinen/actions/sync-labels@main + - uses: ivuorinen/actions/sync-labels@625c37446b1c7e219755a40807f825c9283f6e05 # 25.7.7 diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..2b178f5 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,7 @@ +{ + "default": true, + "MD007": { "indent": 4 }, + "MD013": { "line_length": 120 }, + "MD033": false, + "MD041": false +} \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..34a900c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,119 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is a Fish shell plugin that automatically loads the correct Node.js version from `.nvmrc` files when +changing directories. The plugin uses Fisher as its package manager. + +## Architecture + +The plugin consists of two main Fish functions: + +- `nvm_auto_use.fish` - Main function that triggers on directory changes (`--on-variable PWD`) and handles + the automatic Node.js version switching +- `nvm_find_nvmrc.fish` - Utility function that searches for `.nvmrc` files in the current directory and parent directories + +## Development Commands + +### Linting and Code Quality + +```bash +# Install all linting tools (markdownlint-cli, jsonlint, jq) +make install-tools + +# Run all linting checks +make lint + +# Fix auto-fixable linting issues +make lint-fix + +# Individual linting commands +make lint-fish # Lint Fish shell files +make lint-markdown # Lint Markdown files +make lint-json # Lint JSON files +``` + +#### Manual Fish Commands + +```fish +# Format all Fish files (required before commits) +find . -name "*.fish" -exec fish_indent --write {} \; + +# Check formatting without modifying files +find . -name "*.fish" -exec fish_indent --check {} \; + +# Validate Fish syntax +fish -n functions/*.fish completions/*.fish +``` + +### Installation/Testing + +```bash +# Test plugin installation using Makefile +make test +``` + +#### Manual Installation Commands + +```fish +# Install the plugin locally for testing +fisher install . + +# Remove the plugin +fisher remove ivuorinen/nvm-auto-use.fish +``` + +### Configuration Commands + +```fish +# View current configuration +nvm_auto_use_config + +# Enable/disable features +nvm_auto_use_config silent on +nvm_auto_use_config auto_install off +nvm_auto_use_config manager fnm + +# Set debounce timing +nvm_auto_use_config debounce 1000 + +# Exclude directories +nvm_auto_use_config exclude "build" +``` + +### Testing the Functions + +```fish +# Test the nvmrc finder function +nvm_find_nvmrc + +# Test version extraction +nvm_extract_version .nvmrc + +# Test directory change trigger (create a test .nvmrc file) +echo "18.0.0" > .nvmrc +cd . # This should trigger nvm_auto_use + +# Check version status +nvm_version_status +``` + +## Key Implementation Details + +- The plugin hooks into Fish's variable change system using `--on-variable PWD` +- Supports multiple Node.js version managers: nvm, fnm, volta, asdf +- Supports multiple file formats: `.nvmrc`, `.node-version`, `.tool-versions`, `package.json` engines.node +- Includes performance optimizations: caching, debouncing, directory exclusions +- Configurable features: silent mode, auto-install toggle, notifications, project-only mode +- Error handling includes checking if Node.js is available and graceful fallback when versions can't be switched +- The search for version files traverses up the directory tree until it finds one or reaches the root directory + +## Code Quality Standards + +- All Fish code must be formatted with `fish_indent` before committing +- Functions should include description flags (`-d "description"`) +- Use proper Fish conventions for variable scoping (`set -l`, `set -g`, `set -gx`) +- Include comprehensive error handling and input validation +- Follow Fish best practices for command substitution and string handling diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..171c5b3 --- /dev/null +++ b/Makefile @@ -0,0 +1,137 @@ +# Makefile for nvm-auto-use.fish + +.PHONY: help install-tools lint lint-fish lint-markdown lint-json lint-fix lint-check test clean + +# Default target +help: + @echo "Available targets:" + @echo " install-tools - Install all linting tools" + @echo " lint - Run all linting checks" + @echo " lint-fish - Lint Fish shell files" + @echo " lint-markdown - Lint Markdown files" + @echo " lint-json - Lint JSON files" + @echo " lint-fix - Fix auto-fixable linting issues" + @echo " lint-check - Check linting without fixing" + @echo " test - Run tests (install plugin locally)" + @echo " clean - Clean temporary files" + +# Install all required linting tools +install-tools: + @echo "Installing linting tools..." + # Install markdownlint-cli for markdown linting + @if ! command -v markdownlint >/dev/null 2>&1; then \ + echo "Installing markdownlint-cli..."; \ + npm install -g markdownlint-cli; \ + else \ + echo "markdownlint-cli already installed"; \ + fi + # Install jsonlint for JSON linting + @if ! command -v jsonlint >/dev/null 2>&1; then \ + echo "Installing jsonlint..."; \ + npm install -g jsonlint; \ + else \ + echo "jsonlint already installed"; \ + fi + # Install jq for JSON processing (backup) + @if ! command -v jq >/dev/null 2>&1; then \ + echo "Installing jq..."; \ + if command -v brew >/dev/null 2>&1; then \ + brew install jq; \ + elif command -v apt-get >/dev/null 2>&1; then \ + sudo apt-get install -y jq; \ + elif command -v yum >/dev/null 2>&1; then \ + sudo yum install -y jq; \ + else \ + echo "Please install jq manually"; \ + fi; \ + else \ + echo "jq already installed"; \ + fi + @echo "All linting tools installed!" + +# Run all linting checks +lint: lint-fish lint-markdown lint-json + +# Lint Fish shell files +lint-fish: + @echo "Linting Fish files..." + @find . -name "*.fish" -type f | while read -r file; do \ + echo "Checking $$file..."; \ + fish_indent --check "$$file" || { \ + echo "Formatting issues found in $$file"; \ + exit 1; \ + }; \ + done + @echo "Validating Fish syntax..." + @fish -n functions/*.fish completions/*.fish 2>/dev/null || { \ + echo "Syntax errors found in Fish files"; \ + exit 1; \ + } + @echo "Fish files passed linting!" + +# Lint Markdown files +lint-markdown: + @echo "Linting Markdown files..." + @if command -v markdownlint >/dev/null 2>&1; then \ + markdownlint --config .markdownlint.json *.md || { \ + echo "Markdown linting failed"; \ + exit 1; \ + }; \ + else \ + echo "markdownlint not found, skipping markdown linting"; \ + fi + @echo "Markdown files passed linting!" + +# Lint JSON files +lint-json: + @echo "Linting JSON files..." + @find . -name "*.json" -type f | while read -r file; do \ + echo "Checking $$file..."; \ + if command -v jsonlint >/dev/null 2>&1; then \ + jsonlint "$$file" >/dev/null || { \ + echo "JSON syntax error in $$file"; \ + exit 1; \ + }; \ + elif command -v jq >/dev/null 2>&1; then \ + jq empty "$$file" >/dev/null || { \ + echo "JSON syntax error in $$file"; \ + exit 1; \ + }; \ + else \ + echo "No JSON linter found, skipping $$file"; \ + fi; \ + done + @echo "JSON files passed linting!" + +# Fix auto-fixable linting issues +lint-fix: + @echo "Fixing linting issues..." + @echo "Formatting Fish files..." + @find . -name "*.fish" -type f -exec fish_indent --write {} \; + @if command -v markdownlint >/dev/null 2>&1; then \ + echo "Fixing Markdown files..."; \ + markdownlint --config .markdownlint.json --fix *.md 2>/dev/null || true; \ + fi + @echo "Linting fixes applied!" + +# Check linting without fixing +lint-check: lint + +# Test the plugin by installing it locally +test: + @echo "Testing plugin installation..." + @if command -v fisher >/dev/null 2>&1; then \ + fisher install .; \ + echo "Plugin installed successfully!"; \ + echo "Run 'fisher remove ivuorinen/nvm-auto-use.fish' to uninstall"; \ + else \ + echo "Fisher not found. Please install Fisher package manager first."; \ + exit 1; \ + fi + +# Clean temporary files +clean: + @echo "Cleaning temporary files..." + @find . -name "*.tmp" -type f -delete 2>/dev/null || true + @find . -name ".DS_Store" -type f -delete 2>/dev/null || true + @echo "Cleanup complete!" \ No newline at end of file diff --git a/README.md b/README.md index 0d1ff99..dc061c2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # nvm-auto-use.fish -Automates loading the correct Node.js version from `.nvmrc` in Fish shell. +Intelligent Node.js version management for Fish shell with automatic version switching, multi-manager support, +and extensive configuration options. ## Installation @@ -10,18 +11,122 @@ Ensure you have [fisher](https://github.com/jorgebucaran/fisher) installed, then fisher install ivuorinen/nvm-auto-use.fish ``` -## Usage +## Features -This script automatically detects the `.nvmrc` file in your current or -parent directories and loads the specified Node.js version. +### 🚀 **Automatic Version Switching** -If the specified version is not installed, it will be installed -automatically using `nvm install`. +- Detects Node.js version files when changing directories +- Supports multiple file formats: `.nvmrc`, `.node-version`, `.tool-versions`, `package.json` engines.node +- Handles version aliases: `lts`, `latest`, `stable`, `node` +- Automatic version installation when missing + +### ⚡ **Performance & UX** + +- **Smart caching** - Avoids redundant file reads and version switches +- **Debouncing** - Prevents rapid switching during quick navigation +- **Silent mode** - Suppress output messages +- **Visual indicators** - Display current Node.js version in prompt + +### 🔧 **Multi-Manager Compatibility** + +- **nvm** - Node Version Manager +- **fnm** - Fast Node Manager +- **volta** - JavaScript toolchain manager +- **asdf** - Extendable version manager + +### ⚙️ **Extensive Configuration** + +- Toggle automatic installation +- Directory exclusion patterns +- Configurable debounce timing +- Manager preference selection +- Project-only activation mode + +### 🔔 **Developer Tools** + +- Desktop notifications for version switches +- Environment variable export (`NODE_VERSION`) +- Fish shell completions +- Detailed status reporting + +## Quick Start + +After installation, the plugin works automatically! Simply navigate to any directory with a Node.js version file: + +```fish +# Create a project with specific Node version +echo "18.17.0" > .nvmrc +cd . # Automatically switches to Node.js v18.17.0 + +# Works with package.json too +echo '{"engines": {"node": ">=16.0.0"}}' > package.json +cd . # Switches to compatible Node.js version +``` + +## Configuration + +Customize the plugin behavior with `nvm_auto_use_config`: + +```fish +# View current settings +nvm_auto_use_config + +# Enable silent mode +nvm_auto_use_config silent on + +# Disable automatic installation +nvm_auto_use_config auto_install off + +# Set preferred version manager +nvm_auto_use_config manager fnm + +# Adjust debounce timing (milliseconds) +nvm_auto_use_config debounce 1000 + +# Exclude directories +nvm_auto_use_config exclude "build" +nvm_auto_use_config exclude "dist" + +# Reset all settings +nvm_auto_use_config reset +``` + +## Supported File Formats + +| File | Format | Example | +|------|--------|---------| +| `.nvmrc` | Plain version | `18.17.0` or `lts/hydrogen` | +| `.node-version` | Plain version | `18.17.0` | +| `.tool-versions` | Tool + version | `nodejs 18.17.0` | +| `package.json` | engines.node field | `"engines": {"node": ">=16.0.0"}` | + +## Utility Functions + +```fish +# Check current Node.js status +nvm_version_status + +# Get version for prompt integration +nvm_version_prompt # Returns: ⬢ 18.17.0 + +# Control silent mode +nvm_auto_use_silent on/off + +# Detect available version managers +nvm_compat_detect +``` + +## Requirements + +- Fish shell 3.0+ +- At least one supported Node.js version manager: + - [nvm](https://github.com/nvm-sh/nvm) + - [fnm](https://github.com/Schniz/fnm) + - [volta](https://volta.sh/) + - [asdf](https://asdf-vm.com/) with nodejs plugin ## Uninstall -To remove the plugin, run: - ```fish fisher remove ivuorinen/nvm-auto-use.fish ``` diff --git a/completions/nvm_auto_use_config.fish b/completions/nvm_auto_use_config.fish new file mode 100644 index 0000000..33aa5e8 --- /dev/null +++ b/completions/nvm_auto_use_config.fish @@ -0,0 +1,27 @@ +# Completions for nvm_auto_use_config +complete -c nvm_auto_use_config -f + +# Main commands +complete -c nvm_auto_use_config -n "not __fish_seen_subcommand_from auto_install silent debounce exclude include manager reset" -a auto_install -d "Toggle automatic version installation" +complete -c nvm_auto_use_config -n "not __fish_seen_subcommand_from auto_install silent debounce exclude include manager reset" -a silent -d "Toggle silent mode" +complete -c nvm_auto_use_config -n "not __fish_seen_subcommand_from auto_install silent debounce exclude include manager reset" -a debounce -d "Set debounce time in milliseconds" +complete -c nvm_auto_use_config -n "not __fish_seen_subcommand_from auto_install silent debounce exclude include manager reset" -a exclude -d "Add directory pattern to exclusion list" +complete -c nvm_auto_use_config -n "not __fish_seen_subcommand_from auto_install silent debounce exclude include manager reset" -a include -d "Remove directory pattern from exclusion list" +complete -c nvm_auto_use_config -n "not __fish_seen_subcommand_from auto_install silent debounce exclude include manager reset" -a manager -d "Set preferred version manager" +complete -c nvm_auto_use_config -n "not __fish_seen_subcommand_from auto_install silent debounce exclude include manager reset" -a reset -d "Reset all configuration to defaults" + +# Boolean options +complete -c nvm_auto_use_config -n "__fish_seen_subcommand_from auto_install silent" -a "on enable true 1" -d Enable +complete -c nvm_auto_use_config -n "__fish_seen_subcommand_from auto_install silent" -a "off disable false 0" -d Disable + +# Manager options +complete -c nvm_auto_use_config -n "__fish_seen_subcommand_from manager" -a nvm -d "Use Node Version Manager" +complete -c nvm_auto_use_config -n "__fish_seen_subcommand_from manager" -a fnm -d "Use Fast Node Manager" +complete -c nvm_auto_use_config -n "__fish_seen_subcommand_from manager" -a volta -d "Use Volta" +complete -c nvm_auto_use_config -n "__fish_seen_subcommand_from manager" -a asdf -d "Use asdf" + +# Common directory patterns for exclusion +complete -c nvm_auto_use_config -n "__fish_seen_subcommand_from exclude" -a node_modules -d "Exclude node_modules directories" +complete -c nvm_auto_use_config -n "__fish_seen_subcommand_from exclude" -a ".git" -d "Exclude .git directories" +complete -c nvm_auto_use_config -n "__fish_seen_subcommand_from exclude" -a build -d "Exclude build directories" +complete -c nvm_auto_use_config -n "__fish_seen_subcommand_from exclude" -a dist -d "Exclude dist directories" diff --git a/functions/nvm_auto_use.fish b/functions/nvm_auto_use.fish index d52dc4d..cc61a3f 100644 --- a/functions/nvm_auto_use.fish +++ b/functions/nvm_auto_use.fish @@ -1,17 +1,130 @@ function nvm_auto_use --on-variable PWD - set -l nvmrc_file (nvm_find_nvmrc) - if test -n "$nvmrc_file" - set -l node_version (cat "$nvmrc_file") - - # Check the current version - set -l current_version (node -v 2>/dev/null | sed 's/v//') - - if test "$node_version" != "$current_version" - if not nvm use $node_version 2>/dev/null - echo "Node.js version $node_version not found, installing..." - nvm install $node_version && nvm use $node_version - end + # Detect available Node.js version manager + set -l available_managers (nvm_compat_detect 2>/dev/null | tail -n 1) + if test -z "$available_managers" + return end - end -end + # Use preferred manager or first available + set -l manager + if test -n "$_nvm_auto_use_preferred_manager" + if contains "$_nvm_auto_use_preferred_manager" $available_managers + set manager "$_nvm_auto_use_preferred_manager" + end + end + + if test -z "$manager" + set manager $available_managers[1] + end + + # Check if project detection is enabled and we're in a Node.js project + if set -q _nvm_auto_use_project_only + if not nvm_project_detect + return + end + end + + # Export NODE_VERSION environment variable + if command -q node + set -gx NODE_VERSION (node -v 2>/dev/null | string replace 'v' '') + end + + # Check for excluded directories + set -l current_dir (pwd) + for pattern in $_nvm_auto_use_excluded_dirs node_modules .git + if string match -q "*/$pattern" "$current_dir"; or string match -q "*/$pattern/*" "$current_dir" + return + end + end + + # Debouncing: prevent rapid switching + set -l debounce_ms (_nvm_auto_use_get_debounce) + set -l current_time (date +%s%3N 2>/dev/null; or date +%s) + if test -n "$_nvm_auto_use_last_change" + set -l time_diff (math "$current_time - $_nvm_auto_use_last_change") + if test $time_diff -lt $debounce_ms + return + end + end + set -g _nvm_auto_use_last_change $current_time + + set -l nvmrc_file (nvm_find_nvmrc) + + # Cache check: if same file and version, skip processing + if test "$nvmrc_file" = "$_nvm_auto_use_cached_file" + return + end + + if test -n "$nvmrc_file" + set -l node_version (nvm_extract_version "$nvmrc_file") + + # Cache the file path + set -g _nvm_auto_use_cached_file "$nvmrc_file" + + # Validate node version format (basic semver or major version) + if not string match -qr '^v?[0-9]+(\..*)?$' "$node_version" + if not set -q _nvm_auto_use_silent + echo "Invalid Node.js version format in $nvmrc_file: $node_version" >&2 + end + return 1 + end + + # Remove 'v' prefix if present + set node_version (string replace -r '^v' '' "$node_version") + + # Cache the version + set -g _nvm_auto_use_cached_version "$node_version" + + # Check the current version + set -l current_version + if command -q node + set current_version (node -v 2>/dev/null | sed 's/v//') + end + + if test "$node_version" != "$current_version" + if not set -q _nvm_auto_use_silent + echo "Switching to Node.js v$node_version" + end + + # Send notification if enabled + if not set -q _nvm_auto_use_silent + nvm_notify "Switched to Node.js v$node_version" + end + + if not nvm_compat_use $manager $node_version 2>/dev/null + # Check if auto-install is disabled + if set -q _nvm_auto_use_no_install + if not set -q _nvm_auto_use_silent + echo "Node.js version $node_version not found (auto-install disabled)" >&2 + end + return 1 + end + + if not set -q _nvm_auto_use_silent + echo "Node.js version $node_version not found, installing..." + end + if nvm_compat_install $manager $node_version >/dev/null 2>&1 + nvm_compat_use $manager $node_version >/dev/null 2>&1 + if not set -q _nvm_auto_use_silent + echo "Installed and switched to Node.js v$node_version" + end + else + if not set -q _nvm_auto_use_silent + echo "Failed to install Node.js version $node_version" >&2 + end + return 1 + end + end + + # Update cached version after successful switch + set -g _nvm_auto_use_cached_version "$node_version" + + # Update NODE_VERSION environment variable + set -gx NODE_VERSION "$node_version" + end + else + # Clear cache if no .nvmrc found + set -e _nvm_auto_use_cached_file + set -e _nvm_auto_use_cached_version + end +end diff --git a/functions/nvm_auto_use_config.fish b/functions/nvm_auto_use_config.fish new file mode 100644 index 0000000..f0f88a2 --- /dev/null +++ b/functions/nvm_auto_use_config.fish @@ -0,0 +1,100 @@ +function nvm_auto_use_config -d "Configure nvm-auto-use settings" + if test (count $argv) -eq 0 + echo "nvm-auto-use configuration:" + echo " auto_install: "(test -n "$_nvm_auto_use_no_install"; and echo "disabled"; or echo "enabled") + echo " silent: "(test -n "$_nvm_auto_use_silent"; and echo "enabled"; or echo "disabled") + echo " debounce_ms: "(_nvm_auto_use_get_debounce) + echo " excluded_dirs: "(_nvm_auto_use_get_excluded_dirs) + echo " preferred_manager: "(test -n "$_nvm_auto_use_preferred_manager"; and echo "$_nvm_auto_use_preferred_manager"; or echo "auto-detect") + return + end + + switch $argv[1] + case auto_install + switch $argv[2] + case on enable true 1 + set -e _nvm_auto_use_no_install + echo "Auto-install enabled" + case off disable false 0 + set -g _nvm_auto_use_no_install 1 + echo "Auto-install disabled" + case '*' + echo "Usage: nvm_auto_use_config auto_install [on|off]" + end + case silent + switch $argv[2] + case on enable true 1 + set -g _nvm_auto_use_silent 1 + echo "Silent mode enabled" + case off disable false 0 + set -e _nvm_auto_use_silent + echo "Silent mode disabled" + case '*' + echo "Usage: nvm_auto_use_config silent [on|off]" + end + case debounce + if test -n "$argv[2]" -a (string match -r '^[0-9]+$' "$argv[2]") + set -g _nvm_auto_use_debounce_ms $argv[2] + echo "Debounce set to $argv[2]ms" + else + echo "Usage: nvm_auto_use_config debounce " + end + case exclude + if test -n "$argv[2]" + set -g _nvm_auto_use_excluded_dirs $_nvm_auto_use_excluded_dirs $argv[2] + echo "Added $argv[2] to excluded directories" + else + echo "Usage: nvm_auto_use_config exclude " + end + case include + if test -n "$argv[2]" + set -l index (contains -i "$argv[2]" $_nvm_auto_use_excluded_dirs) + if test -n "$index" + set -e _nvm_auto_use_excluded_dirs[$index] + echo "Removed $argv[2] from excluded directories" + else + echo "$argv[2] was not in excluded directories" + end + else + echo "Usage: nvm_auto_use_config include " + end + case manager + if test -n "$argv[2]" + if contains "$argv[2]" nvm fnm volta asdf + set -g _nvm_auto_use_preferred_manager "$argv[2]" + echo "Preferred manager set to $argv[2]" + else + echo "Unsupported manager. Supported: nvm, fnm, volta, asdf" + end + else + set -e _nvm_auto_use_preferred_manager + echo "Reset to auto-detect manager" + end + case reset + set -e _nvm_auto_use_no_install + set -e _nvm_auto_use_silent + set -e _nvm_auto_use_debounce_ms + set -e _nvm_auto_use_excluded_dirs + set -e _nvm_auto_use_preferred_manager + echo "Configuration reset to defaults" + case '*' + echo "Usage: nvm_auto_use_config [auto_install|silent|debounce|exclude|include|manager|reset] [value]" + return 1 + end +end + +function _nvm_auto_use_get_debounce + if test -n "$_nvm_auto_use_debounce_ms" + echo "$_nvm_auto_use_debounce_ms" + else + echo 500 + end +end + +function _nvm_auto_use_get_excluded_dirs + if test -n "$_nvm_auto_use_excluded_dirs" + string join ', ' $_nvm_auto_use_excluded_dirs + else + echo "node_modules, .git" + end +end diff --git a/functions/nvm_auto_use_silent.fish b/functions/nvm_auto_use_silent.fish new file mode 100644 index 0000000..fc2cd89 --- /dev/null +++ b/functions/nvm_auto_use_silent.fish @@ -0,0 +1,22 @@ +function nvm_auto_use_silent -d "Enable or disable silent mode for nvm-auto-use" + if test (count $argv) -eq 0 + if set -q _nvm_auto_use_silent + echo "Silent mode: enabled" + else + echo "Silent mode: disabled" + end + return + end + + switch $argv[1] + case on enable true 1 + set -g _nvm_auto_use_silent 1 + echo "Silent mode enabled" + case off disable false 0 + set -e _nvm_auto_use_silent + echo "Silent mode disabled" + case '*' + echo "Usage: nvm_auto_use_silent [on|off]" + return 1 + end +end diff --git a/functions/nvm_compat_detect.fish b/functions/nvm_compat_detect.fish new file mode 100644 index 0000000..4862c63 --- /dev/null +++ b/functions/nvm_compat_detect.fish @@ -0,0 +1,71 @@ +function nvm_compat_detect -d "Detect available Node.js version managers" + set -l managers + + if command -q nvm + set managers $managers nvm + end + + if command -q fnm + set managers $managers fnm + end + + if command -q volta + set managers $managers volta + end + + if command -q asdf; and test -f ~/.tool-versions + if grep -q nodejs ~/.tool-versions 2>/dev/null + set managers $managers asdf + end + end + + if test (count $managers) -eq 0 + echo "No supported Node.js version managers found" + return 1 + end + + echo "Available managers:" (string join ", " $managers) + echo $managers +end + +function nvm_compat_use -a manager version -d "Use specified version with detected manager" + if test -z "$manager" -o -z "$version" + echo "Usage: nvm_compat_use " + return 1 + end + + switch $manager + case nvm + nvm use $version + case fnm + fnm use $version + case volta + volta pin node@$version + case asdf + asdf local nodejs $version + case '*' + echo "Unsupported manager: $manager" + return 1 + end +end + +function nvm_compat_install -a manager version -d "Install specified version with detected manager" + if test -z "$manager" -o -z "$version" + echo "Usage: nvm_compat_install " + return 1 + end + + switch $manager + case nvm + nvm install $version + case fnm + fnm install $version + case volta + volta install node@$version + case asdf + asdf install nodejs $version + case '*' + echo "Unsupported manager: $manager" + return 1 + end +end diff --git a/functions/nvm_extract_version.fish b/functions/nvm_extract_version.fish new file mode 100644 index 0000000..7f67391 --- /dev/null +++ b/functions/nvm_extract_version.fish @@ -0,0 +1,51 @@ +function nvm_extract_version -a file_path -d "Extract Node.js version from various file formats" + if test -z "$file_path" + return 1 + end + + set -l file_name (basename "$file_path") + set -l version_info (string split ':' "$file_path") + set -l actual_file $version_info[1] + set -l format $version_info[2] + + if not test -f "$actual_file" -a -r "$actual_file" + return 1 + end + + switch "$format" + case engines.node + # Extract from package.json engines.node field + if command -q jq + set -l version (jq -r '.engines.node // empty' "$actual_file" 2>/dev/null) + if test -n "$version" -a "$version" != null + # Handle version ranges - extract first valid version + set version (string replace -r '^[^0-9]*([0-9]+\.?[0-9]*\.?[0-9]*).*' '$1' "$version") + echo "$version" + return 0 + end + end + case nodejs + # Extract from .tool-versions nodejs line + set -l version (grep '^nodejs ' "$actual_file" | cut -d' ' -f2 | string trim) + if test -n "$version" + echo "$version" + return 0 + end + case '*' + # Standard .nvmrc or .node-version file + set -l version (cat "$actual_file" | string trim) + if test -n "$version" + # Handle nvm aliases + switch "$version" + case 'lts/*' lts latest stable node + if command -q nvm + set version (nvm version-remote "$version" 2>/dev/null | string replace 'v' '') + end + end + echo "$version" + return 0 + end + end + + return 1 +end diff --git a/functions/nvm_find_nvmrc.fish b/functions/nvm_find_nvmrc.fish index 2af1b52..2512ca9 100644 --- a/functions/nvm_find_nvmrc.fish +++ b/functions/nvm_find_nvmrc.fish @@ -1,11 +1,40 @@ function nvm_find_nvmrc - set -l dir (pwd) - while test "$dir" != "/" - if test -f "$dir/.nvmrc" - echo "$dir/.nvmrc" - return - end - set dir (dirname "$dir") - end -end + set -l dir (pwd) + # Validate current directory + if test -z "$dir" + return 1 + end + + while test "$dir" != / + # Check for multiple file formats in order of preference + for file in .nvmrc .node-version .tool-versions package.json + set -l file_path "$dir/$file" + if test -f "$file_path" -a -r "$file_path" + switch $file + case package.json + # Extract engines.node field from package.json + if command -q jq + set -l node_version (jq -r '.engines.node // empty' "$file_path" 2>/dev/null) + if test -n "$node_version" -a "$node_version" != null + echo "$file_path:engines.node" + return 0 + end + end + case .tool-versions + # Check if .tool-versions contains nodejs entry + if grep -q '^nodejs ' "$file_path" 2>/dev/null + echo "$file_path:nodejs" + return 0 + end + case '*' + echo "$file_path" + return 0 + end + end + end + set dir (dirname "$dir") + end + + return 1 +end diff --git a/functions/nvm_notify.fish b/functions/nvm_notify.fish new file mode 100644 index 0000000..a2615f1 --- /dev/null +++ b/functions/nvm_notify.fish @@ -0,0 +1,32 @@ +function nvm_notify -a message -d "Send notification for Node.js version changes" + if test -z "$message" + return 1 + end + + # Check if notifications are enabled + if set -q _nvm_auto_use_no_notifications + return + end + + # Try different notification methods + if command -q osascript # macOS + osascript -e "display notification \"$message\" with title \"nvm-auto-use\"" + else if command -q notify-send # Linux + notify-send nvm-auto-use "$message" + else if command -q terminal-notifier # macOS alternative + terminal-notifier -title nvm-auto-use -message "$message" + end +end + +function nvm_project_detect -d "Check if current directory is a Node.js project" + set -l dir (pwd) + + while test "$dir" != / + if test -f "$dir/package.json" + return 0 + end + set dir (dirname "$dir") + end + + return 1 +end diff --git a/functions/nvm_version_prompt.fish b/functions/nvm_version_prompt.fish new file mode 100644 index 0000000..7f73e0a --- /dev/null +++ b/functions/nvm_version_prompt.fish @@ -0,0 +1,26 @@ +function nvm_version_prompt -d "Display current Node.js version for prompt integration" + if command -q node + set -l version (node -v 2>/dev/null | string replace 'v' '') + if test -n "$version" + echo "⬢ $version" + end + end +end + +function nvm_version_status -d "Show detailed Node.js version status" + if command -q node + set -l version (node -v 2>/dev/null) + set -l npm_version (npm -v 2>/dev/null) + + echo "Node.js: $version" + if test -n "$npm_version" + echo "npm: v$npm_version" + end + + if set -q _nvm_auto_use_cached_file + echo "Auto-use: $_nvm_auto_use_cached_file" + end + else + echo "Node.js: not installed" + end +end