on master help sign in
Make the --help messages much nicer
77b9f09Evan Czaplicki
ui/terminal/src/Main.hs+110−16
@@ -6,6 +6,7 @@ module Main
6
6
7
7
8import GHC.IO.Encoding (setLocaleEncoding, utf8)
8import GHC.IO.Encoding (setLocaleEncoding, utf8)
9+import qualified Data.List as List
9import qualified Text.PrettyPrint.ANSI.Leijen as P
10import qualified Text.PrettyPrint.ANSI.Leijen as P
10import Text.PrettyPrint.ANSI.Leijen ((<>))
11import Text.PrettyPrint.ANSI.Leijen ((<>))
11import Text.Read (readMaybe)
12import Text.Read (readMaybe)
@@ -81,13 +82,19 @@ repl =
81 \ expressions and it will tell you what they evaluate to."
82 \ expressions and it will tell you what they evaluate to."
82
83
83 details =
84 details =
84− Details $ error "TODO"
85+ "The `repl` command opens up an interactive programming session:"
86+
87+ example =
88+ reflow
89+ "Start working through <https://guide.elm-lang.org> to learn how to use this!\
90+ \ It has a whole chapter that uses the REPL for everything, so that is probably\
91+ \ the quickest way to get started."
85
92
86 replFlags =
93 replFlags =
87 flags Repl.Flags
94 flags Repl.Flags
88 |-- flag "interpreter" interpreter "Path to a alternate JS interpreter, like node or nodejs."
95 |-- flag "interpreter" interpreter "Path to a alternate JS interpreter, like node or nodejs."
89 in
96 in
90− Interface "repl" (Common summary) details noArgs replFlags Repl.run
97+ Interface "repl" (Common summary) details example noArgs replFlags Repl.run
91
98
92
99
93interpreter :: Parser String
100interpreter :: Parser String
@@ -113,13 +120,20 @@ reactor =
113 \ click on an Elm file, it compiles it and shows the result."
120 \ click on an Elm file, it compiles it and shows the result."
114
121
115 details =
122 details =
116− Details $ error "TODO"
123+ "The `reactor` command starts a local server on your computer:"
124+
125+ example =
126+ reflow
127+ "After running that command, you would have a server at <http://localhost:8000>\
128+ \ that helps with development. It shows your files like a file viewer. If you\
129+ \ click on an Elm file, it will compile it for you! And you can just press\
130+ \ the refresh button in the browser to recompile things."
117
131
118 reactorFlags =
132 reactorFlags =
119 flags Develop.Flags
133 flags Develop.Flags
120 |-- flag "port" port_ "The port of the server (default: 8000)"
134 |-- flag "port" port_ "The port of the server (default: 8000)"
121 in
135 in
122− Interface "reactor" (Common summary) details noArgs reactorFlags Develop.run
136+ Interface "reactor" (Common summary) details example noArgs reactorFlags Develop.run
123
137
124
138
125port_ :: Parser Int
139port_ :: Parser Int
@@ -145,7 +159,17 @@ make =
145 \ will probably want this level of control during development."
159 \ will probably want this level of control during development."
146
160
147 details =
161 details =
148− Details $ error "TODO"
162+ "The `make` command compiles Elm code into JS or HTML:"
163+
164+ example =
165+ stack
166+ [ reflow
167+ "For example:"
168+ , P.indent 4 $ P.green "elm make src/Main.elm"
169+ , reflow
170+ "This tries to compile an Elm file named src/Main.elm, putting the resulting\
171+ \ JavaScript code in an elm.js file."
172+ ]
149
173
150 makeFlags =
174 makeFlags =
151 flags Make.Flags
175 flags Make.Flags
@@ -153,7 +177,7 @@ make =
153 |-- onOff "debug" "Generate programs in debug mode."
177 |-- onOff "debug" "Generate programs in debug mode."
154 |-- flag "output" Output.output "Specify the name of the resulting JS file (use --output=/dev/null for no output)"
178 |-- flag "output" Output.output "Specify the name of the resulting JS file (use --output=/dev/null for no output)"
155 in
179 in
156− Interface "make" (Common summary) details (zeroOrMore elmFile) makeFlags Make.run
180+ Interface "make" (Common summary) details example (zeroOrMore elmFile) makeFlags Make.run
157
181
158
182
159
183
@@ -168,9 +192,25 @@ install =
168 \ independent, so you can use different versions in different projects."
192 \ independent, so you can use different versions in different projects."
169
193
170 details =
194 details =
171− Details $ error "TODO"
195+ "The `install` command fetches packages from <https://package.elm-lang.org> for\
196+ \ use in your project:"
197+
198+ example =
199+ stack
200+ [ reflow
201+ "For example, if you want to get packages for HTTP and JSON, you would say:"
202+ , P.indent 4 $ P.green $ P.vcat $
203+ [ "elm install elm-lang/http"
204+ , "elm install elm-lang/json"
205+ ]
206+ , reflow
207+ "Those commands would allow you to say `import Http` or `import Json.Decode` in\
208+ \ your project. And every project is independent, so it is no problem if one\
209+ \ project uses version 1.0.0 and another uses 2.0.0. No need to worry about\
210+ \ that sort of thing!"
211+ ]
172 in
212 in
173− Interface "install" (Common summary) details (required package) noFlags Install.run
213+ Interface "install" (Common summary) details example (required package) noFlags Install.run
174
214
175
215
176
216
@@ -181,9 +221,33 @@ publish :: Interface
181publish =
221publish =
182 let
222 let
183 details =
223 details =
184− Details $ error "TODO"
224+ "The `publish` command publishes your package on <https://package.elm-lang.org>\
225+ \ so that anyone in the Elm community can use it."
226+
227+ example =
228+ stack
229+ [ reflow
230+ "Think hard if you are ready to publish NEW packages though!"
231+ , reflow
232+ "Part of what makes Elm great is the packages ecosystem. The fact that\
233+ \ there is usually one option (usually very well done) makes it way\
234+ \ easier to pick packages and become productive. So having a million\
235+ \ packages would be a failure in Elm. We do not need twenty of\
236+ \ everything, all coded in a single weekend."
237+ , reflow
238+ "So as community members gain wisdom through experience, we want\
239+ \ them to share that through thoughtful API design and excellent\
240+ \ documentation. It is more about sharing ideas and insights than\
241+ \ just sharing code! The first step may be asking for advice from\
242+ \ people you respect, or in community forums. The second step may\
243+ \ be using it at work to see if it is as nice as you think. Maybe\
244+ \ it ends up as an experiment on GitHub only. Point is, try to be\
245+ \ respectful of the community and package ecosystem!"
246+ , reflow
247+ "Check out <TODO> for guidance on how to create great packages!"
248+ ]
185 in
249 in
186− Interface "publish" Uncommon details noArgs noFlags Publish.run
250+ Interface "publish" Uncommon details example noArgs noFlags Publish.run
187
251
188
252
189
253
@@ -194,9 +258,16 @@ bump :: Interface
194bump =
258bump =
195 let
259 let
196 details =
260 details =
197− Details $ error "TODO"
261+ "The `bump` command figures out the next version number based on API changes:"
262+
263+ example =
264+ reflow
265+ "Say you just published version 1.0.0, but then decided to remove a function.\
266+ \ I will compare the published API to what you have locally, figure out that\
267+ \ it is a MAJOR change, and bump your version number to 2.0.0. I do this with\
268+ \ all packages, so there cannot be MAJOR changes hiding in PATCH releases in Elm!"
198 in
269 in
199− Interface "bump" Uncommon details noArgs noFlags Bump.run
270+ Interface "bump" Uncommon details example noArgs noFlags Bump.run
200
271
201
272
202
273
@@ -207,9 +278,18 @@ diff :: Interface
207diff =
278diff =
208 let
279 let
209 details =
280 details =
210− Details $
211− "The `diff` command detects API changes. Every Elm package has a known public\
281+ "The `diff` command detects API changes:"
212− \ API, so I can tell you exactly what changed from version to version."
282+
283+ example =
284+ stack
285+ [ reflow
286+ "For example, to see what changed in the HTML package between\
287+ \ versions 1.0.0 and 2.0.0, you can say:"
288+ , P.indent 4 $ P.green $ "elm diff elm-lang/html 1.0.0 2.0.0"
289+ , reflow
290+ "Sometimes a MAJOR change is not actually very big, so\
291+ \ this can help you plan your upgrade timelines."
292+ ]
213
293
214 diffArgs =
294 diffArgs =
215 oneOf
295 oneOf
@@ -219,4 +299,18 @@ diff =
219 , require3 Diff.GlobalInquiry package version version
299 , require3 Diff.GlobalInquiry package version version
220 ]
300 ]
221 in
301 in
222− Interface "diff" Uncommon details diffArgs noFlags Diff.run
302+ Interface "diff" Uncommon details example diffArgs noFlags Diff.run
303+
304+
305+
306+-- HELPERS
307+
308+
309+stack :: [P.Doc] -> P.Doc
310+stack docs =
311+ P.vcat $ List.intersperse "" docs
312+
313+
314+reflow :: String -> P.Doc
315+reflow string =
316+ P.fillSep $ map P.text $ words string
ui/terminal/src/Terminal/Args.hs+6−7
@@ -2,7 +2,6 @@ module Terminal.Args
2 ( simple
2 ( simple
3 , Interface(..)
3 , Interface(..)
4 , Summary(..)
4 , Summary(..)
5− , Details(..)
6 , complex
5 , complex
7 , Flags, noFlags, flags, (|--)
6 , Flags, noFlags, flags, (|--)
8 , Flag, flag, onOff
7 , Flag, flag, onOff
@@ -34,8 +33,8 @@ import qualified Terminal.Args.Error as Error
34-- GET
33-- GET
35
34
36
35
37−simple :: String -> Args args -> Flags flags -> (args -> flags -> IO ()) -> IO ()
36+simple :: String -> P.Doc -> Args args -> Flags flags -> (args -> flags -> IO ()) -> IO ()
38−simple details args_ flags_ callback =
37+simple details example args_ flags_ callback =
39 do argStrings <- Env.getArgs
38 do argStrings <- Env.getArgs
40 case argStrings of
39 case argStrings of
41 "<autocomplete>" : number : chunks ->
40 "<autocomplete>" : number : chunks ->
@@ -44,7 +43,7 @@ simple details args_ flags_ callback =
44
43
45 chunks ->
44 chunks ->
46 if elem "--help" chunks then
45 if elem "--help" chunks then
47− Error.exitWithHelp Nothing details args_ flags_
46+ Error.exitWithHelp Nothing details example args_ flags_
48
47
49 else
48 else
50 case snd $ Chomp.chomp Nothing chunks args_ flags_ of
49 case snd $ Chomp.chomp Nothing chunks args_ flags_ of
@@ -71,9 +70,9 @@ complex intro outro interfaces =
71 Nothing ->
70 Nothing ->
72 Error.exitWithUnknown command (map toName interfaces)
71 Error.exitWithUnknown command (map toName interfaces)
73
72
74− Just (Interface _ _ (Details details) args_ flags_ callback) ->
73+ Just (Interface _ _ details example args_ flags_ callback) ->
75 if elem "--help" chunks then
74 if elem "--help" chunks then
76− Error.exitWithHelp (Just command) details args_ flags_
75+ Error.exitWithHelp (Just command) details example args_ flags_
77
76
78 else
77 else
79 case snd $ Chomp.chomp Nothing chunks args_ flags_ of
78 case snd $ Chomp.chomp Nothing chunks args_ flags_ of
@@ -109,7 +108,7 @@ complexSuggest index strings interfaces =
109 Nothing ->
108 Nothing ->
110 return (map toName interfaces)
109 return (map toName interfaces)
111
110
112− Just (Interface _ _ _ args_ flags_ _) ->
111+ Just (Interface _ _ _ _ args_ flags_ _) ->
113 fst $ Chomp.chomp (Just (index-1)) chunks args_ flags_
112 fst $ Chomp.chomp (Just (index-1)) chunks args_ flags_
114
113
115
114
ui/terminal/src/Terminal/Args/Error.hs+9−7
@@ -20,7 +20,7 @@ import GHC.IO.Handle (hIsTerminalDevice)
20import qualified System.Environment as Env
20import qualified System.Environment as Env
21import qualified System.Exit as Exit
21import qualified System.Exit as Exit
22import qualified System.FilePath as FP
22import qualified System.FilePath as FP
23−import System.IO (stderr)
23+import System.IO (hPutStrLn, stderr)
24import qualified Text.PrettyPrint.ANSI.Leijen as P
24import qualified Text.PrettyPrint.ANSI.Leijen as P
25
25
26import Elm.Utils (nearbyNames, distance)
26import Elm.Utils (nearbyNames, distance)
@@ -76,6 +76,7 @@ exitWith code docs =
76 let adjust = if isTerminal then id else P.plain
76 let adjust = if isTerminal then id else P.plain
77 P.displayIO stderr $ P.renderPretty 1 80 $
77 P.displayIO stderr $ P.renderPretty 1 80 $
78 adjust $ P.vcat $ concatMap (\d -> [d,""]) docs
78 adjust $ P.vcat $ concatMap (\d -> [d,""]) docs
79+ hPutStrLn stderr ""
79 Exit.exitWith code
80 Exit.exitWith code
80
81
81
82
@@ -98,12 +99,13 @@ reflow string =
98-- HELP
99-- HELP
99
100
100
101
101−exitWithHelp :: Maybe String -> String -> Args args -> Flags flags -> IO a
102+exitWithHelp :: Maybe String -> String -> P.Doc -> Args args -> Flags flags -> IO a
102−exitWithHelp maybeCommand details (Args args) flags =
103+exitWithHelp maybeCommand details example (Args args) flags =
103 do command <- toCommand maybeCommand
104 do command <- toCommand maybeCommand
104 exitSuccess $
105 exitSuccess $
105 [ reflow details
106 [ reflow details
106− , P.indent 4 $ P.dullcyan $ P.vcat $ map (argsToDoc command) args
107+ , P.indent 4 $ P.cyan $ P.vcat $ map (argsToDoc command) args
108+ , example
107 ]
109 ]
108 ++
110 ++
109 case flagsToDocs flags [] of
111 case flagsToDocs flags [] of
@@ -111,7 +113,7 @@ exitWithHelp maybeCommand details (Args args) flags =
111 []
113 []
112
114
113 docs@(_:_) ->
115 docs@(_:_) ->
114− [ "It also accepts the following flags to customize its behavior:"
116+ [ "You can customize this command with the following flags:"
115 , P.indent 4 $ stack docs
117 , P.indent 4 $ stack docs
116 ]
118 ]
117
119
@@ -200,7 +202,7 @@ exitWithOverview intro outro interfaces =
200
202
201
203
202toSummary :: String -> Interface -> Maybe P.Doc
204toSummary :: String -> Interface -> Maybe P.Doc
203−toSummary exeName (Interface name summary _ (Args (args:_)) _ _) =
205+toSummary exeName (Interface name summary _ _ (Args (args:_)) _ _) =
204 case summary of
206 case summary of
205 Uncommon ->
207 Uncommon ->
206 Nothing
208 Nothing
@@ -208,7 +210,7 @@ toSummary exeName (Interface name summary _ (Args (args:_)) _ _) =
208 Common summaryString ->
210 Common summaryString ->
209 Just $
211 Just $
210 P.vcat
212 P.vcat
211− [ P.dullcyan $ argsToDoc (exeName ++ " " ++ name) args
213+ [ P.cyan $ argsToDoc (exeName ++ " " ++ name) args
212 , P.indent 4 $ reflow summaryString
214 , P.indent 4 $ reflow summaryString
213 ]
215 ]
214
216
ui/terminal/src/Terminal/Args/Internal.hs+6−9
@@ -3,7 +3,6 @@ module Terminal.Args.Internal
3 ( Interface(..)
3 ( Interface(..)
4 , toName
4 , toName
5 , Summary(..)
5 , Summary(..)
6− , Details(..)
7 , Flags(..)
6 , Flags(..)
8 , Flag(..)
7 , Flag(..)
9 , Parser(..)
8 , Parser(..)
@@ -14,6 +13,9 @@ module Terminal.Args.Internal
14 where
13 where
15
14
16
15
16+import Text.PrettyPrint.ANSI.Leijen (Doc)
17+
18+
17
19
18-- INTERFACE
20-- INTERFACE
19
21
@@ -22,7 +24,8 @@ data Interface where
22 Interface
24 Interface
23 :: String
25 :: String
24 -> Summary
26 -> Summary
25− -> Details
27+ -> String
28+ -> Doc
26 -> Args args
29 -> Args args
27 -> Flags flags
30 -> Flags flags
28 -> (args -> flags -> IO ())
31 -> (args -> flags -> IO ())
@@ -30,7 +33,7 @@ data Interface where
30
33
31
34
32toName :: Interface -> String
35toName :: Interface -> String
33−toName (Interface name _ _ _ _ _) =
36+toName (Interface name _ _ _ _ _ _) =
34 name
37 name
35
38
36
39
@@ -43,12 +46,6 @@ for a more complete explanation.
43data Summary = Common String | Uncommon
46data Summary = Common String | Uncommon
44
47
45
48
46−{-| When you run `elm command --help` this is the first thing people will read.
47−Say what the command does.
48−-}
49−newtype Details = Details String
50−
51−
52
49
53-- FLAGS
50-- FLAGS
54
51