Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Highlight the differences between scripts and modules #1567

Merged
merged 3 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
22 changes: 14 additions & 8 deletions book/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,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 +199,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,10 +428,11 @@ 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)
Expand All @@ -450,17 +454,20 @@ 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
`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.
Expand Down Expand Up @@ -515,5 +522,4 @@ 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.)
> **Note** > `hide` is not a supported keyword at the root of a module (unlike `def` etc.)
43 changes: 37 additions & 6 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,7 +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.
A script's `main` command can have multiple [subcommands](custom_commands.html#subcommands) like `run`, `build`, etc. which allows executing a specific sub-function from the commandline.

For example:

Expand All @@ -117,17 +117,46 @@ def "main build" [] {
print "building"
}

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

```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