Skip to content

Commit 5e15242

Browse files
committed
Moves code that is marked with .top to the beginning of the file
1 parent 649f3da commit 5e15242

File tree

2 files changed

+90
-20
lines changed

2 files changed

+90
-20
lines changed

src/Text/Markdown/Unlit.hs

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
{-# LANGUAGE CPP #-}
2+
{-# LANGUAGE DerivingStrategies #-}
3+
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+
{-# LANGUAGE LambdaCase #-}
25
{-# LANGUAGE OverloadedStrings #-}
36
{-# LANGUAGE ViewPatterns #-}
47
module Text.Markdown.Unlit (
@@ -9,19 +12,22 @@ module Text.Markdown.Unlit (
912
, CodeBlock (..)
1013
, parse
1114
#ifdef TEST
15+
, parseReorderingKey
1216
, parseClasses
1317
#endif
1418
) where
1519

1620
import Prelude ()
1721
import Prelude.Compat
18-
import Data.Maybe
19-
import Data.List.Compat
22+
import Control.Arrow
2023
import Data.Char
24+
import Data.List.Compat
25+
import Data.Maybe
2126
import Data.String
22-
import System.IO
23-
import System.Exit
2427
import System.Environment
28+
import System.Exit
29+
import System.IO
30+
import Text.Read
2531

2632
fenceChars :: [Char]
2733
fenceChars = ['`', '~']
@@ -43,7 +49,7 @@ run args =
4349
-- #line 1 "label"
4450
--
4551
case break (== "-h") args of
46-
(mkSelector -> selector, "-h" : foo) -> case foo of
52+
(mkSelector -> selector, "-h" : files) -> case files of
4753
[src, cur, dst] -> do
4854
readFileUtf8 cur >>= writeFileUtf8 dst . unlit src selector
4955
[src] -> do
@@ -70,20 +76,48 @@ run args =
7076
writeUtf8 handle str = hSetEncoding handle utf8 >> hPutStr handle str
7177

7278
unlit :: FilePath -> Selector -> String -> String
73-
unlit src selector = unlines . concatMap formatCB . filter (toP selector . codeBlockClasses) . parse
79+
unlit src selector = unlines . concatMap formatCodeBlock . sortCodeBlocks . filter (toPredicate selector . codeBlockClasses) . parse
7480
where
75-
formatCB :: CodeBlock -> [String]
76-
formatCB cb = ("#line " ++ show (codeBlockStartLine cb) ++ " " ++ show src) : codeBlockContent cb
81+
formatCodeBlock :: CodeBlock -> [String]
82+
formatCodeBlock cb = ("#line " ++ show (codeBlockStartLine cb) ++ " " ++ show src) : codeBlockContent cb
7783

78-
toP :: Selector -> [String] -> Bool
79-
toP = go
84+
sortCodeBlocks :: [CodeBlock] -> [CodeBlock]
85+
sortCodeBlocks = map fst . sortOn snd . addSortKey
86+
where
87+
addSortKey :: [CodeBlock] -> [(CodeBlock, (ReorderingKey, DeclarationOrder))]
88+
addSortKey = zipWith ((id &&&) . sortKey) [0..]
89+
90+
sortKey :: a -> CodeBlock -> (ReorderingKey, a)
91+
sortKey n code = (reorderingKey code, n)
92+
93+
toPredicate :: Selector -> [String] -> Bool
94+
toPredicate = go
8095
where
8196
go s = case s of
8297
Class c -> elem c
8398
Not p -> not . go p
8499
a :&: b -> (&&) <$> go a <*> go b
85100
a :|: b -> (||) <$> go a <*> go b
86101

102+
newtype DeclarationOrder = DeclarationOrder Int
103+
deriving newtype (Eq, Ord, Enum, Num)
104+
105+
newtype ReorderingKey = ReorderingKey Int
106+
deriving newtype (Eq, Show, Read, Ord, Bounded, Num)
107+
108+
reorderingKey :: CodeBlock -> ReorderingKey
109+
reorderingKey = parseReorderingKey . codeBlockClasses
110+
111+
parseReorderingKey :: [String] -> ReorderingKey
112+
parseReorderingKey = go
113+
where
114+
go :: [String] -> ReorderingKey
115+
go = \ case
116+
[] -> 0
117+
"top" : _ -> minBound
118+
('t' : 'o' : 'p' : ':' : (readMaybe -> Just n)) : _ -> minBound + n
119+
_ : classes -> go classes
120+
87121
infixr 3 :&:
88122
infixr 2 :|:
89123

test/Text/Markdown/UnlitSpec.hs

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,36 +34,72 @@ spec = do
3434
it "unlits code marked with .haskell by default (unless it is marked with .ignore as well)" $ do
3535
withTempFile $ \infile -> withTempFile $ \outfile -> do
3636
writeFile infile . build $ do
37-
"~~~ {.haskell}"
37+
"```haskell"
3838
"some code"
39-
40-
"~~~"
41-
"~~~ {.haskell .ignore}"
39+
"```"
40+
"```haskell ignore"
4241
"some other code"
43-
44-
"~~~"
42+
"```"
4543
run ["-h", "Foo.lhs", infile, outfile]
4644
readFile outfile `shouldReturn` (build $ do
4745
"#line 2 \"Foo.lhs\""
4846
"some code"
4947
)
5048

49+
it "moves code that is marked with .top to the beginning of the file" $ do
50+
withTempFile $ \infile -> withTempFile $ \outfile -> do
51+
writeFile infile . build $ do
52+
"```haskell top"
53+
"module Foo where"
54+
"```"
55+
""
56+
"```haskell"
57+
"foo :: Int"
58+
"foo = 23"
59+
"```"
60+
""
61+
"```haskell top"
62+
"import Bar"
63+
"```"
64+
run ["-h", "Foo.lhs", infile, outfile]
65+
readFile outfile `shouldReturn` (build $ do
66+
"#line 2 \"Foo.lhs\""
67+
"module Foo where"
68+
"#line 11 \"Foo.lhs\""
69+
"import Bar"
70+
"#line 6 \"Foo.lhs\""
71+
"foo :: Int"
72+
"foo = 23"
73+
)
74+
5175
it "can be customized" $ do
5276
withTempFile $ \infile -> withTempFile $ \outfile -> do
5377
writeFile infile . build $ do
54-
"~~~ {.foo}"
78+
"```foo"
5579
"some code"
5680
""
57-
"~~~"
58-
"~~~ {.bar}"
81+
"```"
82+
"``` {.bar}"
5983
"some other code"
60-
"~~~"
84+
"```"
6185
run ["bar", "-h", "Foo.lhs", infile, outfile]
6286
readFile outfile `shouldReturn` (build $ do
6387
"#line 6 \"Foo.lhs\""
6488
"some other code"
6589
)
6690

91+
describe "parseReorderingKey" $ do
92+
it "returns 0" $ do
93+
parseReorderingKey [] `shouldBe` 0
94+
95+
context "with .top" $ do
96+
it "returns minBound" $ do
97+
parseReorderingKey ["top"] `shouldBe` minBound
98+
99+
context "with top:n" $ do
100+
it "returns (minBound + n)" $ do
101+
parseReorderingKey ["top:20"] `shouldBe` minBound + 20
102+
67103
describe "parseSelector" $ do
68104
it "parses + as :&:" $ do
69105
parseSelector "foo+bar+baz" `shouldBe` Just ("foo" :&: "bar" :&: "baz")

0 commit comments

Comments
 (0)