@@ -9,7 +9,7 @@ use std::{
99 str:: FromStr ,
1010} ;
1111
12- use anyhow:: { bail, Context as ResultExt , Result } ;
12+ use anyhow:: { anyhow , bail, Context as ResultExt , Error , Result } ;
1313use indexmap:: IndexMap ;
1414use lazy_static:: lazy_static;
1515use regex:: Regex ;
@@ -125,6 +125,9 @@ pub struct RawPlugin {
125125 /// What templates to apply to each matched file. If this is `None` then the
126126 /// default templates will be applied.
127127 pub apply : Option < Vec < String > > ,
128+ /// Any extra keys,
129+ #[ serde( flatten, deserialize_with = "deserialize_rest_toml_value" ) ]
130+ pub rest : Option < toml:: Value > ,
128131}
129132
130133/// An external configured plugin.
@@ -171,6 +174,9 @@ pub struct RawConfig {
171174 templates : IndexMap < String , Template > ,
172175 /// A map of name to plugin.
173176 pub plugins : IndexMap < String , RawPlugin > ,
177+ /// Any extra keys,
178+ #[ serde( flatten, deserialize_with = "deserialize_rest_toml_value" ) ]
179+ pub rest : Option < toml:: Value > ,
174180}
175181
176182/// The user configuration.
@@ -459,10 +465,46 @@ impl_deserialize_from_str!(git_protocol, GitProtocol, "a Git protocol type");
459465impl_deserialize_from_str ! ( gist_repository, GistRepository , "a Gist identifier" ) ;
460466impl_deserialize_from_str ! ( github_repository, GitHubRepository , "a GitHub repository" ) ;
461467
468+ /// Deserialize the remaining keys into a `Option<toml::Value>`. Empty tables
469+ /// are coerced to `None`.
470+ fn deserialize_rest_toml_value < ' de , D > ( deserializer : D ) -> Result < Option < toml:: Value > , D :: Error >
471+ where
472+ D : de:: Deserializer < ' de > ,
473+ {
474+ let value: toml:: Value = de:: Deserialize :: deserialize ( deserializer) ?;
475+ Ok ( match value {
476+ toml:: Value :: Table ( table) => {
477+ if table. is_empty ( ) {
478+ None
479+ } else {
480+ Some ( toml:: Value :: Table ( table) )
481+ }
482+ }
483+ value => Some ( value) ,
484+ } )
485+ }
486+
462487/////////////////////////////////////////////////////////////////////////
463488// Normalization implementations
464489/////////////////////////////////////////////////////////////////////////
465490
491+ /// Check for extra TOML keys, and if they exist then call the given function on
492+ /// the key.
493+ fn check_extra_toml < F > ( rest : Option < toml:: Value > , mut f : F )
494+ where
495+ F : FnMut ( & str ) -> ( ) ,
496+ {
497+ match rest {
498+ Some ( toml:: Value :: Table ( table) ) => {
499+ for key in table. keys ( ) {
500+ f ( key)
501+ }
502+ }
503+ Some ( _) => unreachable ! ( ) , // unreachable because we are using #[serde(flatten)]
504+ None => { }
505+ }
506+ }
507+
466508/// Check whether the specifed templates actually exist.
467509fn validate_template_names (
468510 apply : & Option < Vec < String > > ,
@@ -517,7 +559,12 @@ enum TempSource {
517559impl RawPlugin {
518560 /// Normalize a `RawPlugin` into a `Plugin` which is simpler and easier
519561 /// to handle.
520- pub fn normalize ( self , name : String , templates : & IndexMap < String , Template > ) -> Result < Plugin > {
562+ pub fn normalize (
563+ self ,
564+ name : String ,
565+ templates : & IndexMap < String , Template > ,
566+ warnings : & mut Vec < Error > ,
567+ ) -> Result < Plugin > {
521568 let Self {
522569 git,
523570 gist,
@@ -530,6 +577,7 @@ impl RawPlugin {
530577 dir,
531578 uses,
532579 apply,
580+ rest,
533581 } = self ;
534582
535583 let is_reference_some = reference. is_some ( ) ;
@@ -582,6 +630,10 @@ impl RawPlugin {
582630 }
583631 } ;
584632
633+ check_extra_toml ( rest, |key| {
634+ warnings. push ( anyhow ! ( "unused config key: `plugins.{}.{}`" , name, key) )
635+ } ) ;
636+
585637 match raw_source {
586638 TempSource :: External ( source) => {
587639 if !source. is_git ( ) && is_reference_some {
@@ -639,12 +691,13 @@ impl RawConfig {
639691 }
640692
641693 /// Normalize a `RawConfig` into a `Config`.
642- fn normalize ( self ) -> Result < Config > {
694+ fn normalize ( self , mut warnings : & mut Vec < Error > ) -> Result < Config > {
643695 let Self {
644696 matches,
645697 apply,
646698 templates,
647699 plugins,
700+ rest,
648701 } = self ;
649702
650703 // Check that the templates can be compiled.
@@ -666,11 +719,15 @@ impl RawConfig {
666719 for ( name, plugin) in plugins {
667720 normalized_plugins. push (
668721 plugin
669- . normalize ( name. clone ( ) , & templates)
722+ . normalize ( name. clone ( ) , & templates, & mut warnings )
670723 . with_context ( s ! ( "failed to normalize plugin `{}`" , name) ) ?,
671724 ) ;
672725 }
673726
727+ check_extra_toml ( rest, |key| {
728+ warnings. push ( anyhow ! ( "unused config key: `{}`" , key) )
729+ } ) ;
730+
674731 Ok ( Config {
675732 matches,
676733 apply,
@@ -682,11 +739,11 @@ impl RawConfig {
682739
683740impl Config {
684741 /// Read a `Config` from the given path.
685- pub fn from_path < P > ( path : P ) -> Result < Self >
742+ pub fn from_path < P > ( path : P , mut warnings : & mut Vec < Error > ) -> Result < Self >
686743 where
687744 P : AsRef < Path > ,
688745 {
689- Ok ( RawConfig :: from_path ( path) ?. normalize ( ) ?)
746+ Ok ( RawConfig :: from_path ( path) ?. normalize ( & mut warnings ) ?)
690747 }
691748}
692749
@@ -896,7 +953,7 @@ mod tests {
896953 let text = format ! ( "{} = '{}'\n {} = '{}'" , a, example_a, b, example_b) ;
897954 let e = toml:: from_str :: < RawPlugin > ( & text)
898955 . unwrap ( )
899- . normalize ( "test" . to_string ( ) , & IndexMap :: new ( ) )
956+ . normalize ( "test" . to_string ( ) , & IndexMap :: new ( ) , & mut Vec :: new ( ) )
900957 . unwrap_err ( ) ;
901958 assert_eq ! ( e. to_string( ) , "plugin `test` has multiple source fields" )
902959 }
@@ -922,7 +979,9 @@ mod tests {
922979 ..Default :: default ( )
923980 } ;
924981 assert_eq ! (
925- raw_plugin. normalize( name, & IndexMap :: new( ) ) . unwrap( ) ,
982+ raw_plugin
983+ . normalize( name, & IndexMap :: new( ) , & mut Vec :: new( ) )
984+ . unwrap( ) ,
926985 expected
927986 ) ;
928987 }
@@ -950,7 +1009,9 @@ mod tests {
9501009 ..Default :: default ( )
9511010 } ;
9521011 assert_eq ! (
953- raw_plugin. normalize( name, & IndexMap :: new( ) ) . unwrap( ) ,
1012+ raw_plugin
1013+ . normalize( name, & IndexMap :: new( ) , & mut Vec :: new( ) )
1014+ . unwrap( ) ,
9541015 expected
9551016 ) ;
9561017 }
@@ -974,7 +1035,9 @@ mod tests {
9741035 ..Default :: default ( )
9751036 } ;
9761037 assert_eq ! (
977- raw_plugin. normalize( name, & IndexMap :: new( ) ) . unwrap( ) ,
1038+ raw_plugin
1039+ . normalize( name, & IndexMap :: new( ) , & mut Vec :: new( ) )
1040+ . unwrap( ) ,
9781041 expected
9791042 ) ;
9801043 }
@@ -1003,7 +1066,9 @@ mod tests {
10031066 ..Default :: default ( )
10041067 } ;
10051068 assert_eq ! (
1006- raw_plugin. normalize( name, & IndexMap :: new( ) ) . unwrap( ) ,
1069+ raw_plugin
1070+ . normalize( name, & IndexMap :: new( ) , & mut Vec :: new( ) )
1071+ . unwrap( ) ,
10071072 expected
10081073 ) ;
10091074 }
@@ -1030,7 +1095,9 @@ mod tests {
10301095 ..Default :: default ( )
10311096 } ;
10321097 assert_eq ! (
1033- raw_plugin. normalize( name, & IndexMap :: new( ) ) . unwrap( ) ,
1098+ raw_plugin
1099+ . normalize( name, & IndexMap :: new( ) , & mut Vec :: new( ) )
1100+ . unwrap( ) ,
10341101 expected
10351102 ) ;
10361103 }
@@ -1056,7 +1123,9 @@ mod tests {
10561123 ..Default :: default ( )
10571124 } ;
10581125 assert_eq ! (
1059- raw_plugin. normalize( name, & IndexMap :: new( ) ) . unwrap( ) ,
1126+ raw_plugin
1127+ . normalize( name, & IndexMap :: new( ) , & mut Vec :: new( ) )
1128+ . unwrap( ) ,
10601129 expected
10611130 ) ;
10621131 }
@@ -1083,7 +1152,9 @@ mod tests {
10831152 ..Default :: default ( )
10841153 } ;
10851154 assert_eq ! (
1086- raw_plugin. normalize( name, & IndexMap :: new( ) ) . unwrap( ) ,
1155+ raw_plugin
1156+ . normalize( name, & IndexMap :: new( ) , & mut Vec :: new( ) )
1157+ . unwrap( ) ,
10871158 expected
10881159 ) ;
10891160 }
@@ -1106,7 +1177,9 @@ mod tests {
11061177 ..Default :: default ( )
11071178 } ;
11081179 assert_eq ! (
1109- raw_plugin. normalize( name, & IndexMap :: new( ) ) . unwrap( ) ,
1180+ raw_plugin
1181+ . normalize( name, & IndexMap :: new( ) , & mut Vec :: new( ) )
1182+ . unwrap( ) ,
11101183 expected
11111184 ) ;
11121185 }
@@ -1124,7 +1197,7 @@ mod tests {
11241197 ..Default :: default ( )
11251198 } ;
11261199 let error = raw_plugin
1127- . normalize ( "test" . to_string ( ) , & IndexMap :: new ( ) )
1200+ . normalize ( "test" . to_string ( ) , & IndexMap :: new ( ) , & mut Vec :: new ( ) )
11281201 . unwrap_err ( ) ;
11291202 assert_eq ! (
11301203 error. to_string( ) ,
@@ -1145,7 +1218,7 @@ mod tests {
11451218 ..Default :: default ( )
11461219 } ;
11471220 let error = raw_plugin
1148- . normalize ( "test" . to_string ( ) , & IndexMap :: new ( ) )
1221+ . normalize ( "test" . to_string ( ) , & IndexMap :: new ( ) , & mut Vec :: new ( ) )
11491222 . unwrap_err ( ) ;
11501223 assert_eq ! (
11511224 error. to_string( ) ,
@@ -1170,7 +1243,9 @@ mod tests {
11701243 ..Default :: default ( )
11711244 } ;
11721245 assert_eq ! (
1173- raw_plugin. normalize( name, & IndexMap :: new( ) ) . unwrap( ) ,
1246+ raw_plugin
1247+ . normalize( name, & IndexMap :: new( ) , & mut Vec :: new( ) )
1248+ . unwrap( ) ,
11741249 expected
11751250 ) ;
11761251 }
@@ -1187,7 +1262,9 @@ mod tests {
11871262 ..Default :: default ( )
11881263 } ;
11891264 assert_eq ! (
1190- raw_plugin. normalize( name, & IndexMap :: new( ) ) . unwrap( ) ,
1265+ raw_plugin
1266+ . normalize( name, & IndexMap :: new( ) , & mut Vec :: new( ) )
1267+ . unwrap( ) ,
11911268 expected
11921269 ) ;
11931270 }
@@ -1200,7 +1277,7 @@ mod tests {
12001277 ..Default :: default ( )
12011278 } ;
12021279 let error = raw_plugin
1203- . normalize ( "test" . to_string ( ) , & IndexMap :: new ( ) )
1280+ . normalize ( "test" . to_string ( ) , & IndexMap :: new ( ) , & mut Vec :: new ( ) )
12041281 . unwrap_err ( ) ;
12051282 assert_eq ! (
12061283 error. to_string( ) ,
@@ -1219,7 +1296,7 @@ mod tests {
12191296 ..Default :: default ( )
12201297 } ;
12211298 let error = raw_plugin
1222- . normalize ( "test" . to_string ( ) , & IndexMap :: new ( ) )
1299+ . normalize ( "test" . to_string ( ) , & IndexMap :: new ( ) , & mut Vec :: new ( ) )
12231300 . unwrap_err ( ) ;
12241301 assert_eq ! ( error. to_string( ) , "unknown template `test`" ) ;
12251302 }
@@ -1228,6 +1305,6 @@ mod tests {
12281305 fn config_from_path_example ( ) {
12291306 let mut path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) ;
12301307 path. push ( "docs/plugins.example.toml" ) ;
1231- Config :: from_path ( path) . unwrap ( ) ;
1308+ Config :: from_path ( path, & mut Vec :: new ( ) ) . unwrap ( ) ;
12321309 }
12331310}
0 commit comments