Skip to content

Commit 37fdcf3

Browse files
committed
Allow to freely intermix GHC flags and Hspec options on the command-line
Don't accept Hspec's `-f <formatter>`, as it collides with GHC flags. Instead, `--format <formatter>` can be used.
1 parent 8e3bf07 commit 37fdcf3

4 files changed

Lines changed: 57 additions & 31 deletions

File tree

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,17 @@ additional GHC options on the command line:
1212

1313
sensei -isrc -itest test/Spec.hs
1414

15-
Command-line arguments that look like Hspec options are passed to Hspec. To
16-
avoid ambiguity, GHC options have to be given before any Hspec options:
15+
Command-line arguments that look like Hspec options are passed to Hspec:
1716

1817
sensei -isrc -itest test/Spec.hs --no-color --match foo
1918

20-
All command-line arguments after the last `--` are passed to Hspec, regardless
21-
of how they look:
19+
Hspec's `-f` option collides with GHC flags. To avoid ambiguity, `sensei` does
20+
not accept Hspec's `-f` option. Use `--format` instead:
21+
22+
sensei -isrc -itest test/Spec.hs --format progress -fdiagnostics-as-json
23+
24+
A `--` disables any command-line processing. All command-line arguments after
25+
the last `--` are unconditionally passed to Hspec:
2226

2327
sensei -isrc -itest test/Spec.hs -- --no-color --match foo
2428

src/Options.hs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,46 @@
11
module Options (splitArgs) where
22

33
import Imports
4+
import Data.Coerce (coerce)
5+
import qualified GHC.List as List
46

57
import System.Console.GetOpt
68

79
splitArgs :: [String] -> ([String], [String])
810
splitArgs args = case break (== "--") $ reverse args of
911
(xs, "--" : ys) -> (reverse ys, reverse xs)
10-
_ -> case filter isHspecArgs $ tails args of
11-
x : _ -> (dropEnd (length x) args, x)
12-
[] -> (args, [])
13-
where
14-
isHspecArgs :: [String] -> Bool
15-
isHspecArgs xs = case getOpt Permute options xs of
16-
(result, [], []) -> all (== Valid) result
17-
_ -> False
12+
_ -> partitionOptions $ classify args
13+
14+
newtype GhcOption = GhcOption [String]
15+
newtype HspecOption = HspecOption [String]
16+
17+
type Option = Either GhcOption HspecOption
18+
19+
ghcOption :: [String] -> Option
20+
ghcOption = Left . GhcOption
21+
22+
hspecOption :: [String] -> Option
23+
hspecOption = Right . HspecOption
24+
25+
partitionOptions :: [Option] -> ([String], [String])
26+
partitionOptions = bimap (List.concat . coerce) (List.concat . coerce) . partitionEithers
27+
28+
classify :: [String] -> [Option]
29+
classify = takeHspec >>> \ case
30+
([], []) -> []
31+
([], ghc : args) -> ghcOption [ghc] : classify args
32+
(hspec, args) -> hspecOption hspec : classify args
33+
34+
takeHspec :: [String] -> ([String], [String])
35+
takeHspec = \ case
36+
a : args | isHspecArgs [a] -> ([a], args)
37+
a : b : args | isHspecArgs [a, b] -> ([a, b], args)
38+
args -> ([], args)
1839

19-
dropEnd :: Int -> [a] -> [a]
20-
dropEnd n = reverse . drop n . reverse
40+
isHspecArgs :: [String] -> Bool
41+
isHspecArgs xs = case getOpt Permute options xs of
42+
(result, [], []) -> all (== Valid) result
43+
_ -> False
2144

2245
data Valid = Valid | Invalid
2346
deriving (Eq, Show)
@@ -52,7 +75,7 @@ options = concat [
5275
, reqArg "" "seed" "N"
5376
, reqArg "" "skip" "PATTERN"
5477
, reqArg "a" "qc-max-success" "N"
55-
, reqArg "f" "format" "NAME"
78+
, reqArg "" "format" "NAME"
5679
, reqArg "m" "match" "PATTERN"
5780
, [Option "p" ["print-slow-items"] (OptArg (maybe Valid intArg) "N") ""]
5881
]

test/Language/Haskell/GhciWrapperSpec.hs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{-# LANGUAGE CPP #-}
2-
module Language.Haskell.GhciWrapperSpec (main, spec) where
2+
module Language.Haskell.GhciWrapperSpec (spec) where
33

44
import Helper hiding (diagnostic, ghciConfig)
55
import qualified Helper
@@ -9,9 +9,6 @@ import qualified Data.ByteString.Char8 as ByteString
99
import Language.Haskell.GhciWrapper (Config(..), Interpreter(..), ReloadStatus(..), Extract(..))
1010
import qualified Language.Haskell.GhciWrapper as Interpreter
1111

12-
main :: IO ()
13-
main = hspec spec
14-
1512
withInterpreter :: [String] -> (Interpreter -> IO a) -> IO a
1613
withInterpreter args action = do
1714
c <- Helper.ghciConfig

test/OptionsSpec.hs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
1-
module OptionsSpec (main, spec) where
1+
module OptionsSpec (spec) where
22

33
import Helper
44

55
import Options
66

7-
main :: IO ()
8-
main = hspec spec
9-
107
spec :: Spec
118
spec = do
12-
describe "splitArgs" $ do
13-
it "returns longest matching list of Hspec options from end of given list" $ do
14-
splitArgs ["foo", "--bar", "-m", "FooSpec", "-a", "1000"] `shouldBe` (["foo", "--bar"], ["-m", "FooSpec", "-a", "1000"])
9+
describe "splitArgs" do
10+
it "passes command-line arguments that look like Hspec options to Hspec" do
11+
splitArgs ["foo", "-m", "FooSpec", "--bar", "-a", "1000"] `shouldBe`
12+
(["foo", "--bar"], ["-m", "FooSpec", "-a", "1000"])
13+
14+
it "passes -f options to GHC" do
15+
splitArgs ["--format", "checks", "-fno-diagnostics-as-json"] `shouldBe`
16+
(["-fno-diagnostics-as-json"], ["--format", "checks"])
1517

16-
it "assumes everything after the last '--' to be Hspec options" $ do
18+
it "assumes everything after the last '--' to be Hspec options" do
1719
splitArgs ["foo", "bar", "--", "foo", "baz"] `shouldBe` (["foo", "bar"], ["foo", "baz"])
1820

19-
context "with -p" $ do
20-
it "recognizes -p as an Hspec option" $ do
21+
context "with -p" do
22+
it "recognizes -p as an Hspec option" do
2123
splitArgs ["-p"] `shouldBe` ([], ["-p"])
2224

23-
it "recognizes -pN as an Hspec option" $ do
25+
it "recognizes -pN as an Hspec option" do
2426
splitArgs ["-p20"] `shouldBe` ([], ["-p20"])
2527

26-
it "recognizes -packageNAME as a GHC option" $ do
28+
it "recognizes -packageNAME as a GHC option" do
2729
splitArgs ["-packagebase"] `shouldBe` (["-packagebase"], [])

0 commit comments

Comments
 (0)