|
1 | 1 | module Main where
|
2 | 2 |
|
| 3 | +import Control.Applicative |
3 | 4 | import Control.Monad.Trans.State
|
4 | 5 | import Data.Aeson (encode)
|
5 | 6 | import qualified Data.ByteString.Lazy as B
|
@@ -35,86 +36,95 @@ type Convert a = State () a
|
35 | 36 | runConvert :: Convert a -> a
|
36 | 37 | runConvert c = evalState c ()
|
37 | 38 |
|
38 |
| -convertDocument :: forall tags. tags ~ SupportedTags => GenerateTagParser tags => TagHandler tags (Convert P.Blocks) -> Document tags -> P.Pandoc |
39 |
| -convertDocument handler (Document blocks) = runConvert $ P.doc . V.foldMap id <$> traverse convertBlock blocks |
40 |
| - where |
41 |
| - convertBlock :: Block tags -> Convert P.Blocks |
42 |
| - convertBlock = \case |
43 |
| - Paragraph i -> convertParagraph i |
44 |
| - Heading heading -> convertHeading heading |
45 |
| - Quote quote -> convertQuote quote |
46 |
| - List list -> convertList list |
47 |
| - HorizonalLine -> convertHorizonalLine |
48 |
| - Marker marker -> convertMarker marker |
49 |
| - Tag tag -> convertTag tag |
50 |
| - |
51 |
| - convertParagraph :: Inline -> Convert P.Blocks |
52 |
| - convertParagraph = fmap P.para . convertInline |
53 |
| - |
54 |
| - convertMarker :: Marker -> Convert P.Blocks |
55 |
| - convertMarker = error "not implemented" |
56 |
| - |
57 |
| - convertList :: List -> Convert P.Blocks |
58 |
| - convertList = \case |
59 |
| - UnorderedList ul -> |
60 |
| - fmap (P.bulletList . V.toList) $ |
61 |
| - traverse (applicativeConcatMap convertListBlock) $ |
62 |
| - ul ^. uListItems |
63 |
| - OrderedList ol -> |
64 |
| - fmap (P.bulletList . V.toList) $ |
65 |
| - traverse (applicativeConcatMap convertListBlock) $ |
66 |
| - ol ^. oListItems |
67 |
| - TaskList tl -> |
68 |
| - let convertTaskListBlock taskStatus lb = convertListBlock lb |
69 |
| - in fmap (P.bulletList . V.toList) $ |
70 |
| - traverse (\(taskStatus, items) -> applicativeConcatMap (convertTaskListBlock taskStatus) items) $ |
71 |
| - tl ^. tListItems |
72 |
| - convertQuote :: Quote -> Convert P.Blocks |
73 |
| - convertQuote quote = P.blockQuote . P.para <$> convertInline (quote ^. quoteContent) |
74 |
| - |
75 |
| - convertListBlock :: ListBlock -> Convert P.Blocks |
76 |
| - convertListBlock = \case |
77 |
| - ListParagraph i -> P.para <$> convertInline i |
78 |
| - SubList l -> convertList l |
79 |
| - |
80 |
| - convertHeading :: Heading tags -> Convert P.Blocks |
81 |
| - convertHeading heading = do |
82 |
| - text <- convertInline $ heading ^. headingText |
83 |
| - let header = P.header (succ . fromEnum $ heading ^. headingLevel) text |
84 |
| - subBlocks <- applicativeConcatMap convertBlock (heading ^. headingContent) |
85 |
| - pure $ header <> subBlocks |
86 |
| - |
87 |
| - convertHorizonalLine :: Convert P.Blocks |
88 |
| - convertHorizonalLine = pure P.horizontalRule |
89 |
| - |
90 |
| - convertInline :: Inline -> Convert P.Inlines |
91 |
| - convertInline = \case |
92 |
| - Text t -> pure $ P.text t |
93 |
| - Bold inline -> P.strong <$> convertInline inline |
94 |
| - Italic inline -> P.emph <$> convertInline inline |
95 |
| - Underline inline -> P.underline <$> convertInline inline |
96 |
| - Strikethrough inline -> P.strikeout <$> convertInline inline |
97 |
| - Superscript inline -> P.superscript <$> convertInline inline |
98 |
| - Subscript inline -> P.subscript <$> convertInline inline |
99 |
| - Spoiler inline -> P.strikeout <$> convertInline inline -- TODO: No native spoilers in pandoc |
100 |
| - ConcatInline inlines -> V.foldMap id <$> traverse convertInline inlines |
101 |
| - Link url inlines -> P.link url "" <$> convertInline inlines -- TODO: Investigate title field |
102 |
| - Space -> pure P.space |
103 |
| - Verbatim t -> pure $ P.code t |
104 |
| - Math t -> pure $ P.math t |
105 |
| - convertTag :: SomeTag tags -> Convert P.Blocks |
106 |
| - convertTag = handleSomeTag handler |
107 |
| - |
108 |
| -type SupportedTags = FromList '["code", "math", "comment", "embed", "document.meta"] |
| 39 | +convertDocument :: GenerateTagParser tags => TagHandler tags (Convert P.Blocks) -> Document tags -> P.Pandoc |
| 40 | +convertDocument handler (Document blocks) = runConvert $ P.doc . V.foldMap id <$> traverse (convertBlock handler) blocks |
| 41 | + |
| 42 | +convertBlock :: TagHandler tags (Convert P.Blocks) -> Block tags -> Convert P.Blocks |
| 43 | +convertBlock handler = \case |
| 44 | + Paragraph i -> convertParagraph i |
| 45 | + Heading heading -> convertHeading handler heading |
| 46 | + Quote quote -> convertQuote quote |
| 47 | + List list -> convertList list |
| 48 | + HorizonalLine -> convertHorizonalLine |
| 49 | + Marker marker -> convertMarker marker |
| 50 | + Tag tag -> handleSomeTag handler tag |
| 51 | + |
| 52 | +convertParagraph :: Inline -> Convert P.Blocks |
| 53 | +convertParagraph = fmap P.para . convertInline |
| 54 | + |
| 55 | +convertMarker :: Marker -> Convert P.Blocks |
| 56 | +convertMarker = error "not implemented" |
| 57 | + |
| 58 | +convertList :: List -> Convert P.Blocks |
| 59 | +convertList = \case |
| 60 | + UnorderedList ul -> |
| 61 | + fmap (P.bulletList . V.toList) $ |
| 62 | + traverse (applicativeConcatMap convertListBlock) $ |
| 63 | + ul ^. uListItems |
| 64 | + OrderedList ol -> |
| 65 | + fmap (P.bulletList . V.toList) $ |
| 66 | + traverse (applicativeConcatMap convertListBlock) $ |
| 67 | + ol ^. oListItems |
| 68 | + TaskList tl -> |
| 69 | + let convertTaskListBlock taskStatus lb = convertListBlock lb |
| 70 | + in fmap (P.bulletList . V.toList) $ |
| 71 | + traverse (\(taskStatus, items) -> applicativeConcatMap (convertTaskListBlock taskStatus) items) $ |
| 72 | + tl ^. tListItems |
| 73 | + |
| 74 | +convertQuote :: Quote -> Convert P.Blocks |
| 75 | +convertQuote quote = P.blockQuote . P.para <$> convertInline (quote ^. quoteContent) |
| 76 | + |
| 77 | +convertListBlock :: ListBlock -> Convert P.Blocks |
| 78 | +convertListBlock = \case |
| 79 | + ListParagraph i -> P.para <$> convertInline i |
| 80 | + SubList l -> convertList l |
| 81 | + |
| 82 | +convertHeading :: TagHandler tags (Convert P.Blocks) -> Heading tags -> Convert P.Blocks |
| 83 | +convertHeading handler heading = do |
| 84 | + text <- convertInline $ heading ^. headingText |
| 85 | + let header = P.header (succ . fromEnum $ heading ^. headingLevel) text |
| 86 | + subBlocks <- applicativeConcatMap (convertBlock handler) (heading ^. headingContent) |
| 87 | + pure $ header <> subBlocks |
| 88 | + |
| 89 | +convertHorizonalLine :: Convert P.Blocks |
| 90 | +convertHorizonalLine = pure P.horizontalRule |
| 91 | + |
| 92 | +convertInline :: Inline -> Convert P.Inlines |
| 93 | +convertInline = \case |
| 94 | + Text t -> pure $ P.text t |
| 95 | + Bold inline -> P.strong <$> convertInline inline |
| 96 | + Italic inline -> P.emph <$> convertInline inline |
| 97 | + Underline inline -> P.underline <$> convertInline inline |
| 98 | + Strikethrough inline -> P.strikeout <$> convertInline inline |
| 99 | + Superscript inline -> P.superscript <$> convertInline inline |
| 100 | + Subscript inline -> P.subscript <$> convertInline inline |
| 101 | + Spoiler inline -> P.strikeout <$> convertInline inline -- TODO: No native spoilers in pandoc |
| 102 | + ConcatInline inlines -> V.foldMap id <$> traverse convertInline inlines |
| 103 | + Link url inlines -> P.link url "" <$> convertInline inlines -- TODO: Investigate title field |
| 104 | + Space -> pure P.space |
| 105 | + Verbatim t -> pure $ P.code t |
| 106 | + Math t -> pure $ P.math t |
| 107 | + |
| 108 | +type SupportedTags = FromList '["code", "math", "comment", "embed", "document.meta", "table"] |
109 | 109 |
|
110 | 110 | tagHandler :: TagHandler SupportedTags (Convert P.Blocks)
|
111 |
| -tagHandler = code `mergeHandler` math `mergeHandler` comment `mergeHandler` embed `mergeHandler` documentMeta |
| 111 | +tagHandler = code `mergeHandler` math `mergeHandler` comment `mergeHandler` embed `mergeHandler` documentMeta `mergeHandler` table |
112 | 112 | where
|
113 | 113 | code = handleTag @"code" $ \_language text -> pure $ P.codeBlock text
|
114 | 114 | math = handleTag @"math" $ \_ text -> pure $ P.plain $ P.displayMath text
|
115 | 115 | comment = handleTag @"comment" $ \_ text -> pure mempty
|
116 | 116 | embed = handleTag @"embed" $ \_embedType url -> pure $ P.plain $ P.image url "" mempty
|
117 | 117 | documentMeta = handleTag @"document.meta" $ \_ _ -> pure mempty
|
| 118 | + table = handleTag @"table" $ \_ (Table rows) -> |
| 119 | + if V.length rows == 0 |
| 120 | + then pure mempty |
| 121 | + else |
| 122 | + let header = V.head rows |
| 123 | + body = V.drop 1 rows |
| 124 | + in P.simpleTable <$> convertTableRow header <*> traverse convertTableRow (V.toList body) |
| 125 | + where |
| 126 | + convertTableRow TableRowDelimiter = pure [P.horizontalRule] |
| 127 | + convertTableRow (TableRowInlines inlines) = traverse (fmap P.plain . convertInline) (V.toList inlines) |
118 | 128 |
|
119 | 129 | vecToMany :: V.Vector a -> P.Many a
|
120 | 130 | vecToMany = P.Many . S.fromList . V.toList
|
|
0 commit comments