moduleData.Configger(Config,load,from,merge,mergeSection,items,set,get,values)whereimportControl.DangerousimportControl.Monad.TransimportData.MaybeimportData.String.UtilsimportText.ParserCombinators.ParsectypeConfig=[(String,[(String,String)])]-- Merge two configurationsmerge::Config->Config->Configmergeab=foldrmergeSectionba-- Merge a section into a configurationmergeSection::(String,[(String,String)])->Config->ConfigmergeSection(a,as)((b,bs):rest)|a==b=(a,as++bs):restmergeSectiona(b:bs)=b:mergeSectionabsmergeSectiona[]=[a]-- Add a settingset::String->String->String->Config->Configsetskvconf=mergeSection(s,[(k,v)])conf-- Get the first value of a settingget::String->String->Config->MaybeStringgetskconf=lookupsconf>>=lookupk-- Get all values of a settingvalues::String->String->Config->[String]valuesskconf=letvars=fromMaybe[](lookupsconf)ours=filter((k==).fst)varsinmapsndours-- Get the items in a section of a configurationitems::String->Config->[(String,String)]itemsnameconf=fromMaybe[](lookupnameconf)-- Load a configuration from a fileload::(Errorablem,MonadIOm)=>FilePath->String->mConfigloaddefaultsfilename=dotext<-liftIO$readFilefilenamedangerize$parse(filedefaults)filenametext-- Load a configuration from a string-- (Won't be able to throw as nice error messages)from::(Errorablem)=>String->String->mConfigfromstrdefaults=dangerize$parse(filedefaults)"(unknown)"str-- | Parsersfile::String->GenParserCharstConfigfiledefaults=dofree<-sepEndBysetting(many1eol)named<-sepEndBysection(many1eol)return$mergeSection(defaults,free)namedsection::GenParserCharst(String,[(String,String)])section=dow>>char'['>>wname<-wordw>>char']'>>many1eol>>return()vars<-sepEndBysettingeolreturn(name,vars)setting::GenParserCharst(String,String)setting=dovar<-w>>wordw>>oneOf":=">>wval<-w>>wordreturn(var,val)word::GenParserCharstStringword=dostr<-many1(noneOf":=[]\n")return$stripstrw::GenParserCharst()w=many(oneOf" \t")>>return()eol::GenParserCharst()eol=w>>char'\n'>>return()