module System.Console.Haskeline.History(
History(),
emptyHistory,
addHistory,
addHistoryUnlessConsecutiveDupe,
addHistoryRemovingAllDupes,
historyLines,
readHistory,
writeHistory,
stifleHistory,
stifleAmount,
) where
import qualified Data.Sequence as Seq
import Data.Sequence ( Seq, (<|), ViewL(..), ViewR(..), viewl, viewr )
import Data.Foldable (toList)
import Control.Exception
import System.Directory(doesFileExist)
import qualified System.IO as IO
import System.Console.Haskeline.Recover
data History = History {History -> Seq [Char]
histLines :: Seq String,
History -> Maybe Int
stifleAmt :: Maybe Int}
stifleAmount :: History -> Maybe Int
stifleAmount :: History -> Maybe Int
stifleAmount = History -> Maybe Int
stifleAmt
instance Show History where
show :: History -> [Char]
show = Seq [Char] -> [Char]
forall a. Show a => a -> [Char]
show (Seq [Char] -> [Char])
-> (History -> Seq [Char]) -> History -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. History -> Seq [Char]
histLines
emptyHistory :: History
emptyHistory :: History
emptyHistory = Seq [Char] -> Maybe Int -> History
History Seq [Char]
forall a. Seq a
Seq.empty Maybe Int
forall a. Maybe a
Nothing
historyLines :: History -> [String]
historyLines :: History -> [[Char]]
historyLines = Seq [Char] -> [[Char]]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Seq [Char] -> [[Char]])
-> (History -> Seq [Char]) -> History -> [[Char]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. History -> Seq [Char]
histLines
readHistory :: FilePath -> IO History
readHistory :: [Char] -> IO History
readHistory [Char]
file = (IOException -> IO History) -> IO History -> IO History
forall e a. Exception e => (e -> IO a) -> IO a -> IO a
handle (\(IOException
_::IOException) -> History -> IO History
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return History
emptyHistory) (IO History -> IO History) -> IO History -> IO History
forall a b. (a -> b) -> a -> b
$ do
exists <- [Char] -> IO Bool
doesFileExist [Char]
file
contents <- if exists
then readUTF8File file
else return ""
_ <- evaluate (length contents)
return History {histLines = Seq.fromList $ lines contents,
stifleAmt = Nothing}
writeHistory :: FilePath -> History -> IO ()
writeHistory :: [Char] -> History -> IO ()
writeHistory [Char]
file = (IOException -> IO ()) -> IO () -> IO ()
forall e a. Exception e => (e -> IO a) -> IO a -> IO a
handle (\(IOException
_::IOException) -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
(IO () -> IO ()) -> (History -> IO ()) -> History -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char] -> IO ()
writeUTF8File [Char]
file
([Char] -> IO ()) -> (History -> [Char]) -> History -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Char]] -> [Char]
unlines ([[Char]] -> [Char]) -> (History -> [[Char]]) -> History -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. History -> [[Char]]
historyLines
stifleHistory :: Maybe Int -> History -> History
stifleHistory :: Maybe Int -> History -> History
stifleHistory Maybe Int
Nothing History
hist = History
hist {stifleAmt = Nothing}
stifleHistory a :: Maybe Int
a@(Just Int
n) History
hist = History {histLines :: Seq [Char]
histLines = Seq [Char] -> Seq [Char]
forall {a}. Seq a -> Seq a
stifleFnc (History -> Seq [Char]
histLines History
hist),
stifleAmt :: Maybe Int
stifleAmt = Maybe Int
a}
where
stifleFnc :: Seq a -> Seq a
stifleFnc = if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Seq [Char] -> Int
forall a. Seq a -> Int
Seq.length (History -> Seq [Char]
histLines History
hist)
then Seq a -> Seq a
forall a. a -> a
id
else [a] -> Seq a
forall a. [a] -> Seq a
Seq.fromList ([a] -> Seq a) -> (Seq a -> [a]) -> Seq a -> Seq a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take Int
n ([a] -> [a]) -> (Seq a -> [a]) -> Seq a -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Seq a -> [a]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList
addHistory :: String -> History -> History
addHistory :: [Char] -> History -> History
addHistory [Char]
s History
h = History
h {histLines = maybeDropLast (stifleAmt h) (s <| (histLines h))}
maybeDropLast :: Maybe Int -> Seq a -> Seq a
maybeDropLast :: forall a. Maybe Int -> Seq a -> Seq a
maybeDropLast Maybe Int
maxAmt Seq a
hs
| Bool
rightSize = Seq a
hs
| Bool
otherwise = case Seq a -> ViewR a
forall a. Seq a -> ViewR a
viewr Seq a
hs of
ViewR a
EmptyR -> Seq a
hs
Seq a
hs' :> a
_ -> Seq a
hs'
where
rightSize :: Bool
rightSize = Bool -> (Int -> Bool) -> Maybe Int -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Seq a -> Int
forall a. Seq a -> Int
Seq.length Seq a
hs) Maybe Int
maxAmt
addHistoryUnlessConsecutiveDupe :: String -> History -> History
addHistoryUnlessConsecutiveDupe :: [Char] -> History -> History
addHistoryUnlessConsecutiveDupe [Char]
h History
hs = case Seq [Char] -> ViewL [Char]
forall a. Seq a -> ViewL a
viewl (History -> Seq [Char]
histLines History
hs) of
[Char]
h1 :< Seq [Char]
_ | [Char]
h[Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
==[Char]
h1 -> History
hs
ViewL [Char]
_ -> [Char] -> History -> History
addHistory [Char]
h History
hs
addHistoryRemovingAllDupes :: String -> History -> History
addHistoryRemovingAllDupes :: [Char] -> History -> History
addHistoryRemovingAllDupes [Char]
h History
hs = [Char] -> History -> History
addHistory [Char]
h History
hs {histLines = filteredHS}
where
filteredHS :: Seq [Char]
filteredHS = [[Char]] -> Seq [Char]
forall a. [a] -> Seq a
Seq.fromList ([[Char]] -> Seq [Char]) -> [[Char]] -> Seq [Char]
forall a b. (a -> b) -> a -> b
$ ([Char] -> Bool) -> [[Char]] -> [[Char]]
forall a. (a -> Bool) -> [a] -> [a]
filter ([Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
/= [Char]
h) ([[Char]] -> [[Char]]) -> [[Char]] -> [[Char]]
forall a b. (a -> b) -> a -> b
$ Seq [Char] -> [[Char]]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Seq [Char] -> [[Char]]) -> Seq [Char] -> [[Char]]
forall a b. (a -> b) -> a -> b
$ History -> Seq [Char]
histLines History
hs
readUTF8File :: FilePath -> IO String
readUTF8File :: [Char] -> IO [Char]
readUTF8File [Char]
file = do
h <- [Char] -> IOMode -> IO Handle
IO.openFile [Char]
file IOMode
IO.ReadMode
IO.hSetEncoding h $ transliterateFailure IO.utf8
IO.hSetNewlineMode h IO.noNewlineTranslation
contents <- IO.hGetContents h
_ <- evaluate (length contents)
IO.hClose h
return contents
writeUTF8File :: FilePath -> String -> IO ()
writeUTF8File :: [Char] -> [Char] -> IO ()
writeUTF8File [Char]
file [Char]
contents = do
h <- [Char] -> IOMode -> IO Handle
IO.openFile [Char]
file IOMode
IO.WriteMode
IO.hSetEncoding h IO.utf8
IO.hSetNewlineMode h IO.noNewlineTranslation
IO.hPutStr h contents
IO.hClose h