packages feed

ghcitui-0.2.0.0: lib/ghcitui-core/Ghcitui/Ghcid/ParseTabCompletions.hs

{-# LANGUAGE QuasiQuotes #-}

module Ghcitui.Ghcid.ParseTabCompletions (ParseError (..), parseCompletionsWithHeader) where

import Control.Error (readMay)
import Data.Array ((!))
import Data.String.Interpolate (i)
import qualified Data.Text as T
import Text.Regex.TDFA (MatchResult (..), (=~~))

import Ghcitui.Ghcid.ParseError (ParseError (..)) -- Re-export.

{- | Parse a completion result which begins with a header.

    Example input:
    [ "4 4 \"hello \""
    , "\"world\""
    , "\"wyvern\""
    , "\"withers\""
    , "\"wonderbolts\""]

    See https://downloads.haskell.org/ghc/latest/docs/users_guide/ghci.html#ghci-cmd-:complete
-}
parseCompletionsWithHeader
    :: [T.Text]
    -- ^ Full :complete output to parse.
    -> Either ParseError (T.Text, [T.Text])
    -- ^ Failure message (Left) or Completion possibilities (Right)
parseCompletionsWithHeader (headerLine : rest) = do
    sharedPrefix <- eSharedPrefix
    completions <- parseCompletions rest
    pure (sharedPrefix, completions)
  where
    eSharedPrefix = case (headerLine =~~ reg :: Maybe (MatchResult T.Text)) of
        Just match -> Right (mrSubs match ! 1)
        Nothing -> Left $ ParseError [i|Failed to parse ':complete' header line: '#{headerLine}'|]
    reg = ".* \"(.*)\"$" :: T.Text
parseCompletionsWithHeader _ = Left $ ParseError "Failed to parse completions with no header line"

parseCompletions
    :: [T.Text]
    -- ^ Completion lines.
    -> Either ParseError [T.Text]
    -- ^ Completion possibilities.
parseCompletions = mapM mapper
  where
    mapper x =
        maybe
            (Left $ ParseError [i|Failed to parse ':completion' entry '#{x}'|])
            (Right . T.pack)
            (readMay . T.unpack $ x)