nushell: Can't use standard library module within the standard library (?)

Describe the bug

Trying to add a call to std log info in crates/nu-std/lib/dirs.nu for, e.g, std dirs next, another module in the standard library.

It would be a grave restriction indeed if some commands in the standard library could not be used within other commands of the standard library.

How to reproduce

  1. in crates/nu-std/lib/dirs.nu (for example), add use std log info in either of the locations indicated below (or both).
  2. `〉cargo run – -c ‘use std *; dirs next’
  3. or do a build and run the binary: > cargo build; target/debug/nu -c 'use std *; dirs next'

Expected behavior

Info log output from invoked dirs next command

Screenshots

10 repetitions of the ‘module not found’ error, all from the same source line.

~/src/rust/nushell〉cargo run -- -c 'use std *; dirs next'
    Finished dev [unoptimized + debuginfo] target(s) in 0.25s
     Running `target/debug/nu -c 'use std *; dirs next'`
Error: nu::parser::module_not_found

  × Module not found.
    ╭─[dirs:33:1]
 33 │ ] {
 34 │     use std "log info"
    ·         ─┬─
    ·          ╰── module not found
 35 │ 
    ╰────
  help: module files and their paths must be available before your script is run as parsing occurs before anything
        is evaluated

Error: nu::parser::module_not_found

  × Module not found.
    ╭─[dirs:33:1]
 33 │ ] {
 34 │     use std "log info"
    ·         ─┬─
    ·          ╰── module not found
 35 │ 
    ╰────
  help: module files and their paths must be available before your script is run as parsing occurs before anything
        is evaluated

Error: nu::parser::module_not_found

  × Module not found.
    ╭─[dirs:33:1]
 33 │ ] {
 34 │     use std "log info"
    ·         ─┬─
    ·          ╰── module not found
 35 │ 
    ╰────
  help: module files and their paths must be available before your script is run as parsing occurs before anything
        is evaluated

Error: nu::parser::module_not_found

  × Module not found.
    ╭─[dirs:33:1]
 33 │ ] {
 34 │     use std "log info"
    ·         ─┬─
    ·          ╰── module not found
 35 │ 
    ╰────
  help: module files and their paths must be available before your script is run as parsing occurs before anything
        is evaluated

Error: nu::parser::module_not_found

  × Module not found.
    ╭─[dirs:33:1]
 33 │ ] {
 34 │     use std "log info"
    ·         ─┬─
    ·          ╰── module not found
 35 │ 
    ╰────
  help: module files and their paths must be available before your script is run as parsing occurs before anything
        is evaluated

Error: nu::parser::module_not_found

  × Module not found.
    ╭─[dirs:33:1]
 33 │ ] {
 34 │     use std "log info"
    ·         ─┬─
    ·          ╰── module not found
 35 │ 
    ╰────
  help: module files and their paths must be available before your script is run as parsing occurs before anything
        is evaluated

Error: nu::parser::module_not_found

  × Module not found.
    ╭─[dirs:33:1]
 33 │ ] {
 34 │     use std "log info"
    ·         ─┬─
    ·          ╰── module not found
 35 │ 
    ╰────
  help: module files and their paths must be available before your script is run as parsing occurs before anything
        is evaluated

Error: nu::parser::module_not_found

  × Module not found.
    ╭─[dirs:33:1]
 33 │ ] {
 34 │     use std "log info"
    ·         ─┬─
    ·          ╰── module not found
 35 │ 
    ╰────
  help: module files and their paths must be available before your script is run as parsing occurs before anything
        is evaluated

Error: nu::parser::module_not_found

  × Module not found.
    ╭─[dirs:33:1]
 33 │ ] {
 34 │     use std "log info"
    ·         ─┬─
    ·          ╰── module not found
 35 │ 
    ╰────
  help: module files and their paths must be available before your script is run as parsing occurs before anything
        is evaluated

Error: nu::parser::module_not_found

  × Module not found.
    ╭─[dirs:33:1]
 33 │ ] {
 34 │     use std "log info"
    ·         ─┬─
    ·          ╰── module not found
 35 │ 
    ╰────
  help: module files and their paths must be available before your script is run as parsing occurs before anything
        is evaluated

thread 'main' panicked at 'Internal error: can't run a predeclaration without a body', crates/nu-protocol/src/signature.rs:686:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Error: nu::shell::column_not_found

  

Configuration

key value
version 0.78.1
branch stdlib_contributing
commit_hash f2b977b9c59931ad2b5e55174e63ebbec50b8cbe
build_os linux-x86_64
build_target x86_64-unknown-linux-gnu
rust_version rustc 1.66.1 (90743e729 2023-01-10)
rust_channel 1.66.1-x86_64-unknown-linux-gnu
cargo_version cargo 1.66.1 (ad779e08b 2023-01-10)
build_time 2023-04-07 21:17:57 -04:00
build_rust_channel debug
features default, zip
installed_plugins

Additional context

Here’s the relevant chunk of dirs.nu:

# Maintain a list of working directories and navigates them

use std "log info"

# the directory stack
export-env {
    let-env DIRS_POSITION = 0
    let-env DIRS_LIST = [($env.PWD | path expand)]
}

# Add one or more directories to the list.
# PWD becomes first of the newly added directories.
export def-env "dirs add" [
    ...paths: string    # directory or directories to add to working list
    ] {
        mut abspaths = []
        for p in $paths {
            let exp = ($p | path expand)
            if ($exp | path type) != 'dir' {
                let span = (metadata $p).span
                error make {msg: "not a directory", label: {text: "not a directory", start: $span.start, end: $span.end } }
            }
        $abspaths = ($abspaths | append $exp)

        }
        let-env DIRS_LIST = ($env.DIRS_LIST | insert ($env.DIRS_POSITION + 1) $abspaths | flatten)
        let-env DIRS_POSITION = $env.DIRS_POSITION + 1

    _fetch 0
}

# Advance to the next directory in the list or wrap to beginning.
export def-env "dirs next" [
    N:int = 1   # number of positions to move.
] {
    use std "log info"

    _fetch $N
    log info $"advancing to position ($env.DIRS_POSITION)"
}

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 15 (14 by maintainers)

Commits related to this issue

Most upvoted comments

@bobhy The file cache would allow you to use use log.nu from inside std.nu loaded inside Nushell without the files being on the disk. It would need to be marked as a “virtual file” or something like that which would bypass the otherwise mandatory check whether the file contents have changed (they cannot change because it’s read-only). At least that’s my idea how to solve this problem that doesn’t require redesigning the current module system.

@amtoine, as a quick fix, it seems reasonable to me to load helpers first so they can be used by all, like log and assert.

Ah, I see. Seems like we should finally create the long-awaited file cache and make use etc. aware of it. Then, when calling use log.nu, the parser would look into the cache first, see that log.nu was already parsed before and give the parsed module without reparsing. That way you don’t need the file to be on disk. Since the file is not in the file system, there is no chance it could change, so it should be safe to do so. We could` also write out the stdlib into real files but that brings issues with versioning etc.

If possible, I’d prefer not having submodules aware of being a part of some top module because it adds a lot of complexity and hinders code reuse. So far, we used a simple file-based module system that I think works quite well and is very straightforward. The stdlib is special because it doesn’t have real files at runtime, but I think that’s the only case where you’d have a Nushell module without a corresponding .nu file. The only other one I can think of are plugins in the future. If we make the file cache aware of this, we should be able to get around it.