11use itertools:: Itertools ;
22use log:: { debug, info} ;
33use ra_ap_base_db:: SourceDatabase ;
4- use ra_ap_base_db:: SourceDatabaseFileInputExt ;
54use ra_ap_hir:: Semantics ;
65use ra_ap_ide_db:: RootDatabase ;
76use ra_ap_load_cargo:: { load_workspace_at, LoadCargoConfig , ProcMacroServerChoice } ;
@@ -21,19 +20,24 @@ use ra_ap_vfs::VfsPath;
2120use std:: borrow:: Cow ;
2221use std:: path:: { Path , PathBuf } ;
2322use triomphe:: Arc ;
24- pub enum RustAnalyzer {
25- WithDatabase { db : RootDatabase , vfs : Vfs } ,
26- WithoutDatabase ( ) ,
23+ pub enum RustAnalyzer < ' a > {
24+ WithSemantics {
25+ vfs : & ' a Vfs ,
26+ semantics : Semantics < ' a , RootDatabase > ,
27+ } ,
28+ WithoutSemantics ,
2729}
28- pub struct ParseResult < ' a > {
30+ pub struct ParseResult {
2931 pub ast : SourceFile ,
3032 pub text : Arc < str > ,
3133 pub errors : Vec < SyntaxError > ,
3234 pub file_id : Option < EditionedFileId > ,
33- pub semantics : Option < Semantics < ' a , RootDatabase > > ,
3435}
35- impl RustAnalyzer {
36- pub fn new ( project : & ProjectManifest , scratch_dir : & Path ) -> Self {
36+ impl < ' a > RustAnalyzer < ' a > {
37+ pub fn load_workspace (
38+ project : & ProjectManifest ,
39+ scratch_dir : & Path ,
40+ ) -> Option < ( RootDatabase , Vfs ) > {
3741 let config = CargoConfig {
3842 sysroot : Some ( RustLibSource :: Discover ) ,
3943 target_dir : ra_ap_paths:: Utf8PathBuf :: from_path_buf ( scratch_dir. to_path_buf ( ) )
@@ -50,14 +54,55 @@ impl RustAnalyzer {
5054 let manifest = project. manifest_path ( ) ;
5155
5256 match load_workspace_at ( manifest. as_ref ( ) , & config, & load_config, & progress) {
53- Ok ( ( db, vfs, _macro_server) ) => RustAnalyzer :: WithDatabase { db, vfs } ,
57+ Ok ( ( db, vfs, _macro_server) ) => Some ( ( db, vfs) ) ,
5458 Err ( err) => {
5559 log:: error!( "failed to load workspace for {}: {}" , manifest, err) ;
56- RustAnalyzer :: WithoutDatabase ( )
60+ None
5761 }
5862 }
5963 }
60- pub fn parse ( & mut self , path : & Path ) -> ParseResult < ' _ > {
64+ pub fn new ( vfs : & ' a Vfs , semantics : Semantics < ' a , RootDatabase > ) -> Self {
65+ RustAnalyzer :: WithSemantics { vfs, semantics }
66+ }
67+ pub fn semantics ( & ' a self ) -> Option < & ' a Semantics < ' a , RootDatabase > > {
68+ match self {
69+ RustAnalyzer :: WithSemantics { vfs : _, semantics } => Some ( semantics) ,
70+ RustAnalyzer :: WithoutSemantics => None ,
71+ }
72+ }
73+ pub fn parse ( & self , path : & Path ) -> ParseResult {
74+ if let RustAnalyzer :: WithSemantics { vfs, semantics } = self {
75+ if let Some ( file_id) = Utf8PathBuf :: from_path_buf ( path. to_path_buf ( ) )
76+ . ok ( )
77+ . and_then ( |x| AbsPathBuf :: try_from ( x) . ok ( ) )
78+ . map ( VfsPath :: from)
79+ . and_then ( |x| vfs. file_id ( & x) )
80+ {
81+ if let Ok ( input) = std:: panic:: catch_unwind ( || semantics. db . file_text ( file_id) ) {
82+ let file_id = EditionedFileId :: current_edition ( file_id) ;
83+ let source_file = semantics. parse ( file_id) ;
84+ let errors = semantics
85+ . db
86+ . parse_errors ( file_id)
87+ . into_iter ( )
88+ . flat_map ( |x| x. to_vec ( ) )
89+ . collect ( ) ;
90+
91+ return ParseResult {
92+ ast : source_file,
93+ text : input,
94+ errors,
95+ file_id : Some ( file_id) ,
96+ } ;
97+ } else {
98+ log:: debug!(
99+ "No text available for file_id '{:?}', falling back to loading file '{}' from disk." ,
100+ file_id,
101+ path. to_string_lossy( )
102+ )
103+ }
104+ }
105+ }
61106 let mut errors = Vec :: new ( ) ;
62107 let input = match std:: fs:: read ( path) {
63108 Ok ( data) => data,
@@ -71,32 +116,6 @@ impl RustAnalyzer {
71116 } ;
72117 let ( input, err) = from_utf8_lossy ( & input) ;
73118
74- if let RustAnalyzer :: WithDatabase { vfs, db } = self {
75- if let Some ( file_id) = Utf8PathBuf :: from_path_buf ( path. to_path_buf ( ) )
76- . ok ( )
77- . and_then ( |x| AbsPathBuf :: try_from ( x) . ok ( ) )
78- . map ( VfsPath :: from)
79- . and_then ( |x| vfs. file_id ( & x) )
80- {
81- db. set_file_text ( file_id, & input) ;
82- let semantics = Semantics :: new ( db) ;
83-
84- let file_id = EditionedFileId :: current_edition ( file_id) ;
85- let source_file = semantics. parse ( file_id) ;
86- errors. extend (
87- db. parse_errors ( file_id)
88- . into_iter ( )
89- . flat_map ( |x| x. to_vec ( ) ) ,
90- ) ;
91- return ParseResult {
92- ast : source_file,
93- text : input. as_ref ( ) . into ( ) ,
94- errors,
95- file_id : Some ( file_id) ,
96- semantics : Some ( semantics) ,
97- } ;
98- }
99- }
100119 let parse = ra_ap_syntax:: ast:: SourceFile :: parse ( & input, Edition :: CURRENT ) ;
101120 errors. extend ( parse. errors ( ) ) ;
102121 errors. extend ( err) ;
@@ -105,7 +124,6 @@ impl RustAnalyzer {
105124 text : input. as_ref ( ) . into ( ) ,
106125 errors,
107126 file_id : None ,
108- semantics : None ,
109127 }
110128 }
111129}
0 commit comments