2626#include < sstream>
2727#include < string>
2828#include < string_view>
29- #include < unordered_map>
3029#include < unordered_set>
3130#include < vector>
32- #include < fstream>
3331#include < cstdlib>
3432#include < cctype>
3533
@@ -54,51 +52,6 @@ namespace
5452 << " \n " ;
5553 }
5654
57- std::vector<std::string> read_code_frame_lines (
58- const fs::path &file,
59- std::size_t line,
60- std::size_t contextLines,
61- std::size_t maxLineWidth)
62- {
63- std::vector<std::string> out;
64-
65- if (file.empty () || line == 0 )
66- return out;
67-
68- std::ifstream in (file);
69- if (!in)
70- return out;
71-
72- const std::size_t startLine =
73- line > contextLines ? line - contextLines : 1 ;
74-
75- const std::size_t endLine = line + contextLines;
76-
77- std::string current;
78- std::size_t currentLine = 0 ;
79-
80- while (std::getline (in, current))
81- {
82- ++currentLine;
83-
84- if (currentLine < startLine)
85- continue ;
86-
87- if (currentLine > endLine)
88- break ;
89-
90- if (maxLineWidth > 0 && current.size () > maxLineWidth)
91- {
92- current = current.substr (0 , maxLineWidth);
93- current += " ..." ;
94- }
95-
96- out.push_back (current);
97- }
98-
99- return out;
100- }
101-
10255 std::string hint_for_compiler_error (
10356 const vix::cli::errors::CompilerError &err)
10457 {
@@ -126,9 +79,10 @@ namespace
12679 return " Declare the symbol before use, include the right header, or check the namespace." ;
12780 }
12881
129- if (message.find (" was not declared in this scope" ) != std::string::npos)
82+ if (message.find (" has not been declared" ) != std::string::npos ||
83+ message.find (" was not declared in this scope" ) != std::string::npos)
13084 {
131- return " Declare the symbol before use, include the right header, or move the function definition above the call ." ;
85+ return " Include the header that declares this name or check its namespace ." ;
13286 }
13387
13488 if (message.find (" does not name a type" ) != std::string::npos)
@@ -171,37 +125,6 @@ namespace
171125 return {};
172126 }
173127
174- vix::cli::build::BuildDiagnostic diagnostic_from_compiler_error (
175- const vix::cli::errors::CompilerError &err,
176- const std::string &contextMessage)
177- {
178- vix::cli::build::BuildDiagnostic diagnostic;
179-
180- diagnostic.title =
181- contextMessage.empty ()
182- ? " Build failed"
183- : contextMessage;
184-
185- diagnostic.error = err.message ;
186- diagnostic.hint = hint_for_compiler_error (err);
187-
188- diagnostic.location .file = err.file ;
189- diagnostic.location .line =
190- err.line > 0 ? static_cast <std::size_t >(err.line ) : 0 ;
191- diagnostic.location .column =
192- err.column > 0 ? static_cast <std::size_t >(err.column ) : 0 ;
193-
194- diagnostic.codeFrame .location = diagnostic.location ;
195- diagnostic.codeFrame .lines =
196- read_code_frame_lines (
197- fs::path (err.file ),
198- diagnostic.location .line ,
199- 2 ,
200- 120 );
201-
202- return diagnostic;
203- }
204-
205128 bool handle_unrecognized_cli_option_as_script_runtime_args (
206129 std::string_view log)
207130 {
@@ -386,15 +309,6 @@ namespace vix::cli
386309 if (pipeline.tryHandle (errors, ctx))
387310 return true ;
388311
389- std::unordered_map<std::string, int > counts;
390- counts.reserve (errors.size ());
391-
392- for (const auto &err : errors)
393- {
394- const std::string key = err.file + " |" + err.message ;
395- ++counts[key];
396- }
397-
398312 std::vector<CompilerError> unique;
399313 unique.reserve (errors.size ());
400314
@@ -403,7 +317,14 @@ namespace vix::cli
403317
404318 for (const auto &err : errors)
405319 {
406- const std::string key = err.file + " |" + err.message ;
320+ const std::string key =
321+ err.file +
322+ " |" +
323+ std::to_string (err.line ) +
324+ " |" +
325+ std::to_string (err.column ) +
326+ " |" +
327+ err.message ;
407328
408329 if (seen.insert (key).second )
409330 unique.push_back (err);
@@ -414,72 +335,81 @@ namespace vix::cli
414335 std::cerr << RED
415336 << " error: "
416337 << RESET
417- << contextMessage
338+ << (contextMessage.empty ()
339+ ? " Build failed"
340+ : contextMessage)
418341 << " \n " ;
419342
420- print_hint (" no unique compiler error was detected; inspect the raw compiler output" );
421-
422- if (!cleanedLog.empty ())
423- std::cerr << cleanedLog << " \n " ;
343+ print_hint (
344+ " no compiler error could be extracted; "
345+ " run with VIX_LOG_LEVEL=debug to inspect the full output" );
424346
425347 return false ;
426348 }
427349
428- std::cerr << RED
429- << " error: "
430- << RESET
431- << contextMessage
432- << " \n " ;
350+ /*
351+ * Show the first compiler error by default.
352+ *
353+ * Compiler errors frequently cascade: once the parser cannot
354+ * understand one declaration, it may report several secondary
355+ * errors. Showing the first error keeps the output focused for
356+ * beginners.
357+ */
358+ const std::size_t maxToShow = 1 ;
433359
434360 CodeFrameOptions codeFrameOptions;
435- codeFrameOptions.contextLines = 2 ;
361+ codeFrameOptions.contextLines = 1 ;
436362 codeFrameOptions.maxLineWidth = 120 ;
437363 codeFrameOptions.tabWidth = 4 ;
364+ codeFrameOptions.leadingBlankLine = true ;
438365
439- const std::size_t maxToShow =
440- std::min<std::size_t >(unique.size (), 3 );
441-
442- for (std::size_t i = 0 ; i < maxToShow; ++i)
366+ for (std::size_t i = 0 ;
367+ i < unique.size () && i < maxToShow;
368+ ++i)
443369 {
444- const auto &err = unique[i];
445-
446- const vix::cli::build::BuildDiagnostic diagnostic =
447- ::diagnostic_from_compiler_error (
448- err,
449- contextMessage);
450-
451- vix::cli::build::print_build_diagnostic (
452- std::cerr,
453- diagnostic);
370+ const CompilerError &err = unique[i];
454371
455- const std::string key = err.file + " |" + err.message ;
456- const auto it = counts.find (key);
372+ std::cerr << RED
373+ << " error: "
374+ << RESET
375+ << err.message
376+ << " \n " ;
457377
458- if (it != counts.end () && it->second > 1 )
459- {
460- vix::cli::build::print_build_warning (
461- std::cerr,
462- std::to_string (it->second - 1 ) + " similar error(s) hidden" );
463- }
378+ /*
379+ * Use the shared codeframe contract directly.
380+ *
381+ * This avoids creating a second list of source lines with
382+ * incorrect line-number assumptions.
383+ */
384+ printCodeFrame (
385+ err,
386+ ctx,
387+ codeFrameOptions);
388+
389+ const std::string hint =
390+ hint_for_compiler_error (err);
391+
392+ if (!hint.empty ())
393+ print_hint (hint);
464394 }
465395
466- if (unique.size () > maxToShow)
396+ const std::size_t hiddenCount =
397+ unique.size () > maxToShow
398+ ? unique.size () - maxToShow
399+ : 0 ;
400+
401+ if (hiddenCount > 0 )
467402 {
468403 std::cerr << " \n "
469404 << GRAY
470- << (unique.size () - maxToShow)
471- << " more distinct error(s) hidden. Run with --verbose for full output."
405+ << hiddenCount
406+ << " more compiler error"
407+ << (hiddenCount == 1 ? " " : " s" )
408+ << " hidden. Run with --verbose to see them."
472409 << RESET
473410 << " \n " ;
474411 }
475412
476- if (!sourceFile.empty ())
477- {
478- vix::cli::build::print_build_info (
479- std::cerr,
480- " at: " + sourceFile.string ());
481- }
482-
483413 return true ;
484414 }
485415} // namespace vix::cli
0 commit comments