@@ -31,54 +31,56 @@ def print_code_snippet(file_path, line_num, context=3):
31
31
print (f"Could not read file { file_path } : { e } " )
32
32
33
33
34
- def parse_rustc_json (stderr : str , file ):
34
+ def parse_rustc_json (stderr : str , file_path ):
35
35
"""
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.
40
37
41
38
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 .
44
41
45
42
Returns:
46
- Any
43
+ None
47
44
"""
48
45
for line in stderr .splitlines ():
49
46
line = line .strip ()
50
47
if not line :
51
48
continue
49
+
52
50
try :
53
- obj = json .loads (line )
51
+ diagnostic = json .loads (line )
54
52
except json .JSONDecodeError :
55
53
continue
56
- if obj .get ("$message_type" ) != "diagnostic" :
54
+
55
+ if diagnostic .get ("$message_type" ) != "diagnostic" :
57
56
continue
58
57
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
62
60
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" , [])
78
63
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
79
81
80
82
def check_rust_test_errors (app , exception ):
81
- """
83
+ """
82
84
Sphinx 'build-finished' event handler that compiles the generated Rust file in test mode.
83
85
84
86
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):
89
91
app: The Sphinx application object. Must have an `output_rust_file` attribute containing
90
92
the path to the generated Rust source file.
91
93
exception: Exception raised during the build process, or None if the build completed successfully.
92
-
93
94
"""
94
95
rs_path = app .output_rust_file
95
96
# Run the Rust compiler in test mode with JSON error output format.
96
97
# capturing stdout and stderr as text.
97
98
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
99
101
capture_output = True ,
100
102
text = True
101
103
)
0 commit comments