Add all LabeledError structure parts to error make#17037
Add all LabeledError structure parts to error make#17037fdncred merged 6 commits intonushell:mainfrom
LabeledError structure parts to error make#17037Conversation
1dae8a9 to
b937116
Compare
Added tests for these new inputs, changed the help output.
b937116 to
67220e6
Compare
|
It would be good to have something in the release notes summary that can go in the release notes |
url and code options to error makeLabeledError structure parts to error make
|
Did a quick rewrite as a separate commit. To me it's a lot cleaner, but it does change the error messages for failed parsing on some of the elements. |
2e7a511 to
a6fff64
Compare
a6fff64 to
f653ddb
Compare
|
Are we ready to move forward with this? @cptpiepmatz did you want to look at this further, I can't remember. |
|
I'll take a look at today |
cptpiepmatz
left a comment
There was a problem hiding this comment.
The implementation looks great, thank you!
|
wow, high praise. @KaiSforza was there anything else you wanted to do or are you ready to land this? |
|
I think it's good as a first pass! There's a few errors that are only going to be encountered with the new options (spans from |
|
Thanks |
## User-facing Changes
* New arguments! (`error make "hello"`)
* New parts for `error_struct`! (`error make {inner: [] labels: []
...}`)
* Pipeline inputs for chained errors! (`try {error make foo} catch
{error make bar}`)
* Pipeline inputs for normal errors! (`"help" | error make`)
* External errors! (`error make {src: {path: $nu.cofig-path} ...}`)
* Backwards compatibility!
### Arguments and Inputs
The main changes are in how the arguments are passed. Everything is
still backwards compatible with the old `error make` commands, there's
just a nice extra layer we get from the pipeline and a few new args
(that were already added in #17037). There are some new ways to
(hopefully intentionally) cause an error, such as using a naked `error
make`, pipelines from records and simple string input!
#### Inputs
Because `error make` will just make an error anyway, it can technically
take any input to make an error, but only properly formatted record
input will create a chain. the `x | f $in` pattern can be used for
string input, if that is more comfortable.
#### With no arguments
This is a completely new way to do this, with no arguments the `error
make` invocation is highlighted, along with a simple `originates from
here` message. This makes normal errors very easy to create without any
special message setup.
```
> error make
Error: nu::shell::error
× originates from here
╭─[entry #4:1:1]
1 │ error make
· ──────────
╰────
```
#### Create a single argument
* With pipeline input: `{msg: foo} | error make`
* With an argument: `error make {msg: foo}`
* With a string argument: `error make foo`
```
Error: nu:🐚:error
× foo
╭─[entry #2:1:12]
1 │ error make {msg: foo}
· ──────────
╰────
```
#### Chaining errors together
These will automatically create a chain of errors, placing the pipeline
as an `inner` to the argument. This can very easily be used to get a bit
more detail in a try loop using the naked `error make`:
```
Error: nu:🐚:error
× originates from here
╭─[source:1:31]
1 │ try {error make "foo"} catch {error make}
· ──────────
╰────
Error: nu:🐚:error
× foo
╭─[source:1:6]
1 │ try {error make "foo"} catch {error make}
· ──────────
╰────
```
Or with more complex errors:
* With both, combining the errors: `{msg: foo} | error make bar`
* With the raw error from try: `try {error make foo} catch {error make
bar}`
Both are equivalent to:
* `error make {msg: bar inner: [{msg: foo}]}`
```
Error: nu:🐚:error
× bar
╭─[entry #1:1:29]
1 │ try {error make foo} catch {error make bar}
· ──────────
╰────
Error: nu:🐚:error
× foo
╭─[entry #1:1:6]
1 │ try {error make foo} catch {error make bar}
· ──────────
╰────
```
### Labels
As is noticeable in the examples above, simple errors no longer use an
extra line for the label. If no label is present, `error make` will
place a bar under the span of itself or the argument to `error make`.
Labels have also gotten a bit of a rewrite, but they're pretty much the
same as those in #17037, except for `label`, which is now only a single
label (not `oneof<list, label>`).
#### Simple Labels
`label.text` and `labels.*.text` is no longer required for a span to
show up, an empty text will simply underline. This example can either
use `label: $record` or be written as `labels: [$record]`:
```
> def f [x] {
error make {msg: here label: {span: (metadata $x).span}}
}
f abcd
Error: nu::shell::error
× here
╭─[entry #7:4:3]
3 │ }
4 │ f abcd
· ────
╰────
```
#### Multiple labels
Any number of labels can be added in the `labels` column, allowing for
more detailed error messages, especially for functions:
```
> def f [x y z] {
error make {msg: here labels: [
{text: "there" span: (metadata $x).span}
{text: "everywhere" span: (metadata $y).span}
{text: "somewhere" span: (metadata $z).span}
]
}
}
f abcd [x y z] {d: a}
Error: nu:🐚:error
× here
╭─[entry #11:9:3]
8 │ }
9 │ f abcd [x y z] {d: a}
· ──┬─ ───┬─── ───┬──
· │ │ ╰── somewhere
· │ ╰── everywhere
· ╰── there
╰────
```
#### External sources
There is a `ShellError::OutsideSpannedLabeledError` that can be used to
refer to external sources, not just the internal nushell spanns. This
has been expanded to allow the multi-label stuff to work using the new
`src` column:
```
> "foo\nbar\nbaz" | save -f /tmp/foo.bar
error make {
msg: 'error here'
src: {path: /tmp/foo.bar}
labels: [
{text: "this" span: {start: 4 end: 7}}
]
}
Error: nu:🐚:outside
× error here
╭─[/tmp/foo.bar:2:1]
1 │ foo
2 │ bar
· ─┬─
· ╰── this
3 │ baz
╰────
```
### Errors That Can't be Caught
These will not work since `try` will never get parsed:
- `try {1 + ""} catch {error make badmath}`
- (TODO: Add more examples)
## Internal Changes
Most of the parsing from an error record to an actual error is now moved
into `nu-protocol`, using `FromValue` to turn it into a useful internal
type.
### `nu-protocol::LabeledError`
This struct has a few changes, the main one being the type of
`LabeledError.inner`. It is now a `ShellError`, not another
`LabeledError`. It should be trivial to do a `.into()` for things that
already use `LabeledError.with_inner(x)`.
### `nu-protocol::ShellError::into_value`
I renamed the old `into_value` to `into_full_value` to better say what
it is, since it doesn't just do the `IntoValue::into_value` method, it
also requires some context to create the `Value`. Now `ShellError` has
an `IntoValue` implementation matching other types.
### `nu-protocol::ShellError::{OutsideSource, OutsideSourceNoUrl}`
Miette's derived types don't have a nice way to maybe include a url, so
there are now two types! These allow using multiple labels on outside
sources. They are used internally for the new `{src: {}}` part of the
`error_struct`, and they look a lot more like the `LabeledError`, but
without the need for a separate type and all the fun `impl`s that would
require for the `Diagnostic::source_code` method.
### Misc
* Spelling fix: `into_chainned` => `into_chained`
## Current bugs:
- [x] `OutsideSpannedLabeledError`
The inner most error of `try {']' from nuon} catch {error make}` will
reference `span: {start: 0, end: 1}`, which in `']' from nuon` will
point to the `]` character, but when it does this in `error make` as an
input it will point to the very first character (probably the `n` in
`nu`).
## Release notes summary - What our users need to know
### New `error make` functionality!
* New arguments! (`error make "hello"`)
* New parts for `error_struct`! (`error make {inner: [] labels: []
...}`)
* Pipeline inputs for chained errors! (`try {error make foo} catch
{error make bar}`)
* Pipeline inputs for normal errors! (`"help" | error make`)
* External errors! (`error make {src: {path: $nu.cofig-path} ...}`)
* Backwards compatibility!
## Tasks after submitting
<!-- Remove any tasks which aren't relevant for your PR, or add your own
-->
- [ ] Update the
[documentation](https://github.com/nushell/nushell.github.io)
This allows all of the inputs to a
LabeledErrorstructure to be accessed from inside of Nushell scripts, not just plugins, including:1 + "")']' | from nuon)nu::shell::errorurlkeyThis is a complete rewrite of the
error makecommand usingFromValueto simplify the parsing a lot. I did have to write aFromValueimplementation fornu_protocol::Spanthat goes from a record into aSpanobject. The error checking happens in there instead of inerror makenow.Here are a few examples:
The
(link)is clickable if the right$env.configsettings are enabled, or it will printhttps://example.comto the screen.Release notes summary - What our users need to know
LabeledErrorstructure to theerror_structargument oferror makeTasks after submitting