{-# LANGUAGE OverloadedStrings #-}{-
Copyright (C) 2006-2010 Puneeth Chaganti <punchagan@gmail.com>
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.Writers.Org
Copyright : Copyright (C) 2010 Puneeth Chaganti
License : GNU GPL, version 2 or above
Maintainer : Puneeth Chaganti <punchagan@gmail.com>
Stability : alpha
Portability : portable
Conversion of 'Pandoc' documents to Emacs Org-Mode.
Org-Mode: <http://orgmode.org>
-}moduleText.Pandoc.Writers.Org(writeOrg)whereimportText.Pandoc.DefinitionimportText.Pandoc.OptionsimportText.Pandoc.SharedimportText.Pandoc.Writers.SharedimportText.Pandoc.PrettyimportText.Pandoc.Templates(renderTemplate')importData.List(intersect,intersperse,transpose)importControl.Monad.StateimportControl.Applicative((<$>))dataWriterState=WriterState{stNotes::[[Block]],stLinks::Bool,stImages::Bool,stHasMath::Bool,stOptions::WriterOptions}-- | Convert Pandoc to Org.writeOrg::WriterOptions->Pandoc->StringwriteOrgoptsdocument=letst=WriterState{stNotes=[],stLinks=False,stImages=False,stHasMath=False,stOptions=opts}inevalState(pandocToOrgdocument)st-- | Return Org representation of document.pandocToOrg::Pandoc->StateWriterStateStringpandocToOrg(Pandocmetablocks)=doopts<-liftMstOptionsgetletcolwidth=ifwriterWrapTextoptsthenJust$writerColumnsoptselseNothingmetadata<-metaToJSONopts(fmap(rendercolwidth).blockListToOrg)(fmap(rendercolwidth).inlineListToOrg)metabody<-blockListToOrgblocksnotes<-liftM(reverse.stNotes)get>>=notesToOrg-- note that the notes may contain refs, so we do them firsthasMath<-liftMstHasMathgetletmain=rendercolwidth$foldl($+$)empty$[body,notes]letcontext=defField"body"main$defField"math"hasMath$metadataifwriterStandaloneoptsthenreturn$renderTemplate'(writerTemplateopts)contextelsereturnmain-- | Return Org representation of notes.notesToOrg::[[Block]]->StateWriterStateDocnotesToOrgnotes=mapM(\(num,note)->noteToOrgnumnote)(zip[1..]notes)>>=return.vsep-- | Return Org representation of a note.noteToOrg::Int->[Block]->StateWriterStateDocnoteToOrgnumnote=docontents<-blockListToOrgnoteletmarker="["++shownum++"] "return$hang(lengthmarker)(textmarker)contents-- | Escape special characters for Org.escapeString::String->StringescapeString=escapeStringUsing$[('\x2014',"---"),('\x2013',"--"),('\x2019',"'"),('\x2026',"...")]++backslashEscapes"^_"-- | Convert Pandoc block element to Org.blockToOrg::Block-- ^ Block element->StateWriterStateDocblockToOrgNull=returnemptyblockToOrg(Divattrsbs)=docontents<-blockListToOrgbsletstartTag=tagWithAttrs"div"attrsletendTag=text"</div>"return$blankline$$"#+BEGIN_HTML"$$nest2startTag$$"#+END_HTML"$$blankline$$contents$$blankline$$"#+BEGIN_HTML"$$nest2endTag$$"#+END_HTML"$$blanklineblockToOrg(Plaininlines)=inlineListToOrginlines-- title beginning with fig: indicates that the image is a figureblockToOrg(Para[Imagetxt(src,'f':'i':'g':':':tit)])=docapt<-ifnulltxtthenreturnemptyelse(\c->"#+CAPTION: "<>c<>blankline)`fmap`inlineListToOrgtxtimg<-inlineToOrg(Imagetxt(src,tit))return$capt<>imgblockToOrg(Parainlines)=docontents<-inlineListToOrginlinesreturn$contents<>blanklineblockToOrg(RawBlock"html"str)=return$blankline$$"#+BEGIN_HTML"$$nest2(textstr)$$"#+END_HTML"$$blanklineblockToOrg(RawBlockfstr)|f=="org"||f=="latex"||f=="tex"=return$textstrblockToOrg(RawBlock__)=returnemptyblockToOrgHorizontalRule=return$blankline$$"--------------"$$blanklineblockToOrg(Headerlevel_inlines)=docontents<-inlineListToOrginlinesletheaderStr=text$iflevel>999then" "elsereplicatelevel'*'return$headerStr<>" "<>contents<>blanklineblockToOrg(CodeBlock(_,classes,_)str)=doopts<-stOptions<$>getlettabstop=writerTabStopoptsletat=classes`intersect`["asymptote","C","clojure","css","ditaa","dot","emacs-lisp","gnuplot","haskell","js","latex","ledger","lisp","matlab","mscgen","ocaml","octave","oz","perl","plantuml","python","R","ruby","sass","scheme","screen","sh","sql","sqlite"]let(beg,end)=caseatof[]->("#+BEGIN_EXAMPLE","#+END_EXAMPLE")(x:_)->("#+BEGIN_SRC "++x,"#+END_SRC")return$textbeg$$nesttabstop(textstr)$$textend$$blanklineblockToOrg(BlockQuoteblocks)=docontents<-blockListToOrgblocksreturn$blankline$$"#+BEGIN_QUOTE"$$nest2contents$$"#+END_QUOTE"$$blanklineblockToOrg(Tablecaption'__headersrows)=docaption''<-inlineListToOrgcaption'letcaption=ifnullcaption'thenemptyelse("#+CAPTION: "<>caption'')headers'<-mapMblockListToOrgheadersrawRows<-mapM(mapMblockListToOrg)rowsletnumChars=maximum.mapoffset-- FIXME: width is not being used.letwidthsInChars=map((+2).numChars)$transpose(headers':rawRows)-- FIXME: Org doesn't allow blocks with height more than 1.lethpipeBlocksblocks=hcat[beg,middle,end]whereh=maximum(mapheightblocks)sep'=lblock3$vcat(maptext$replicateh" | ")beg=lblock2$vcat(maptext$replicateh"| ")end=lblock2$vcat(maptext$replicateh" |")middle=hcat$interspersesep'blocksletmakeRow=hpipeBlocks.zipWithlblockwidthsInCharslethead'=makeRowheaders'rows'<-mapM(\row->docols<-mapMblockListToOrgrowreturn$makeRowcols)rowsletborderch=char'|'<>charch<>(hcat$intersperse(charch<>char'+'<>charch)$map(\l->text$replicatelch)widthsInChars)<>charch<>char'|'letbody=vcatrows'lethead''=ifallnullheadersthenemptyelsehead'$$border'-'return$head''$$body$$caption$$blanklineblockToOrg(BulletListitems)=docontents<-mapMbulletListItemToOrgitems-- ensure that sublists have preceding blank linereturn$blankline$+$vcatcontents$$blanklineblockToOrg(OrderedList(start,_,delim)items)=doletdelim'=casedelimofTwoParens->OneParenx->xletmarkers=take(lengthitems)$orderedListMarkers(start,Decimal,delim')letmaxMarkerLength=maximum$maplengthmarkersletmarkers'=map(\m->lets=maxMarkerLength-lengthminm++replicates' ')markerscontents<-mapM(\(item,num)->orderedListItemToOrgitemnum)$zipmarkers'items-- ensure that sublists have preceding blank linereturn$blankline$$vcatcontents$$blanklineblockToOrg(DefinitionListitems)=docontents<-mapMdefinitionListItemToOrgitemsreturn$vcatcontents$$blankline-- | Convert bullet list item (list of blocks) to Org.bulletListItemToOrg::[Block]->StateWriterStateDocbulletListItemToOrgitems=docontents<-blockListToOrgitemsreturn$hang3"- "(contents<>cr)-- | Convert ordered list item (a list of blocks) to Org.orderedListItemToOrg::String-- ^ marker for list item->[Block]-- ^ list item (list of blocks)->StateWriterStateDocorderedListItemToOrgmarkeritems=docontents<-blockListToOrgitemsreturn$hang(lengthmarker+1)(textmarker<>space)(contents<>cr)-- | Convert defintion list item (label, list of blocks) to Org.definitionListItemToOrg::([Inline],[[Block]])->StateWriterStateDocdefinitionListItemToOrg(label,defs)=dolabel'<-inlineListToOrglabelcontents<-liftMvcat$mapMblockListToOrgdefsreturn$hang3"- "$label'<>" :: "<>(contents<>cr)-- | Convert list of Pandoc block elements to Org.blockListToOrg::[Block]-- ^ List of block elements->StateWriterStateDocblockListToOrgblocks=mapMblockToOrgblocks>>=return.vcat-- | Convert list of Pandoc inline elements to Org.inlineListToOrg::[Inline]->StateWriterStateDocinlineListToOrglst=mapMinlineToOrglst>>=return.hcat-- | Convert Pandoc inline element to Org.inlineToOrg::Inline->StateWriterStateDocinlineToOrg(Span_lst)=inlineListToOrglstinlineToOrg(Emphlst)=docontents<-inlineListToOrglstreturn$"/"<>contents<>"/"inlineToOrg(Stronglst)=docontents<-inlineListToOrglstreturn$"*"<>contents<>"*"inlineToOrg(Strikeoutlst)=docontents<-inlineListToOrglstreturn$"+"<>contents<>"+"inlineToOrg(Superscriptlst)=docontents<-inlineListToOrglstreturn$"^{"<>contents<>"}"inlineToOrg(Subscriptlst)=docontents<-inlineListToOrglstreturn$"_{"<>contents<>"}"inlineToOrg(SmallCapslst)=inlineListToOrglstinlineToOrg(QuotedSingleQuotelst)=docontents<-inlineListToOrglstreturn$"'"<>contents<>"'"inlineToOrg(QuotedDoubleQuotelst)=docontents<-inlineListToOrglstreturn$"\""<>contents<>"\""inlineToOrg(Cite_lst)=inlineListToOrglstinlineToOrg(Code_str)=return$"="<>textstr<>"="inlineToOrg(Strstr)=return$text$escapeStringstrinlineToOrg(Mathtstr)=domodify$\st->st{stHasMath=True}return$ift==InlineMaththen"$"<>textstr<>"$"else"$$"<>textstr<>"$$"inlineToOrg(RawInlinefstr)|f=="tex"||f=="latex"=return$textstrinlineToOrg(RawInline__)=returnemptyinlineToOrg(LineBreak)=returncr-- there's no line break in OrginlineToOrgSpace=returnspaceinlineToOrg(Linktxt(src,_))=docasetxtof[Strx]|escapeURIx==src->-- autolinkdomodify$\s->s{stLinks=True}return$"[["<>textx<>"]]"_->docontents<-inlineListToOrgtxtmodify$\s->s{stLinks=True}return$"[["<>textsrc<>"]["<>contents<>"]]"inlineToOrg(Image_(source,_))=domodify$\s->s{stImages=True}return$"[["<>textsource<>"]]"inlineToOrg(Notecontents)=do-- add to notes in statenotes<-get>>=(return.stNotes)modify$\st->st{stNotes=contents:notes}letref=show$(lengthnotes)+1return$" ["<>textref<>"]"