content: {-# LANGUAGE OverloadedStrings #-}
  module Main
    ( main
    )
    where
  
  
  import Prelude hiding (init)
  import qualified Data.List as List
  import qualified Text.PrettyPrint.ANSI.Leijen as P
  import Text.PrettyPrint.ANSI.Leijen ((<>))
  import Text.Read (readMaybe)
  
  import qualified Elm.Version as V
  import Terminal
  import Terminal.Helpers
  
  import qualified Bump
  import qualified Diff
  import qualified Init
  import qualified Install
  import qualified Make
  import qualified Publish
  import qualified Repl
  
  
  
  -- MAIN
  
  
  main :: IO ()
  main =
    Terminal.app intro outro
      [ repl
      , init
      , make
      , install
      , bump
      , diff
      , publish
      ]
  
  
  intro :: P.Doc
  intro =
    P.vcat
      [ P.fillSep
          ["Hi,","thank","you","for","trying","out"
          ,P.green "Elm"
          ,P.green (P.text (V.toChars V.compiler)) <> "."
          ,"I hope you like it!"
          ]
      , ""
      , P.black "-------------------------------------------------------------------------------"
      , P.black "I highly recommend working through <https://guide.elm-lang.org> to get started."
      , P.black "It teaches many important concepts, including how to use `elm` in the terminal."
      , P.black "-------------------------------------------------------------------------------"
      ]
  
  
  outro :: P.Doc
  outro =
    P.fillSep $ map P.text $ words $
      "Be sure to ask on the Elm slack if you run into trouble! Folks are friendly and\
      \ happy to help out. They hang out there because it is fun, so be kind to get the\
      \ best results!"
  
  
  
  -- INIT
  
  
  init :: Terminal.Command
  init =
    let
      summary =
        "Start an Elm project. It creates a starter elm.json file and\
        \ provides a link explaining what to do from there."
  
      details =
        "The `init` command helps start Elm projects:"
  
      example =
        reflow
          "It will ask permission to create an elm.json file, the one thing common\
          \ to all Elm projects. It also provides a link explaining what to do from there."
    in
    Terminal.Command "init" (Common summary) details example noArgs noFlags Init.run
  
  
  
  -- REPL
  
  
  repl :: Terminal.Command
  repl =
    let
      summary =
        "Open up an interactive programming session. Type in Elm expressions\
        \ like (2 + 2) or (String.length \"test\") and see if they equal four!"
  
      details =
        "The `repl` command opens up an interactive programming session:"
  
      example =
        reflow
          "Start working through <https://guide.elm-lang.org> to learn how to use this!\
          \ It has a whole chapter that uses the REPL for everything, so that is probably\
          \ the quickest way to get started."
  
      replFlags =
        flags Repl.Flags
          |-- flag "interpreter" interpreter "Path to a alternate JS interpreter, like node or nodejs."
          |-- 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."
    in
    Terminal.Command "repl" (Common summary) details example noArgs replFlags Repl.run
  
  
  interpreter :: Parser String
  interpreter =
    Parser
      { _singular = "interpreter"
      , _plural = "interpreters"
      , _parser = Just
      , _suggest = \_ -> return []
      , _examples = \_ -> return ["node","nodejs"]
      }
  
  
  -- MAKE
  
  
  make :: Terminal.Command
  make =
    let
      details =
        "The `make` command compiles Elm code into JS or HTML:"
  
      example =
        stack
          [ reflow
              "For example:"
          , P.indent 4 $ P.green "elm make src/Main.elm"
          , reflow
              "This tries to compile an Elm file named src/Main.elm, generating an index.html\
              \ file if possible."
          ]
  
      makeFlags =
        flags Make.Flags
          |-- 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!"
          |-- 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."
          |-- onOff "sourcemaps" "Add sourcemaps to the resulting JS file. This let's you debug Elm code in a JS debugger, at the cost of longer compile times and a bigger JS file."
          |-- 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!"
          |-- 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!"
          |-- flag "docs" Make.docsFile "Generate a JSON file of documentation for a package."
    in
    Terminal.Command "make" Uncommon details example (zeroOrMore elmFile) makeFlags Make.run
  
  
  
  -- INSTALL
  
  
  install :: Terminal.Command
  install =
    let
      details =
        "The `install` command fetches packages from <https://package.elm-lang.org> for\
        \ use in your project:"
  
      example =
        stack
          [ reflow
              "For example, if you want to get packages for HTTP and JSON, you would say:"
          , P.indent 4 $ P.green $ P.vcat $
                [ "elm install elm/http"
                , "elm install elm/json"
                ]
          , reflow
              "Notice that you must say the AUTHOR name and PROJECT name! After running those\
              \ commands, you could say `import Http` or `import Json.Decode` in your code."
          , reflow
              "What if two projects use different versions of the same package? No problem!\
              \ Each project is independent, so there cannot be conflicts like that!"
          ]
  
      installArgs =
        oneOf
          [ require0 Install.NoArgs
          , require1 Install.Install package
          ]
    in
    Terminal.Command "install" Uncommon details example installArgs noFlags Install.run
  
  
  
  -- PUBLISH
  
  
  publish :: Terminal.Command
  publish =
    let
      details =
        "The `publish` command publishes your package on <https://package.elm-lang.org>\
        \ so that anyone in the Elm community can use it."
  
      example =
        stack
          [ reflow
              "Think hard if you are ready to publish NEW packages though!"
          , reflow
              "Part of what makes Elm great is the packages ecosystem. The fact that\
              \ there is usually one option (usually very well done) makes it way\
              \ easier to pick packages and become productive. So having a million\
              \ packages would be a failure in Elm. We do not need twenty of\
              \ everything, all coded in a single weekend."
          , reflow
              "So as community members gain wisdom through experience, we want\
              \ them to share that through thoughtful API design and excellent\
              \ documentation. It is more about sharing ideas and insights than\
              \ just sharing code! The first step may be asking for advice from\
              \ people you respect, or in community forums. The second step may\
              \ be using it at work to see if it is as nice as you think. Maybe\
              \ it ends up as an experiment on GitHub only. Point is, try to be\
              \ respectful of the community and package ecosystem!"
          , reflow
              "Check out <https://package.elm-lang.org/help/design-guidelines> for guidance on how to create great packages!"
          ]
    in
    Terminal.Command "publish" Uncommon details example noArgs noFlags Publish.run
  
  
  
  -- BUMP
  
  
  bump :: Terminal.Command
  bump =
    let
      details =
        "The `bump` command figures out the next version number based on API changes:"
  
      example =
        reflow
          "Say you just published version 1.0.0, but then decided to remove a function.\
          \ I will compare the published API to what you have locally, figure out that\
          \ it is a MAJOR change, and bump your version number to 2.0.0. I do this with\
          \ all packages, so there cannot be MAJOR changes hiding in PATCH releases in Elm!"
    in
    Terminal.Command "bump" Uncommon details example noArgs noFlags Bump.run
  
  
  
  -- DIFF
  
  
  diff :: Terminal.Command
  diff =
    let
      details =
        "The `diff` command detects API changes:"
  
      example =
        stack
          [ reflow
              "For example, to see what changed in the HTML package between\
              \ versions 1.0.0 and 2.0.0, you can say:"
          , P.indent 4 $ P.green $ "elm diff elm/html 1.0.0 2.0.0"
          , reflow
              "Sometimes a MAJOR change is not actually very big, so\
              \ this can help you plan your upgrade timelines."
          ]
  
      diffArgs =
        oneOf
          [ require0 Diff.CodeVsLatest
          , require1 Diff.CodeVsExactly version
          , require2 Diff.LocalInquiry version version
          , require3 Diff.GlobalInquiry package version version
          ]
    in
    Terminal.Command "diff" Uncommon details example diffArgs noFlags Diff.run
  
  
  
  -- HELPERS
  
  
  stack :: [P.Doc] -> P.Doc
  stack docs =
    P.vcat $ List.intersperse "" docs
  
  
  reflow :: String -> P.Doc
  reflow string =
    P.fillSep $ map P.text $ words string
  