Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 66 additions & 51 deletions book/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ then

The result should be similar as in the previous section.

> **Note**
> that the `use greetings.nu hello` call here first implicitly creates the `greetings` module,
> then takes `hello` from it. You could also write it as `module greetings.nu`, `use greetings hello`.
> Using `module` can be useful if you're not interested in any definitions from the module but want to,
> e.g., re-export the module (`export module greetings.nu`).
::: tip Note
Note that the `use greetings.nu hello` call here first implicitly creates the `greetings` module,
then takes `hello` from it. You could also write it as `module greetings.nu`, `use greetings hello`.
Using `module` can be useful if you're not interested in any definitions from the module but want to,
e.g., re-export the module (`export module greetings.nu`).
:::

## Modules from Directories

Expand Down Expand Up @@ -112,7 +113,7 @@ then

The name of the module follows the same rule as module created from a file: Stem of the directory name, i.e., the directory name, is used as the module name. Again, you could do this as a two-step action using `module` and `use` separately, as explained in the previous section.

::: tip
::: tip Note
You can define `main` command inside `mod.nu` to create a command named after the module directory.
:::

Expand Down Expand Up @@ -186,6 +187,8 @@ The `main` is exported only when

Importing definitions selectively (`use greetings.nu hello` or `use greetings.nu [hello hi]`) does not define the `greetings` command from `main`. You can, however, selectively import `main` using `use greetings main` (or `[main]`) which defines _only_ the `greetings` command without pulling in `hello` or `hi`.

Additionally, `main` has special behavior if used in a script file, regardless of whether it is exported or not. See the [section on scripts](scripts.html#parameterizing-scripts) for more details.

Apart from commands (`def`, `def --env`), known externals (`extern`) can also be named `main`.

## Submodules and Subcommands
Expand All @@ -197,8 +200,9 @@ Submodules are modules inside modules. They are automatically created when you c

The difference is that `export module some-module` _only_ adds the module as a submodule, while `export use some-module` _also_ re-exports the submodule's definitions. Since definitions of submodules are available when importing from a module, `export use some-module` is typically redundant, unless you want to re-export its definitions without the namespace prefix.

> **Note**
> `module` without `export` defines only a local module, it does not export a submodule.
::: tip Note
`module` without `export` defines only a local module, it does not export a submodule.
:::

Let's illustrate this with an example. Assume three files:

Expand Down Expand Up @@ -425,58 +429,68 @@ A common pattern in traditional shells is dumping and auto-sourcing files from a
Here we'll create a simple completion module with a submodule dedicated to some Git completions:

1. Create the completion directory
`mkdir ($nu.default-config-dir | path join completions)`

`mkdir ($nu.default-config-dir | path join completions)`

2. Create an empty `mod.nu` for it
`touch ($nu.default-config-dir | path join completions mod.nu)`

`touch ($nu.default-config-dir | path join completions mod.nu)`

3. Put the following snippet in `git.nu` under the `completions` directory
```nu
export extern main [
--version(-v)
-C: string
# ... etc.
]

export extern add [
--verbose(-v)
--dry-run(-n)
# ... etc.
]

export extern checkout [
branch: string@complete-git-branch
]

def complete-git-branch [] {
# ... code to list git branches
}
```

```nu
export extern main [
--version(-v)
-C: string
# ... etc.
]

export extern add [
--verbose(-v)
--dry-run(-n)
# ... etc.
]

export extern checkout [
branch: string@complete-git-branch
]

def complete-git-branch [] {
# ... code to list git branches
}
```

4. Add `export module git.nu` to `mod.nu`
5. Add the parent of the `completions` directory to your NU_LIB_DIRS inside `env.nu`
```nu
$env.NU_LIB_DIRS = [
...
$nu.default-config-dir
]
```
6. import the completions to Nushell in your `config.nu`
`use completions *`
Now you've set up a directory where you can put your completion files and you should have some Git completions the next time you start Nushell

> **Note**
> This will use the file name (in our example `git` from `git.nu`) as the module name. This means some completions might not work if the definition has the base command in its name.
> For example, if you defined our known externals in our `git.nu` as `export extern 'git push' []`, etc. and followed the rest of the steps, you would get subcommands like `git git push`, etc.
> You would need to call `use completions git *` to get the desired subcommands. For this reason, using `main` as outlined in the step above is the preferred way to define subcommands.
```nu
$env.NU_LIB_DIRS = [
...
$nu.default-config-dir
]
```

6. Import the completions to Nushell in your `config.nu`:

`use completions *`

Now you've set up a directory where you can put your completion files, and you should have some Git completions the next time you start Nushell.

::: tip Note
This will use the file name (in our example `git` from `git.nu`) as the module name. This means some completions might not work if the definition has the base command in its name.
For example, if you defined our known externals in our `git.nu` as `export extern 'git push' []`, etc. and followed the rest of the steps, you would get subcommands like `git git push`, etc.
You would need to call `use completions git *` to get the desired subcommands. For this reason, using `main` as outlined in the step above is the preferred way to define subcommands.
:::

### Setting environment + aliases (conda style)

`def --env` commands, `export-env` block and aliases can be used to dynamically manipulate "virtual environments" (a concept well known from Python).

We use it in our official virtualenv integration https://github.com/pypa/virtualenv/blob/main/src/virtualenv/activation/nushell/activate.nu
We use it in our [official virtualenv integration](https://github.com/pypa/virtualenv/blob/main/src/virtualenv/activation/nushell/activate.nu). Another example is our [unofficial Conda module](https://github.com/nushell/nu_scripts/blob/main/modules/virtual_environments/conda.nu).

Another example could be our unofficial Conda module: https://github.com/nushell/nu_scripts/blob/f86a060c10f132407694e9ba0f536bfe3ee51efc/modules/virtual_environments/conda.nu

> **Warning**
> Work In Progress
::: warning
Work in progress
:::

## Hiding

Expand Down Expand Up @@ -515,5 +529,6 @@ It can be one of the following:

- Hides all the module's exports, without the prefix

> **Note**
> `hide` is not a supported keyword at the root of a module (unlike `def` etc.)
:::tip Note
`hide` is not a supported keyword at the root of a module (unlike `def` etc.)
:::
47 changes: 39 additions & 8 deletions book/scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ greet "world"

A script file defines the definitions for custom commands as well as the main script itself, which will run after the custom commands are defined.

In the above, first `greet` is defined by the Nushell interpreter. This allows us to later call this definition. We could have written the above as:
In the above example, first `greet` is defined by the Nushell interpreter. This allows us to later call this definition. We could have written the above as:

```nu
greet "world"
Expand Down Expand Up @@ -75,9 +75,9 @@ def main [x: int] {

## Argument Type Interpretation

By default, arguments provided to a script are interpreted with the type `Type::Any`, implying that they are not constrained to a specific data type and can be dynamically interpreted as fitting any of the available data types during script execution.
By default, arguments provided to a script are interpreted with the type `Type::Any`, implying that they are not constrained to a specific data type and can be dynamically interpreted as fitting any of the available data types during script execution.

In the previous example, `main [x: int]` denotes that the argument x should possess an integer data type. However, if arguments are not explicitly typed, they will be parsed according to their apparent data type.
In the previous example, `main [x: int]` denotes that the argument x should possess an integer data type. However, if arguments are not explicitly typed, they will be parsed according to their apparent data type.

For example:

Expand All @@ -103,9 +103,7 @@ Hello string +1

## Subcommands

A script can have multiple sub-commands like `run`, `build`, etc. which allows to execute a specific main sub-function. The important part is to expose them correctly with `def main [] {}`. See more details in the [Custom Command](custom_commands.html#sub-commands) section.

For example:
A script can have multiple [subcommands](custom_commands.html#subcommands), like `run` or `build` for example:

```nu
# myscript.nu
Expand All @@ -117,17 +115,48 @@ def "main build" [] {
print "building"
}

# important for the command to be exposed to the outside
def main [] {}
def main [] {
print "hello from myscript!"
}
```

You can then execute the script's subcommands when calling it:

```nu
> nu myscript.nu
hello from myscript!
> nu myscript.nu build
building
> nu myscript.nu run
running
```

[Unlike modules](modules.html#main), `main` does _not_ need to exported in order to be visible. In the above example, our `main` command is not `export def`, however it was still executed when running `nu myscript.nu`. If we had used myscript as a module by running `use myscript.nu`, rather than running `myscript.nu` as a script, trying to execute the `myscript` command would not work since `myscript` is not exported.

It is important to note that you must define a `main` command in order for subcommands of `main` to be correctly exposed. For example, if we had just defined the `run` and `build` subcommands, they wouldn't be accessible when running the script:

```nu
# myscript.nu
def "main run" [] {
print "running"
}

def "main build" [] {
print "building"
}
```

```nu
> nu myscript.nu build
> nu myscript.nu run
```

This is a limitation of the way scripts are currently processed. If your script only has subcommands, you can add an empty `main` to expose the subcommands, like so:

```nu
def main [] {}
```

## Shebangs (`#!`)

On Linux and macOS you can optionally use a [shebang](<https://en.wikipedia.org/wiki/Shebang_(Unix)>) to tell the OS that a file should be interpreted by Nu. For example, with the following in a file named `myscript`:
Expand All @@ -141,7 +170,9 @@ On Linux and macOS you can optionally use a [shebang](<https://en.wikipedia.org/
> ./myscript
Hello World!
```

For script to have access to standard input, `nu` should be invoked with `--stdin` flag:

```nu
#!/usr/bin/env -S nu --stdin
echo $"stdin: ($in)"
Expand Down