Skip to content

Commit 0b2597c

Browse files
committed
Fix cabal info parser issue
1 parent 3a68af4 commit 0b2597c

File tree

4 files changed

+363
-14
lines changed

4 files changed

+363
-14
lines changed

haskell-language-server.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ test-suite hls-cabal-plugin-tests
308308
, base
309309
, bytestring
310310
, Cabal-syntax >= 3.7
311+
, containers
311312
, extra
312313
, filepath
313314
, ghcide

plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/CabalInfoParser.hs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ module Ide.Plugin.Cabal.CabalInfoParser (parseCabalInfo, cabalInfo) where
66
import Data.Map.Strict (Map)
77
import Data.Text (Text)
88
import Data.Void (Void)
9-
import Text.Megaparsec (MonadParsec (..), Parsec, chunk, many,
10-
parse, sepBy, single, (<|>))
9+
import Text.Megaparsec (MonadParsec (..), Parsec, chunk, failure,
10+
many, parse, single, (<|>))
1111

12-
import Control.Monad (void)
12+
import Control.Monad (void, when)
1313
import Data.Either.Extra (mapLeft)
1414
import qualified Data.Map.Strict as Map
1515
import qualified Data.Text as T
@@ -21,11 +21,9 @@ parseCabalInfo = mapLeft (T.pack . show) . parse cabalInfo ""
2121

2222
type CabalInfoParserError = Text
2323

24-
-- TODO: parse eof at the end to avoid early exits
2524
cabalInfo :: Parser (Map Text (Map Text [Text]))
2625
cabalInfo = do
27-
entries <- cabalInfoEntry `sepBy` chunk "\n\n"
28-
void $ takeWhileP (Just "trailing whitespace") (`elem` (" \t\r\n" :: String))
26+
entries <- many $ try cabalInfoEntry
2927
eof
3028

3129
pure $ Map.fromList entries
@@ -39,13 +37,18 @@ cabalInfoEntry = do
3937

4038
void restOfLine
4139

42-
pairs <- many $ try kvPair
40+
pairs <- many $ try field
41+
42+
void $ takeWhileP (Just "trailing whitespace") (`elem` (" \t\r\n" :: String))
4343

4444
pure (name, Map.fromList pairs)
4545

46-
kvPair :: Parser (Text, [Text])
47-
kvPair = do
46+
field :: Parser (Text, [Text])
47+
field = do
4848
spacesBeforeKey <- spaces
49+
-- We assume that all fields are indented ==> fail if that ain't so.
50+
when (T.null spacesBeforeKey) $ failure Nothing mempty
51+
4952
key <- takeWhileP (Just "field name") (/= ':')
5053
void $ single ':'
5154
spacesAfterKey <- spaces
Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,39 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
13
module CabalInfoParser (cabalInfoParserUnitTests) where
24

35
import System.FilePath ((</>))
4-
import Test.Hls (TestTree, testCase,
5-
testGroup, (@?))
6+
import Test.Hls (Assertion, TestTree,
7+
assertFailure, testCase,
8+
testGroup, (@=?), (@?))
69
import Utils (testDataDir)
710

811
import qualified Data.Text.IO as TIO
912

1013
import Data.Either (isRight)
1114
import Ide.Plugin.Cabal.CabalInfoParser (parseCabalInfo)
1215

16+
import Data.Map.Strict (Map)
17+
import qualified Data.Map.Strict as Map
18+
import Data.Text (Text)
19+
1320
cabalInfoParserUnitTests :: TestTree
1421
cabalInfoParserUnitTests = testGroup "cabal info Parser Tests"
1522
[ simpleParsingWorks
23+
, simpleMultiEntryParsingWorks
1624
]
1725
where
18-
simpleParsingWorks = testCase "Simple parsing works" $ do
19-
res <- parseCabalInfo <$> TIO.readFile (testDataDir </> "cabal-info" </> "text.cabal-info")
20-
isRight res @? "Failed to parse well-formed input"
26+
simpleParsingWorks =
27+
testCase "Simple parsing works" $ testParserWithFile "text.cabal-info" $ \ci -> do
28+
Map.keys ci @=? ["text"]
29+
30+
simpleMultiEntryParsingWorks =
31+
testCase "Simple parsing works for multiple packages" $ testParserWithFile "containers-base.cabal-info" $ \ci -> do
32+
Map.keys ci @=? ["base", "containers"]
33+
34+
testParserWithFile :: FilePath -> (Map Text (Map Text [Text]) -> Assertion) -> Assertion
35+
testParserWithFile file f = do
36+
res <- parseCabalInfo <$> TIO.readFile (testDataDir </> "cabal-info" </> file)
37+
case res of
38+
Left _ -> assertFailure "Failed to parse well-formed input"
39+
Right ci -> f ci

0 commit comments

Comments
 (0)