-
Notifications
You must be signed in to change notification settings - Fork 323
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
Reloading file in LS after desynchronization. #6752
Conversation
Turned to draft after realizing some FIXMEs were left in code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only minor nit-picks.
impl Default for LanguageServerContent { | ||
fn default() -> Self { | ||
Self::Unknown | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: it's possible to derive Default
and mark the needed variant with the #[default]
attribute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. For some reason, I thought it's possible only when all variants have no fields.
/// Send to LanguageServer update about received notification about module. Returns the new | ||
/// content summery of Language Server state. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The second sentence is no longer accurate.
new_file: &SourceFile, | ||
edits: Vec<TextEdit>, | ||
execute: bool, | ||
) -> impl Future<Output = FallibleResult<ParsedContentSummary>> + 'static { | ||
) -> impl Future<Output = ()> + 'static { | ||
println!("---\n{}---\n", new_file.content); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug left over?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed all printlns.
debug!("Actual digest: {actual_old} => {actual_new}"); | ||
debug!("Declared digest: {} => {}", edits.old_version, edits.new_version); | ||
debug!("New content:\n===\n{new_content}\n==="); | ||
println!("Actual digest: {actual_old} => {actual_new}"); | ||
println!("Declared digest: {} => {}", edits.old_version, edits.new_version); | ||
println!("New content:\n===\n{new_content}\n==="); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I believe debug!
(and other) messages are still visible in regular tests, so this change should be unnecessary.
Co-authored-by: Ilya Bogdanov <fumlead@gmail.com>
app/gui/src/controller/upload.rs
Outdated
@@ -77,6 +77,8 @@ pub struct FileToUpload<DataProvider> { | |||
#[derive(Clone, Debug)] | |||
pub struct FileUploadProcess<DataProvider> { | |||
bin_connection: Rc<binary::Connection>, | |||
// See FIXME in upload_chunk method. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any FIXME in upload_chunk
method. Is this still necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a change committed to a wrong branch.
#6689 also contains the change, once it will be merged, here it should disappear from diff.
QA report 🥦No issues spotted. I tried opening large projects and doing many edits in quick succession, enabling CPU throttling and even toggling offline mode. The IDE was able to recover from all of those. |
…fter_desynchronization
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested on my pet project. I can no longer reproduce Invalid Version errors, so I think it's a step forward. Ideally, it would be cool to somehow notify the user about the reload because I guess they can be surprised about lost of last edit?
fn reopen_file_in_language_server(&self) -> BoxFuture<FallibleResult> { | ||
info!("Ignoring request for reopening file in the Language Server, because it's not connected"); | ||
future::ready_boxed(Ok(())) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
100 chars
#[derive(Clone, Debug, Default)] | ||
enum LanguageServerContent { | ||
/// The content is synchronized with our module state after last fully handled notification. | ||
Synchronized(ParsedContentSummary), | ||
/// The content is not synchronized with our module state after last fully handled | ||
/// notification, probably due to connection error when sending update. | ||
Desynchronized(ContentSummary), | ||
} | ||
|
||
impl LanguageServerContent { | ||
fn summary(&self) -> &ContentSummary { | ||
match self { | ||
LanguageServerContent::Synchronized(content) => &content.summary, | ||
LanguageServerContent::Desynchronized(content) => content, | ||
} | ||
} | ||
/// The content is not known due to an unrecognized error received from the Language Server | ||
/// after applying the last update. We don't know if, and to what extent it was applied. | ||
#[default] | ||
Unknown, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it better than Option<ParsedContentSummary>
?
self.language_server.client.close_text_file(file_path).await?; | ||
info!("Reopening file {file_path}."); | ||
if let Err(error) = self.language_server.client.close_text_file(file_path).await { | ||
error!("Error while reopening file {file_path}: Closing operation failed: {error} Trying to open the file anyway."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
100 chars
/// Listen for all module changes and sends proper updates to the Language Server. | ||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sends
-> send
) -> impl Future<Output = ()> { | ||
/// Listen for all module changes and sends proper updates to the Language Server. | ||
/// | ||
/// This function returns once the notifications from underlying [module model](plain::Module) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
double space after the
new_file: SourceFile, | ||
) -> impl Future<Output = FallibleResult<ParsedContentSummary>> + 'static { | ||
) -> impl Future<Output = ()> + 'static { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the Output
not default to ()
? If not, this is an IMO surprising design of this lib.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Associated type defaults are not in stable Rust yet and unstable feature is incomplete, especially around trait objects.
rust-lang/rust#29661 ...since 2015!
debug!("Updating the LS content digest to: {:?}", summary); | ||
ls_content.replace(LanguageServerContent::Synchronized(summary)); | ||
} | ||
Err(err) => { | ||
error!("Error during sending text change to Language Server: {err}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor inconsistency - some errors use LS
, some use Language Server
. I think that abbreviations are always worse than full names, so I'd be thankful for moving them to full names instead.
* develop: Use state sent with `GET /directories` instead of querying state separately (#6794) Run TypeScript typechecking and eslint on Lint CI (#6603) Disable cloud backend for unverified users; use local backend as default backend; minor bugfixes (#6779) Reloading file in LS after desynchronization. (#6752) Missing conversion of hash key in EqualsNode (#6803) feat: set constructor args tag values (#6801)
Pull Request Description
Fixes #5203
This PR changes behavior when
text/applyChange
returned error.Before we always assumed that the change was not applied, and tried to send full synchronization still assuming old file content. But this was not the case on some errors (timeouts for example). Now we instead reopen the file (getting its actual content) and then make a full invalidation.
Also added a shortcut allowing manual file reloading, what may be useful in some kinds of error (and also allowed me testing of reopening file in the application).
Important Notes
The unit tests of sending text updates were improved: now we actually check if all expected messages are emitted from the IDE.
Checklist
Please ensure that the following checklist has been satisfied before submitting the PR:
Screenshots/screencasts have been attached, if there are any visual changes. For interactive or animated visual changes, a screencast is preferred.Scala,
Java,
and
Rust
style guides. In case you are using a language not listed above, follow the Rust style guide.
./run ide build
.