module Unison.CommandLine.Welcome
  ( CodebaseInitStatus (..),
    Welcome (..),
    asciiartUnison,
    run,
    welcome,
  )
where

import Unison.Codebase.Editor.Input
import Unison.Prelude
import Unison.Util.Pretty qualified as P
import Prelude hiding (readFile, writeFile)

data Welcome = Welcome
  { Welcome -> Onboarding
onboarding :: Onboarding, -- Onboarding States
    Welcome -> Text
unisonVersion :: Text,
    Welcome -> Bool
showWelcomeHint :: Bool
  }

-- Previously Created is different from Previously Onboarded because a user can
-- 1.) create a new codebase
-- 2.) decide not to go through the onboarding flow until later and exit
-- 3.) then reopen their blank codebase
data CodebaseInitStatus
  = NewlyCreatedCodebase -- Can transition to [Base, Author, Finished]
  | PreviouslyCreatedCodebase -- Can transition to [Base, Author, Finished, PreviouslyOnboarded].
  deriving (Int -> CodebaseInitStatus -> ShowS
[CodebaseInitStatus] -> ShowS
CodebaseInitStatus -> String
(Int -> CodebaseInitStatus -> ShowS)
-> (CodebaseInitStatus -> String)
-> ([CodebaseInitStatus] -> ShowS)
-> Show CodebaseInitStatus
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CodebaseInitStatus -> ShowS
showsPrec :: Int -> CodebaseInitStatus -> ShowS
$cshow :: CodebaseInitStatus -> String
show :: CodebaseInitStatus -> String
$cshowList :: [CodebaseInitStatus] -> ShowS
showList :: [CodebaseInitStatus] -> ShowS
Show, CodebaseInitStatus -> CodebaseInitStatus -> Bool
(CodebaseInitStatus -> CodebaseInitStatus -> Bool)
-> (CodebaseInitStatus -> CodebaseInitStatus -> Bool)
-> Eq CodebaseInitStatus
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CodebaseInitStatus -> CodebaseInitStatus -> Bool
== :: CodebaseInitStatus -> CodebaseInitStatus -> Bool
$c/= :: CodebaseInitStatus -> CodebaseInitStatus -> Bool
/= :: CodebaseInitStatus -> CodebaseInitStatus -> Bool
Eq)

data Onboarding
  = Init CodebaseInitStatus -- Can transition to [Author, Finished, PreviouslyOnboarded]
  | Author -- Can transition to [Finished]
  -- End States
  | Finished
  | PreviouslyOnboarded
  deriving (Int -> Onboarding -> ShowS
[Onboarding] -> ShowS
Onboarding -> String
(Int -> Onboarding -> ShowS)
-> (Onboarding -> String)
-> ([Onboarding] -> ShowS)
-> Show Onboarding
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Onboarding -> ShowS
showsPrec :: Int -> Onboarding -> ShowS
$cshow :: Onboarding -> String
show :: Onboarding -> String
$cshowList :: [Onboarding] -> ShowS
showList :: [Onboarding] -> ShowS
Show, Onboarding -> Onboarding -> Bool
(Onboarding -> Onboarding -> Bool)
-> (Onboarding -> Onboarding -> Bool) -> Eq Onboarding
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Onboarding -> Onboarding -> Bool
== :: Onboarding -> Onboarding -> Bool
$c/= :: Onboarding -> Onboarding -> Bool
/= :: Onboarding -> Onboarding -> Bool
Eq)

welcome :: CodebaseInitStatus -> Text -> Bool -> Welcome
welcome :: CodebaseInitStatus -> Text -> Bool -> Welcome
welcome CodebaseInitStatus
initStatus Text
unisonVersion Bool
showWelcomeHint =
  Onboarding -> Text -> Bool -> Welcome
Welcome (CodebaseInitStatus -> Onboarding
Init CodebaseInitStatus
initStatus) Text
unisonVersion Bool
showWelcomeHint

run :: Welcome -> [Either Event Input]
run :: Welcome -> [Either Event Input]
run Welcome {$sel:onboarding:Welcome :: Welcome -> Onboarding
onboarding = Onboarding
onboarding, $sel:unisonVersion:Welcome :: Welcome -> Text
unisonVersion = Text
version, $sel:showWelcomeHint:Welcome :: Welcome -> Bool
showWelcomeHint = Bool
showWelcomeHint} = do
  Onboarding -> [Either Event Input] -> [Either Event Input]
go Onboarding
onboarding []
  where
    go :: Onboarding -> [Either Event Input] -> [Either Event Input]
    go :: Onboarding -> [Either Event Input] -> [Either Event Input]
go Onboarding
onboarding [Either Event Input]
acc =
      case Onboarding
onboarding of
        Init CodebaseInitStatus
NewlyCreatedCodebase -> do
          Onboarding -> [Either Event Input] -> [Either Event Input]
go Onboarding
PreviouslyOnboarded (Either Event Input
headerMsg Either Event Input -> [Either Event Input] -> [Either Event Input]
forall a. a -> [a] -> [a]
: [Either Event Input]
acc)
          where
            headerMsg :: Either Event Input
headerMsg = Pretty ColorText -> Either Event Input
toInput (Text -> Pretty ColorText
header Text
version)
        Init CodebaseInitStatus
PreviouslyCreatedCodebase -> do
          Onboarding -> [Either Event Input] -> [Either Event Input]
go Onboarding
PreviouslyOnboarded (Either Event Input
headerMsg Either Event Input -> [Either Event Input] -> [Either Event Input]
forall a. a -> [a] -> [a]
: [Either Event Input]
acc)
          where
            headerMsg :: Either Event Input
headerMsg = Pretty ColorText -> Either Event Input
toInput (Text -> Pretty ColorText
header Text
version)
        Onboarding
Author ->
          Onboarding -> [Either Event Input] -> [Either Event Input]
go Onboarding
Finished (Either Event Input
authorMsg Either Event Input -> [Either Event Input] -> [Either Event Input]
forall a. a -> [a] -> [a]
: [Either Event Input]
acc)
          where
            authorMsg :: Either Event Input
authorMsg = Pretty ColorText -> Either Event Input
toInput Pretty ColorText
authorSuggestion
        -- These are our two terminal Welcome conditions, at the end we reverse the order of the desired input commands otherwise they come out backwards
        Onboarding
Finished -> [Either Event Input] -> [Either Event Input]
forall a. [a] -> [a]
reverse (Pretty ColorText -> Either Event Input
toInput (Bool -> Pretty ColorText
getStarted Bool
showWelcomeHint) Either Event Input -> [Either Event Input] -> [Either Event Input]
forall a. a -> [a] -> [a]
: [Either Event Input]
acc)
        Onboarding
PreviouslyOnboarded -> [Either Event Input] -> [Either Event Input]
forall a. [a] -> [a]
reverse (Pretty ColorText -> Either Event Input
toInput (Bool -> Pretty ColorText
getStarted Bool
showWelcomeHint) Either Event Input -> [Either Event Input] -> [Either Event Input]
forall a. a -> [a] -> [a]
: [Either Event Input]
acc)

toInput :: P.Pretty P.ColorText -> Either Event Input
toInput :: Pretty ColorText -> Either Event Input
toInput Pretty ColorText
pretty =
  Input -> Either Event Input
forall a b. b -> Either a b
Right (Input -> Either Event Input) -> Input -> Either Event Input
forall a b. (a -> b) -> a -> b
$ Pretty ColorText -> Input
CreateMessage Pretty ColorText
pretty

asciiartUnison :: P.Pretty P.ColorText
asciiartUnison :: Pretty ColorText
asciiartUnison =
  Pretty ColorText -> Pretty ColorText
P.red Pretty ColorText
" _____"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.hiYellow Pretty ColorText
"     _             "
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText
forall s. IsString s => Pretty s
P.newline
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.red Pretty ColorText
"|  |  |"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.hiRed Pretty ColorText
"___"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.hiYellow Pretty ColorText
"|_|"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.hiGreen Pretty ColorText
"___ "
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.cyan Pretty ColorText
"___ "
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.purple Pretty ColorText
"___ "
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText
forall s. IsString s => Pretty s
P.newline
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.red Pretty ColorText
"|  |  |   "
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.hiYellow Pretty ColorText
"| |"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.hiGreen Pretty ColorText
"_ -"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.cyan Pretty ColorText
"| . |"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.purple Pretty ColorText
"   |"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText
forall s. IsString s => Pretty s
P.newline
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.red Pretty ColorText
"|_____|"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.hiRed Pretty ColorText
"_|_"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.hiYellow Pretty ColorText
"|_|"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.hiGreen Pretty ColorText
"___"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.cyan Pretty ColorText
"|___|"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.purple Pretty ColorText
"_|_|"

header :: Text -> P.Pretty P.ColorText
header :: Text -> Pretty ColorText
header Text
version =
  Pretty ColorText
asciiartUnison
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText
forall s. IsString s => Pretty s
P.newline
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText
forall s. IsString s => Pretty s
P.newline
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> [Pretty ColorText] -> Pretty ColorText
forall (f :: * -> *) s.
(Foldable f, IsString s) =>
f (Pretty s) -> Pretty s
P.linesSpaced
      [ Pretty ColorText -> Pretty ColorText
forall s. (ListLike s Char, IsString s) => Pretty s -> Pretty s
P.wrap Pretty ColorText
"👋 Welcome to Unison!",
        Pretty ColorText -> Pretty ColorText
forall s. (ListLike s Char, IsString s) => Pretty s -> Pretty s
P.wrap (Pretty ColorText
"You are running version: " Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.bold (Text -> Pretty ColorText
forall s. IsString s => Text -> Pretty s
P.text Text
version))
      ]

authorSuggestion :: P.Pretty P.ColorText
authorSuggestion :: Pretty ColorText
authorSuggestion =
  Pretty ColorText
forall s. IsString s => Pretty s
P.newline
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> [Pretty ColorText] -> Pretty ColorText
forall (f :: * -> *) s.
(Foldable f, IsString s) =>
f (Pretty s) -> Pretty s
P.lines
      [ Pretty ColorText -> Pretty ColorText
forall s. (ListLike s Char, IsString s) => Pretty s -> Pretty s
P.wrap Pretty ColorText
"📜🪶 You might want to set up your author information next.",
        Pretty ColorText -> Pretty ColorText
forall s. (ListLike s Char, IsString s) => Pretty s -> Pretty s
P.wrap Pretty ColorText
"Type" Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
P.hiBlue Pretty ColorText
" create.author" Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText
" to create an author for this codebase",
        Pretty ColorText -> Pretty ColorText
forall s. Pretty s -> Pretty s
P.group (Pretty ColorText
forall s. IsString s => Pretty s
P.newline Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
forall s. (ListLike s Char, IsString s) => Pretty s -> Pretty s
P.wrap Pretty ColorText
"Read about how to link your author to your code at"),
        Pretty ColorText -> Pretty ColorText
forall s. (ListLike s Char, IsString s) => Pretty s -> Pretty s
P.wrap (Pretty ColorText -> Pretty ColorText)
-> Pretty ColorText -> Pretty ColorText
forall a b. (a -> b) -> a -> b
$ Pretty ColorText -> Pretty ColorText
P.blue Pretty ColorText
"https://www.unison-lang.org/docs/tooling/configuration/"
      ]

getStarted :: Bool -> P.Pretty P.ColorText
getStarted :: Bool -> Pretty ColorText
getStarted Bool
showWelcomeHint =
  Pretty ColorText -> Pretty ColorText
forall s. (ListLike s Char, IsString s) => Pretty s -> Pretty s
P.wrap Pretty ColorText
"📚 Read the official docs at https://www.unison-lang.org/docs/"
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText
forall s. IsString s => Pretty s
P.newline
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText
forall s. IsString s => Pretty s
P.newline
    Pretty ColorText -> Pretty ColorText -> Pretty ColorText
forall a. Semigroup a => a -> a -> a
<> Pretty ColorText -> Pretty ColorText
forall s. (ListLike s Char, IsString s) => Pretty s -> Pretty s
P.wrap
      ( if Bool
showWelcomeHint
          then Pretty ColorText
"Hint: Type 'projects' to list all your projects, or 'project.create' to start something new."
          else Pretty ColorText
"Type 'project.create' to get started."
      )