From 0948af9cc549f0ea3b85fa760aa521b8deaad2c0 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 29 Jun 2021 11:15:40 -0700 Subject: [PATCH] Docx writer: Add table numbering for captioned tables. The numbers are added using fields, so that Word can create a list of tables that will update automatically. --- src/Text/Pandoc/Writers/Docx/Table.hs | 31 +++++++++++++++++++++++--- src/Text/Pandoc/Writers/Docx/Types.hs | 2 ++ test/Tests/Writers/OOXML.hs | 4 +++- test/docx/golden/image.docx | Bin 26774 -> 26776 bytes 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/Text/Pandoc/Writers/Docx/Table.hs b/src/Text/Pandoc/Writers/Docx/Table.hs index 49917e315..7a84c5278 100644 --- a/src/Text/Pandoc/Writers/Docx/Table.hs +++ b/src/Text/Pandoc/Writers/Docx/Table.hs @@ -17,7 +17,7 @@ import Control.Monad.State.Strict import Data.Array import Data.Text (Text) import Text.Pandoc.Definition -import Text.Pandoc.Class.PandocMonad (PandocMonad) +import Text.Pandoc.Class.PandocMonad (PandocMonad, translateTerm) import Text.Pandoc.Writers.Docx.Types import Text.Pandoc.Shared import Text.Printf (printf) @@ -25,6 +25,7 @@ import Text.Pandoc.Writers.GridTable hiding (Table) import Text.Pandoc.Writers.OOXML import Text.Pandoc.XML.Light as XML hiding (Attr) import qualified Data.Text as T +import qualified Text.Pandoc.Translations as Term import qualified Text.Pandoc.Writers.GridTable as Grid tableToOpenXML :: PandocMonad m @@ -33,15 +34,23 @@ tableToOpenXML :: PandocMonad m -> WS m [Content] tableToOpenXML blocksToOpenXML gridTable = do setFirstPara - let (Grid.Table _attr caption colspecs _rowheads thead tbodies tfoot) = + let (Grid.Table (ident,_,_) caption colspecs _rowheads thead tbodies tfoot) = gridTable let (Caption _maybeShortCaption captionBlocks) = caption + tablenum <- gets stNextTableNum + unless (null captionBlocks) $ + modify $ \st -> st{ stNextTableNum = tablenum + 1 } + let tableid = if T.null ident + then "table" <> tshow tablenum + else ident + tablename <- translateTerm Term.Table let captionStr = stringify captionBlocks let aligns = map fst $ elems colspecs captionXml <- if null captionBlocks then return [] else withParaPropM (pStyleM "Table Caption") - $ blocksToOpenXML captionBlocks + $ blocksToOpenXML + $ addLabel tableid tablename tablenum captionBlocks -- We set "in table" after processing the caption, because we don't -- want the "Table Caption" style to be overwritten with "Compact". modify $ \s -> s { stInTable = True } @@ -81,6 +90,22 @@ tableToOpenXML blocksToOpenXML gridTable = do modify $ \s -> s { stInTable = False } return $ captionXml ++ [Elem tbl] +addLabel :: Text -> Text -> Int -> [Block] -> [Block] +addLabel tableid tablename tablenum bs = + case bs of + (Para ils : rest) -> Para (label : Space : ils) : rest + (Plain ils : rest) -> Plain (label : Space : ils) : rest + _ -> Para [label] : bs + where + label = Span (tableid,[],[]) + [Str (tablename <> "\160"), + RawInline (Format "openxml") + (" " \\* ARABIC \">" + <> tshow tablenum + <> ""), + Str ":"] + -- | Parts of a table data RowType = HeadRow | BodyRow | FootRow diff --git a/src/Text/Pandoc/Writers/Docx/Types.hs b/src/Text/Pandoc/Writers/Docx/Types.hs index 36ac45ad2..74b8d2753 100644 --- a/src/Text/Pandoc/Writers/Docx/Types.hs +++ b/src/Text/Pandoc/Writers/Docx/Types.hs @@ -118,6 +118,7 @@ data WriterState = WriterState{ , stDynamicTextProps :: Set.Set CharStyleName , stCurId :: Int , stNextFigureNum :: Int + , stNextTableNum :: Int } defaultWriterState :: WriterState @@ -139,6 +140,7 @@ defaultWriterState = WriterState{ , stDynamicTextProps = Set.empty , stCurId = 20 , stNextFigureNum = 1 + , stNextTableNum = 1 } setFirstPara :: PandocMonad m => WS m () diff --git a/test/Tests/Writers/OOXML.hs b/test/Tests/Writers/OOXML.hs index c1e47622d..83f05cfec 100644 --- a/test/Tests/Writers/OOXML.hs +++ b/test/Tests/Writers/OOXML.hs @@ -55,7 +55,9 @@ testArchive :: (WriterOptions -> Pandoc -> PandocIO BL.ByteString) -> IO Archive testArchive writerFn opts fp = do txt <- T.readFile fp - bs <- runIOorExplode $ readNative def txt >>= writerFn opts + bs <- runIOorExplode $ do + setTranslations "en-US" + readNative def txt >>= writerFn opts return $ toArchive bs compareFileList :: FilePath -> Archive -> Archive -> Maybe String diff --git a/test/docx/golden/image.docx b/test/docx/golden/image.docx index 9fe65326f6feba24d58407a3d0a6e2977daaeb31..7c2d8a9ac8163caa78e641f9f5406b6bfbac3f4f 100644 GIT binary patch delta 1635 zcmZ9MdpOg39LKlO%>6Q#DVMRW&0Rt|g<=si)s&}`Tf(;7>YQ37YQ&Mk!tY3^gqnNE zEpuFA8q+F^D3)q9P1LaPBC4MD5R7TUFzWuzTbn@(&Ca$mXDy$Akunl@-q5fCa7>V z^;6E9rx@ex)tW3z2lVq$v0J;v+T}cYQIdAU-uq!`T5cvbkzU zg6b9XLl56%1$qGP=nfO+R-e?F@NbB;MPU$!{LEf>@UH5TWqw~(c=TCGA-0rd=Fe)4 zD6ensRv1?xl|FFZKCe?QxHs8(m~=Cv7O&M$JjBh9(kNtI+tRXKhohEY zq!A@-D?0|cx_o8?9c&W9C-FV%u%|-snA|SNEqE6?-pJFymnl0|7N+a*B-`gU%W;^H zUlD$v-Tcd;8;yQ{P>PVlTZxQ+W>Yu-@Z!6v6_W$haj4r=6V_4Z!9-h9gDYbGEvxtw4zEtfeO!R_9Y5aazc zTZ6ItWO=|1Q3%t*h$+DME=k!4l@RjygT12N^^@xaE>m4 z30GA9&S$l=s5s?-1oonPrc2~GY7z}9$vw8D0;EaEGpYgP+Ndm%{(CDZR;l9)(K=M; zt(C(ds$)=2)I2mfJnnyZ=;o~~40`-Uu)~6VQ=})e`rIek#N)3N+8hTTmwhzOC%3LN zI33CUeA=AX5tPev#ZM={yICL7v?bcdXj<2I`7GQ_=6hqV3n5Ow64s%thz8gxn${C`hd&1jg!gl zFE5ZPTN?JTDqF5Gy6j#m7vwOyhB`Tyx%y64pE+km{fe2@G`B|YNO4DN9Fq{O+6u=?a zpjripn03|eRd|R18HObO$C_{`0#vcEtw0^{)j~6)JFV4{f^c(=wMZE8p@DLb z((p;}Am^z1TF)E%nI${ofv#Al9M2+BL#wzDG z{A$;*;Lm|nKZ-$=8d1vxZk8)qf2%o`*z)yJ>Zu=UJVrT3W!X0M1B%T$7SFHNZnukf zk=JA{$Ua#iVrh4?kV59=Xb8chP)0@@W09H_*ot_>ZBb5~;~lp(a2#z2pUk*T zU%14lXgEpQ2!?gM5<#A=Rt5j2VE$9E58l$D!oe@@7OQ!(9Y#JctXh?ug`tpRtH~0b zpPO8lubr{pU<*_e*iZ?|6ApSC!`}7AuAs#*DFg2@Pr&0EEXx_hU7_nPA#~gS{?6`D z8!-MYR1eArw8P8{!J#C*O2b4!Adonz=}Ya$+5{X8GY2oQ!t|hBKt-4l2v4Qp1Wbh) zfS^d#gMI}F)b$8S3Qho>ivBU|45~KN4Je_a!Q@_PJQI*m4cF^#jKQU+NQ(_f4f&&} zbcX@3G-L3>UYZ_s6bPeXK}eMX0Vt)dm+F(kJTO69e^-I72OS3RbPSm0Mc0F|u|Nk_ O8;GZ?!EHmqr~d^iQrchu delta 1642 zcmZ9M2{6=c9LM*+wC!fM>}%y8t6ewARN7Lkm>i8WEeb8E>@IfYsHo`O8mznM?mX@j z&LN+1w#n6_?3!an)@#{aZ!^YdX?IwNN6DK9j#KiSWu-OsDxQ#tSG=H3522Bwh4e#y z=CSr+JUWfRWqRUWv`ANrT^20@MtV$>BfnSoGtO4nH-CLYjTe9C8`@YLV3n|!?=VO| ziLswkW33!4tDrc8>gk9D2&AxTNj#jvdS$vy)6wy)CdJc0oWrmMJ3$nRENa47xevuqus&5B^7y}Jd^XK zLOm+&)m3z_?lvk*-@YE>X^!qTqO9}T=lgy*T2-^rg0nMOV==_~W=i#I zf9Uws29BVt+iE7)>50>jUtL4PfOdd2%D}Ir!w>8p`dhN$nJJx4xcPaQu5m<0JX;Xj zquYo?1@a^Ep*y6P;)iFVPdu|2tnoq4JzOZ+KK#{(=|Xg9?}1pixCr&vX;X@x02 z#@+q1(=}VmR@7QpW_;Q7ecv*H!g)|*>!{ph^E zZsKWSp=Eu#R6wndwV=2cZ?mFveIvT zk7fnLH`GbJPH#OuIWcxPWMy$(D)#`Fd-m#6m6^;cGi8a{%bz~rDl6UEc$_5Qcm{*J z9H?}rVMwiFQa^S^W~B8lx!0QzUQVX$z>clQ1md5>@UrJxa2=<Le^Q?*`<$G< zOrL3C=owMCz=UtmH0E>b9ak1C`|RQvi2tbH)Zt>3^9=v7VEXIFWif%o*Z_A}Pa8Du zMva3h&zt5WP7-jNs}9t*jdZOJF1--G5_(5e^UGhwRnPDG;TluDzU8GbxT{7OW=!1| zQhjV^m{t~VYw#U^6CYCC&yQ6qs;j`C`s}0eXOq5{zDJqCGKJL8S+H7L&==QKYrf$z z8fI}RhJbsGE2kA5Ka zNO%lv)$y?1He1&`e(NWdUFq`0D(Rsw%nJA1U^9N-fC zP144wiFP}NzR2U?^|L9jwLpB-aFH3k(p5Z5o0B8sr?%J7(eX_#Krm0^rX6yfP*dEm zkdP9)qIXWr&}@S|SOj|5+kGE0L96z2z<2}ejA`Lu*6eociOX-H;>o3ZcX6HZRrl`h zXz{MisVK*XCKw8w%&y7mxw9`hW+h=JKG?V5L7 zxT$}jATg7nl0V~jr!>r7ZO`X`=-qSYsh{#zk(5!hu0_&|-L95FKjj1`{v2~@>gL$B z0q+3$@IXgEa};bTq=vP@u980>MGOrqHNn><%GV5FJm|J&g57lf_jlI2X~X^{HzM!~ z0vVcQ_)$W7qLsW52t<%*%Zv8!wFM37ph+8TEC3_|@#|}bVi`oB8Y*BYz@=J6K!v_C zw!(m85`j5r8*|NLB?2ns$t070y*v>>AP$Kt;eU4!os6MeCK=9d6eV1TMwlcRFf1Zc z0fY=dX^6_g!Z+qDA|QZREM*vCM4$@gvDP{@i(ncWW35%ex)Xs;NW)zT4zm_PCd77E KLutFgP5%Y{9^PvJ