Skip to content

Commit 5b8ff84

Browse files
authored
Merge pull request #408 from BinderDavid/add-helper-tool
Small tool for generating the scaffolding of a new error message.
2 parents fabe1b3 + 34c1cca commit 5b8ff84

File tree

4 files changed

+267
-36
lines changed

4 files changed

+267
-36
lines changed

.github/workflows/hlint.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
push:
55
paths:
66
- 'message-index/site.hs'
7+
- 'message-index/create-message-template.hs'
78
branches:
89
- main
910

@@ -19,6 +20,5 @@ jobs:
1920
- name: Check site.hs with hlint
2021
uses: haskell-actions/hlint-scan@v1
2122
with:
22-
path: |
23-
message-index/site.hs
23+
path: message-index/site.hs message-index/create-message-template.hs
2424
hints: message-index/.hlint.yml

.github/workflows/ormolu.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ on:
44
push:
55
paths:
66
- '**/site.hs'
7+
- '**/create-message-template.hs'
78
branches:
89
- main
910
pull_request:
1011
paths:
1112
- '**/site.hs'
13+
- '**/create-message-template.hs'
1214
types:
1315
- opened
1416
- synchronize
@@ -25,3 +27,4 @@ jobs:
2527
with:
2628
pattern: |
2729
**/site.hs
30+
**/create-message-template.hs
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
module Main where
2+
3+
import Control.Monad (forM, forM_)
4+
import Data.Char (isLower, isSpace, toLower, toUpper)
5+
import System.Directory (createDirectory)
6+
import System.FilePath ((<.>), (</>))
7+
import System.IO (BufferMode (..), hSetBuffering, stdout)
8+
import Text.Read (readMaybe)
9+
10+
-------------------------------------------------------------------------------
11+
-- Run this tool with `runghc` on the commandline:
12+
13+
-- $ runghc create-message-template.hs
14+
15+
-------------------------------------------------------------------------------
16+
17+
-------------------------------------------------------------------------------
18+
-- Querying the user about the diagnostic
19+
-------------------------------------------------------------------------------
20+
21+
-- | Remove leading and trailing whitespace, and convert to lower case.
22+
normalize :: String -> String
23+
normalize = fmap toLower . strip
24+
where
25+
strip = f . f
26+
f = reverse . dropWhile isSpace
27+
28+
-- Querying for the tool: GHC / GHCup / Stack
29+
30+
data Tool = GHC | GHCup | Stack deriving (Show)
31+
32+
readTool :: IO Tool
33+
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+
putStr "Input (Default = GHC): "
39+
ln <- getLine
40+
case normalize ln of
41+
"1" -> pure GHC
42+
"ghc" -> pure GHC
43+
"2" -> pure GHCup
44+
"ghcup" -> pure GHCup
45+
"3" -> pure Stack
46+
"stack" -> pure Stack
47+
"" -> pure GHC
48+
_ -> do
49+
putStrLn "Didn't understand input. Please type a tool name or a number."
50+
readTool
51+
52+
-- Querying for the error code
53+
54+
-- | We need to encode the error code as a string in order
55+
-- to preserve leading 0's.
56+
type ErrorCode = String
57+
58+
readCode :: IO ErrorCode
59+
readCode = do
60+
putStrLn "What is the numeric code that you want to document."
61+
putStrLn "For example, enter \"01234\" if you want to document GHC-01234."
62+
putStr "Input: "
63+
ln <- getLine
64+
case readMaybe ln :: Maybe Int of
65+
Nothing -> do
66+
putStrLn "Could not parse the input as an integer. Only enter the numeric part of the error."
67+
readCode
68+
Just _ -> pure ln
69+
70+
-- Title
71+
type Title = String
72+
73+
readTitle :: IO Title
74+
readTitle = do
75+
putStrLn "What is the title of the error message?"
76+
putStrLn "This is used as the title of the documentation page as well as in links to the page."
77+
putStr "Input: "
78+
getLine
79+
80+
-- Summary
81+
type Summary = String
82+
83+
readSummary :: IO Summary
84+
readSummary = do
85+
putStrLn "Give a short summary of the error message."
86+
putStrLn "This appears on the overview page that lists all the documented errors and warnings."
87+
putStr "Input: "
88+
getLine
89+
90+
-- Severity
91+
data Severity = Error | Warning deriving (Show)
92+
93+
readSeverity :: IO Severity
94+
readSeverity = do
95+
putStrLn "What is the severity of the diagnostic."
96+
putStrLn " 1) Error"
97+
putStrLn " 2) Warning"
98+
putStr "Input (Default = Error): "
99+
ln <- getLine
100+
case normalize ln of
101+
"1" -> pure Error
102+
"error" -> pure Error
103+
"2" -> pure Warning
104+
"warning" -> pure Warning
105+
"" -> pure Error
106+
_ -> do
107+
putStrLn "Please type \"error\" or \"warning\" or a number."
108+
readSeverity
109+
110+
-- Warning flag
111+
type WarningFlag = String
112+
113+
-- | Only ask for a warning flag if Severity = Warning.
114+
readWarningFlag :: Severity -> IO (Maybe WarningFlag)
115+
readWarningFlag Warning = do
116+
putStrLn "What is the warning flag which enables this warning?"
117+
putStrLn "For example, enter \"-Wtabs\" if you are documenting GHC's warning about tabs in your source file."
118+
putStrLn "You can leave this blank if you're not sure."
119+
putStr "Input: "
120+
Just <$> getLine
121+
readWarningFlag _ = pure Nothing
122+
123+
-- Version
124+
type Version = String
125+
126+
readVersion :: IO Version
127+
readVersion = do
128+
putStrLn "Which version of the tool emitted the numeric code (not the message) for the first time?"
129+
putStrLn "Note: For GHC this is most likely 9.6.1."
130+
putStr "Input: "
131+
getLine
132+
133+
-- Examples
134+
type Examples = [String]
135+
136+
validateExampleName :: String -> Bool
137+
validateExampleName "" = False
138+
validateExampleName str@(s : _) = not (any isSpace str) && isLower s
139+
140+
-- | Only ask for examples if the system is GHC.
141+
readExamples :: Tool -> IO Examples
142+
readExamples GHC = do
143+
putStrLn "How many examples should be generated?"
144+
putStr "Input: "
145+
ln <- getLine
146+
case readMaybe ln :: Maybe Int of
147+
Nothing -> pure []
148+
Just n -> forM [1 .. n] readExample
149+
readExamples _ = pure []
150+
151+
readExample :: Int -> IO String
152+
readExample i = do
153+
putStrLn ("Give a name for example " <> show i)
154+
putStrLn "The name should not contain spaces and begin with a lowercase letter."
155+
putStr "Input: "
156+
ln <- getLine
157+
if validateExampleName ln then pure ln else readExample i
158+
159+
-- Template
160+
data Template = MkTemplate
161+
{ tool :: Tool,
162+
code :: ErrorCode,
163+
title :: Title,
164+
summary :: Summary,
165+
severity :: Severity,
166+
warningflag :: Maybe WarningFlag,
167+
introduced :: Version,
168+
examples :: Examples
169+
}
170+
deriving (Show)
171+
172+
readTemplate :: IO Template
173+
readTemplate = do
174+
putStrLn "This tool helps you create the scaffolding for a new error message on the error-message-index."
175+
putStrLn "You can leave any of the text fields blank and fill them in by hand later."
176+
putStrLn ""
177+
sys <- readTool
178+
putStrLn ""
179+
code <- readCode
180+
putStrLn ""
181+
title <- readTitle
182+
putStrLn ""
183+
summary <- readSummary
184+
putStrLn ""
185+
severity <- readSeverity
186+
putStrLn ""
187+
warningflag <- readWarningFlag severity
188+
putStrLn ""
189+
version <- readVersion
190+
putStrLn ""
191+
examples <- readExamples sys
192+
pure (MkTemplate sys code title summary severity warningflag version examples)
193+
194+
-------------------------------------------------------------------------------
195+
-- Creating the files and directories from the template
196+
-------------------------------------------------------------------------------
197+
198+
createFiles :: Template -> IO ()
199+
createFiles tmpl = do
200+
putStrLn "Creating scaffolding for the following configuration:"
201+
print tmpl
202+
putStrLn ""
203+
204+
-- Create the new directory "messages/XXX-NNNNNN/" and "messages/XXX-NNNNNN/index.md"
205+
let message_dir = "messages" </> case tool tmpl of { GHC -> "GHC-"; GHCup -> "GHCup-"; Stack -> "S-" } ++ code tmpl
206+
createDirectory message_dir
207+
let toplvl_index =
208+
unlines
209+
[ "---",
210+
"title: " <> title tmpl,
211+
"summary: " <> summary tmpl,
212+
"severity: " <> case severity tmpl of Warning -> "warning"; Error -> "error",
213+
"introduced: " <> introduced tmpl,
214+
"---",
215+
"",
216+
"Insert your error message here."
217+
]
218+
writeFile (message_dir </> "index.md") toplvl_index
219+
220+
-- Create the example directories and entries:
221+
-- - "messages/XXX-NNNNNN/" and "messages/XXX-NNNNNN/example-name/index.md"
222+
-- - "messages/XXX-NNNNNN/example-name/before/" and "messages/XXX-NNNNNN/example-name/before/Module.hs"
223+
-- - "messages/XXX-NNNNNN/example-name/after/" and "messages/XXX-NNNNNN/example-name/after/Module.hs"
224+
forM_ (examples tmpl) $ \example -> do
225+
let example_dir = message_dir </> example
226+
let uppercase "" = ""
227+
uppercase (s : ss) = toUpper s : ss
228+
let example_name = uppercase example
229+
createDirectory example_dir
230+
createDirectory (example_dir </> "before")
231+
createDirectory (example_dir </> "after")
232+
let example_index =
233+
unlines
234+
[ "---",
235+
"title: <insert a title for this example here>",
236+
"---"
237+
]
238+
writeFile (example_dir </> "index.md") example_index
239+
let before_module =
240+
unlines
241+
[ "module " <> example_name <> " where",
242+
"",
243+
"-- Insert the example containing a bug here."
244+
]
245+
writeFile (example_dir </> "before" </> example_name <.> "hs") before_module
246+
let after_module =
247+
unlines
248+
[ "module " <> example_name <> " where",
249+
"",
250+
"-- Insert the fixed example here."
251+
]
252+
writeFile (example_dir </> "after" </> example_name <.> "hs") after_module
253+
254+
-------------------------------------------------------------------------------
255+
-- Main
256+
-------------------------------------------------------------------------------
257+
258+
main :: IO ()
259+
main = do
260+
hSetBuffering stdout NoBuffering
261+
tmpl <- readTemplate
262+
createFiles tmpl

message-index/makeFolder.sh

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)