Skip to content

Commit

Permalink
LS: Sort projects by specificity
Browse files Browse the repository at this point in the history
commit-id:81b8f857
  • Loading branch information
mkaput committed Jun 4, 2024
1 parent 7a30040 commit e90f415
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ impl Project for CairoProject {
vec![&self.project_path]
}

fn main_manifest_file(&self) -> &Path {
&self.project_path
}

fn reload(&mut self) {
let project_config = ProjectConfig::from_file(&self.project_path)
.with_context(|| {
Expand Down
47 changes: 43 additions & 4 deletions crates/cairo-lang-language-server/src/project/manager.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::cmp::Reverse;
use std::path::Path;

use cairo_lang_compiler::db::RootDatabase;
Expand Down Expand Up @@ -33,13 +34,11 @@ use crate::toolchain::scarb::ScarbToolchain;
/// As an output of processing these events, the manager updates the analysis database inputs with
/// the new state of projects, via the [`ProjectManager::apply_db_changes`] method.
pub struct ProjectManager {
// FIXME(mkaput): Projects must be sorted from the most specific to the least specific,
// so that linear scanning for project related to a file would be correct.
// FIXME(mkaput): Scarb workspace have an ability to self-modify their root path, and thus
// it is possible, that duplicate projects could happen during the lifetime of the server.
// These need to be deduplicated.
/// List of loaded projects.
projects: Vec<Box<dyn Project>>,
projects: ProjectsCollection,

/// The unmanaged `core` crate manager.
unmanaged_core_crate: UnmanagedCoreCrate,
Expand Down Expand Up @@ -69,7 +68,7 @@ impl ProjectManager {
Some(manifest_path) => {
debug!("loading project: {}", manifest_path.as_path().display());
let project = self.initialize_project(manifest_path);
self.projects.push(project);
self.projects.insert(project);
}
None if is_cairo_file(path) => {
// TODO(mkaput): Implement detached files.
Expand Down Expand Up @@ -135,3 +134,43 @@ impl ProjectManager {
fn is_cairo_file(path: &Path) -> bool {
path.extension().map_or(false, |ext| ext == CAIRO_FILE_EXTENSION)
}

/// A list of loaded projects, sorted by project specificity.
#[derive(Default)]
struct ProjectsCollection(Vec<Box<dyn Project>>);

impl ProjectsCollection {
/// Inserts an element to the collection, ensuring the sorting invariant is preserved.
fn insert(&mut self, project: Box<dyn Project>) {
self.0.push(project);
self.0.sort_by_cached_key(|p| Reverse(p.main_manifest_file().to_owned()))
}

/// Returns an iterator over the list.
fn iter(&self) -> std::slice::Iter<'_, Box<dyn Project>> {
self.0.iter()
}

/// Returns an iterator that allows modifying each value.
fn iter_mut(&mut self) -> std::slice::IterMut<'_, Box<dyn Project>> {
self.0.iter_mut()
}
}

impl<'a> IntoIterator for &'a ProjectsCollection {
type Item = &'a Box<dyn Project>;
type IntoIter = std::slice::Iter<'a, Box<dyn Project>>;

fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}

impl<'a> IntoIterator for &'a mut ProjectsCollection {
type Item = &'a mut Box<dyn Project>;
type IntoIter = std::slice::IterMut<'a, Box<dyn Project>>;

fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
3 changes: 3 additions & 0 deletions crates/cairo-lang-language-server/src/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ trait Project: Send {
/// This list may also include lockfiles.
fn manifest_files(&self) -> Vec<&Path>;

/// Gets the main manifest file of this project.
fn main_manifest_file(&self) -> &Path;

/// Forces the project to reload its state.
fn reload(&mut self);

Expand Down
7 changes: 7 additions & 0 deletions crates/cairo-lang-language-server/src/project/scarb/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ impl Project for ScarbWorkspace {
.collect()
}

fn main_manifest_file(&self) -> &Path {
match &self.metadata {
Some(metadata) => metadata.workspace.manifest_path.as_std_path(),
None => &self.manifest_path,
}
}

fn reload(&mut self) {
self.do_reload();
}
Expand Down

0 comments on commit e90f415

Please sign in to comment.