{-# LANGUAGE PatternGuards #-}{-
Copyright (C) 2008 Andrea Rossato <andrea.rossato@ing.unitn.it>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}{- |
Module : Text.Pandoc.Biblio
Copyright : Copyright (C) 2008-2010 Andrea Rossato
License : GNU GPL, version 2 or above
Maintainer : Andrea Rossato <andrea.rossato@unitn.it>
Stability : alpha
Portability : portable
-}moduleText.Pandoc.Biblio(processBiblio)whereimportData.ListimportData.UniqueimportData.Char(isDigit)importqualifiedData.MapasMimportText.CSLhiding(Cite(..),Citation(..))importqualifiedText.CSLasCSL(Cite(..))importText.Pandoc.DefinitionimportText.Pandoc.GenericimportText.Pandoc.Shared(stringify)importText.ParserCombinators.ParsecimportControl.Monad-- | Process a 'Pandoc' document by adding citations formatted-- according to a CSL style, using 'citeproc' from citeproc-hs.processBiblio::FilePath->MaybeFilePath->[Reference]->Pandoc->IOPandocprocessBibliocslfileabrfilerp=ifnullrthenreturnpelsedocsl<-readCSLFilecslfileabbrevs<-caseabrfileofJustf->readJsonAbbrevFilefNothing->return[]p'<-bottomUpMsetHashpletgrps=queryWithgetCitationp'style=csl{styleAbbrevs=abbrevs}result=citeprocprocOptsstyler(setNearNotestyle$map(maptoCslCite)grps)cits_map=M.fromList$zipgrps(citationsresult)biblioList=map(renderPandoc'style)(bibliographyresult)Pandocmb=bottomUp(processCitestylecits_map)p'b'=bottomUpmvPunct$deNotebreturn$Pandocm$b'++biblioList-- | Substitute 'Cite' elements with formatted citations.processCite::Style->M.Map[Citation][FormattedOutput]->Inline->InlineprocessCitescs(Citet_)=caseM.lookuptcsofJust(x:xs)|isTextualCitationt&&not(nullxs)->letxs'=renderPandocsxsinifstyleClasss=="note"thenCitet(renderPandocs[x]++[Note[Paraxs']])elseCitet(renderPandocs[x]++[Space|not(startWithPunctxs')]++xs')|otherwise->ifstyleClasss=="note"thenCitet[Note[Para$renderPandocs(x:xs)]]elseCitet(renderPandocs(x:xs))_->Strong[Str"???"]-- TODO raise error instead?processCite__x=xisNote::Inline->BoolisNote(Note_)=TrueisNote(Cite_[Note_])=TrueisNote_=FalsemvPunct::[Inline]->[Inline]mvPunct(Space:Space:xs)=Space:xsmvPunct(Space:x:ys)|isNotex,startWithPunctys=Str(headInlineys):x:tailFirstInlineStrysmvPunct(Space:x:ys)|isNotex=x:ysmvPunctxs=xssanitize::[Inline]->[Inline]sanitizexs|endWithPunctxs=toCapitalxs|otherwise=toCapital(xs++[Str"."])deNote::[Block]->[Block]deNote=topDowngowherego(Note[Paraxs])=Note$bottomUpgo'[Para$sanitizexs]go(Notexs)=Note$bottomUpgo'xsgox=xgo'(Note[Paraxs]:ys)=ifstartWithPunctys&&endWithPunctxstheninitInlinexs++yselsexs++ysgo'xs=xsisTextualCitation::[Citation]->BoolisTextualCitation(c:_)=citationModec==AuthorInTextisTextualCitation_=False-- | Retrieve all citations from a 'Pandoc' docuument. To be used with-- 'queryWith'.getCitation::Inline->[[Citation]]getCitationi|Citet_<-i=[t]|otherwise=[]setHash::Citation->IOCitationsetHash(Citationipscmnn_)=hashUnique`fmap`newUnique>>=return.CitationipscmnntoCslCite::Citation->CSL.CitetoCslCitec=let(l,s)=locatorWords$citationSuffixc(la,lo)=parseLocatorlcitMode=casecitationModecofAuthorInText->(True,False)SuppressAuthor->(False,True)NormalCitation->(False,False)inemptyCite{CSL.citeId=citationIdc,CSL.citePrefix=PandocText$citationPrefixc,CSL.citeSuffix=PandocText$s,CSL.citeLabel=la,CSL.citeLocator=lo,CSL.citeNoteNumber=show$citationNoteNumc,CSL.authorInText=fstcitMode,CSL.suppressAuthor=sndcitMode,CSL.citeHash=citationHashc}locatorWords::[Inline]->(String,[Inline])locatorWordsinp=caseparsepLocatorWords"suffix"$breakupinpofRightr->rLeft_->("",inp)wherebreakup[]=[]breakup(Strx:xs)=mapStr(splitupx)++breakupxsbreakup(x:xs)=x:breakupxssplitup=groupBy(\xy->x/='\160'&&y/='\160')pLocatorWords::GenParserInlinest(String,[Inline])pLocatorWords=dol<-pLocators<-getInput-- rest is suffixiflengthl>0&&lastl==','thenreturn(initl,Str",":s)elsereturn(l,s)pMatch::(Inline->Bool)->GenParserInlinestInlinepMatchcondition=try$dot<-anyTokenguard$conditiontreturntpSpace::GenParserInlinestInlinepSpace=pMatch(\t->t==Space||t==Str"\160")pLocator::GenParserInlinestStringpLocator=try$dooptional$pMatch(==Str",")optionalpSpacef<-many1(notFollowedBypSpace>>anyToken)gs<-many1pWordWithDigitsreturn$stringifyf++(' ':unwordsgs)pWordWithDigits::GenParserInlinestStringpWordWithDigits=try$dopSpacer<-many1(notFollowedBypSpace>>anyToken)lets=stringifyrguard$anyisDigitsreturns