on f4401ac help sign in
elk/terminal/src/Main.hs
338 lines 10 kB history raw
1{-# LANGUAGE OverloadedStrings #-}
2module Main
3 ( main
4 )
5 where
8import Prelude hiding (init)
9import qualified Data.List as List
10import qualified Text.PrettyPrint.ANSI.Leijen as P
11import Text.PrettyPrint.ANSI.Leijen ((<>))
12import Text.Read (readMaybe)
14import qualified Elm.Version as V
15import Terminal.Args
16import Terminal.Args.Helpers
18import qualified Bump
19import qualified Develop
20import qualified Diff
21import qualified Init
22import qualified Install
23import qualified Make
24import qualified Publish
25import qualified Repl
29-- MAIN
32main :: IO ()
33main =
34 complex intro outro
35 [ repl
36 , init
37 , reactor
38 , make
39 , install
40 , bump
41 , diff
42 , publish
43 ]
46intro :: P.Doc
47intro =
48 P.vcat
49 [ P.fillSep
50 ["Hi,","thank","you","for","trying","out"
51 ,P.green "Elm"
52 ,P.green (P.text (V.toChars V.compiler)) <> "."
53 ,"I hope you like it!"
54 ]
55 , ""
56 , P.black "-------------------------------------------------------------------------------"
57 , P.black "I highly recommend working through <https://guide.elm-lang.org> to get started."
58 , P.black "It teaches many important concepts, including how to use `elm` in the terminal."
59 , P.black "-------------------------------------------------------------------------------"
60 ]
63outro :: P.Doc
64outro =
65 P.fillSep $ map P.text $ words $
66 "Be sure to ask on the Elm slack if you run into trouble! Folks are friendly and\
67 \ happy to help out. They hang out there because it is fun, so be kind to get the\
68 \ best results!"
72-- INIT
75init :: Interface
76init =
77 let
78 summary =
79 "Start an Elm project. It creates a starter elm.json file and\
80 \ provides a link explaining what to do from there."
82 details =
83 "The `init` command helps start Elm projects:"
85 example =
86 reflow
87 "It will ask permission to create an elm.json file, the one thing common\
88 \ to all Elm projects. It also provides a link explaining what to do from there."
89 in
90 Interface "init" (Common summary) details example noArgs noFlags Init.run
94-- REPL
97repl :: Interface
98repl =
99 let
100 summary =
101 "Open up an interactive programming session. Type in Elm expressions\
102 \ like (2 + 2) or (String.length \"test\") and see if they equal four!"
104 details =
105 "The `repl` command opens up an interactive programming session:"
107 example =
108 reflow
109 "Start working through <https://guide.elm-lang.org> to learn how to use this!\
110 \ It has a whole chapter that uses the REPL for everything, so that is probably\
111 \ the quickest way to get started."
113 replFlags =
114 flags Repl.Flags
115 |-- flag "interpreter" interpreter "Path to a alternate JS interpreter, like node or nodejs."
116 |-- onOff "no-colors" "Turn off the colors in the REPL. This can help if you are having trouble reading the values. Some terminals use a custom color scheme that diverges significantly from the standard ANSI colors, so another path may be to pick a more standard color scheme."
117 in
118 Interface "repl" (Common summary) details example noArgs replFlags Repl.run
121interpreter :: Parser String
122interpreter =
123 Parser
124 { _singular = "interpreter"
125 , _plural = "interpreters"
126 , _parser = Just
127 , _suggest = \_ -> return []
128 , _examples = \_ -> return ["node","nodejs"]
129 }
133-- REACTOR
136reactor :: Interface
137reactor =
138 let
139 summary =
140 "Compile code with a click. It opens a file viewer in your browser, and\
141 \ when you click on an Elm file, it compiles and you see the result."
143 details =
144 "The `reactor` command starts a local server on your computer:"
146 example =
147 reflow
148 "After running that command, you would have a server at <http://localhost:8000>\
149 \ that helps with development. It shows your files like a file viewer. If you\
150 \ click on an Elm file, it will compile it for you! And you can just press\
151 \ the refresh button in the browser to recompile things."
153 reactorFlags =
154 flags Develop.Flags
155 |-- flag "port" port_ "The port of the server (default: 8000)"
156 in
157 Interface "reactor" (Common summary) details example noArgs reactorFlags Develop.run
160port_ :: Parser Int
161port_ =
162 Parser
163 { _singular = "port"
164 , _plural = "ports"
165 , _parser = readMaybe
166 , _suggest = \_ -> return []
167 , _examples = \_ -> return ["3000","8000"]
168 }
172-- MAKE
175make :: Interface
176make =
177 let
178 details =
179 "The `make` command compiles Elm code into JS or HTML:"
181 example =
182 stack
183 [ reflow
184 "For example:"
185 , P.indent 4 $ P.green "elm make src/Main.elm"
186 , reflow
187 "This tries to compile an Elm file named src/Main.elm, putting the resulting\
188 \ JavaScript code in an elm.js file."
189 ]
191 makeFlags =
192 flags Make.Flags
193 |-- onOff "debug" "Turn on the time-travelling debugger. It allows you to rewind and replay events. The events can be imported/exported into a file, which makes for very precise bug reports!"
194 |-- onOff "optimize" "Turn on optimizations to make code smaller and faster. For example, the compiler renames record fields to be as short as possible and unboxes values to reduce allocation."
195 |-- flag "output" Make.output "Specify the name of the resulting JS file. For example --output=assets/elm.js to generate the JS at assets/elm.js or --output=/dev/null to generate no output at all!"
196 |-- flag "report" Make.reportType "You can say --report=json to get error messages as JSON. This is only really useful if you are an editor plugin. Humans should avoid it!"
197 |-- flag "docs" Make.docsFile "Generate a JSON file of documentation for a package. Eventually it will be possible to preview docs with `reactor` because it is quite hard to deal with these JSON files directly."
198 in
199 Interface "make" Uncommon details example (zeroOrMore elmFile) makeFlags Make.run
203-- INSTALL
206install :: Interface
207install =
208 let
209 details =
210 "The `install` command fetches packages from <https://package.elm-lang.org> for\
211 \ use in your project:"
213 example =
214 stack
215 [ reflow
216 "For example, if you want to get packages for HTTP and JSON, you would say:"
217 , P.indent 4 $ P.green $ P.vcat $
218 [ "elm install elm/http"
219 , "elm install elm/json"
220 ]
221 , reflow
222 "Notice that you must say the AUTHOR name and PROJECT name! After running those\
223 \ commands, you could say `import Http` or `import Json.Decode` in your code."
224 , reflow
225 "What if two projects use different versions of the same package? No problem!\
226 \ Each project is independent, so there cannot be conflicts like that!"
227 ]
229 installArgs =
230 oneOf
231 [ require0 Install.NoArgs
232 , require1 Install.Install package
233 ]
234 in
235 Interface "install" Uncommon details example installArgs noFlags Install.run
239-- PUBLISH
242publish :: Interface
243publish =
244 let
245 details =
246 "The `publish` command publishes your package on <https://package.elm-lang.org>\
247 \ so that anyone in the Elm community can use it."
249 example =
250 stack
251 [ reflow
252 "Think hard if you are ready to publish NEW packages though!"
253 , reflow
254 "Part of what makes Elm great is the packages ecosystem. The fact that\
255 \ there is usually one option (usually very well done) makes it way\
256 \ easier to pick packages and become productive. So having a million\
257 \ packages would be a failure in Elm. We do not need twenty of\
258 \ everything, all coded in a single weekend."
259 , reflow
260 "So as community members gain wisdom through experience, we want\
261 \ them to share that through thoughtful API design and excellent\
262 \ documentation. It is more about sharing ideas and insights than\
263 \ just sharing code! The first step may be asking for advice from\
264 \ people you respect, or in community forums. The second step may\
265 \ be using it at work to see if it is as nice as you think. Maybe\
266 \ it ends up as an experiment on GitHub only. Point is, try to be\
267 \ respectful of the community and package ecosystem!"
268 , reflow
269 "Check out https://package.elm-lang.org/help/design-guidelines for guidance on how to create great packages!"
270 ]
271 in
272 Interface "publish" Uncommon details example noArgs noFlags Publish.run
276-- BUMP
279bump :: Interface
280bump =
281 let
282 details =
283 "The `bump` command figures out the next version number based on API changes:"
285 example =
286 reflow
287 "Say you just published version 1.0.0, but then decided to remove a function.\
288 \ I will compare the published API to what you have locally, figure out that\
289 \ it is a MAJOR change, and bump your version number to 2.0.0. I do this with\
290 \ all packages, so there cannot be MAJOR changes hiding in PATCH releases in Elm!"
291 in
292 Interface "bump" Uncommon details example noArgs noFlags Bump.run
296-- DIFF
299diff :: Interface
300diff =
301 let
302 details =
303 "The `diff` command detects API changes:"
305 example =
306 stack
307 [ reflow
308 "For example, to see what changed in the HTML package between\
309 \ versions 1.0.0 and 2.0.0, you can say:"
310 , P.indent 4 $ P.green $ "elm diff elm/html 1.0.0 2.0.0"
311 , reflow
312 "Sometimes a MAJOR change is not actually very big, so\
313 \ this can help you plan your upgrade timelines."
314 ]
316 diffArgs =
317 oneOf
318 [ require0 Diff.CodeVsLatest
319 , require1 Diff.CodeVsExactly version
320 , require2 Diff.LocalInquiry version version
321 , require3 Diff.GlobalInquiry package version version
322 ]
323 in
324 Interface "diff" Uncommon details example diffArgs noFlags Diff.run
328-- HELPERS
331stack :: [P.Doc] -> P.Doc
332stack docs =
333 P.vcat $ List.intersperse "" docs
336reflow :: String -> P.Doc
337reflow string =
338 P.fillSep $ map P.text $ words string