@@ -424,21 +424,95 @@ pub fn parse_config_content(content: &str, format: ConfigFormat) -> std::io::Res
424424 ConfigFormat :: Toml => toml:: from_str ( content) . map_err ( |e| {
425425 std:: io:: Error :: new (
426426 std:: io:: ErrorKind :: InvalidData ,
427- format ! ( "Failed to parse TOML config: {e}" ) ,
427+ format_toml_error ( & e , content ) ,
428428 )
429429 } ) ,
430430 ConfigFormat :: JsonC => {
431431 let stripped = strip_json_comments ( content) ;
432432 serde_json:: from_str ( & stripped) . map_err ( |e| {
433433 std:: io:: Error :: new (
434434 std:: io:: ErrorKind :: InvalidData ,
435- format ! ( "Failed to parse JSON config: {e}" ) ,
435+ format_json_error ( & e , & stripped ) ,
436436 )
437437 } )
438438 }
439439 }
440440}
441441
442+ /// Format a TOML parse error with user-friendly context.
443+ fn format_toml_error ( e : & toml:: de:: Error , content : & str ) -> String {
444+ let lines: Vec < & str > = content. lines ( ) . collect ( ) ;
445+ let mut msg = String :: from ( "Configuration error in TOML file:\n " ) ;
446+
447+ // Try to extract line/column information
448+ let err_str = e. to_string ( ) ;
449+ if let Some ( span) = e. span ( ) {
450+ // Calculate line number from byte offset
451+ let mut line_num = 1 ;
452+ let mut col = 1 ;
453+ for ( i, c) in content. chars ( ) . enumerate ( ) {
454+ if i >= span. start {
455+ break ;
456+ }
457+ if c == '\n' {
458+ line_num += 1 ;
459+ col = 1 ;
460+ } else {
461+ col += 1 ;
462+ }
463+ }
464+
465+ msg. push_str ( & format ! ( " Error at line {}, column {}:\n " , line_num, col) ) ;
466+
467+ // Show the problematic line if available
468+ if line_num > 0 && line_num <= lines. len ( ) {
469+ let line_content = lines[ line_num - 1 ] ;
470+ msg. push_str ( & format ! ( " {}: {}\n " , line_num, line_content) ) ;
471+ // Show pointer to the column
472+ if col > 0 {
473+ msg. push_str ( & format ! (
474+ " {} {}\n " ,
475+ " " . repeat( line_num. to_string( ) . len( ) ) ,
476+ " " . repeat( col - 1 ) + "^"
477+ ) ) ;
478+ }
479+ }
480+ }
481+
482+ msg. push_str ( & format ! ( " Problem: {}\n " , err_str) ) ;
483+ msg. push_str ( " Hint: Check for missing quotes, unclosed brackets, or invalid syntax." ) ;
484+ msg
485+ }
486+
487+ /// Format a JSON parse error with user-friendly context.
488+ fn format_json_error ( e : & serde_json:: Error , content : & str ) -> String {
489+ let lines: Vec < & str > = content. lines ( ) . collect ( ) ;
490+ let mut msg = String :: from ( "Configuration error in JSON file:\n " ) ;
491+
492+ let line_num = e. line ( ) ;
493+ let col = e. column ( ) ;
494+
495+ msg. push_str ( & format ! ( " Error at line {}, column {}:\n " , line_num, col) ) ;
496+
497+ // Show the problematic line if available
498+ if line_num > 0 && line_num <= lines. len ( ) {
499+ let line_content = lines[ line_num - 1 ] ;
500+ msg. push_str ( & format ! ( " {}: {}\n " , line_num, line_content) ) ;
501+ // Show pointer to the column
502+ if col > 0 {
503+ msg. push_str ( & format ! (
504+ " {} {}\n " ,
505+ " " . repeat( line_num. to_string( ) . len( ) ) ,
506+ " " . repeat( col. saturating_sub( 1 ) ) + "^"
507+ ) ) ;
508+ }
509+ }
510+
511+ msg. push_str ( & format ! ( " Problem: {}\n " , e) ) ;
512+ msg. push_str ( " Hint: Check for missing commas, unclosed braces, or trailing commas." ) ;
513+ msg
514+ }
515+
442516#[ cfg( test) ]
443517mod tests {
444518 use super :: * ;
0 commit comments