@@ -341,15 +341,30 @@ impl KdlDocument {
341
341
///
342
342
/// If the `v1-fallback` feature is enabled, this method will first try to
343
343
/// parse the string as a KDL v2 document, and, if that fails, it will try
344
- /// to parse again as a KDL v1 document. If both fail, only the v2 parse
345
- /// errors will be returned.
344
+ /// to parse again as a KDL v1 document. If both fail, a heuristic will be
345
+ /// applied to try and detect the "intended" KDL version, and that version's
346
+ /// error(s) will be returned.
346
347
pub fn parse ( s : & str ) -> Result < Self , KdlError > {
347
348
#[ cfg( not( feature = "v1-fallback" ) ) ]
348
349
{
349
350
KdlDocument :: parse_v2 ( s)
350
351
}
351
352
#[ cfg( feature = "v1-fallback" ) ]
352
353
{
354
+ let v2_res = KdlDocument :: parse_v2 ( s) ;
355
+ if let Err ( err) = v2_res {
356
+ let v1_res = KdlDocument :: parse_v2 ( s) ;
357
+ if v1_res. is_err ( ) && detect_v2 ( s) {
358
+ v2_res
359
+ } else if detect_v1 ( s) {
360
+ v1_res
361
+ } else {
362
+ // This does matter, because detection short-circuits.
363
+ v2_res
364
+ }
365
+ } else {
366
+ v2_res
367
+ }
353
368
KdlDocument :: parse_v2 ( s) . or_else ( |e| KdlDocument :: parse_v1 ( s) . map_err ( |_| e) )
354
369
}
355
370
}
@@ -455,6 +470,55 @@ impl From<kdlv1::KdlDocument> for KdlDocument {
455
470
}
456
471
}
457
472
473
+ /// Applies heuristics to get an idea of whether the string might be intended to
474
+ /// be v2.
475
+ #[ allow( unused) ]
476
+ pub ( crate ) fn detect_v2 ( input : & str ) -> bool {
477
+ for line in input. lines ( ) {
478
+ if line. contains ( "kdl-version 2" )
479
+ || line. contains ( "#true" )
480
+ || line. contains ( "#false" )
481
+ || line. contains ( "#null" )
482
+ || line. contains ( "#inf" )
483
+ || line. contains ( "#-inf" )
484
+ || line. contains ( "#nan" )
485
+ || line. contains ( " #\" " )
486
+ || line. contains ( "\" \" \" " )
487
+ // Very very rough attempt at finding unquoted strings. We give up
488
+ // the first time we see a quoted one on a line.
489
+ || ( !line. contains ( '"' ) && line
490
+ . split_whitespace ( )
491
+ . skip ( 1 )
492
+ . any ( |x| {
493
+ x. chars ( )
494
+ . next ( )
495
+ . map ( |d| !d. is_ascii_digit ( ) && d != '-' && d != '+' )
496
+ . unwrap_or_default ( )
497
+ } ) )
498
+ {
499
+ return true ;
500
+ }
501
+ }
502
+ false
503
+ }
504
+
505
+ /// Applies heuristics to get an idea of whether the string might be intended to
506
+ /// be v2.
507
+ #[ allow( unused) ]
508
+ pub ( crate ) fn detect_v1 ( input : & str ) -> bool {
509
+ input
510
+ . lines ( )
511
+ . next ( )
512
+ . map ( |l| l. contains ( "kdl-version 1" ) )
513
+ . unwrap_or ( false )
514
+ || input. contains ( " true" )
515
+ || input. contains ( " false" )
516
+ || input. contains ( " null" )
517
+ || input. contains ( "r#\" " )
518
+ || input. contains ( " \" \n " )
519
+ || input. contains ( " \" \r \n " )
520
+ }
521
+
458
522
impl std:: str:: FromStr for KdlDocument {
459
523
type Err = KdlError ;
460
524
@@ -1109,91 +1173,8 @@ mirror_session #true
1109
1173
"## ;
1110
1174
pretty_assertions:: assert_eq!( KdlDocument :: v1_to_v2( v1) ?, v2, "Converting a v1 doc to v2" ) ;
1111
1175
pretty_assertions:: assert_eq!( KdlDocument :: v2_to_v1( v2) ?, v1, "Converting a v2 doc to v1" ) ;
1112
- Ok ( ( ) )
1113
- }
1114
-
1115
- #[ cfg( feature = "v1" ) ]
1116
- #[ test]
1117
- fn v2_to_v1 ( ) -> miette:: Result < ( ) > {
1118
- let original = r##"
1119
- // If you'd like to override the default keybindings completely, be sure to change "keybinds" to "keybinds clear-defaults=true"
1120
- keybinds {
1121
- normal {
1122
- // uncomment this and adjust key if using copy_on_select=false
1123
- // bind "Alt c" { Copy; }
1124
- }
1125
- locked {
1126
- bind "Ctrl g" { SwitchToMode "Normal"; }
1127
- }
1128
- resize {
1129
- bind "Ctrl n" { SwitchToMode "Normal"; }
1130
- bind "h" "Left" { Resize "Increase Left"; }
1131
- bind "j" "Down" { Resize "Increase Down"; }
1132
- bind "k" "Up" { Resize "Increase Up"; }
1133
- bind "l" "Right" { Resize "Increase Right"; }
1134
- bind "H" { Resize "Decrease Left"; }
1135
- bind "J" { Resize "Decrease Down"; }
1136
- bind "K" { Resize "Decrease Up"; }
1137
- bind "L" { Resize "Decrease Right"; }
1138
- bind "=" "+" { Resize "Increase"; }
1139
- bind "-" { Resize "Decrease"; }
1140
- }
1141
- }
1142
- // Plugin aliases - can be used to change the implementation of Zellij
1143
- // changing these requires a restart to take effect
1144
- plugins {
1145
- tab-bar location="zellij:tab-bar"
1146
- status-bar location="zellij:status-bar"
1147
- welcome-screen location="zellij:session-manager" {
1148
- welcome_screen true
1149
- }
1150
- filepicker location="zellij:strider" {
1151
- cwd "/"
1152
- }
1153
- }
1154
- mouse_mode false
1155
- mirror_session true
1156
- "## ;
1157
- let expected = r##"
1158
- // If you'd like to override the default keybindings completely, be sure to change "keybinds" to "keybinds clear-defaults=true"
1159
- keybinds {
1160
- normal {
1161
- // uncomment this and adjust key if using copy_on_select=false
1162
- // bind "Alt c" { Copy; }
1163
- }
1164
- locked {
1165
- bind "Ctrl g" { SwitchToMode Normal; }
1166
- }
1167
- resize {
1168
- bind "Ctrl n" { SwitchToMode Normal; }
1169
- bind h Left { Resize "Increase Left"; }
1170
- bind j Down { Resize "Increase Down"; }
1171
- bind k Up { Resize "Increase Up"; }
1172
- bind l Right { Resize "Increase Right"; }
1173
- bind H { Resize "Decrease Left"; }
1174
- bind J { Resize "Decrease Down"; }
1175
- bind K { Resize "Decrease Up"; }
1176
- bind L { Resize "Decrease Right"; }
1177
- bind "=" + { Resize Increase; }
1178
- bind - { Resize Decrease; }
1179
- }
1180
- }
1181
- // Plugin aliases - can be used to change the implementation of Zellij
1182
- // changing these requires a restart to take effect
1183
- plugins {
1184
- tab-bar location=zellij:tab-bar
1185
- status-bar location=zellij:status-bar
1186
- welcome-screen location=zellij:session-manager {
1187
- welcome_screen #true
1188
- }
1189
- filepicker location=zellij:strider {
1190
- cwd "/"
1191
- }
1192
- }
1193
- mouse_mode #false
1194
- mirror_session #true
1195
- "## ;
1196
- pretty_assertions:: assert_eq!( KdlDocument :: v1_to_v2( original) ?, expected) ;
1176
+ assert ! ( super :: detect_v1( v1) ) ;
1177
+ assert ! ( super :: detect_v2( v2) ) ;
1197
1178
Ok ( ( ) )
1198
1179
}
1199
1180
}
0 commit comments