@@ -24,7 +24,8 @@ use ide_db::{
2424use itertools:: Itertools ;
2525use paths:: { Utf8Path , Utf8PathBuf } ;
2626use project_model:: {
27- CargoConfig , CargoFeatures , ProjectJson , ProjectJsonData , ProjectManifest , RustLibSource ,
27+ CargoConfig , CargoFeatures , ProjectJson , ProjectJsonData , ProjectJsonFromCommand ,
28+ ProjectManifest , RustLibSource ,
2829} ;
2930use rustc_hash:: { FxHashMap , FxHashSet } ;
3031use semver:: Version ;
@@ -761,7 +762,13 @@ enum RatomlFile {
761762
762763#[ derive( Debug , Clone ) ]
763764pub struct Config {
764- discovered_projects : Vec < ProjectManifest > ,
765+ /// Projects that have a Cargo.toml or a rust-project.json in a
766+ /// parent directory, so we can discover them by walking the
767+ /// file system.
768+ discovered_projects_from_filesystem : Vec < ProjectManifest > ,
769+ /// Projects whose configuration was generated by a command
770+ /// configured in discoverConfig.
771+ discovered_projects_from_command : Vec < ProjectJsonFromCommand > ,
765772 /// The workspace roots as registered by the LSP client
766773 workspace_roots : Vec < AbsPathBuf > ,
767774 caps : ClientCapabilities ,
@@ -1054,19 +1061,19 @@ impl Config {
10541061 ( config, e, should_update)
10551062 }
10561063
1057- pub fn add_linked_projects ( & mut self , data : ProjectJsonData , buildfile : AbsPathBuf ) {
1058- let linked_projects = & mut self . client_config . 0 . global . linkedProjects ;
1059-
1060- let new_project = ManifestOrProjectJson :: DiscoveredProjectJson { data, buildfile } ;
1061- match linked_projects {
1062- Some ( projects) => {
1063- match projects. iter_mut ( ) . find ( |p| p. manifest ( ) == new_project. manifest ( ) ) {
1064- Some ( p) => * p = new_project,
1065- None => projects. push ( new_project) ,
1066- }
1064+ pub fn add_discovered_project_from_command (
1065+ & mut self ,
1066+ data : ProjectJsonData ,
1067+ buildfile : AbsPathBuf ,
1068+ ) {
1069+ for proj in self . discovered_projects_from_command . iter_mut ( ) {
1070+ if proj. buildfile == buildfile {
1071+ proj. data = data;
1072+ return ;
10671073 }
1068- None => * linked_projects = Some ( vec ! [ new_project] ) ,
10691074 }
1075+
1076+ self . discovered_projects_from_command . push ( ProjectJsonFromCommand { data, buildfile } ) ;
10701077 }
10711078}
10721079
@@ -1344,7 +1351,8 @@ impl Config {
13441351
13451352 Config {
13461353 caps : ClientCapabilities :: new ( caps) ,
1347- discovered_projects : Vec :: new ( ) ,
1354+ discovered_projects_from_filesystem : Vec :: new ( ) ,
1355+ discovered_projects_from_command : Vec :: new ( ) ,
13481356 root_path,
13491357 snippets : Default :: default ( ) ,
13501358 workspace_roots,
@@ -1365,7 +1373,7 @@ impl Config {
13651373 if discovered. is_empty ( ) {
13661374 tracing:: error!( "failed to find any projects in {:?}" , & self . workspace_roots) ;
13671375 }
1368- self . discovered_projects = discovered;
1376+ self . discovered_projects_from_filesystem = discovered;
13691377 }
13701378
13711379 pub fn remove_workspace ( & mut self , path : & AbsPath ) {
@@ -1687,42 +1695,59 @@ impl Config {
16871695 self . workspace_discoverConfig ( ) . as_ref ( )
16881696 }
16891697
1690- pub fn linked_or_discovered_projects ( & self ) -> Vec < LinkedProject > {
1691- match self . linkedProjects ( ) . as_slice ( ) {
1692- [ ] => {
1693- let exclude_dirs: Vec < _ > =
1694- self . files_excludeDirs ( ) . iter ( ) . map ( |p| self . root_path . join ( p) ) . collect ( ) ;
1695- self . discovered_projects
1696- . iter ( )
1697- . filter ( |project| {
1698- !exclude_dirs. iter ( ) . any ( |p| project. manifest_path ( ) . starts_with ( p) )
1699- } )
1700- . cloned ( )
1701- . map ( LinkedProject :: from)
1702- . collect ( )
1698+ fn discovered_projects ( & self ) -> Vec < ManifestOrProjectJson > {
1699+ let exclude_dirs: Vec < _ > =
1700+ self . files_excludeDirs ( ) . iter ( ) . map ( |p| self . root_path . join ( p) ) . collect ( ) ;
1701+
1702+ let mut projects = vec ! [ ] ;
1703+ for fs_proj in & self . discovered_projects_from_filesystem {
1704+ let manifest_path = fs_proj. manifest_path ( ) ;
1705+ if exclude_dirs. iter ( ) . any ( |p| manifest_path. starts_with ( p) ) {
1706+ continue ;
17031707 }
1704- linked_projects => linked_projects
1705- . iter ( )
1706- . filter_map ( |linked_project| match linked_project {
1707- ManifestOrProjectJson :: Manifest ( it) => {
1708- let path = self . root_path . join ( it) ;
1709- ProjectManifest :: from_manifest_file ( path)
1710- . map_err ( |e| tracing:: error!( "failed to load linked project: {}" , e) )
1711- . ok ( )
1712- . map ( Into :: into)
1713- }
1714- ManifestOrProjectJson :: DiscoveredProjectJson { data, buildfile } => {
1715- let root_path =
1716- buildfile. parent ( ) . expect ( "Unable to get parent of buildfile" ) ;
17171708
1718- Some ( ProjectJson :: new ( None , root_path, data. clone ( ) ) . into ( ) )
1719- }
1720- ManifestOrProjectJson :: ProjectJson ( it) => {
1721- Some ( ProjectJson :: new ( None , & self . root_path , it. clone ( ) ) . into ( ) )
1722- }
1723- } )
1724- . collect ( ) ,
1709+ let buf: Utf8PathBuf = manifest_path. to_path_buf ( ) . into ( ) ;
1710+ projects. push ( ManifestOrProjectJson :: Manifest ( buf) ) ;
1711+ }
1712+
1713+ for dis_proj in & self . discovered_projects_from_command {
1714+ projects. push ( ManifestOrProjectJson :: DiscoveredProjectJson {
1715+ data : dis_proj. data . clone ( ) ,
1716+ buildfile : dis_proj. buildfile . clone ( ) ,
1717+ } ) ;
17251718 }
1719+
1720+ projects
1721+ }
1722+
1723+ pub fn linked_or_discovered_projects ( & self ) -> Vec < LinkedProject > {
1724+ let linked_projects = self . linkedProjects ( ) ;
1725+ let projects = if linked_projects. is_empty ( ) {
1726+ self . discovered_projects ( )
1727+ } else {
1728+ linked_projects. clone ( )
1729+ } ;
1730+
1731+ projects
1732+ . iter ( )
1733+ . filter_map ( |linked_project| match linked_project {
1734+ ManifestOrProjectJson :: Manifest ( it) => {
1735+ let path = self . root_path . join ( it) ;
1736+ ProjectManifest :: from_manifest_file ( path)
1737+ . map_err ( |e| tracing:: error!( "failed to load linked project: {}" , e) )
1738+ . ok ( )
1739+ . map ( Into :: into)
1740+ }
1741+ ManifestOrProjectJson :: DiscoveredProjectJson { data, buildfile } => {
1742+ let root_path = buildfile. parent ( ) . expect ( "Unable to get parent of buildfile" ) ;
1743+
1744+ Some ( ProjectJson :: new ( None , root_path, data. clone ( ) ) . into ( ) )
1745+ }
1746+ ManifestOrProjectJson :: ProjectJson ( it) => {
1747+ Some ( ProjectJson :: new ( None , & self . root_path , it. clone ( ) ) . into ( ) )
1748+ }
1749+ } )
1750+ . collect ( )
17261751 }
17271752
17281753 pub fn prefill_caches ( & self ) -> bool {
@@ -2282,18 +2307,6 @@ where
22822307 se. serialize_str ( path. as_str ( ) )
22832308}
22842309
2285- impl ManifestOrProjectJson {
2286- fn manifest ( & self ) -> Option < & Utf8Path > {
2287- match self {
2288- ManifestOrProjectJson :: Manifest ( manifest) => Some ( manifest) ,
2289- ManifestOrProjectJson :: DiscoveredProjectJson { buildfile, .. } => {
2290- Some ( buildfile. as_ref ( ) )
2291- }
2292- ManifestOrProjectJson :: ProjectJson ( _) => None ,
2293- }
2294- }
2295- }
2296-
22972310#[ derive( Serialize , Deserialize , Debug , Clone ) ]
22982311#[ serde( rename_all = "snake_case" ) ]
22992312enum ExprFillDefaultDef {
0 commit comments