1
1
use itertools:: Itertools ;
2
2
use log:: { debug, info} ;
3
3
use ra_ap_base_db:: SourceDatabase ;
4
- use ra_ap_base_db:: SourceDatabaseFileInputExt ;
5
4
use ra_ap_hir:: Semantics ;
6
5
use ra_ap_ide_db:: RootDatabase ;
7
6
use ra_ap_load_cargo:: { load_workspace_at, LoadCargoConfig , ProcMacroServerChoice } ;
@@ -21,19 +20,24 @@ use ra_ap_vfs::VfsPath;
21
20
use std:: borrow:: Cow ;
22
21
use std:: path:: { Path , PathBuf } ;
23
22
use 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 ,
27
29
}
28
- pub struct ParseResult < ' a > {
30
+ pub struct ParseResult {
29
31
pub ast : SourceFile ,
30
32
pub text : Arc < str > ,
31
33
pub errors : Vec < SyntaxError > ,
32
34
pub file_id : Option < EditionedFileId > ,
33
- pub semantics : Option < Semantics < ' a , RootDatabase > > ,
34
35
}
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 ) > {
37
41
let config = CargoConfig {
38
42
sysroot : Some ( RustLibSource :: Discover ) ,
39
43
target_dir : ra_ap_paths:: Utf8PathBuf :: from_path_buf ( scratch_dir. to_path_buf ( ) )
@@ -50,14 +54,55 @@ impl RustAnalyzer {
50
54
let manifest = project. manifest_path ( ) ;
51
55
52
56
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) ) ,
54
58
Err ( err) => {
55
59
log:: error!( "failed to load workspace for {}: {}" , manifest, err) ;
56
- RustAnalyzer :: WithoutDatabase ( )
60
+ None
57
61
}
58
62
}
59
63
}
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
+ }
61
106
let mut errors = Vec :: new ( ) ;
62
107
let input = match std:: fs:: read ( path) {
63
108
Ok ( data) => data,
@@ -71,32 +116,6 @@ impl RustAnalyzer {
71
116
} ;
72
117
let ( input, err) = from_utf8_lossy ( & input) ;
73
118
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
- }
100
119
let parse = ra_ap_syntax:: ast:: SourceFile :: parse ( & input, Edition :: CURRENT ) ;
101
120
errors. extend ( parse. errors ( ) ) ;
102
121
errors. extend ( err) ;
@@ -105,7 +124,6 @@ impl RustAnalyzer {
105
124
text : input. as_ref ( ) . into ( ) ,
106
125
errors,
107
126
file_id : None ,
108
- semantics : None ,
109
127
}
110
128
}
111
129
}
0 commit comments