Similar to many other programming languages, Nushell also has modules that let you import custom commands into a current scope.
However, since Nushell is also a shell, modules allow you to import environment variables which can be used to conveniently activate/deactivate various environments.
## Basics
A simple module can be defined like this:
```
> module greetings {
export def hello [name: string] {
$"hello ($name)!"
}
export def hi [where: string] {
$"hi ($where)!"
}
}
```
We defined `hello` and `hi` custom commands inside a `greetings` module.
The `export` keyword makes it possible to later import the commands from the module.
The collection of exported symbols from a module is called an **overlay**.
You can say that the module `greetings` exports an overlay which consists of two custom commands "hello" and "hi".
By itself, the module does not do anything.
We can verify its existence by printing all available overlays:
We should allow exporting aliases as it is a common tool for creating shell environments alongside environment variables.
We need to decide a proper syntax.
### Recursive modules
We should allow using modules within modules.
That is, allowing to use `use` (and `hide`?) within the `module name { ... }` block or a module file.
This leads to a more generic question of having some standard project layout.
### Renaming imports
To avoid name clashing.
For example: `use dataframe as df`.
### Dynamic names for environment variables
The `load-env` command exists because we needed to define the environment variable name at runtime.
Currently, both `let-env` and `export env` require static environment variable names.
Could we allow them to accept an expression in place of the name?
For example `export env (whoami | str screaming-snake-case).0 { "foo" }` or `let-env (whoami | str screaming-snake-case).0 = "foo"`
### To Source or Not To Source
Currently, there are two ways to define a module in a file:
Write the literal `module name { ... }` into a file, use `source` run the file, then `use` to import from the module.
The second way is to use the `use name.nu` directly, which does not require the `module name { ... }` wrapper.
We can keep it as it is, or push into one of the following directions:
1. Rename `source` to `run` and modify it so that it runs in its own scope. Any modifications would be lost, it would be more like running a custom command. This would make it impossible for a random script to modify your environment since the only way to do that would be with the module files and the `use` command. The disadvantage is that it makes it impossible to have "startup scripts" and places some roadblocks to the user experience.
2. Remove `use` and rely on `source` and `module name { ... }` only. This resembles, e.g., Julia's `include(file.jl)` style and makes it quite intuitive. It is not very "pure" or "secure" as dedicated module files with `use`.
We might explore these as we start creating bigger programs and get a feel how a Nushell project structure could look like (and whether or not we should try to enforce one).
## Unlikely Design Ideas
### Exporting variables
`export var name { ... }` which would export a variable the same way you export environment variable.
This would allow for defining global constants in a module (think `math PI`) but can lead to bugs overwriting existing variables.
Use custom commands instead: `export def PI [] { 3.14159 }`.