mirror of
https://github.com/swarm-game/swarm.git
synced 2024-09-11 22:58:21 +03:00
This is a followup on top of #1583 which turns `swarm format` into a tool for porting existing Swarm code into the newest syntax, via an extra `--v0.5` argument. In particular, this PR: - Generalizes the parser to take a configuration record, which among other things contains the language version being parsed. - Adds code to allow the parser to parse either the current syntax or one version ago (when types did not start with capital letter) depending on the version in the configuration. - The idea is to have the parser always support the current version and one older version, so we can always upgrade version n to version n+1. - Adds a new flag `--v0.5` to the `format` subcommand which causes the input to be parsed in v0.5 mode. However, the output of `format` will always use the latest syntax. Thus, `swarm format --v0.5` reads code in v0.5 format and prints it in the latest format, so this can be used to automatically port existing `.sw` files. This PR also makes a few minor improvements to pretty-printing.
136 lines
4.8 KiB
Haskell
136 lines
4.8 KiB
Haskell
{-# LANGUAGE LambdaCase #-}
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
{-# LANGUAGE TemplateHaskell #-}
|
|
|
|
-- |
|
|
-- SPDX-License-Identifier: BSD-3-Clause
|
|
module Main where
|
|
|
|
import Data.Foldable qualified
|
|
import GitHash (GitInfo, giBranch, giHash, tGitInfoCwdTry)
|
|
import Options.Applicative
|
|
import Swarm.App (appMain)
|
|
import Swarm.Language.Format
|
|
import Swarm.Language.LSP (lspMain)
|
|
import Swarm.Language.Parser.Core (LanguageVersion (..))
|
|
import Swarm.TUI.Model (AppOpts (..), ColorMode (..))
|
|
import Swarm.TUI.Model.UI (defaultInitLgTicksPerSecond)
|
|
import Swarm.Version
|
|
import Swarm.Web (defaultPort)
|
|
import System.IO (hPrint, stderr)
|
|
import Text.Read (readMaybe)
|
|
|
|
gitInfo :: Maybe GitInfo
|
|
gitInfo = either (const Nothing) Just $$tGitInfoCwdTry
|
|
|
|
commitInfo :: String
|
|
commitInfo = case gitInfo of
|
|
Nothing -> ""
|
|
Just git -> " (" <> giBranch git <> "@" <> take 10 (giHash git) <> ")"
|
|
|
|
data CLI
|
|
= Run AppOpts
|
|
| Format FormatConfig
|
|
| LSP
|
|
| Version
|
|
|
|
cliParser :: Parser CLI
|
|
cliParser =
|
|
subparser
|
|
( mconcat
|
|
[ command "format" (info (Format <$> parseFormat) (progDesc "Format a file"))
|
|
, command "lsp" (info (pure LSP) (progDesc "Start the LSP"))
|
|
, command "version" (info (pure Version) (progDesc "Get current and upstream version."))
|
|
]
|
|
)
|
|
<|> Run
|
|
<$> ( AppOpts
|
|
<$> seed
|
|
<*> scenario
|
|
<*> run
|
|
<*> autoplay
|
|
<*> speedFactor
|
|
<*> cheat
|
|
<*> color
|
|
<*> webPort
|
|
<*> pure gitInfo
|
|
)
|
|
where
|
|
input :: Parser FormatInput
|
|
input =
|
|
flag' Stdin (long "stdin" <> help "Read code from stdin")
|
|
<|> (InputFile <$> strArgument (metavar "FILE"))
|
|
|
|
output :: Parser FormatOutput
|
|
output =
|
|
flag Stdout Stdout (long "stdout" <> help "Write formatted code to stdout (default)")
|
|
<|> (OutputFile <$> strOption (long "output" <> short 'o' <> metavar "FILE" <> help "Write formatted code to an output file"))
|
|
<|> flag' Inplace (long "inplace" <> short 'i' <> help "Format file in place")
|
|
|
|
widthOpt :: Parser FormatWidth
|
|
widthOpt = option auto (long "width" <> metavar "COLUMNS" <> help "Use layout with maximum width")
|
|
|
|
langVer :: Parser LanguageVersion
|
|
langVer = flag SwarmLangLatest SwarmLang0_5 (long "v0.5" <> help "Read (& convert) code from Swarm version 0.5")
|
|
|
|
parseFormat :: Parser FormatConfig
|
|
parseFormat = FormatConfig <$> input <*> output <*> optional widthOpt <*> langVer <**> helper
|
|
|
|
seed :: Parser (Maybe Int)
|
|
seed = optional $ option auto (long "seed" <> short 's' <> metavar "INT" <> help "Seed to use for world generation")
|
|
|
|
webPort :: Parser (Maybe Int)
|
|
webPort =
|
|
optional $
|
|
option
|
|
auto
|
|
( long "web"
|
|
<> metavar "PORT"
|
|
<> help ("Set the web service port (or disable it with 0). Default to " <> show defaultPort <> ".")
|
|
)
|
|
scenario :: Parser (Maybe String)
|
|
scenario = optional $ strOption (long "scenario" <> short 'i' <> metavar "FILE" <> help "Name of an input scenario to load")
|
|
run :: Parser (Maybe String)
|
|
run = optional $ strOption (long "run" <> short 'r' <> metavar "FILE" <> help "Run the commands in a file at startup")
|
|
autoplay :: Parser Bool
|
|
autoplay = switch (long "autoplay" <> short 'a' <> help "Automatically run the solution defined in the scenario, if there is one. Mutually exclusive with --run.")
|
|
speedFactor :: Parser Int
|
|
speedFactor = option auto (long "speed" <> short 'm' <> value defaultInitLgTicksPerSecond <> help "Initial game speed multiplier")
|
|
cheat :: Parser Bool
|
|
cheat = switch (long "cheat" <> short 'x' <> help "Enable cheat mode. This allows toggling Creative Mode with Ctrl+v and unlocks \"Testing\" scenarios in the menu.")
|
|
color :: Parser (Maybe ColorMode)
|
|
color = optional $ option colorModeParser (long "color" <> short 'c' <> metavar "MODE" <> help "Use none/8/16/full color mode.")
|
|
colorModeParser =
|
|
Data.Foldable.asum
|
|
[ ColorMode8 <$ text "8"
|
|
, ColorMode16 <$ text "16"
|
|
, ColorMode240 <$> maybeReader (\case ('2' : '4' : '0' : '_' : w) -> readMaybe w; _ -> Nothing)
|
|
, FullColor <$ text "full"
|
|
, NoColor <$ text "none"
|
|
]
|
|
text t = maybeReader (\x -> if x == t then Just x else Nothing)
|
|
|
|
cliInfo :: ParserInfo CLI
|
|
cliInfo =
|
|
info
|
|
(cliParser <**> helper)
|
|
( header ("Swarm game - " <> version <> commitInfo)
|
|
<> progDesc "To play the game simply run without any command."
|
|
<> fullDesc
|
|
)
|
|
|
|
showVersion :: IO ()
|
|
showVersion = do
|
|
putStrLn $ "Swarm game - " <> version <> commitInfo
|
|
up <- getNewerReleaseVersion gitInfo
|
|
either (hPrint stderr) (putStrLn . ("New upstream release: " <>)) up
|
|
|
|
main :: IO ()
|
|
main = do
|
|
cli <- execParser cliInfo
|
|
case cli of
|
|
Run opts -> appMain opts
|
|
Format cfg -> formatSwarmIO cfg
|
|
LSP -> lspMain
|
|
Version -> showVersion
|