@@ -8,6 +8,7 @@ use std::{
88} ;
99
1010use paths:: AbsPath ;
11+ use semver:: Version ;
1112use stdx:: JodChild ;
1213
1314use crate :: {
@@ -30,13 +31,8 @@ pub(crate) struct ProcMacroServerProcess {
3031
3132#[ derive( Debug , Clone ) ]
3233pub ( crate ) enum Protocol {
33- LegacyJson {
34- mode : SpanMode ,
35- } ,
36- #[ expect( dead_code) ]
37- Postcard {
38- mode : SpanMode ,
39- } ,
34+ LegacyJson { mode : SpanMode } ,
35+ LegacyPostcard { mode : SpanMode } ,
4036}
4137
4238/// Maintains the state of the proc-macro server process.
@@ -54,50 +50,76 @@ impl ProcMacroServerProcess {
5450 env : impl IntoIterator <
5551 Item = ( impl AsRef < std:: ffi:: OsStr > , & ' a Option < impl ' a + AsRef < std:: ffi:: OsStr > > ) ,
5652 > + Clone ,
53+ version : Option < & Version > ,
5754 ) -> io:: Result < ProcMacroServerProcess > {
58- let create_srv = || {
59- let mut process = Process :: run ( process_path, env. clone ( ) ) ?;
60- let ( stdin, stdout) = process. stdio ( ) . expect ( "couldn't access child stdio" ) ;
55+ const VERSION : Version = Version :: new ( 1 , 93 , 0 ) ;
56+ // we do `>` for nightly as this started working in the middle of the 1.93 nightly release, so we dont want to break on half of the nightlies
57+ let has_working_format_flag = version. map_or ( false , |v| {
58+ if v. pre . as_str ( ) == "nightly" { * v > VERSION } else { * v >= VERSION }
59+ } ) ;
6160
62- io:: Result :: Ok ( ProcMacroServerProcess {
63- state : Mutex :: new ( ProcessSrvState { process, stdin, stdout } ) ,
64- version : 0 ,
65- protocol : Protocol :: LegacyJson { mode : SpanMode :: Id } ,
66- exited : OnceLock :: new ( ) ,
67- } )
61+ let formats: & [ _ ] = if has_working_format_flag {
62+ & [
63+ ( Some ( "postcard-legacy" ) , Protocol :: LegacyPostcard { mode : SpanMode :: Id } ) ,
64+ ( Some ( "json-legacy" ) , Protocol :: LegacyJson { mode : SpanMode :: Id } ) ,
65+ ]
66+ } else {
67+ & [ ( None , Protocol :: LegacyJson { mode : SpanMode :: Id } ) ]
6868 } ;
69- let mut srv = create_srv ( ) ?;
70- tracing:: info!( "sending proc-macro server version check" ) ;
71- match srv. version_check ( ) {
72- Ok ( v) if v > version:: CURRENT_API_VERSION => {
73- #[ allow( clippy:: disallowed_methods) ]
74- let process_version = Command :: new ( process_path)
75- . arg ( "--version" )
76- . output ( )
77- . map ( |output| String :: from_utf8_lossy ( & output. stdout ) . trim ( ) . to_owned ( ) )
78- . unwrap_or_else ( |_| "unknown version" . to_owned ( ) ) ;
79- Err ( io:: Error :: other ( format ! (
80- "Your installed proc-macro server is too new for your rust-analyzer. API version: {}, server version: {process_version}. \
69+
70+ let mut err = None ;
71+ for & ( format, ref protocol) in formats {
72+ let create_srv = || {
73+ let mut process = Process :: run ( process_path, env. clone ( ) , format) ?;
74+ let ( stdin, stdout) = process. stdio ( ) . expect ( "couldn't access child stdio" ) ;
75+
76+ io:: Result :: Ok ( ProcMacroServerProcess {
77+ state : Mutex :: new ( ProcessSrvState { process, stdin, stdout } ) ,
78+ version : 0 ,
79+ protocol : protocol. clone ( ) ,
80+ exited : OnceLock :: new ( ) ,
81+ } )
82+ } ;
83+ let mut srv = create_srv ( ) ?;
84+ tracing:: info!( "sending proc-macro server version check" ) ;
85+ match srv. version_check ( ) {
86+ Ok ( v) if v > version:: CURRENT_API_VERSION => {
87+ #[ allow( clippy:: disallowed_methods) ]
88+ let process_version = Command :: new ( process_path)
89+ . arg ( "--version" )
90+ . output ( )
91+ . map ( |output| String :: from_utf8_lossy ( & output. stdout ) . trim ( ) . to_owned ( ) )
92+ . unwrap_or_else ( |_| "unknown version" . to_owned ( ) ) ;
93+ err = Some ( io:: Error :: other ( format ! (
94+ "Your installed proc-macro server is too new for your rust-analyzer. API version: {}, server version: {process_version}. \
8195 This will prevent proc-macro expansion from working. Please consider updating your rust-analyzer to ensure compatibility with your current toolchain.",
82- version:: CURRENT_API_VERSION
83- ) ) )
84- }
85- Ok ( v) => {
86- tracing:: info!( "Proc-macro server version: {v}" ) ;
87- srv. version = v;
88- if srv. version >= version:: RUST_ANALYZER_SPAN_SUPPORT
89- && let Ok ( mode) = srv. enable_rust_analyzer_spans ( )
90- {
91- srv. protocol = Protocol :: LegacyJson { mode } ;
96+ version:: CURRENT_API_VERSION
97+ ) ) ) ;
98+ }
99+ Ok ( v) => {
100+ tracing:: info!( "Proc-macro server version: {v}" ) ;
101+ srv. version = v;
102+ if srv. version >= version:: RUST_ANALYZER_SPAN_SUPPORT
103+ && let Ok ( new_mode) = srv. enable_rust_analyzer_spans ( )
104+ {
105+ match & mut srv. protocol {
106+ Protocol :: LegacyJson { mode } | Protocol :: LegacyPostcard { mode } => {
107+ * mode = new_mode
108+ }
109+ }
110+ }
111+ tracing:: info!( "Proc-macro server protocol: {:?}" , srv. protocol) ;
112+ return Ok ( srv) ;
113+ }
114+ Err ( e) => {
115+ tracing:: info!( %e, "proc-macro version check failed" ) ;
116+ err = Some ( io:: Error :: other ( format ! (
117+ "proc-macro server version check failed: {e}"
118+ ) ) )
92119 }
93- tracing:: info!( "Proc-macro server protocol: {:?}" , srv. protocol) ;
94- Ok ( srv)
95- }
96- Err ( e) => {
97- tracing:: info!( %e, "proc-macro version check failed" ) ;
98- Err ( io:: Error :: other ( format ! ( "proc-macro server version check failed: {e}" ) ) )
99120 }
100121 }
122+ Err ( err. unwrap ( ) )
101123 }
102124
103125 /// Returns the server error if the process has exited.
@@ -106,7 +128,7 @@ impl ProcMacroServerProcess {
106128 }
107129
108130 pub ( crate ) fn use_postcard ( & self ) -> bool {
109- matches ! ( self . protocol, Protocol :: Postcard { .. } )
131+ matches ! ( self . protocol, Protocol :: LegacyPostcard { .. } )
110132 }
111133
112134 /// Retrieves the API version of the proc-macro server.
@@ -118,23 +140,23 @@ impl ProcMacroServerProcess {
118140 pub ( crate ) fn rust_analyzer_spans ( & self ) -> bool {
119141 match self . protocol {
120142 Protocol :: LegacyJson { mode } => mode == SpanMode :: RustAnalyzer ,
121- Protocol :: Postcard { mode } => mode == SpanMode :: RustAnalyzer ,
143+ Protocol :: LegacyPostcard { mode } => mode == SpanMode :: RustAnalyzer ,
122144 }
123145 }
124146
125147 /// Checks the API version of the running proc-macro server.
126148 fn version_check ( & self ) -> Result < u32 , ServerError > {
127149 match self . protocol {
128150 Protocol :: LegacyJson { .. } => legacy_protocol:: version_check ( self ) ,
129- Protocol :: Postcard { .. } => legacy_protocol:: version_check ( self ) ,
151+ Protocol :: LegacyPostcard { .. } => legacy_protocol:: version_check ( self ) ,
130152 }
131153 }
132154
133155 /// Enable support for rust-analyzer span mode if the server supports it.
134156 fn enable_rust_analyzer_spans ( & self ) -> Result < SpanMode , ServerError > {
135157 match self . protocol {
136158 Protocol :: LegacyJson { .. } => legacy_protocol:: enable_rust_analyzer_spans ( self ) ,
137- Protocol :: Postcard { .. } => legacy_protocol:: enable_rust_analyzer_spans ( self ) ,
159+ Protocol :: LegacyPostcard { .. } => legacy_protocol:: enable_rust_analyzer_spans ( self ) ,
138160 }
139161 }
140162
@@ -145,7 +167,7 @@ impl ProcMacroServerProcess {
145167 ) -> Result < Result < Vec < ( String , ProcMacroKind ) > , String > , ServerError > {
146168 match self . protocol {
147169 Protocol :: LegacyJson { .. } => legacy_protocol:: find_proc_macros ( self , dylib_path) ,
148- Protocol :: Postcard { .. } => legacy_protocol:: find_proc_macros ( self , dylib_path) ,
170+ Protocol :: LegacyPostcard { .. } => legacy_protocol:: find_proc_macros ( self , dylib_path) ,
149171 }
150172 }
151173
@@ -220,8 +242,9 @@ impl Process {
220242 env : impl IntoIterator <
221243 Item = ( impl AsRef < std:: ffi:: OsStr > , & ' a Option < impl ' a + AsRef < std:: ffi:: OsStr > > ) ,
222244 > ,
245+ format : Option < & str > ,
223246 ) -> io:: Result < Process > {
224- let child = JodChild ( mk_child ( path, env) ?) ;
247+ let child = JodChild ( mk_child ( path, env, format ) ?) ;
225248 Ok ( Process { child } )
226249 }
227250
@@ -241,6 +264,7 @@ fn mk_child<'a>(
241264 extra_env : impl IntoIterator <
242265 Item = ( impl AsRef < std:: ffi:: OsStr > , & ' a Option < impl ' a + AsRef < std:: ffi:: OsStr > > ) ,
243266 > ,
267+ format : Option < & str > ,
244268) -> io:: Result < Child > {
245269 #[ allow( clippy:: disallowed_methods) ]
246270 let mut cmd = Command :: new ( path) ;
@@ -250,6 +274,10 @@ fn mk_child<'a>(
250274 ( key, None ) => cmd. env_remove ( key) ,
251275 } ;
252276 }
277+ if let Some ( format) = format {
278+ cmd. arg ( "--format" ) ;
279+ cmd. arg ( format) ;
280+ }
253281 cmd. env ( "RUST_ANALYZER_INTERNALS_DO_NOT_USE" , "this is unstable" )
254282 . stdin ( Stdio :: piped ( ) )
255283 . stdout ( Stdio :: piped ( ) )
0 commit comments