Skip to content

Commit 8b6488e

Browse files
author
Home
committed
intermediate markdown wrapping
1 parent 250ba83 commit 8b6488e

File tree

3 files changed

+69
-48
lines changed

3 files changed

+69
-48
lines changed

bore.cabal

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ cabal-version: 2.2
55
-- see: https://github.com/sol/hpack
66

77
name: bore
8-
version: 0.23.0.0
8+
version: 0.24.0.0
99
synopsis: Build gopherholes.
1010
description: Static site builder, but for gopherholes. Manage phlogs with tags, use the Markdown renderer and Mustache templating system.
1111
category: Network
@@ -87,8 +87,6 @@ library
8787
, neat-interpolation
8888
, network-uri
8989
, optparse-applicative
90-
, pandoc
91-
, pandoc-types
9290
, parsec
9391
, prettyprinter
9492
, raw-strings-qq
@@ -152,8 +150,6 @@ executable bore
152150
, neat-interpolation
153151
, network-uri
154152
, optparse-applicative
155-
, pandoc
156-
, pandoc-types
157153
, parsec
158154
, prettyprinter
159155
, raw-strings-qq
@@ -215,8 +211,6 @@ test-suite bore-test
215211
, neat-interpolation
216212
, network-uri
217213
, optparse-applicative
218-
, pandoc
219-
, pandoc-types
220214
, parsec
221215
, prettyprinter
222216
, raw-strings-qq

package.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ dependencies:
7171
- spacecookie
7272
- edit-distance
7373
- safe
74-
- pandoc
75-
- pandoc-types
7674

7775
library:
7876
source-dirs: src

src/Bore/Text/Wrap.hs

Lines changed: 68 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,78 @@
1-
{- | Wrap text in Markdown format without converting tabs to spaces.
1+
{-# LANGUAGE OverloadedStrings #-}
2+
{-# LANGUAGE FlexibleInstances #-}
3+
{-# LANGUAGE MultiParamTypeClasses #-}
4+
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
25

3-
This module has two problems because of the hacky solution:
4-
5-
1. Gopher links have the potential of being wrapped in the middle of the link, which would
6-
break the link.
7-
2. The tab character is preserved by using a placeholder, which is not ideal.
8-
9-
-}
10-
module Bore.Text.Wrap (wrapMarkdown) where
6+
module Bore.Text.Wrap where
117

8+
import Commonmark
129
import Data.Text (Text)
1310
import qualified Data.Text as T
14-
import Text.Pandoc
11+
import Text.Wrap (wrapText, defaultWrapSettings)
12+
import Control.Monad.Reader (Reader, asks, runReader)
13+
14+
-- Configuration for the renderer
15+
data WrapConfig = WrapConfig
16+
{ lineWidth :: Int -- Configurable line width
17+
}
18+
19+
-- Custom Renderer for Wrapping Text
20+
newtype WrapRenderer = WrapRenderer { getWrappedText :: Reader WrapConfig Text }
21+
22+
instance Show WrapRenderer where
23+
show (WrapRenderer t) = show (runReader t (WrapConfig 80))
24+
instance Rangeable WrapRenderer where
25+
ranged _ (WrapRenderer t) = WrapRenderer t
26+
instance HasAttributes WrapRenderer where
27+
addAttributes _ (WrapRenderer t) = WrapRenderer t
28+
29+
instance Semigroup WrapRenderer where
30+
WrapRenderer a <> WrapRenderer b = WrapRenderer $ (<>) <$> a <*> b
31+
32+
instance Monoid WrapRenderer where
33+
mempty = WrapRenderer $ pure ""
1534

16-
-- Define the placeholder
17-
tabPlaceholder :: Text
18-
tabPlaceholder = "\FFFF"
35+
-- Handle Paragraphs
36+
instance IsBlock WrapRenderer WrapRenderer where
37+
paragraph (WrapRenderer content) = WrapRenderer $ do
38+
width <- asks lineWidth
39+
wrapped <- content
40+
if '\t' `T.elem` wrapped
41+
then return $ wrapped <> "\n\n"
42+
else return $ wrapText defaultWrapSettings width wrapped <> "\n\n"
43+
plain = id
44+
thematicBreak = WrapRenderer $ return "------------------------------\n"
45+
blockQuote = id -- need to wrap this too
46+
heading _ = id
47+
codeBlock _ t = WrapRenderer $ return $ "```\n" <> t <> "\n```\n\n"
48+
rawBlock _ t = WrapRenderer $ return t
49+
list _ _ items = mconcat items -- wrap this too
50+
referenceLinkDefinition _ _ = mempty
1951

20-
-- Preprocess: Replace tabs with placeholder
21-
preprocess :: Text -> Text
22-
preprocess = T.replace "\t" tabPlaceholder
52+
-- Handle Inline Elements
53+
instance IsInline WrapRenderer where
54+
str t = WrapRenderer $ return t
55+
softBreak = WrapRenderer $ return " "
56+
lineBreak = WrapRenderer $ return "\n"
57+
emph (WrapRenderer t) = WrapRenderer $ fmap ("*" <>) (fmap (<> "*") t)
58+
strong (WrapRenderer t) = WrapRenderer $ fmap ("**" <>) (fmap (<> "**") t)
59+
code t = WrapRenderer $ return $ "`" <> t <> "`"
60+
link _ _ (WrapRenderer t) = WrapRenderer t
61+
image _ _ (WrapRenderer t) = WrapRenderer t
62+
escapedChar c = WrapRenderer $ return $ T.singleton c
63+
entity t = WrapRenderer $ return t
64+
rawInline _ rawContent = WrapRenderer $ return rawContent
2365

24-
-- Postprocess: Replace placeholder back to tabs
25-
postprocess :: Text -> Text
26-
postprocess = T.replace tabPlaceholder "\t"
66+
-- Parse and Render Markdown
67+
wrapMarkdownParagraphs :: Int -> Text -> Either String Text
68+
wrapMarkdownParagraphs width input =
69+
case commonmark "source" input of
70+
Left err -> Left $ show err
71+
Right (WrapRenderer result) ->
72+
Right $ runReader result (WrapConfig width)
2773

28-
-- | Word wrap a Markdown document without converting tabs to spaces
2974
wrapMarkdown :: Int -> Text -> Text
3075
wrapMarkdown width input =
31-
let
32-
preprocessedInput = preprocess input
33-
34-
result = runPure $ do
35-
-- Parse the preprocessed Markdown input into Pandoc AST
36-
pandoc <- readMarkdown def { readerExtensions = pandocExtensions } preprocessedInput
37-
38-
-- Render the Pandoc AST back to Markdown with wrapping settings
39-
writeMarkdown def
40-
{ writerWrapText = WrapAuto
41-
, writerColumns = width
42-
}
43-
pandoc
44-
45-
wrappedOutput = case result of
46-
Left err -> error $ show err
47-
Right output -> postprocess output
48-
in
49-
wrappedOutput
76+
case wrapMarkdownParagraphs width input of
77+
Left err -> "Error: " <> T.pack err
78+
Right output -> output

0 commit comments

Comments
 (0)