Fix mv error message issues (arrows, Windows paths) (#7197)

# Description

BEFORE (notice Windows paths look wrong):
```
〉mv 8 9
Error:
  × Destination file already exists
   ╭─[entry #22:1:1]
 1 │ mv 8 9
   ·      ┬
   ·      ╰── you can use -f, --force to force overwriting the destination
   ╰────

〉mv d1 tmp
Error:
  × Can't move "C:\\Users\\Leon\\TODO\\d1" to "C:\\Users\\Leon\\TODO\\tmp\\d1"
   ╭─[entry #19:1:1]
 1 │ mv d1 tmp
   ·       ─┬─
   ·        ╰── Directory not empty
   ╰────

```
AFTER (full paths are now included in the arrows' messages to make lines
like `mv $foo` entirely unambiguous):
```
〉mv 8 9
Error:
  × Destination file already exists
   ╭─[entry #4:1:1]
 1 │ mv 8 9
   ·      ┬
   ·      ╰── Destination file 'C:\Users\Leon\TODO\tmp\9' already exists
   ╰────
  help: you can use -f, --force to force overwriting the destination

〉mv d1 tmp
Error:
  × Can't move 'C:\Users\Leon\TODO\d1' to 'C:\Users\Leon\TODO\tmp\d1'
   ╭─[entry #3:1:1]
 1 │ mv d1 tmp
   ·       ─┬─
   ·        ╰── Directory 'C:\Users\Leon\TODO\tmp' is not empty
   ╰────

```
# User-Facing Changes

See above.

# 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 --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass

# 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.
This commit is contained in:
Leon 2022-11-23 13:55:13 +10:00 committed by GitHub
parent b662c2eb96
commit a0b3a48e8b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 8 deletions

View file

@ -107,9 +107,15 @@ impl Command for Mv {
if destination.exists() && !force && !destination.is_dir() && !source.is_dir() { if destination.exists() && !force && !destination.is_dir() && !source.is_dir() {
return Err(ShellError::GenericError( return Err(ShellError::GenericError(
"Destination file already exists".into(), "Destination file already exists".into(),
"you can use -f, --force to force overwriting the destination".into(), // These messages all use to_string_lossy() because
// showing the full path reduces misinterpretation of the message.
// Also, this is preferable to {:?} because that renders Windows paths incorrectly.
format!(
"Destination file '{}' already exists",
destination.to_string_lossy()
),
Some(spanned_destination.span), Some(spanned_destination.span),
None, Some("you can use -f, --force to force overwriting the destination".into()),
Vec::new(), Vec::new(),
)); ));
} }
@ -119,20 +125,26 @@ impl Command for Mv {
{ {
return Err(ShellError::GenericError( return Err(ShellError::GenericError(
"Can only move multiple sources if destination is a directory".into(), "Can only move multiple sources if destination is a directory".into(),
"destination must be a directory when multiple sources".into(), "destination must be a directory when moving multiple sources".into(),
Some(spanned_destination.span), Some(spanned_destination.span),
None, None,
Vec::new(), Vec::new(),
)); ));
} }
// This is the case where you move a directory A to the interior of directory B, but directory B
// already has a non-empty directory named A.
if source.is_dir() && destination.is_dir() { if source.is_dir() && destination.is_dir() {
if let Some(name) = source.file_name() { if let Some(name) = source.file_name() {
let dst = destination.join(name); let dst = destination.join(name);
if dst.is_dir() { if dst.is_dir() {
return Err(ShellError::GenericError( return Err(ShellError::GenericError(
format!("Can't move {:?} to {:?}", source, dst), format!(
"Directory not empty".into(), "Can't move '{}' to '{}'",
source.to_string_lossy(),
dst.to_string_lossy()
),
format!("Directory '{}' is not empty", destination.to_string_lossy()),
Some(spanned_destination.span), Some(spanned_destination.span),
None, None,
Vec::new(), Vec::new(),
@ -148,8 +160,8 @@ impl Command for Mv {
if let Some(Ok(filename)) = some_if_source_is_destination { if let Some(Ok(filename)) = some_if_source_is_destination {
return Err(ShellError::GenericError( return Err(ShellError::GenericError(
format!( format!(
"Not possible to move {:?} to itself", "Not possible to move '{}' to itself",
filename.file_name().unwrap_or(filename.as_os_str()) filename.to_string_lossy()
), ),
"cannot move to itself".into(), "cannot move to itself".into(),
Some(spanned_destination.span), Some(spanned_destination.span),

View file

@ -403,7 +403,7 @@ fn mv_directory_with_same_name() {
"# "#
); );
assert!(actual.err.contains("Directory not empty")); assert!(actual.err.contains("is not empty"));
}) })
} }