{-# LANGUAGE OverloadedStrings #-}

module Linenoise.Completion
  ( byWord
  )
where

import Data.Text (Text)
import qualified Data.Text as Text

-- | Complete by word.
byWord :: Monad m => (Text -> m [Text]) -> (Text -> m [Text])
byWord :: forall (m :: * -> *).
Monad m =>
(Text -> m [Text]) -> Text -> m [Text]
byWord Text -> m [Text]
f Text
line = do
  let split :: [Text]
split = Text -> [Text]
Text.words Text
line
  case [Text]
split of
    [] -> Text -> m [Text]
f Text
line
    [Text
_] -> Text -> m [Text]
f Text
line
    [Text]
sp -> do
      let (Text
x, [Text]
xs) = ([Text] -> Text
forall a. HasCallStack => [a] -> a
last [Text]
sp, [Text] -> [Text]
forall a. HasCallStack => [a] -> [a]
init [Text]
sp)
      [Text]
res <- Text -> m [Text]
f Text
x
      case [Text]
res of
        [] -> [Text] -> m [Text]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Text
line]
        [Text
y] ->
          [Text] -> m [Text]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [[Text] -> Text
Text.unwords [Text]
xs Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
trimComplete Text
x Text
y Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" "]
        [Text]
ys ->
          [Text] -> m [Text]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((Text -> Text) -> [Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (Text -> [Text] -> Text -> Text
complete Text
x [Text]
xs) [Text]
ys)

complete :: Text -> [Text] -> Text -> Text
complete :: Text -> [Text] -> Text -> Text
complete Text
x [Text]
xs Text
y =
  [Text] -> Text
Text.unwords [Text]
xs Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> Text
trimComplete Text
x Text
y

trimComplete :: Text -> Text -> Text
trimComplete :: Text -> Text -> Text
trimComplete = Int -> Text -> Text
Text.drop (Int -> Text -> Text) -> (Text -> Int) -> Text -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Int
Text.length