mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 13:48:50 +00:00
Merge #5299
5299: Reload when new example/test/etc is added r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
fd6fb78440
5 changed files with 107 additions and 42 deletions
|
@ -155,7 +155,7 @@ impl CargoWorkspace {
|
||||||
if let Some(target) = cargo_features.target.as_ref() {
|
if let Some(target) = cargo_features.target.as_ref() {
|
||||||
meta.other_options(vec![String::from("--filter-platform"), target.clone()]);
|
meta.other_options(vec![String::from("--filter-platform"), target.clone()]);
|
||||||
}
|
}
|
||||||
let meta = meta.exec().with_context(|| {
|
let mut meta = meta.exec().with_context(|| {
|
||||||
format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display())
|
format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
@ -175,6 +175,7 @@ impl CargoWorkspace {
|
||||||
|
|
||||||
let ws_members = &meta.workspace_members;
|
let ws_members = &meta.workspace_members;
|
||||||
|
|
||||||
|
meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
|
||||||
for meta_pkg in meta.packages {
|
for meta_pkg in meta.packages {
|
||||||
let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } =
|
let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } =
|
||||||
meta_pkg;
|
meta_pkg;
|
||||||
|
@ -210,7 +211,7 @@ impl CargoWorkspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let resolve = meta.resolve.expect("metadata executed with deps");
|
let resolve = meta.resolve.expect("metadata executed with deps");
|
||||||
for node in resolve.nodes {
|
for mut node in resolve.nodes {
|
||||||
let source = match pkg_by_id.get(&node.id) {
|
let source = match pkg_by_id.get(&node.id) {
|
||||||
Some(&src) => src,
|
Some(&src) => src,
|
||||||
// FIXME: replace this and a similar branch below with `.unwrap`, once
|
// FIXME: replace this and a similar branch below with `.unwrap`, once
|
||||||
|
@ -221,6 +222,7 @@ impl CargoWorkspace {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
|
||||||
for dep_node in node.deps {
|
for dep_node in node.deps {
|
||||||
let pkg = match pkg_by_id.get(&dep_node.pkg) {
|
let pkg = match pkg_by_id.get(&dep_node.pkg) {
|
||||||
Some(&pkg) => pkg,
|
Some(&pkg) => pkg,
|
||||||
|
|
|
@ -26,6 +26,7 @@ use crate::{
|
||||||
to_proto::url_from_abs_path,
|
to_proto::url_from_abs_path,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
use ra_prof::profile;
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Copy, Clone)]
|
#[derive(Eq, PartialEq, Copy, Clone)]
|
||||||
pub(crate) enum Status {
|
pub(crate) enum Status {
|
||||||
|
@ -122,6 +123,10 @@ impl GlobalState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn process_changes(&mut self) -> bool {
|
pub(crate) fn process_changes(&mut self) -> bool {
|
||||||
|
let _p = profile("GlobalState::process_changes");
|
||||||
|
let mut fs_changes = Vec::new();
|
||||||
|
let mut has_fs_changes = false;
|
||||||
|
|
||||||
let change = {
|
let change = {
|
||||||
let mut change = AnalysisChange::new();
|
let mut change = AnalysisChange::new();
|
||||||
let (vfs, line_endings_map) = &mut *self.vfs.write();
|
let (vfs, line_endings_map) = &mut *self.vfs.write();
|
||||||
|
@ -130,13 +135,14 @@ impl GlobalState {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let fs_op = changed_files.iter().any(|it| it.is_created_or_deleted());
|
|
||||||
if fs_op {
|
|
||||||
let roots = self.source_root_config.partition(&vfs);
|
|
||||||
change.set_roots(roots)
|
|
||||||
}
|
|
||||||
|
|
||||||
for file in changed_files {
|
for file in changed_files {
|
||||||
|
if file.is_created_or_deleted() {
|
||||||
|
if let Some(path) = vfs.file_path(file.file_id).as_path() {
|
||||||
|
fs_changes.push((path.to_path_buf(), file.change_kind));
|
||||||
|
has_fs_changes = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let text = if file.exists() {
|
let text = if file.exists() {
|
||||||
let bytes = vfs.file_contents(file.file_id).to_vec();
|
let bytes = vfs.file_contents(file.file_id).to_vec();
|
||||||
match String::from_utf8(bytes).ok() {
|
match String::from_utf8(bytes).ok() {
|
||||||
|
@ -152,10 +158,15 @@ impl GlobalState {
|
||||||
};
|
};
|
||||||
change.change_file(file.file_id, text);
|
change.change_file(file.file_id, text);
|
||||||
}
|
}
|
||||||
|
if has_fs_changes {
|
||||||
|
let roots = self.source_root_config.partition(&vfs);
|
||||||
|
change.set_roots(roots);
|
||||||
|
}
|
||||||
change
|
change
|
||||||
};
|
};
|
||||||
|
|
||||||
self.analysis_host.apply_change(change);
|
self.analysis_host.apply_change(change);
|
||||||
|
self.maybe_refresh(&fs_changes);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ use crate::{
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
use ra_project_model::ProjectWorkspace;
|
use ra_project_model::ProjectWorkspace;
|
||||||
|
use vfs::ChangeKind;
|
||||||
|
|
||||||
pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
|
pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
|
||||||
log::info!("initial config: {:#?}", config);
|
log::info!("initial config: {:#?}", config);
|
||||||
|
@ -197,39 +198,49 @@ impl GlobalState {
|
||||||
}
|
}
|
||||||
self.analysis_host.maybe_collect_garbage();
|
self.analysis_host.maybe_collect_garbage();
|
||||||
}
|
}
|
||||||
Event::Vfs(task) => match task {
|
Event::Vfs(mut task) => {
|
||||||
vfs::loader::Message::Loaded { files } => {
|
let _p = profile("GlobalState::handle_event/vfs");
|
||||||
let vfs = &mut self.vfs.write().0;
|
loop {
|
||||||
for (path, contents) in files {
|
match task {
|
||||||
let path = VfsPath::from(path);
|
vfs::loader::Message::Loaded { files } => {
|
||||||
if !self.mem_docs.contains(&path) {
|
let vfs = &mut self.vfs.write().0;
|
||||||
vfs.set_file_contents(path, contents)
|
for (path, contents) in files {
|
||||||
|
let path = VfsPath::from(path);
|
||||||
|
if !self.mem_docs.contains(&path) {
|
||||||
|
vfs.set_file_contents(path, contents)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vfs::loader::Message::Progress { n_total, n_done } => {
|
||||||
|
if n_total == 0 {
|
||||||
|
self.transition(Status::Invalid);
|
||||||
|
} else {
|
||||||
|
let state = if n_done == 0 {
|
||||||
|
self.transition(Status::Loading);
|
||||||
|
Progress::Begin
|
||||||
|
} else if n_done < n_total {
|
||||||
|
Progress::Report
|
||||||
|
} else {
|
||||||
|
assert_eq!(n_done, n_total);
|
||||||
|
self.transition(Status::Ready);
|
||||||
|
Progress::End
|
||||||
|
};
|
||||||
|
self.report_progress(
|
||||||
|
"roots scanned",
|
||||||
|
state,
|
||||||
|
Some(format!("{}/{}", n_done, n_total)),
|
||||||
|
Some(Progress::percentage(n_done, n_total)),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// Coalesce many VFS event into a single loop turn
|
||||||
vfs::loader::Message::Progress { n_total, n_done } => {
|
task = match self.loader.receiver.try_recv() {
|
||||||
if n_total == 0 {
|
Ok(task) => task,
|
||||||
self.transition(Status::Invalid);
|
Err(_) => break,
|
||||||
} else {
|
|
||||||
let state = if n_done == 0 {
|
|
||||||
self.transition(Status::Loading);
|
|
||||||
Progress::Begin
|
|
||||||
} else if n_done < n_total {
|
|
||||||
Progress::Report
|
|
||||||
} else {
|
|
||||||
assert_eq!(n_done, n_total);
|
|
||||||
self.transition(Status::Ready);
|
|
||||||
Progress::End
|
|
||||||
};
|
|
||||||
self.report_progress(
|
|
||||||
"roots scanned",
|
|
||||||
state,
|
|
||||||
Some(format!("{}/{}", n_done, n_total)),
|
|
||||||
Some(Progress::percentage(n_done, n_total)),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Event::Flycheck(task) => match task {
|
Event::Flycheck(task) => match task {
|
||||||
flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => {
|
flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => {
|
||||||
let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
|
let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
|
||||||
|
@ -428,7 +439,9 @@ impl GlobalState {
|
||||||
if let Some(flycheck) = &this.flycheck {
|
if let Some(flycheck) = &this.flycheck {
|
||||||
flycheck.handle.update();
|
flycheck.handle.update();
|
||||||
}
|
}
|
||||||
this.maybe_refresh(params.text_document.uri.as_str());
|
if let Ok(abs_path) = from_proto::abs_path(¶ms.text_document.uri) {
|
||||||
|
this.maybe_refresh(&[(abs_path, ChangeKind::Modify)]);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})?
|
})?
|
||||||
.on::<lsp_types::notification::DidChangeConfiguration>(|this, _params| {
|
.on::<lsp_types::notification::DidChangeConfiguration>(|this, _params| {
|
||||||
|
|
|
@ -6,7 +6,7 @@ use flycheck::FlycheckHandle;
|
||||||
use ra_db::{CrateGraph, SourceRoot, VfsPath};
|
use ra_db::{CrateGraph, SourceRoot, VfsPath};
|
||||||
use ra_ide::AnalysisChange;
|
use ra_ide::AnalysisChange;
|
||||||
use ra_project_model::{PackageRoot, ProcMacroClient, ProjectWorkspace};
|
use ra_project_model::{PackageRoot, ProcMacroClient, ProjectWorkspace};
|
||||||
use vfs::{file_set::FileSetConfig, AbsPath};
|
use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{Config, FilesWatcher, LinkedProject},
|
config::{Config, FilesWatcher, LinkedProject},
|
||||||
|
@ -14,9 +14,11 @@ use crate::{
|
||||||
lsp_ext,
|
lsp_ext,
|
||||||
main_loop::Task,
|
main_loop::Task,
|
||||||
};
|
};
|
||||||
|
use ra_prof::profile;
|
||||||
|
|
||||||
impl GlobalState {
|
impl GlobalState {
|
||||||
pub(crate) fn update_configuration(&mut self, config: Config) {
|
pub(crate) fn update_configuration(&mut self, config: Config) {
|
||||||
|
let _p = profile("GlobalState::update_configuration");
|
||||||
let old_config = mem::replace(&mut self.config, config);
|
let old_config = mem::replace(&mut self.config, config);
|
||||||
if self.config.lru_capacity != old_config.lru_capacity {
|
if self.config.lru_capacity != old_config.lru_capacity {
|
||||||
self.analysis_host.update_lru_capacity(old_config.lru_capacity);
|
self.analysis_host.update_lru_capacity(old_config.lru_capacity);
|
||||||
|
@ -27,8 +29,8 @@ impl GlobalState {
|
||||||
self.reload_flycheck();
|
self.reload_flycheck();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub(crate) fn maybe_refresh(&mut self, saved_doc_url: &str) {
|
pub(crate) fn maybe_refresh(&mut self, changes: &[(AbsPathBuf, ChangeKind)]) {
|
||||||
if !(saved_doc_url.ends_with("Cargo.toml") || saved_doc_url.ends_with("Cargo.lock")) {
|
if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match self.status {
|
match self.status {
|
||||||
|
@ -40,6 +42,41 @@ impl GlobalState {
|
||||||
} else {
|
} else {
|
||||||
self.transition(Status::NeedsReload);
|
self.transition(Status::NeedsReload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool {
|
||||||
|
const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
|
||||||
|
const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
|
||||||
|
|
||||||
|
if path.ends_with("Cargo.toml") || path.ends_with("Cargo.lock") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if change_kind == ChangeKind::Modify {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if path.extension().map(|it| it.to_str()) != Some("rs".into()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if IMPLICIT_TARGET_FILES.iter().any(|it| path.ends_with(it)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
let parent = match path.parent() {
|
||||||
|
Some(it) => it,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
if IMPLICIT_TARGET_DIRS.iter().any(|it| parent.ends_with(it)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if path.ends_with("main.rs") {
|
||||||
|
let grand_parent = match parent.parent() {
|
||||||
|
Some(it) => it,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
if IMPLICIT_TARGET_DIRS.iter().any(|it| grand_parent.ends_with(it)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub(crate) fn transition(&mut self, new_status: Status) {
|
pub(crate) fn transition(&mut self, new_status: Status) {
|
||||||
self.status = new_status;
|
self.status = new_status;
|
||||||
|
@ -79,6 +116,7 @@ impl GlobalState {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) {
|
pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) {
|
||||||
|
let _p = profile("GlobalState::switch_workspaces");
|
||||||
log::info!("reloading projects: {:?}", self.config.linked_projects);
|
log::info!("reloading projects: {:?}", self.config.linked_projects);
|
||||||
|
|
||||||
let mut has_errors = false;
|
let mut has_errors = false;
|
||||||
|
@ -267,6 +305,7 @@ pub(crate) struct SourceRootConfig {
|
||||||
|
|
||||||
impl SourceRootConfig {
|
impl SourceRootConfig {
|
||||||
pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec<SourceRoot> {
|
pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec<SourceRoot> {
|
||||||
|
let _p = profile("SourceRootConfig::partition");
|
||||||
self.fsc
|
self.fsc
|
||||||
.partition(vfs)
|
.partition(vfs)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -70,7 +70,7 @@ impl ChangedFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||||
pub enum ChangeKind {
|
pub enum ChangeKind {
|
||||||
Create,
|
Create,
|
||||||
Modify,
|
Modify,
|
||||||
|
|
Loading…
Reference in a new issue