2020-10-02 08:45:09 -05:00
|
|
|
//! Defines a unit of change that can applied to the database to get the next
|
|
|
|
//! state. Changes are transactional.
|
|
|
|
|
|
|
|
use std::{fmt, sync::Arc};
|
|
|
|
|
|
|
|
use salsa::Durability;
|
|
|
|
use vfs::FileId;
|
|
|
|
|
|
|
|
use crate::{CrateGraph, SourceDatabaseExt, SourceRoot, SourceRootId};
|
|
|
|
|
|
|
|
/// Encapsulate a bunch of raw `.set` calls on the database.
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct Change {
|
|
|
|
pub roots: Option<Vec<SourceRoot>>,
|
|
|
|
pub files_changed: Vec<(FileId, Option<Arc<String>>)>,
|
|
|
|
pub crate_graph: Option<CrateGraph>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for Change {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
2021-02-28 05:57:41 -06:00
|
|
|
let mut d = fmt.debug_struct("Change");
|
2020-10-02 08:45:09 -05:00
|
|
|
if let Some(roots) = &self.roots {
|
|
|
|
d.field("roots", roots);
|
|
|
|
}
|
|
|
|
if !self.files_changed.is_empty() {
|
|
|
|
d.field("files_changed", &self.files_changed.len());
|
|
|
|
}
|
|
|
|
if self.crate_graph.is_some() {
|
|
|
|
d.field("crate_graph", &self.crate_graph);
|
|
|
|
}
|
|
|
|
d.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Change {
|
|
|
|
pub fn new() -> Change {
|
|
|
|
Change::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
|
|
|
|
self.roots = Some(roots);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn change_file(&mut self, file_id: FileId, new_text: Option<Arc<String>>) {
|
|
|
|
self.files_changed.push((file_id, new_text))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_crate_graph(&mut self, graph: CrateGraph) {
|
|
|
|
self.crate_graph = Some(graph);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn apply(self, db: &mut dyn SourceDatabaseExt) {
|
|
|
|
let _p = profile::span("RootDatabase::apply_change");
|
|
|
|
if let Some(roots) = self.roots {
|
|
|
|
for (idx, root) in roots.into_iter().enumerate() {
|
|
|
|
let root_id = SourceRootId(idx as u32);
|
|
|
|
let durability = durability(&root);
|
|
|
|
for file_id in root.iter() {
|
|
|
|
db.set_file_source_root_with_durability(file_id, root_id, durability);
|
|
|
|
}
|
|
|
|
db.set_source_root_with_durability(root_id, Arc::new(root), durability);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (file_id, text) in self.files_changed {
|
|
|
|
let source_root_id = db.file_source_root(file_id);
|
|
|
|
let source_root = db.source_root(source_root_id);
|
|
|
|
let durability = durability(&source_root);
|
|
|
|
// XXX: can't actually remove the file, just reset the text
|
|
|
|
let text = text.unwrap_or_default();
|
|
|
|
db.set_file_text_with_durability(file_id, text, durability)
|
|
|
|
}
|
|
|
|
if let Some(crate_graph) = self.crate_graph {
|
|
|
|
db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn durability(source_root: &SourceRoot) -> Durability {
|
|
|
|
if source_root.is_library {
|
|
|
|
Durability::HIGH
|
|
|
|
} else {
|
|
|
|
Durability::LOW
|
|
|
|
}
|
|
|
|
}
|