feat(watch): implement --debounce flag with duration#16187
feat(watch): implement --debounce flag with duration#16187Bahex merged 11 commits intonushell:mainfrom
Conversation
This new flag has a weird issue with calculating the durations. When I timed it with a debounce time of 1min, it registered the write at 1m11s...
|
Testing this again after the short change, when I make the debounce time 1min, it registers the write after 1m5s. |
|
After investigating this, it seems to be an issue with the crate that does the inode watching itself (notify_debouncer_full). It does not seem to use hooks for file changes and instead monitors them at regular intervals. [1] https://docs.rs/notify-debouncer-full/latest/notify_debouncer_full/fn.new_debouncer.html |
|
|
Regarding 1 Regarding 2 |
|
ya, debounce-ms wouldn't make sense for other duration units |
sholderbach
left a comment
There was a problem hiding this comment.
Thanks for tackling this so quickly, looks pretty much as expected!
| debounce_duration = match u64::try_from(val.item) { | ||
| Ok(val) => Duration::from_millis(val), | ||
| Err(_) => { | ||
| return Err(ShellError::TypeMismatch { | ||
| err_message: "Debounce duration is invalid".to_string(), | ||
| span: val.span, | ||
| }); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
if you are referring to the second error, it is actually a type mismatch. This condition occurs when using --debounce-ms with an arg that can not be converted to a u64.
There was a problem hiding this comment.
In the Ok case we would want to send the deprecation warning that you use the old style flag. (at least that's how we did handled that so far)
There was a problem hiding this comment.
You mean stop execution and exit with the warning? So that the old flag is never actually executed?
I.e.
Ok(_) => return Err(ShellWarning::Deprecated ...)There was a problem hiding this comment.
No still running but reporting the warning before returning the old result. I think that mechanism was revised with #16147 (before you would run report_error or similar with a ShellError::DeprecationWarning.)
There was a problem hiding this comment.
Sounds good! I implemented your feedback
There was a problem hiding this comment.
yes, this should be handled via a DeprecationEntry. You don't need to do anything special at run-time, just handle it the same way as before (maybe add a comment noting to remove the section of code once we remove the deprecated option)
Here's an example of how you can set this up, you should add a fn deprecation_info to the impl Command for Watch and then use DeprecationType::Flag. Also we generally do two releases out for deprecations, so you can set since to 0.106.0 and expected_removal to 0.108.0. Let me know if you have any issues!
| internal_span: Span, | ||
| }, | ||
| Duration { | ||
| /// The duration in nanoseconds. |
There was a problem hiding this comment.
good catch, wouldn't have guessed that that was not documented here
There was a problem hiding this comment.
I was confused initially. Thought it'd be milliseconds
| @@ -120,7 +121,18 @@ impl Command for Watch { | |||
| } | |||
| (None, Some(val)) => { | |||
| debounce_duration = match u64::try_from(val.item) { | |||
There was a problem hiding this comment.
This I was not sure about. If someone can tell me what its supposed to say, I can adjust it. We should then document this as well
There was a problem hiding this comment.
good point, I didn't even think to document the new deprecation process. I can add something to devdocs when I get a chance
There was a problem hiding this comment.
Is this correct, or do I have to change something here?
lucascherzer
left a comment
There was a problem hiding this comment.
@132ikl is this what you meant?
|
I'll have a look at the failed CI tomorrow |
|
Yes, the |
132ikl
left a comment
There was a problem hiding this comment.
one small thing, otherwise looks good to me 😄
| (Some(v), None) => match v.item { | ||
| dur @ Value::Duration { val, .. } => { | ||
| debounce_duration = match u64::try_from(val) { | ||
| Ok(d) => Duration::from_nanos(d), | ||
| Err(_) => { | ||
| return Err(ShellError::TypeMismatch { | ||
| err_message: "Debounce duration is invalid".to_string(), | ||
| span: dur.span(), | ||
| }); | ||
| } | ||
| }; | ||
| } | ||
| // This should be unreachable, as the parser will fail | ||
| // before this is ever called. I will leave it in anyways | ||
| // so we can handle it gracefully once it never arrives | ||
| any => { |
There was a problem hiding this comment.
I think we can just do this here:
| (Some(v), None) => match v.item { | |
| dur @ Value::Duration { val, .. } => { | |
| debounce_duration = match u64::try_from(val) { | |
| Ok(d) => Duration::from_nanos(d), | |
| Err(_) => { | |
| return Err(ShellError::TypeMismatch { | |
| err_message: "Debounce duration is invalid".to_string(), | |
| span: dur.span(), | |
| }); | |
| } | |
| }; | |
| } | |
| // This should be unreachable, as the parser will fail | |
| // before this is ever called. I will leave it in anyways | |
| // so we can handle it gracefully once it never arrives | |
| any => { | |
| (Some(v), None) => { | |
| let Value::Duration { val, ..} = v.item else { | |
| return Err(ShellError::TypeMismatch { | |
| err_message: "Debounce duration must be a duration".to_string(), | |
| span: v.span, | |
| }); | |
| } | |
| val |
this suggestion won't apply cleanly since I can't do a suggestion over unchanged lines, but the any match branch would have to be manually removed as well
There was a problem hiding this comment.
fair, that is kind of repetitive. In c92711c, I removed the any branch and refactored this according to your suggestion. I also use v.item.span() instead of v.span due to the deprecation notice
There was a problem hiding this comment.
Semantically there is a difference between the Spanned.span returned from a CallExt/Call argument handler and the span inherent to the Value which you get by Value.span() (and is stored in internal_span.
The Spanned<T> should be filled with the span of the particular argument expression while the Value has its span pointing to its point of creation.
While this should be the same for a literal I think this would point to two different locations when you for example pass a variable to an argument
let foo = 42
bar --baz $fooThere was a problem hiding this comment.
So do you want this to use v.span instead? What about the deprecation notice - how is this planned to go in the future?
|
Can you prepare a paragraph for the upcoming release notes mentioning what you have to going forward. Either by expanding |
This PR reverts the breaking change of short flag change of `watch -d` to `--debounce` instead of `--debounce-ms`. This fully prevents #16187 from being a breaking change. Before #16187: ```nushell watch -d 1000 foo {} # => Now watching files at "/home/rose/foo". Press ctrl+c to abort. ``` Before this PR (after #16187): ```nushell watch -d 1000 foo {} # => Error: nu::parser::parse_mismatch # => # => × Parse mismatch during operation. # => ╭─[entry #15:1:10] # => 1 │ watch -d 1000 foo {} # => · ──┬─ # => · ╰── expected duration with valid units # => ╰──── ``` After this PR (after #16187): ```nushell watch -d 1000 foo {} # => Warning: nu::parser::deprecated # => # => ⚠ Flag deprecated. # => ╭─[entry #3:1:7] # => 1 │ watch -d 1000 foo {} # => · ─┬ # => · ╰── watch --debounce-ms was deprecated in 0.107.0 and will be removed in 0.109.0. # => ╰──── # => help: `--debounce-ms` will be removed in favour of `--debounce` # => # => Now watching files at "/home/rose/foo". Press ctrl+c to abort. ``` This PR also fixes the `DeprecationEntry` which incorrectly had a `--` in it, which I failed to realize when reviewing #16187. We should add a `debug_assert` or something for this. Rel: #16187 ## Release notes summary - What our users need to know N/A ## Tasks after submitting - [ ] Add `debug_assert` for `DeprecationType::Flag`s with `--`
Sorry, I overlooked this. Does this still need to be done? |
|
no worries, I added a release notes summary for the PR already |
|
thanks :D |
Fixes #16178
Description
This PR implement --debounce flag with duration for
watch.This new flag has a weird issue with calculating the durations.
When I timed it with a debounce time of 1min, it registered the write at 1m11s...
User-Facing Changes
Release notes summary
New
watch --debounceoptionThe
watchcommand now has--debounceflag, which takes a duration value. This will replace the--debounce-msflag which takes an int rather than a duration, and will eventually take over its-dshort flag.Deprecate
watch --debounce-msWith the new watch --debounce option, the
--debounce-msoption is no longer necessary. Usewatch --debouncewith a duration value instead.Tests + Formatting
toolkit fmttoolkit clippytoolkit testtoolkit test stdlibAfter Submitting
Update the online docs for
watch:--debounce: duration-dis now the shorthand of--debounce--debounce-mswill be deprecated