Skip to content

Add nushell support#17

Open
andrestielau wants to merge 22 commits into
jvPalma:masterfrom
andrestielau:add-nushell-support
Open

Add nushell support#17
andrestielau wants to merge 22 commits into
jvPalma:masterfrom
andrestielau:add-nushell-support

Conversation

@andrestielau
Copy link
Copy Markdown

Description

Add Nushell as a first-class shell alongside Bash, Zsh, and Fish. This includes shell-aware
script dispatch (.nu/.sh preference based on caller shell), POSIX alias/config parsing for
Nushell, a monolithic tab completion system using the unified _dr_filesystem_find signature,
bootstrap via ~/.drrc.nu, and installer/dev setup integration.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as
    expected)
  • Documentation update
  • Refactor (no functional changes)
  • Other (please describe):

Testing

  • Tested on Bash
  • Tested on Zsh
  • Tested on Fish (if applicable)
  • ShellCheck passes with no errors

36 BATS tests covering script dispatch, alias/config loading, completion finder, hidden
directory pruning, and sort ordering. All passing. Nu-dependent tests auto-skip when Nushell is
not installed.

$ ./test.sh
Found 4 test file(s):
  core/shared/dotrun/core/scripts.bats                                                          
  core/shared/dotrun/shell/nu/aliases.bats
  core/shared/dotrun/shell/nu/configs.bats                                                      
  core/shared/dotrun/shell/nu/dr_completion.bats          
                                                                                                
1..36                                                                                           
ok 1 find_script_file: explicit .sh extension finds .sh file
ok 2 find_script_file: explicit .nu extension finds .nu file                                    
...                                                       
ok 36 source parses without error                                                               
                                                                                                
Checklist
                                                                                                
- Documentation updated (if needed)                       
- CHANGELOG.md updated
- Code follows the project's style guidelines
- No new warnings introduced                                                                    

Related Issues                                                                                  
                                                          
Screenshots/Output                                                                              

# Explicit extension dispatch                                                                   
$ dr testscript.sh                                        
bash version                                                                                    

$ dr testscript.nu                                                                              
nu version                                                

# Shell-aware preference (from Nushell, prefers .nu)                                            
$ dr testscript
nu version                                                                                      
                                                          
# Script creation
$ dr set myscript.nu   # Creates .nu with Nushell template
$ dr set myscript.sh   # Creates .sh with Bash template                                         

# Reload from Nushell                                                                           
$ dr reload                                               
Nushell does not support reload from a child process.                                           
Run this in your Nushell session:
  source ~/.drrc.nu 

andrestielau and others added 21 commits March 25, 2026 14:36
Design document for adding Nushell as a first-class shell in dotrun,
covering bootstrap, alias/config loading, script dispatch, completions,
installation, and testing strategy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
14-task implementation plan covering: script template, shell detection,
multi-extension dispatch, script creation, alias/config loaders,
completion system, bootstrap, installer, dev setup, reload message,
documentation, test runner, and integration verification.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ence

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
validate_script_name() now permits dots so dr set myscript.nu works.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ride

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rride

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove `local` keyword outside function in dr reload handler (C1)
- Preserve file extension in move_script() for .nu files (I1)
- Update list_feature_files_tree.sh to find both .sh and .nu scripts (I2)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Added Nushell-specific directory to CONTRIBUTING.md.
- Updated .drrc.nu to capture environment variables from Bash.
- Removed .nu script support from scripts.bats and scripts.sh.
- Deleted unused .nu template and related files.
- Updated README.md to reflect changes in Nushell integration.
- Removed tests and configurations related to .nu files.
- Adjusted dr_completion to only consider .sh files for script completion.
}

# Validate a script file is executable and not a broken symlink
_validate_script_file() {
Copy link
Copy Markdown
Collaborator

@jvPalma-anchorage jvPalma-anchorage Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function should be created before the top of the find_script_file function, since it uses is internally, and depending on the shell, it can break it to use something not yet loaded/created

Comment on lines +28 to +30
"scripts" => "🚀 Script"
"aliases" => "📝 Alias file"
"configs" => "⚙️ Config"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be just the icons, because this is supposed to append to the autocomplete filenames of the FEATURE file we are accessing, so, when we do:

dr -a <TAB>

we should se something like:

  📝 01.customalias.aliases
  📝 02.customalias.aliases

but with this, we would get:

  📝 Alias file 01.customalias.aliases
  📝 Alias file 02.customalias.aliases

Comment on lines +159 to +169
} else if ("-col" in $words) or ("collections" in $words) {
[
{value: "add", description: "➕ Add collection"}
{value: "list", description: "📋 List collections"}
{value: "list:details", description: "📋 List with details"}
{value: "remove", description: "🗑️ Remove collection"}
{value: "set", description: "⚙️ Set collection"}
{value: "sync", description: "🔄 Sync collections"}
{value: "update", description: "⬆️ Update collections"}
]
} else {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we dont have this format anywhere, but i like it
lets just make the spacing between the icon and text equal, as the Remove/Set/Update have 2_spaces instead of 1_space like the others

}
| each {|p|
let basename = ($p | path basename)
{value: $"($prefix)($basename)/", description: "📁 Folder"}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also be something like

Suggested change
{value: $"($prefix)($basename)/", description: "📁 Folder"}
{value: $"($prefix)($basename)/", description: $"📁 ($basename)"}

Copy link
Copy Markdown
Collaborator

@jvPalma-anchorage jvPalma-anchorage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work getting nushell integration started — the completion system is well-structured, the bats test coverage is solid, and the capture-foreign-env function is a clever approach.

There are some critical issues to address before merge (alias parsing bugs, parse-time source crashes), plus architectural alignment needed with the project spec. See inline comments below.

Key themes:

  1. Alias generation has parsing bugs and skips complex aliases — spec requires bash -c wrapping for all
  2. source in nushell is parse-time — missing files crash the entire shell config
  3. Architecture should follow the modular shell/nushell/ pattern (4 files) instead of the monolithic .drrc.nu approach
  4. Directory should be shell/nushell/ (not shell/nu/) for consistency with bash/, zsh/, fish/

Version: This adds a new shell as a first-class citizen — recommend bumping to v4.0.0 (not 3.2.0). Current master is 3.1.3, so the VERSION file will also need rebasing.

I've prepared an OpenSpec proposal (openspec/changes/add-nushell-integration/) with the full spec, design decisions, and task breakdown. Please review it for the expected architecture and requirements.

Comment thread VERSION
@@ -1 +1 @@
3.1.2
3.2.0
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new major feature (fourth shell as a first-class citizen), not a minor bump. Recommend v4.0.0 instead of 3.2.0.

Also, master is currently at 3.1.3 — this will conflict on rebase.

Comment thread CONTRIBUTING.md
│ │ │ ├── bash/ # Bash-specific code
│ │ │ ├── zsh/ # Zsh-specific code
│ │ │ └── fish/ # Fish-specific code
│ │ │ └── nu/ # Nushell-specific code
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two issues:

  1. The └── fish/ on the line above should become ├── fish/ since nushell/ follows it
  2. Directory name should be nushell/ (not nu/) for consistency with bash/, zsh/, fish/

Comment thread core/home/.drrc.nu
@@ -0,0 +1,56 @@
# DotRun Configuration - Nushell
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Architecture: split into modular files

The project follows a pattern where each shell has its own directory under shell/<name>/ with dedicated files for configs, aliases, and completion. This file combines config loading, alias generation, and sourcing into one monolithic file placed outside the shell directory.

Requested change: Split into the modular pattern:

shell/nushell/
├── dr_config_loader.nu   # Entry point (sources the others)
├── configs.nu            # Parse *.config files → load-env
├── aliases.nu            # Generate + source alias temp file
└── dr_completion.nu      # Tab completion (already exists)

The user's config.nu would then have:

source ~/.local/share/dotrun/shell/nushell/dr_config_loader.nu

See openspec/changes/add-nushell-integration/design.md for the full design rationale.

Comment thread core/home/.drrc.nu

# Capture environment from the bash .drrc (the actual source of truth)
# This runs .drrc in bash and captures all env var changes.
def capture-foreign-env [
Copy link
Copy Markdown
Collaborator

@jvPalma-anchorage jvPalma-anchorage Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

capture-foreign-env — acknowledge the complexity, but harden the implementation

After reviewing the actual config files in ~/.config/dotrun/configs/, I want to correct my earlier suggestion. These are NOT simple export KEY=value files — they contain:

  • Bash functions with lazy-loading patterns (e.g., nvm_lazy_load(), wrapper functions for nvm, node, npm, yarn)
  • Conditional logic based on $CURRENT_SHELL (gcloud, fzf shell-specific integrations)
  • source/eval commands (cargo env, fzf --bash/--zsh)
  • Array operations and loops (PATH deduplication, multi-path addition)
  • Shell-specific tool integrations (gcloud completion loading)

Given this complexity, running the configs through bash and capturing the resulting env vars is actually the right approach — you cannot parse these natively in nushell.

However, the implementation still needs hardening:

  1. Fence string (<ENV_CAPTURE_EVAL_FENCE>) — use a UUID-like token to avoid silent corruption if any env var contains that string
  2. SCRIPT_TO_SOURCE env var name — rename to something collision-proof like __DR_INTERNAL_EVAL_PAYLOAD__
  3. The approach only captures env var side effects — function definitions (like nvm lazy-loaders) and completions will NOT transfer to nushell. This is an inherent limitation that should be documented.
  4. Shell-specific tool configs (fzf, gcloud) that check $CURRENT_SHELL will need nushell equivalents added by users — document this as a known limitation.

Recommendation: Keep capture-foreign-env for config loading, but move it into a dedicated configs.nu file inside shell/nushell/ rather than inlining it in .drrc.nu.

Comment thread core/home/.drrc.nu
# Runs a bash script that parses alias files and writes Nushell-compatible syntax
# to ~/.cache/dotrun/aliases.nu. Simple aliases translate directly;
# complex aliases (pipes, &&, subshells) are skipped with a comment.
^bash ~/.local/share/dotrun/shell/nu/generate_aliases.sh
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If generate_aliases.sh fails (bash not found, script missing, set -euo pipefail error), no error is caught. The subsequent source on line 53 will crash the shell if the file wasn't created.

At minimum, ensure the generated file always exists (even empty) regardless of script success/failure.

Comment thread install.sh
echo "$INSTALL_HOME/.config/fish/config.fish"
;;
nu)
echo "$INSTALL_HOME/.config/nushell/config.nu"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded path doesn't respect $XDG_CONFIG_HOME. The installer already defines INSTALL_CFG_PATH=${XDG_CONFIG_HOME:-$HOME/.config} at line 9.

On macOS, nushell uses ~/Library/Application Support/nushell/config.nu by default.

Fix:

echo "$INSTALL_CFG_PATH/nushell/config.nu"

`dr reload` cannot modify the parent Nushell environment. Instead, run:

source ~/.drrc.nu

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This row says aliases are "Not supported (Nushell limitation)" but the PR implements alias generation via generate_aliases.sh. The body text above correctly describes the alias system.

Fix: Update to match the implementation, e.g., "Auto-translated via bash -c wrapping".

1. **Dynamic aliases** — Nushell aliases must be defined at parse time, not runtime.
Define aliases directly in your `config.nu`.

2. **`dr reload`** — Cannot modify parent Nushell environment from a child bash process.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generate_aliases.sh is missing from this Files table.

Comment thread test.sh
set -euo pipefail

# DotRun Test Runner
# Discovers and runs all .bats test files
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment says "Discovers and runs all .bats test files" but the find on line 18 only searches $SCRIPT_DIR/core. Either broaden to $SCRIPT_DIR or adjust the comment to say "under core/".

@@ -0,0 +1,182 @@
#!/usr/bin/env bats
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good test coverage for dr-filesystem-find (16 tests). However, there are no tests for the actual completer function nu-complete dr. Missing scenarios:

  • -col/collections namespace returning subcommand list
  • -s, -a, -c namespace routing
  • Pattern filtering (the pattern? parameter)

Consider adding at least a smoke test for the completer with different context strings.

Copy link
Copy Markdown
Collaborator

@jvPalma-anchorage jvPalma-anchorage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work getting nushell integration started — the completion system is well-structured, the bats test coverage is solid, and the capture-foreign-env function is a clever approach.

There are some critical issues to address before merge (alias parsing bugs, parse-time source crashes), plus architectural alignment needed with the project spec. See inline comments below.

Key themes:

  1. Alias generation has parsing bugs and skips complex aliases — spec requires bash -c wrapping for all
  2. source in nushell is parse-time — missing files crash the entire shell config
  3. Architecture should follow the modular shell/nushell/ pattern (4 files) instead of the monolithic .drrc.nu approach
  4. Directory should be shell/nushell/ (not shell/nu/) for consistency with bash/, zsh/, fish/

Version: This adds a new shell as a first-class citizen — recommend bumping to v4.0.0 (not 3.2.0). Current master is 3.1.3, so the VERSION file will also need rebasing.

I've prepared an OpenSpec proposal (openspec/changes/add-nushell-integration/) with the full spec, design decisions, and task breakdown. Please review it for the expected architecture and requirements.

Comment thread VERSION
@@ -1 +1 @@
3.1.2
3.2.0
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new major feature (fourth shell as a first-class citizen), not a minor bump. Recommend v4.0.0 instead of 3.2.0.

Also, master is currently at 3.1.3 — this will conflict on rebase.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not a breaking change, according to semver it doesn't justify a major version change

Comment thread CONTRIBUTING.md
│ │ │ ├── bash/ # Bash-specific code
│ │ │ ├── zsh/ # Zsh-specific code
│ │ │ └── fish/ # Fish-specific code
│ │ │ └── nu/ # Nushell-specific code
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two issues:

  1. The └── fish/ on the line above should become ├── fish/ since nushell/ follows it
  2. Directory name should be nushell/ (not nu/) for consistency with bash/, zsh/, fish/

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree on the tree char used
but if they're named based on their executable or their short forms I think it should stay nu instead of nushell

Comment thread core/home/.drrc.nu
@@ -0,0 +1,56 @@
# DotRun Configuration - Nushell
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Architecture: split into modular files

The project follows a pattern where each shell has its own directory under shell/<name>/ with dedicated files for configs, aliases, and completion. This file combines config loading, alias generation, and sourcing into one monolithic file placed outside the shell directory.

Requested change: Split into the modular pattern:

shell/nushell/
├── dr_config_loader.nu   # Entry point (sources the others)
├── configs.nu            # Parse *.config files → load-env
├── aliases.nu            # Generate + source alias temp file
└── dr_completion.nu      # Tab completion (already exists)

The user's config.nu would then have:

source ~/.local/share/dotrun/shell/nushell/dr_config_loader.nu

See openspec/changes/add-nushell-integration/design.md for the full design rationale.

Comment thread core/home/.drrc.nu

# Capture environment from the bash .drrc (the actual source of truth)
# This runs .drrc in bash and captures all env var changes.
def capture-foreign-env [
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace capture-foreign-env with native config parsing

This approach (run entire bash .drrc, diff the env) is clever but fragile:

  • Fence-based parsing (<ENV_CAPTURE_EVAL_FENCE>) silently corrupts if any env var contains that string — use a UUID-like token if kept
  • SCRIPT_TO_SOURCE env var is visible to all code inside .drrc — name collision risk
  • Spawns a full bash subprocess on every shell startup

Requested change: Parse *.config files natively in nushell using load-env, matching what shell/fish/configs.sh does for fish. The config files are simple export KEY=value lines — no need to run the full bash .drrc to capture them.

Comment thread core/home/.drrc.nu
# Runs a bash script that parses alias files and writes Nushell-compatible syntax
# to ~/.cache/dotrun/aliases.nu. Simple aliases translate directly;
# complex aliases (pipes, &&, subshells) are skipped with a comment.
^bash ~/.local/share/dotrun/shell/nu/generate_aliases.sh
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If generate_aliases.sh fails (bash not found, script missing, set -euo pipefail error), no error is caught. The subsequent source on line 53 will crash the shell if the file wasn't created.

At minimum, ensure the generated file always exists (even empty) regardless of script success/failure.

Comment thread install.sh
echo "$INSTALL_HOME/.config/fish/config.fish"
;;
nu)
echo "$INSTALL_HOME/.config/nushell/config.nu"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded path doesn't respect $XDG_CONFIG_HOME. The installer already defines INSTALL_CFG_PATH=${XDG_CONFIG_HOME:-$HOME/.config} at line 9.

On macOS, nushell uses ~/Library/Application Support/nushell/config.nu by default.

Fix:

echo "$INSTALL_CFG_PATH/nushell/config.nu"

`dr reload` cannot modify the parent Nushell environment. Instead, run:

source ~/.drrc.nu

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This row says aliases are "Not supported (Nushell limitation)" but the PR implements alias generation via generate_aliases.sh. The body text above correctly describes the alias system.

Fix: Update to match the implementation, e.g., "Auto-translated via bash -c wrapping".

1. **Dynamic aliases** — Nushell aliases must be defined at parse time, not runtime.
Define aliases directly in your `config.nu`.

2. **`dr reload`** — Cannot modify parent Nushell environment from a child bash process.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generate_aliases.sh is missing from this Files table.

Comment thread test.sh
set -euo pipefail

# DotRun Test Runner
# Discovers and runs all .bats test files
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment says "Discovers and runs all .bats test files" but the find on line 18 only searches $SCRIPT_DIR/core. Either broaden to $SCRIPT_DIR or adjust the comment to say "under core/".

@@ -0,0 +1,182 @@
#!/usr/bin/env bats
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good test coverage for dr-filesystem-find (16 tests). However, there are no tests for the actual completer function nu-complete dr. Missing scenarios:

  • -col/collections namespace returning subcommand list
  • -s, -a, -c namespace routing
  • Pattern filtering (the pattern? parameter)

Consider adding at least a smoke test for the completer with different context strings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants