дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-08 19:02:17 +02:00
fix(refactor): apply server-versioned edits to files that aren't open (#1295)
gopls sends a document version for every file of a rename, including files the editor never opened. Applying a workspace edit rejected any versioned file without an open document as changed, so a Go rename touching a closed file always failed with "changed; request the refactoring again". For a file that isn't open, the preconditions captured with the edit now decide; an edit without them is still rejected.
Цей коміт міститься в:
1 джерело
6f9819fee7
коміт
f35c781f42
2 files changed
+39
-3
No files matched your search
@@ -402,13 +402,18 @@ impl Documents {
|
||||
return Ok(());
|
||||
}
|
||||
let mut edit = normalize_edit(edit)?;
|
||||
let captured = !edit.preconditions.is_empty();
|
||||
self.prepare_workspace_edit(&mut edit)?;
|
||||
self.validate_preconditions(&edit.preconditions)?;
|
||||
for file in &edit.files {
|
||||
if let FileEdit::Edit { path, version: Some(version), .. } = file {
|
||||
let doc = self.by_path(path).ok_or_else(|| stale(path))?;
|
||||
if i64::from(self.version(doc)?) != i64::from(*version) {
|
||||
return Err(stale(path));
|
||||
match self.by_path(path) {
|
||||
Some(doc) if i64::from(self.version(doc)?) != i64::from(*version) => return Err(stale(path)),
|
||||
Some(_) => {}
|
||||
// Servers version files the editor never opened (gopls renames). The
|
||||
// preconditions captured with the edit already cover its disk contents.
|
||||
None if captured => {}
|
||||
None => return Err(stale(path)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,37 @@ fn matching_document_version_is_applied() {
|
||||
assert_eq!(std::fs::read_to_string(a).unwrap(), "new\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn versioned_edit_of_a_closed_file_is_guarded_by_its_preconditions() {
|
||||
// gopls versions every file of a rename, including ones the editor never opened.
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let path = tmp.path().join("closed.txt");
|
||||
std::fs::write(&path, "old\n").unwrap();
|
||||
let docs = documents();
|
||||
let versioned = || {
|
||||
let mut operation = edit(&path, "new");
|
||||
if let FileEdit::Edit { version, .. } = &mut operation {
|
||||
*version = Some(0);
|
||||
}
|
||||
WorkspaceEdit { files: vec![operation], ..Default::default() }
|
||||
};
|
||||
// Without a snapshot of what the server saw, a version for a closed file can't be trusted.
|
||||
assert_eq!(docs.apply_workspace_edit(&versioned()).unwrap_err().kind, ErrorKind::OutOfSync);
|
||||
assert_eq!(std::fs::read_to_string(&path).unwrap(), "old\n");
|
||||
|
||||
let mut changed = versioned();
|
||||
docs.prepare_workspace_edit(&mut changed).unwrap();
|
||||
std::fs::write(&path, "own\n").unwrap();
|
||||
assert_eq!(docs.apply_workspace_edit(&changed).unwrap_err().kind, ErrorKind::OutOfSync);
|
||||
assert_eq!(std::fs::read_to_string(&path).unwrap(), "own\n");
|
||||
|
||||
std::fs::write(&path, "old\n").unwrap();
|
||||
let mut prepared = versioned();
|
||||
docs.prepare_workspace_edit(&mut prepared).unwrap();
|
||||
docs.apply_workspace_edit(&prepared).unwrap();
|
||||
assert_eq!(std::fs::read_to_string(&path).unwrap(), "new\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unversioned_preview_rejects_changed_disk_and_dirty_buffers() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
|
||||
Reference in new issue
Заблокувати користувача