1
+ #!/usr/bin/env cabal
2
+ {- cabal:
3
+ build-depends: base, haskeline >=0.8, directory >= 1.3, filepath >= 1.4
4
+ -}
1
5
module Main where
2
6
3
7
import Control.Monad (forM , forM_ )
8
+ import Control.Monad.IO.Class (liftIO )
4
9
import Data.Char (isLower , isSpace , toLower , toUpper )
10
+ import Data.Maybe (fromMaybe )
11
+ import System.Console.Haskeline
5
12
import System.Directory (createDirectory , createDirectoryIfMissing )
6
13
import System.FilePath ((<.>) , (</>) )
7
14
import System.IO (BufferMode (.. ), hSetBuffering , stdout )
8
15
import Text.Read (readMaybe )
9
16
10
- -------------------------------------------------------------------------------
11
- -- Run this tool with `runghc` on the commandline:
12
-
13
- -- $ runghc create-message-template.hs
17
+ type ToolM a = InputT IO a
14
18
15
- -------------------------------------------------------------------------------
19
+ getInputLine' :: String -> ToolM String
20
+ getInputLine' s = do
21
+ ln <- getInputLine s
22
+ pure (fromMaybe " " ln)
16
23
17
24
-------------------------------------------------------------------------------
18
25
-- Querying the user about the diagnostic
@@ -29,15 +36,14 @@ normalize = fmap toLower . strip
29
36
30
37
data Tool = GHC | GHCup | Stack | Cabal deriving (Show )
31
38
32
- readTool :: IO Tool
39
+ readTool :: ToolM Tool
33
40
readTool = do
34
- putStrLn " · Which tool's error code do you want to document?"
35
- putStrLn " 1) GHC"
36
- putStrLn " 2) GHCup"
37
- putStrLn " 3) Stack"
38
- putStrLn " 4) Cabal"
39
- putStr " Input (Default = GHC): "
40
- ln <- getLine
41
+ outputStrLn " · Which tool's error code do you want to document?"
42
+ outputStrLn " 1) GHC"
43
+ outputStrLn " 2) GHCup"
44
+ outputStrLn " 3) Stack"
45
+ outputStrLn " 4) Cabal"
46
+ ln <- getInputLine' " Input (Default = GHC): "
41
47
case normalize ln of
42
48
" 1" -> pure GHC
43
49
" ghc" -> pure GHC
@@ -49,7 +55,7 @@ readTool = do
49
55
" cabal" -> pure Cabal
50
56
" " -> pure GHC
51
57
_ -> do
52
- putStrLn " Didn't understand input. Please type a tool name or a number."
58
+ outputStrLn " Didn't understand input. Please type a tool name or a number."
53
59
readTool
54
60
55
61
-- Querying for the error code
@@ -58,80 +64,74 @@ readTool = do
58
64
-- to preserve leading 0's.
59
65
type ErrorCode = String
60
66
61
- readCode :: IO ErrorCode
67
+ readCode :: ToolM ErrorCode
62
68
readCode = do
63
- putStrLn " · What is the numeric code that you want to document?"
64
- putStrLn " For example, enter \" 01234\" if you want to document GHC-01234."
65
- putStr " Input: "
66
- ln <- getLine
69
+ outputStrLn " · What is the numeric code that you want to document?"
70
+ outputStrLn " For example, enter \" 01234\" if you want to document GHC-01234."
71
+ ln <- getInputLine' " Input: "
67
72
case readMaybe ln :: Maybe Int of
68
73
Nothing -> do
69
- putStrLn " Could not parse the input as an integer. Only enter the numeric part of the error."
74
+ outputStrLn " Could not parse the input as an integer. Only enter the numeric part of the error."
70
75
readCode
71
76
Just _ -> pure ln
72
77
73
78
-- Title
74
79
type Title = String
75
80
76
- readTitle :: IO Title
81
+ readTitle :: ToolM Title
77
82
readTitle = do
78
- putStrLn " · What is the title of the error message?"
79
- putStrLn " This is used as the title of the documentation page as well as in links to the page."
80
- putStr " Input: "
81
- getLine
83
+ outputStrLn " · What is the title of the error message?"
84
+ outputStrLn " This is used as the title of the documentation page as well as in links to the page."
85
+ getInputLine' " Input: "
82
86
83
87
-- Summary
84
88
type Summary = String
85
89
86
- readSummary :: IO Summary
90
+ readSummary :: ToolM Summary
87
91
readSummary = do
88
- putStrLn " · Give a short summary of the error message."
89
- putStrLn " This appears on the overview page that lists all the documented errors and warnings."
90
- putStr " Input: "
91
- getLine
92
+ outputStrLn " · Give a short summary of the error message."
93
+ outputStrLn " This appears on the overview page that lists all the documented errors and warnings."
94
+ getInputLine' " Input: "
92
95
93
96
-- Severity
94
97
data Severity = Error | Warning deriving (Show )
95
98
96
- readSeverity :: IO Severity
99
+ readSeverity :: ToolM Severity
97
100
readSeverity = do
98
- putStrLn " · What is the severity of the diagnostic?"
99
- putStrLn " 1) Error"
100
- putStrLn " 2) Warning"
101
- putStr " Input (Default = Error): "
102
- ln <- getLine
101
+ outputStrLn " · What is the severity of the diagnostic?"
102
+ outputStrLn " 1) Error"
103
+ outputStrLn " 2) Warning"
104
+ ln <- getInputLine' " Input (Default = Error): "
103
105
case normalize ln of
104
106
" 1" -> pure Error
105
107
" error" -> pure Error
106
108
" 2" -> pure Warning
107
109
" warning" -> pure Warning
108
110
" " -> pure Error
109
111
_ -> do
110
- putStrLn " Please type \" error\" or \" warning\" or a number."
112
+ outputStrLn " Please type \" error\" or \" warning\" or a number."
111
113
readSeverity
112
114
113
115
-- Warning flag
114
116
type WarningFlag = String
115
117
116
118
-- | Only ask for a warning flag if Severity = Warning.
117
- readWarningFlag :: Severity -> IO (Maybe WarningFlag )
119
+ readWarningFlag :: Severity -> ToolM (Maybe WarningFlag )
118
120
readWarningFlag Warning = do
119
- putStrLn " · What is the warning flag which enables this warning?"
120
- putStrLn " For example, enter \" -Wtabs\" if you are documenting GHC's warning about tabs in your source file."
121
- putStrLn " You can leave this blank if you're not sure."
122
- putStr " Input: "
123
- Just <$> getLine
121
+ outputStrLn " · What is the warning flag which enables this warning?"
122
+ outputStrLn " For example, enter \" -Wtabs\" if you are documenting GHC's warning about tabs in your source file."
123
+ outputStrLn " You can leave this blank if you're not sure."
124
+ Just <$> getInputLine' " Input: "
124
125
readWarningFlag _ = pure Nothing
125
126
126
127
-- Version
127
128
type Version = String
128
129
129
- readVersion :: IO Version
130
+ readVersion :: ToolM Version
130
131
readVersion = do
131
- putStrLn " · Which version of the tool emitted the numeric code (not the message) for the first time?"
132
- putStrLn " Note: For GHC this is most likely 9.6.1."
133
- putStr " Input: "
134
- getLine
132
+ outputStrLn " · Which version of the tool emitted the numeric code (not the message) for the first time?"
133
+ outputStrLn " Note: For GHC this is most likely 9.6.1."
134
+ getInputLine' " Input: "
135
135
136
136
-- Examples
137
137
type Examples = [String ]
@@ -141,23 +141,21 @@ validateExampleName "" = False
141
141
validateExampleName str@ (s : _) = not (any isSpace str) && isLower s
142
142
143
143
-- | Only ask for examples if the system is GHC.
144
- readExamples :: Tool -> IO Examples
144
+ readExamples :: Tool -> ToolM Examples
145
145
readExamples GHC = do
146
- putStrLn " · How many examples should be generated?"
147
- putStr " Input: "
148
- ln <- getLine
146
+ outputStrLn " · How many examples should be generated?"
147
+ ln <- getInputLine' " Input: "
149
148
case readMaybe ln :: Maybe Int of
150
149
Nothing -> pure []
151
150
Just n -> forM [1 .. n] readExample
152
151
readExamples _ = pure []
153
152
154
- readExample :: Int -> IO String
153
+ readExample :: Int -> ToolM String
155
154
readExample i = do
156
- putStrLn " "
157
- putStrLn (" · Give a name for example " <> show i)
158
- putStrLn " The name should not contain spaces and begin with a lowercase letter."
159
- putStr " Input: "
160
- ln <- getLine
155
+ outputStrLn " "
156
+ outputStrLn (" · Give a name for example " <> show i)
157
+ outputStrLn " The name should begin with a lowercase letter and should not contain any spaces."
158
+ ln <- getInputLine' " Input: "
161
159
if validateExampleName ln then pure ln else readExample i
162
160
163
161
-- Template
@@ -173,25 +171,25 @@ data Template = MkTemplate
173
171
}
174
172
deriving (Show )
175
173
176
- readTemplate :: IO Template
174
+ readTemplate :: ToolM Template
177
175
readTemplate = do
178
- putStrLn " This tool helps you create the scaffolding for a new error message on the error-message-index."
179
- putStrLn " You can leave any of the text fields blank and fill them in by hand later."
180
- putStrLn " "
176
+ outputStrLn " This tool helps you create the scaffolding for a new error message on the error-message-index."
177
+ outputStrLn " You can leave any of the text fields blank and fill them in by hand later."
178
+ outputStrLn " "
181
179
sys <- readTool
182
- putStrLn " "
180
+ outputStrLn " "
183
181
code <- readCode
184
- putStrLn " "
182
+ outputStrLn " "
185
183
title <- readTitle
186
- putStrLn " "
184
+ outputStrLn " "
187
185
summary <- readSummary
188
- putStrLn " "
186
+ outputStrLn " "
189
187
severity <- readSeverity
190
- putStrLn " "
188
+ outputStrLn " "
191
189
warningflag <- readWarningFlag severity
192
- putStrLn " "
190
+ outputStrLn " "
193
191
version <- readVersion
194
- putStrLn " "
192
+ outputStrLn " "
195
193
examples <- readExamples sys
196
194
pure (MkTemplate sys code title summary severity warningflag version examples)
197
195
@@ -200,7 +198,7 @@ readTemplate = do
200
198
-------------------------------------------------------------------------------
201
199
202
200
createFiles :: Template -> IO ()
203
- createFiles tmpl = do
201
+ createFiles tmpl = liftIO $ do
204
202
putStrLn " "
205
203
putStrLn " · Creating scaffolding..."
206
204
@@ -268,5 +266,5 @@ createFiles tmpl = do
268
266
main :: IO ()
269
267
main = do
270
268
hSetBuffering stdout NoBuffering
271
- tmpl <- readTemplate
269
+ tmpl <- runInputT defaultSettings readTemplate
272
270
createFiles tmpl
0 commit comments