-
Notifications
You must be signed in to change notification settings - Fork 3
/
buildDocs.hs
executable file
·132 lines (115 loc) · 3.28 KB
/
buildDocs.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/env stack
{-
stack script
--resolver nightly-2021-10-29
--package base
--package deepseq
-}
import Control.Applicative
import Control.DeepSeq
import Data.List
import Data.Maybe
import System.IO
import Text.Read (readMaybe)
main :: IO ()
main = do
mapM_ process $
"README.md" :
"src/WithCli.hs" :
"src/WithCli/HasArguments.hs" :
"src/WithCli/Argument.hs" :
[]
process :: FilePath -> IO ()
process file = do
hPutStrLn stderr ("processing " ++ file)
contents <- strictReadFile file
output <- fillInHoles contents
deepseq output (return ())
writeFile file output
fillInHoles :: String -> IO String
fillInHoles contents = do
let lines = parseLines contents
renderLines <$> fillInLines lines
data Line
= String String
| Instruction String Instruction
isEndInstruction :: Line -> Bool
isEndInstruction (Instruction _ End) = True
isEndInstruction _ = False
data Instruction
= Start FilePath String FileType
| End
deriving (Read)
data FileType
= MarkDown CodeType
| Haddock
deriving (Read)
data CodeType
= Shell
| Haskell
deriving (Read)
renderCodeType :: CodeType -> String
renderCodeType Shell = "shell"
renderCodeType Haskell = "haskell"
parseLines :: String -> [Line]
parseLines = map parse . lines'
where
parse :: String -> Line
parse s
| "###" `isInfixOf` s =
let instruction = unwords $ takeWhile (/= "###") $ drop 2 $ words s in
case (readMaybe instruction :: Maybe Instruction) of
Nothing -> error ("cannot parse: " ++ instruction)
Just x -> Instruction s x
| otherwise = String s
renderLines :: [Line] -> String
renderLines = concat . map (\ (String s) -> s)
fillInLines :: [Line] -> IO [Line]
fillInLines lines = case lines of
[] -> return []
(String s : rest) -> (String s :) <$> fillInLines rest
(Instruction startLine (Start file dropPrefix fileType) : rest) -> do
hPutStrLn stderr ("splicing in " ++ file)
fileContent <-
fromMaybe (error ("not an infix: " ++ dropPrefix)) <$>
stripInfix dropPrefix <$>
readFile file
let (Instruction endLine End : afterEnd) =
dropWhile (not . isEndInstruction) rest
filledInAfterEnd <- fillInLines afterEnd
return $
String startLine :
render fileType startLine fileContent endLine ++
String endLine :
filledInAfterEnd
where
render (MarkDown codeType) startLine fileContent endLine =
String ("\n``` " ++ renderCodeType codeType ++ "\n") :
String fileContent :
String "```\n\n" :
[]
render Haddock startLine fileContent endLine =
String "\n-- |\n" :
String (concat $ map addHaddockCodeMarker $
lines' fileContent) :
String "\n" :
[]
addHaddockCodeMarker :: String -> String
addHaddockCodeMarker "\n" = "-- >\n"
addHaddockCodeMarker s = "-- > " ++ s
strictReadFile :: FilePath -> IO String
strictReadFile file = do
r <- readFile file
deepseq r (return ())
return r
lines' :: String -> [String]
lines' [] = []
lines' s = case span (/= '\n') s of
(line, '\n' : rest) -> (line ++ "\n") : lines' rest
(s, []) -> [s]
stripInfix :: String -> String -> Maybe String
stripInfix needle hay = case hay of
[] -> Nothing
(a : r) ->
stripPrefix needle hay <|>
fmap (a :) (stripInfix needle r)