<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx
you can also mention related issues, PRs or discussions!
-->
# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.
Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->
#14528 mentioned that trying to `open` a file in a directory where you
don't have read access results in a "file not found" error. I
investigated the error and could find the root issue in the
`nu_engine::glob_from` function. It uses `std::path::Path::canonicalize`
some layers down and that may return an `std::io::Error`. All these
errors were handled as "directory not found" which will be translated to
"file not found" in the `open` command. To fix this, I handled the
`PermssionDenied` error kind of the io error and passed that down. Now
trying to `open` a file from a directory with no permissions returns a
"permission denied" error.
Before/After:

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
That error is fixed, so correct error message.
# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use toolkit.nu; toolkit test stdlib"` to run the
tests for the standard library
> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`
# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
fixes#14528
# Description
Adds an `is_glob` function to the nu-glob crate that takes a string
pattern and returns whether or not it's a glob that would be expanded by
nu-glob. Right now, this just means checking if it contains `*`, `?`, or
`[`.
Previously, this same code was duplicated in the following places:
- `ls`: Determining whether to read a folder's contents or expand a glob
- `run_external.rs` in nu-command: Arguments to externals only have
n-dots and tilde expansion applied if they weren't globs
- `glob_from` in nu-engine:
- `glob_from` can get the prefix in a simpler way for non-globs
- If the canonical path for a non-glob path contains glob
metacharacters, it needs to be escaped
- `completion_common.rs` in nu-cli: File/folder completions containing
glob metacharacters need to be wrapped in quotes
All of these locations can use `nu_glob::is_glob` now instead of rolling
their own checks. This does mean that nu-cli now has a dependency on
nu-glob.
# User-Facing Changes
Users of nu-glob will now be able to check if a given pattern is a glob
expanded by nu-glob.
For users of Nushell, completion suggestions for files containing `]`
will no longer be wrapped in quotes if they contain no other glob
metacharacters. This is because unmatched `]`s are ignored by nu-glob,
but we used to consider such file completions contaminated anyway.
# Tests + Formatting
This is a very basic function, so I just added some doctests.
# After Submitting
This is meant to be used in
https://github.com/nushell/nushell/pull/14674.
# Description
When implementing a `Command`, one must also import all the types
present in the function signatures for `Command`. This makes it so that
we often import the same set of types in each command implementation
file. E.g., something like this:
```rust
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
record, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData,
ShellError, Signature, Span, Type, Value,
};
```
This PR adds the `nu_engine::command_prelude` module which contains the
necessary and commonly used types to implement a `Command`:
```rust
// command_prelude.rs
pub use crate::CallExt;
pub use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
record, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, IntoSpanned,
PipelineData, Record, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
};
```
This should reduce the boilerplate needed to implement a command and
also gives us a place to track the breadth of the `Command` API. I tried
to be conservative with what went into the prelude modules, since it
might be hard/annoying to remove items from the prelude in the future.
Let me know if something should be included or excluded.
# Description
Fixes: #11887Fixes: #11626
This pr unify the tilde expand behavior over several filesystem relative
commands. It follows the same rule with glob expansion:
| command | result |
| ----------- | ------ |
| ls ~/aaa | expand tilde
| ls "~/aaa" | don't expand tilde
| let f = "~/aaa"; ls $f | don't expand tilde, if you want to: use `ls
($f \| path expand)`
| let f: glob = "~/aaa"; ls $f | expand tilde, they don't expand on
`mkdir`, `touch` comamnd.
Actually I'm not sure for 4th item, currently it's expanding is just
because it followes the same rule with glob expansion.
### About the change
It changes `expand_path_with` to accept a new argument called
`expand_tilde`, if it's true, expand it, if not, just keep it as `~`
itself.
# User-Facing Changes
After this change, `ls "~/aaa"` won't expand tilde.
# Tests + Formatting
Done
# Description
This is a follow up to
https://github.com/nushell/nushell/pull/11621#issuecomment-1937484322
Also Fixes: #11838
## About the code change
It applys the same logic when we pass variables to external commands:
0487e9ffcb/crates/nu-command/src/system/run_external.rs (L162-L170)
That is: if user input dynamic things(like variables, sub-expression, or
string interpolation), it returns a quoted `NuPath`, then user input
won't be globbed
# User-Facing Changes
Given two input files: `a*c.txt`, `abc.txt`
* `let f = "a*c.txt"; rm $f` will remove one file: `a*c.txt`.
~* `let f = "a*c.txt"; rm --glob $f` will remove `a*c.txt` and
`abc.txt`~
* `let f: glob = "a*c.txt"; rm $f` will remove `a*c.txt` and `abc.txt`
## Rules about globbing with *variable*
Given two files: `a*c.txt`, `abc.txt`
| Cmd Type | example | Result |
| ----- | ------------------ | ------ |
| builtin | let f = "a*c.txt"; rm $f | remove `a*c.txt` |
| builtin | let f: glob = "a*c.txt"; rm $f | remove `a*c.txt` and
`abc.txt`
| builtin | let f = "a*c.txt"; rm ($f \| into glob) | remove `a*c.txt`
and `abc.txt`
| custom | def crm [f: glob] { rm $f }; let f = "a*c.txt"; crm $f |
remove `a*c.txt` and `abc.txt`
| custom | def crm [f: glob] { rm ($f \| into string) }; let f =
"a*c.txt"; crm $f | remove `a*c.txt`
| custom | def crm [f: string] { rm $f }; let f = "a*c.txt"; crm $f |
remove `a*c.txt`
| custom | def crm [f: string] { rm $f }; let f = "a*c.txt"; crm ($f \|
into glob) | remove `a*c.txt` and `abc.txt`
In general, if a variable is annotated with `glob` type, nushell will
expand glob pattern. Or else, we need to use `into | glob` to expand
glob pattern
# Tests + Formatting
Done
# After Submitting
I think `str glob-escape` command will be no-longer required. We can
remove it.
# Description
This pr is a follow up to
[#11569](https://github.com/nushell/nushell/pull/11569#issuecomment-1902279587)
> Revert the logic in https://github.com/nushell/nushell/pull/10694 and
apply the logic in this pr to mv, cp, rv will require a larger change, I
need to think how to achieve the bahavior
And sorry @bobhy for reverting some of your changes.
This pr is going to unify glob behavior on the given commands:
* open
* rm
* cp-old
* mv
* umv
* cp
* du
So they have the same behavior to `ls`, which is:
If given parameter is quoted by single quote(`'`) or double quote(`"`),
don't auto-expand the glob pattern. If not quoted, auto-expand the glob
pattern.
Fixes: #9558Fixes: #10211Fixes: #9310Fixes: #10364
# TODO
But there is one thing remains: if we give a variable to the command, it
will always auto-expand the glob pattern, e.g:
```nushell
let path = "a[123]b"
rm $path
```
I don't think it's expected. But I also think user might want to
auto-expand the glob pattern in variables.
So I'll introduce a new command called `glob escape`, then if user
doesn't want to auto-expand the glob pattern, he can just do this: `rm
($path | glob escape)`
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
# Tests + Formatting
Done
# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
## NOTE
This pr changes the semantic of `GlobPattern`, before this pr, it will
`expand path` after evaluated, this makes `nu_engine::glob_from` have no
chance to glob things right if a path contains glob pattern.
e.g: [#9310
](https://github.com/nushell/nushell/issues/9310#issuecomment-1886824030)
#10211
I think changing the semantic is fine, because it makes glob works if
path contains something like '*'.
It maybe a breaking change if a custom command's argument are annotated
by `: glob`.
# Description
Replace `.to_string()` used in `GenericError` with `.into()` as
`.into()` seems more popular
Replace `Vec::new()` used in `GenericError` with `vec![]` as `vec![]`
seems more popular
(There are so, so many)
# Description
Convert these ShellError variants to named fields:
* CreateNotPossible
* MoveNotPossibleSingle
* DirectoryNotFoundCustom
* DirectoryNotFound
* NotADirectory
* OutOfMemoryError
* PermissionDeniedError
* IOErrorSpanned
* IOError
* IOInterrupted
Also place the `span` field of `DirectoryNotFound` last to match other
errors.
Part of #10700 (almost half done!)
# User-Facing Changes
None
# Tests + Formatting
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`
# After Submitting
N/A
This pr fix clippy warnings in latest clippy version(1.72.0):
Unfortunally it's not easy to handle for [try
fold](https://rust-lang.github.io/rust-clippy/master/index.html#/manual_try_fold)
warning in `start command`
Refer to known issue:
> This lint doesn’t take into account whether a function does something
on the failure case, i.e., whether short-circuiting will affect
behavior. Refactoring to try_fold is not desirable in those cases.
That's the case for our code, which does something on the failure case.
So this pr is making a little refactor on `try_commands`.
should close https://github.com/nushell/nushell/issues/10406
# Description
when writing a script, with variables you try to `ls` or `open`, you
will get a "directory not found" error but the variable won't be
expanded and you won't be able to see which one of the variable was the
issue...
this PR adds this information to the error.
# User-Facing Changes
let's define a variable
```nushell
let does_not_exist = "i_do_not_exist_in_the_current_directory"
```
### before
```nushell
> open $does_not_exist
Error: nu:🐚:directory_not_found
× Directory not found
╭─[entry #7:1:1]
1 │ open $does_not_exist
· ───────┬───────
· ╰── directory not found
╰────
```
```nushell
> ls $does_not_exist
Error: nu:🐚:directory_not_found
× Directory not found
╭─[entry #8:1:1]
1 │ ls $does_not_exist
· ───────┬───────
· ╰── directory not found
╰────
```
### after
```nushell
> open $does_not_exist
Error: nu:🐚:directory_not_found
× Directory not found
╭─[entry #3:1:1]
1 │ open $does_not_exist
· ───────┬───────
· ╰── directory not found
╰────
help: /home/amtoine/documents/repos/github.com/amtoine/nushell/i_do_not_exist_in_the_current_directory does not exist
```
```nushell
> ls $does_not_exist
Error: nu:🐚:directory_not_found
× Directory not found
╭─[entry #4:1:1]
1 │ ls $does_not_exist
· ───────┬───────
· ╰── directory not found
╰────
help: /home/amtoine/documents/repos/github.com/amtoine/nushell/i_do_not_exist_in_the_current_directory does not exist
```
# Tests + Formatting
shouldn't harm anything 🤞
# After Submitting
Fix https://github.com/nushell/nushell/issues/10136
# Description
Current nushell only handle path containing '*' as match pattern and
treat '?' as just normal path.
This pr makes path containing '?' is also processed as pattern.
🔴 **Concerns: Need to design/comfirm a consistent rule to handle
dirs/files with '?' in their names.**
Currently:
- if no dir has exactly same name with pattern, it will print the list
of matched directories
- if pattern exactly matches an empty dir's name, it will just print the
empty dir's content ( i.e. `[]`)
- if pattern exactly matches an dir's name, it will perform pattern
match and print all the dir contains
e.g.
```bash
mkdir src
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ | --------------------------------------------- |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir src
mkdir scc
mkdir scs
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ |
------------------------------------------------ |
| scc | dir | 64 B | Tue, 29 Aug 2023 16:55:31 +0900 (14 seconds ago) |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir s?c
ls s?c
```
print empty (i.e. ls of dir `s?c`)
-----------
```bash
mkdir -p s?c/test
ls s?c
```
|name|type|size|modified|
|-|-|-|-|
|s?c/test|dir|64 B|Tue, 29 Aug 2023 16:47:53 +0900 (2 minutes ago)|
|src/bytes|dir|480 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/charting|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/conversions|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
-----------
# User-Facing Changes
User will be able to use '?' to match directory/file.
# Tests + Formatting
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`
# After Submitting
None
---------
Co-authored-by: Horasal <horsal@horsal.dev>
# Description
This PR is trying to allow you to have `[blah]` in your path and yet
still have `ls` work. This is done by trying to separate the path from
the pattern to be searched for. It may still need more work.
I've tested it with:
- mkdir "[test]"
- cd "[test]"
- ls
Related to #9307
Hopefully fixes#9232
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect -A clippy::result_large_err` to check that
you're using the standard code style
- `cargo test --workspace` to check that all tests pass
- `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the
standard library
> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->
# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
# Description
Fixes#6706.
I took a look at this issue and it seems that the issue is because the
path is canonicalized and thus derives to the target. I've tested it
locally by checking if the path is a symlink and acting accordingly to
not canonicalize it and it seems fine.
In current release if the target is deleted but the symlink remains and
one `ls`'s it, it throws a `directory not found` error. But with the fix
it still shows the symlink (with red background, indicating missing
target).
The change I've applied only triggers when `ls` is done on a symlink, on
all other counts it should basically do the same as before.
# User-Facing Changes
_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
## List existing symlink and target
Current
```
ls a_symlink ╭───┬────────┬──────┬──────┬──────────────╮
│ # │ name │ type │ size │ modified │
├───┼────────┼──────┼──────┼──────────────┤
│ 0 │ a_file │ file │ 0 B │ 20 hours ago │
╰───┴────────┴──────┴──────┴──────────────╯
```
With fix
```
ls a_symlink ╭───┬───────────┬─────────┬──────┬──────────────╮
│ # │ name │ type │ size │ modified │
├───┼───────────┼─────────┼──────┼──────────────┤
│ 0 │ a_symlink │ symlink │ 6 B │ 20 hours ago │
╰───┴───────────┴─────────┴──────┴──────────────╯
```
## List existing symlink with missing target
Current
```
ls symfile_x
Error: nu:🐚:directory_not_found (link)
× Directory not found
╭─[entry #13:1:1]
1 │ ls symfile_x
· ────┬────
· ╰── directory not found
╰────
```
With fix
```
ls symfile_x ╭───┬───────────┬─────────┬──────┬─────────────╮
│ # │ name │ type │ size │ modified │
├───┼───────────┼─────────┼──────┼─────────────┤
│ 0 │ symfile_x │ symlink │ 6 B │ 2 hours ago │
╰───┴───────────┴─────────┴──────┴─────────────╯
```
* Avoid extending the directory without globs in `nu_engine::glob_from`
* avoid joining a `*` to the directory without globs
* remove checks on directory permission and whether it is empty
The previous implemention of `nu_engine::glob_from` will extend the
given directory even if it containes no glob pattern. This commit
overcomes lack of consistency with the function `nu_glob::glob`.
* Add flag -D to ls, to list the directory itself instead of its contents
* add --directory (-d) flag to ls
* correct the difference between the given path and the cwd
* set default path to `.` instead of `./*` when --directory (-d) flag is true
* add comments
* add an example
* add tests
* fmt