diff --git a/System/Console/Haskeline.hs b/System/Console/Haskeline.hs index f42277bc..a1d80f3e 100644 --- a/System/Console/Haskeline.hs +++ b/System/Console/Haskeline.hs @@ -94,6 +94,7 @@ import System.Console.Haskeline.RunCommand import Control.Monad.Catch (MonadMask, handle) import Data.Char (isSpace, isPrint) import Data.Maybe (isJust) +import Control.Monad (when) import System.IO @@ -188,13 +189,18 @@ maybeAddHistory :: forall m . MonadIO m => Maybe String -> InputT m () maybeAddHistory result = do settings :: Settings m <- InputT ask histDupes <- InputT $ asks historyDuplicates + doFlush <- InputT $ asks incAppendHistory case result of Just line | autoAddHistory settings && not (all isSpace line) -> let adder = case histDupes of AlwaysAdd -> addHistory IgnoreConsecutive -> addHistoryUnlessConsecutiveDupe IgnoreAll -> addHistoryRemovingAllDupes - in modifyHistory (adder line) + in do + modifyHistory (adder line) + when doFlush $ case historyFile settings of + Nothing -> pure () + Just f -> liftIO $ appendFile f (line ++ "\n") _ -> return () ---------- diff --git a/System/Console/Haskeline/Command/History.hs b/System/Console/Haskeline/Command/History.hs index f1891f2d..c3e3b40a 100644 --- a/System/Console/Haskeline/Command/History.hs +++ b/System/Console/Haskeline/Command/History.hs @@ -9,6 +9,7 @@ import Data.List import Data.Maybe(fromMaybe) import System.Console.Haskeline.History import Data.IORef +import Control.Monad (when) import Control.Monad.Catch data HistLog = HistLog {pastHistory, futureHistory :: [[Grapheme]]} @@ -28,12 +29,17 @@ histLog :: History -> HistLog histLog hist = HistLog {pastHistory = map stringToGraphemes $ historyLines hist, futureHistory = []} -runHistoryFromFile :: (MonadIO m, MonadMask m) => Maybe FilePath -> Maybe Int - -> ReaderT (IORef History) m a -> m a -runHistoryFromFile Nothing _ f = do +runHistoryFromFile + :: (MonadIO m, MonadMask m) + => Maybe FilePath + -> Maybe Int + -> Bool + -> ReaderT (IORef History) m a + -> m a +runHistoryFromFile Nothing _ _ f = do historyRef <- liftIO $ newIORef emptyHistory runReaderT f historyRef -runHistoryFromFile (Just file) stifleAmt f = do +runHistoryFromFile (Just file) stifleAmt writeHistoryOnExit f = do oldHistory <- liftIO $ readHistory file historyRef <- liftIO $ newIORef $ stifleHistory stifleAmt oldHistory -- Run the action and then write the new history, even on an exception. @@ -41,7 +47,8 @@ runHistoryFromFile (Just file) stifleAmt f = do -- the user's previously-entered commands. -- (Note that this requires using ReaderT (IORef History) instead of StateT. x <- runReaderT f historyRef - `finally` (liftIO $ readIORef historyRef >>= writeHistory file) + `finally` when writeHistoryOnExit + (liftIO $ readIORef historyRef >>= writeHistory file) return x prevHistory, firstHistory :: Save s => s -> HistLog -> (s, HistLog) diff --git a/System/Console/Haskeline/History.hs b/System/Console/Haskeline/History.hs index 3328b033..cc84412e 100644 --- a/System/Console/Haskeline/History.hs +++ b/System/Console/Haskeline/History.hs @@ -62,7 +62,7 @@ readHistory file = handle (\(_::IOException) -> return emptyHistory) $ do then readUTF8File file else return "" _ <- evaluate (length contents) -- force file closed - return History {histLines = Seq.fromList $ lines contents, + return History {histLines = Seq.fromList $ reverse $ lines contents, stifleAmt = Nothing} -- | Writes the line history to the given file. If there is an @@ -70,7 +70,7 @@ readHistory file = handle (\(_::IOException) -> return emptyHistory) $ do writeHistory :: FilePath -> History -> IO () writeHistory file = handle (\(_::IOException) -> return ()) . writeUTF8File file - . unlines . historyLines + . unlines . reverse . historyLines -- | Limit the number of lines stored in the history. stifleHistory :: Maybe Int -> History -> History diff --git a/System/Console/Haskeline/InputT.hs b/System/Console/Haskeline/InputT.hs index d8849b96..3ae2b840 100644 --- a/System/Console/Haskeline/InputT.hs +++ b/System/Console/Haskeline/InputT.hs @@ -181,6 +181,7 @@ execInputT prefs settings run (InputT f) = runReaderT' settings $ runReaderT' prefs $ runKillRing $ runHistoryFromFile (historyFile settings) (maxHistorySize prefs) + (incAppendHistory prefs) $ runReaderT f run -- | Map a user interaction by modifying the base monad computation. diff --git a/System/Console/Haskeline/Prefs.hs b/System/Console/Haskeline/Prefs.hs index 8033a8f8..4b717a52 100644 --- a/System/Console/Haskeline/Prefs.hs +++ b/System/Console/Haskeline/Prefs.hs @@ -48,7 +48,10 @@ data Prefs = Prefs { bellStyle :: !BellStyle, -- presses @TAB@ again. customBindings :: Map.Map Key [Key], -- (termName, keysequence, key) - customKeySequences :: [(Maybe String, String,Key)] + customKeySequences :: [(Maybe String, String,Key)], + incAppendHistory :: Bool + -- ^ If 'True' and @historyFile@ not 'Nothing' + -- flushes command history after every command } deriving Show @@ -77,7 +80,8 @@ defaultPrefs = Prefs {bellStyle = AudibleBell, listCompletionsImmediately = True, historyDuplicates = AlwaysAdd, customBindings = Map.empty, - customKeySequences = [] + customKeySequences = [], + incAppendHistory = False } mkSettor :: Read a => (a -> Prefs -> Prefs) -> String -> Prefs -> Prefs @@ -100,6 +104,7 @@ settors = [("bellstyle", mkSettor $ \x p -> p {bellStyle = x}) ,("historyduplicates", mkSettor $ \x p -> p {historyDuplicates = x}) ,("bind", addCustomBinding) ,("keyseq", addCustomKeySequence) + ,("incappendhistory", mkSettor $ \x p -> p {incAppendHistory = x}) ] addCustomBinding :: String -> Prefs -> Prefs