Skip to content
This repository was archived by the owner on Dec 29, 2022. It is now read-only.

Commit 5ff56f0

Browse files
committed
Track versioned dirty files since last build
Previously only `rustc` was called on a single file or whole `cargo` routine was executed to perform the build and since the build plan, cached from the `cargo` run, is used now in the `workspace_mode` instead, RLS needs to feed it files changed since last build. Since while the build is being performed, the user can further modify files that are currently being built, only files that were modified prior to that will be marked as clean.
1 parent c03ea7b commit 5ff56f0

File tree

2 files changed

+48
-7
lines changed

2 files changed

+48
-7
lines changed

src/actions/notifications.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ impl<'a> NotificationAction<'a> for DidChange {
9898
let ctx = ctx.inited();
9999
let file_path = parse_file_path!(&params.text_document.uri, "on_change")?;
100100

101-
let changes: Vec<Change> = params.content_changes.iter().map(move |i| {
101+
let changes: Vec<Change> = params.content_changes.iter().map(|i| {
102102
if let Some(range) = i.range {
103103
let range = ls_util::range_to_rls(range);
104104
Change::ReplaceText {
@@ -114,6 +114,9 @@ impl<'a> NotificationAction<'a> for DidChange {
114114
}
115115
}).collect();
116116
ctx.vfs.on_changes(&changes).expect("error committing to VFS");
117+
if !changes.is_empty() {
118+
ctx.build_queue.mark_file_dirty(file_path, params.text_document.version)
119+
}
117120

118121
if !ctx.config.lock().unwrap().build_on_save {
119122
ctx.build_current_project(BuildPriority::Normal, out);

src/build/mod.rs

+44-6
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,18 @@ pub struct BuildQueue {
6868
queued: Arc<Mutex<(Build, Build)>>,
6969
}
7070

71+
/// Used when tracking modified files across different builds.
72+
type FileVersion = u64;
73+
7174
// Information needed to run and configure builds.
7275
struct Internals {
7376
// Arguments and environment with which we call rustc.
7477
// This can be further expanded for multi-crate target configuration.
7578
// This lock should only be held transiently.
7679
compilation_cx: Arc<Mutex<CompilationContext>>,
7780
env_lock: Arc<EnvironmentLock>,
81+
/// Set of files that were modified since last build.
82+
dirty_files: Arc<Mutex<HashMap<PathBuf, FileVersion>>>,
7883
vfs: Arc<Vfs>,
7984
// This lock should only be held transiently.
8085
config: Arc<Mutex<Config>>,
@@ -146,7 +151,8 @@ enum Build {
146151
struct PendingBuild {
147152
build_dir: PathBuf,
148153
priority: BuildPriority,
149-
// Closure to execture once the build is complete.
154+
built_files: HashMap<PathBuf, FileVersion>,
155+
// Closure to execute once the build is complete.
150156
and_then: Box<FnBox(BuildResult) + Send + 'static>,
151157
}
152158

@@ -228,6 +234,7 @@ impl BuildQueue {
228234

229235
let build = PendingBuild {
230236
build_dir: new_build_dir.to_owned(),
237+
built_files: self.internals.dirty_files.lock().unwrap().clone(),
231238
priority,
232239
and_then: Box::new(and_then),
233240
};
@@ -324,7 +331,8 @@ impl BuildQueue {
324331
}
325332

326333
// Run the build.
327-
let result = internals.run_build(&build.build_dir, build.priority);
334+
let result = internals.run_build(&build.build_dir, build.priority,
335+
&build.built_files);
328336
// Assert that the build was not squashed.
329337
if let BuildResult::Squashed = result {
330338
unreachable!();
@@ -340,6 +348,14 @@ impl BuildQueue {
340348
}
341349
}
342350
}
351+
352+
/// Marks a given versioned file as dirty since last build. The dirty flag
353+
/// will be cleared by a successful build that builds this or a more recent
354+
/// version of this file.
355+
pub fn mark_file_dirty(&self, file: PathBuf, version: FileVersion) {
356+
trace!("Marking file as dirty: {:?} ({})", file, version);
357+
self.internals.dirty_files.lock().unwrap().insert(file, version);
358+
}
343359
}
344360

345361
impl Internals {
@@ -348,6 +364,7 @@ impl Internals {
348364
compilation_cx: Arc::new(Mutex::new(CompilationContext::new())),
349365
vfs,
350366
config,
367+
dirty_files: Arc::new(Mutex::new(HashMap::new())),
351368
// Since environment is global mutable state and we can run multiple server
352369
// instances, be sure to use a global lock to ensure env var consistency
353370
env_lock: EnvironmentLock::get(),
@@ -356,7 +373,12 @@ impl Internals {
356373
}
357374

358375
// Entry point method for building.
359-
fn run_build(&self, new_build_dir: &Path, priority: BuildPriority) -> BuildResult {
376+
fn run_build(
377+
&self,
378+
new_build_dir: &Path,
379+
priority: BuildPriority,
380+
built_files: &HashMap<PathBuf, FileVersion>,
381+
) -> BuildResult {
360382
trace!("run_build, {:?} {:?}", new_build_dir, priority);
361383

362384
// Check if the build directory changed and update it.
@@ -375,7 +397,23 @@ impl Internals {
375397
}
376398
}
377399

378-
self.build()
400+
let result = self.build();
401+
// On a successful build, clear dirty files that were successfuly built
402+
// now. It's possible that a build was scheduled with given files, but
403+
// user later changed them. These should still be left as dirty (not built).
404+
match *&result {
405+
BuildResult::Success(_, _) | BuildResult::Failure(_, _) => {
406+
let mut dirty_files = self.dirty_files.lock().unwrap();
407+
dirty_files.retain(|file, dirty_version| {
408+
built_files.get(file)
409+
.map(|built_version| built_version < dirty_version)
410+
.unwrap_or(false)
411+
});
412+
trace!("Files still dirty after the build: {:?}", *dirty_files);
413+
},
414+
_ => {}
415+
};
416+
result
379417
}
380418

381419
// Build the project.
@@ -405,9 +443,9 @@ impl Internals {
405443
// If the build plan has already been cached, use it, unless Cargo
406444
// has to be specifically rerun (e.g. when build scripts changed)
407445
let work = {
446+
let modified: Vec<_> = self.dirty_files.lock().unwrap()
447+
.keys().cloned().collect();
408448
let cx = self.compilation_cx.lock().unwrap();
409-
let modified: Vec<_> = self.vfs.get_changes().keys().cloned().collect();
410-
411449
cx.build_plan.prepare_work(&modified)
412450
};
413451
return match work {

0 commit comments

Comments
 (0)