Skip to content

Commit 1714e9b

Browse files
committed
Store history in XDG data directory
1 parent 0327595 commit 1714e9b

File tree

4 files changed

+50
-26
lines changed

4 files changed

+50
-26
lines changed

src/Swarm/TUI/Controller.hs

+6-6
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ import Control.Monad.State
5151
import Data.Bits
5252
import Data.Either (isRight)
5353
import Data.Int (Int64)
54-
import Data.Maybe (isJust)
54+
import Data.Maybe (isJust, mapMaybe)
5555
import qualified Data.Set as S
5656
import qualified Data.Text as T
57+
import qualified Data.Text.IO as T
5758
import Linear
5859
import System.Clock
5960
import Witch (into)
@@ -150,16 +151,15 @@ toggleModal s modal = do
150151
-- the updated REPL history to a @.swarm_history@ file.
151152
shutdown :: AppState -> EventM Name (Next AppState)
152153
shutdown s = do
154+
let hist = mapMaybe getNewEntry (s ^. uiState . uiReplHistory)
155+
liftIO $ (`T.appendFile` T.unlines hist) =<< getSwarmHistoryPath True
153156
let s' = s & uiState . uiReplHistory . traverse %~ markOld
154-
hist = filter isEntry (s' ^. uiState . uiReplHistory)
155-
liftIO $ writeFile ".swarm_history" (show hist)
156157
halt s'
157158
where
158159
markOld (REPLEntry _ e) = REPLEntry False e
159160
markOld r = r
160-
161-
isEntry REPLEntry {} = True
162-
isEntry _ = False
161+
getNewEntry (REPLEntry True t) = Just t
162+
getNewEntry _ = Nothing
163163

164164
------------------------------------------------------------
165165
-- Handling Frame events

src/Swarm/TUI/Model.hs

+4-3
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ import Control.Monad.State
8080
import Data.List (findIndex, sortOn)
8181
import Data.Maybe (fromMaybe)
8282
import Data.Text (Text)
83+
import qualified Data.Text as T
8384
import qualified Data.Vector as V
8485
import System.Clock
85-
import Text.Read (readMaybe)
8686

8787
import Brick
8888
import Brick.Focus
@@ -327,14 +327,15 @@ initLgTicksPerSecond = 3 -- 2^3 = 8 ticks / second
327327
-- time.
328328
initUIState :: ExceptT Text IO UIState
329329
initUIState = liftIO $ do
330-
mhist <- (>>= readMaybe @[REPLHistItem]) <$> readFileMay ".swarm_history"
330+
historyT <- readFileMayT =<< getSwarmHistoryPath False
331+
let history = maybe [] (map (REPLEntry False) . reverse . T.lines) historyT
331332
startTime <- getTime Monotonic
332333
return $
333334
UIState
334335
{ _uiFocusRing = initFocusRing
335336
, _uiReplForm = initReplForm
336337
, _uiReplType = Nothing
337-
, _uiReplHistory = mhist ? []
338+
, _uiReplHistory = history
338339
, _uiReplHistIdx = -1
339340
, _uiReplLast = ""
340341
, _uiInventory = Nothing

src/Swarm/Util.hs

+39-17
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,13 @@ module Swarm.Util (
2424
(?),
2525
maxOn,
2626
maximum0,
27-
readFileMay,
2827
cycleEnum,
2928

29+
-- * Directory utilities
30+
readFileMay,
31+
readFileMayT,
32+
getSwarmHistoryPath,
33+
3034
-- * English language utilities
3135
quote,
3236
squote,
@@ -46,20 +50,27 @@ module Swarm.Util (
4650
liftText,
4751
) where
4852

49-
import Control.Monad (unless)
53+
import Control.Monad (unless, when)
5054
import Control.Monad.Error.Class
5155
import Data.Either.Validation
5256
import Data.Int (Int64)
5357
import Data.Maybe (fromMaybe)
5458
import Data.Text (Text)
5559
import qualified Data.Text as T
60+
import qualified Data.Text.IO as T
5661
import Data.Yaml
5762
import Language.Haskell.TH
5863
import Language.Haskell.TH.Syntax (lift)
5964
import Linear (V2)
6065
import qualified NLP.Minimorph.English as MM
6166
import NLP.Minimorph.Util ((<+>))
62-
import System.Directory (doesFileExist)
67+
import System.Directory (
68+
XdgDirectory (XdgData),
69+
createDirectoryIfMissing,
70+
getXdgDirectory,
71+
)
72+
import System.FilePath
73+
import System.IO.Error (catchIOError)
6374

6475
infixr 1 ?
6576

@@ -83,27 +94,38 @@ maximum0 :: (Num a, Ord a) => [a] -> a
8394
maximum0 [] = 0
8495
maximum0 xs = maximum xs
8596

86-
-- | Safely attempt to read a file, returning @Nothing@ if the file
87-
-- does not exist. \"Safely\" should be read in scare quotes here,
88-
-- since /e.g./ we do nothing to guard against the possibility of a
89-
-- race condition where the file is deleted after the existence
90-
-- check but before trying to read it. But it's not like we're
91-
-- worried about security or anything here.
92-
readFileMay :: FilePath -> IO (Maybe String)
93-
readFileMay file = do
94-
b <- doesFileExist file
95-
case b of
96-
False -> return Nothing
97-
True -> Just <$> readFile file
98-
9997
-- | Take the successor of an 'Enum' type, wrapping around when it
10098
-- reaches the end.
10199
cycleEnum :: (Eq e, Enum e, Bounded e) => e -> e
102100
cycleEnum e
103101
| e == maxBound = minBound
104102
| otherwise = succ e
105103

106-
--------------------------------------------------
104+
------------------------------------------------------------
105+
-- Directory stuff
106+
107+
-- | Safely attempt to read a file.
108+
readFileMay :: FilePath -> IO (Maybe String)
109+
readFileMay = catchIO . readFile
110+
111+
-- | Safely attempt to (efficiently) read a file.
112+
readFileMayT :: FilePath -> IO (Maybe Text)
113+
readFileMayT = catchIO . T.readFile
114+
115+
-- | Turns any IO error into Nothing.
116+
catchIO :: IO a -> IO (Maybe a)
117+
catchIO act = (Just <$> act) `catchIOError` (\_ -> return Nothing)
118+
119+
-- | Get path to swarm history, optionally creating necessary
120+
-- directories. This could fail if user has bad permissions
121+
-- on his own $HOME or $XDG_DATA_HOME which is unlikely.
122+
getSwarmHistoryPath :: Bool -> IO FilePath
123+
getSwarmHistoryPath createDirs = do
124+
swarmData <- getXdgDirectory XdgData "swarm"
125+
when createDirs (createDirectoryIfMissing True swarmData)
126+
pure (swarmData </> "history")
127+
128+
------------------------------------------------------------
107129
-- Some language-y stuff
108130

109131
-- | Prepend a noun with the proper indefinite article (\"a\" or \"an\").

swarm.cabal

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ library
9696
containers >= 0.6.2 && < 0.7,
9797
directory >= 1.3 && < 1.4,
9898
either >= 5.0 && < 5.1,
99+
filepath >= 1.4 && < 1.5,
99100
hashable >= 1.3.4 && < 1.4,
100101
megaparsec >= 9.0 && < 9.2,
101102
hsnoise >= 0.0.2 && < 0.1,

0 commit comments

Comments
 (0)