@@ -31,54 +31,56 @@ def print_code_snippet(file_path, line_num, context=3):
3131 print (f"Could not read file { file_path } : { e } " )
3232
3333
34- def parse_rustc_json (stderr : str , file ):
34+ def parse_rustc_json (stderr : str , file_path ):
3535 """
36- Parses the JSON diagnostics output from `rustc`.
37-
38- This function takes the standard error output (in JSON format) from the Rust compiler (`rustc`)
39- and processes it, possibly filtering or reporting diagnostics relevant to the specified file.
36+ Parses rustc's JSON output and prints only the first error with a single snippet.
4037
4138 Args:
42- stderr (str): The JSON-formatted stderr output from ` rustc` .
43- file: The file object or path that the diagnostics should relate to .
39+ stderr (str): JSON-formatted stderr output from rustc.
40+ file_path: Path to the Rust file .
4441
4542 Returns:
46- Any
43+ None
4744 """
4845 for line in stderr .splitlines ():
4946 line = line .strip ()
5047 if not line :
5148 continue
49+
5250 try :
53- obj = json .loads (line )
51+ diagnostic = json .loads (line )
5452 except json .JSONDecodeError :
5553 continue
56- if obj .get ("$message_type" ) != "diagnostic" :
54+
55+ if diagnostic .get ("$message_type" ) != "diagnostic" :
5756 continue
5857
59- level = obj .get ("level" )
60- msg = obj .get ("message" )
61- spans = obj .get ("spans" , [])
58+ if diagnostic .get ("level" ) != "error" :
59+ continue # skip warnings and notes
6260
63- line_num = None
64- for span in spans :
65- if span .get ("is_primary" ):
66- line_num = span .get ("line_start" )
67- break
68-
69- if line_num is not None :
70- print (f"{ level } : line { line_num } : { msg } " )
71- diag_f = print_code_snippet (file , line_num )
72- if level == "error" :
73- print ("=========================" )
74- print (f" { diag_f } " )
75- print ("=========================\n \n " )
76- else :
77- print (f"{ level } : { msg } " )
61+ message = diagnostic .get ("message" , "" )
62+ spans = diagnostic .get ("spans" , [])
7863
64+ # Try to find a span in the current file
65+ for span in spans :
66+ if span ["file_name" ] == file_path :
67+ line_num = span ["line_start" ]
68+ label = span .get ("label" , "" )
69+ print (f"error: line { line_num } : { message } " )
70+ if label :
71+ print (f"--> { label } " )
72+ print ("=" * 25 )
73+ snippet = print_code_snippet (file_path , line_num , context = 3 )
74+ print (snippet )
75+ print ("=" * 25 )
76+ return # we return because we only print the first error--in json format there can be multiple error messages for 1 error-- if you want to see them comment this line.
77+
78+ # If no span in the file, still print the error
79+ print (f"error: { message } " )
80+ return
7981
8082def check_rust_test_errors (app , exception ):
81- """
83+ """
8284 Sphinx 'build-finished' event handler that compiles the generated Rust file in test mode.
8385
8486 This function is connected to the Sphinx build lifecycle and is executed after the build finishes.
@@ -89,13 +91,13 @@ def check_rust_test_errors(app, exception):
8991 app: The Sphinx application object. Must have an `output_rust_file` attribute containing
9092 the path to the generated Rust source file.
9193 exception: Exception raised during the build process, or None if the build completed successfully.
92-
9394 """
9495 rs_path = app .output_rust_file
9596 # Run the Rust compiler in test mode with JSON error output format.
9697 # capturing stdout and stderr as text.
9798 result = subprocess .run (
98- ["rustc" , "--test" , "--edition=2024" , "--error-format=json" , rs_path ],
99+ ["rustc" , "--test" , "--edition=2024" , "--error-format=json" , "--emit=metadata" , rs_path ],
100+ # --emit=metadata or else rustc will produce a binary ./generated
99101 capture_output = True ,
100102 text = True
101103 )
0 commit comments