module Hoyo.Bookmark (
Bookmark (..)
, Bookmarks (..)
, BookmarkSearchTerm (..)
, formatBookmark
, formatBookmarks
, DefaultBookmark (..)
, getBookmarks
, searchBookmarks
, filterBookmarks
, filterBookmarkByName
, filterBookmarkByDirInfix
, bookmarksFromDefault
, bookmarkCodec
, bookmarksCodec
, defaultBookmarkCodec
, decodeBookmarks
, decodeBookmarksFile
, encodeBookmarks
, encodeBookmarksFile
) where
import Control.Monad (forM, void)
import Control.Monad.Catch
import Control.Monad.IO.Class
import Data.Bifunctor (first)
import Data.Function
import Data.List
import qualified Data.Text as T
import Data.Time
import Hoyo.Internal.Types
import Hoyo.Utils
import Lens.Micro.Extras
import qualified Toml
import Toml (TomlCodec, (.=))
bookmarkCodec :: TomlCodec Bookmark
bookmarkCodec :: TomlCodec Bookmark
bookmarkCodec = FilePath -> Int -> ZonedTime -> Maybe Text -> Bookmark
Bookmark
(FilePath -> Int -> ZonedTime -> Maybe Text -> Bookmark)
-> Codec Bookmark FilePath
-> Codec Bookmark (Int -> ZonedTime -> Maybe Text -> Bookmark)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Key -> TomlCodec FilePath
Toml.string Key
"directory" TomlCodec FilePath
-> (Bookmark -> FilePath) -> Codec Bookmark FilePath
forall field a object.
Codec field a -> (object -> field) -> Codec object a
.= Bookmark -> FilePath
_bookmarkDirectory
Codec Bookmark (Int -> ZonedTime -> Maybe Text -> Bookmark)
-> Codec Bookmark Int
-> Codec Bookmark (ZonedTime -> Maybe Text -> Bookmark)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Key -> TomlCodec Int
Toml.int Key
"index" TomlCodec Int -> (Bookmark -> Int) -> Codec Bookmark Int
forall field a object.
Codec field a -> (object -> field) -> Codec object a
.= Bookmark -> Int
_bookmarkIndex
Codec Bookmark (ZonedTime -> Maybe Text -> Bookmark)
-> Codec Bookmark ZonedTime
-> Codec Bookmark (Maybe Text -> Bookmark)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Key -> TomlCodec ZonedTime
Toml.zonedTime Key
"created" TomlCodec ZonedTime
-> (Bookmark -> ZonedTime) -> Codec Bookmark ZonedTime
forall field a object.
Codec field a -> (object -> field) -> Codec object a
.= Bookmark -> ZonedTime
_bookmarkCreationTime
Codec Bookmark (Maybe Text -> Bookmark)
-> Codec Bookmark (Maybe Text) -> TomlCodec Bookmark
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> TomlCodec Text -> TomlCodec (Maybe Text)
forall a. TomlCodec a -> TomlCodec (Maybe a)
Toml.dioptional (Key -> TomlCodec Text
Toml.text Key
"name") TomlCodec (Maybe Text)
-> (Bookmark -> Maybe Text) -> Codec Bookmark (Maybe Text)
forall field a object.
Codec field a -> (object -> field) -> Codec object a
.= Bookmark -> Maybe Text
_bookmarkName
defaultBookmarkCodec :: TomlCodec DefaultBookmark
defaultBookmarkCodec :: TomlCodec DefaultBookmark
defaultBookmarkCodec = FilePath -> Maybe Text -> DefaultBookmark
DefaultBookmark
(FilePath -> Maybe Text -> DefaultBookmark)
-> Codec DefaultBookmark FilePath
-> Codec DefaultBookmark (Maybe Text -> DefaultBookmark)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Key -> TomlCodec FilePath
Toml.string Key
"directory" TomlCodec FilePath
-> (DefaultBookmark -> FilePath) -> Codec DefaultBookmark FilePath
forall field a object.
Codec field a -> (object -> field) -> Codec object a
.= DefaultBookmark -> FilePath
_defaultBookmarkDirectory
Codec DefaultBookmark (Maybe Text -> DefaultBookmark)
-> Codec DefaultBookmark (Maybe Text) -> TomlCodec DefaultBookmark
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> TomlCodec Text -> TomlCodec (Maybe Text)
forall a. TomlCodec a -> TomlCodec (Maybe a)
Toml.dioptional (Key -> TomlCodec Text
Toml.text Key
"name") TomlCodec (Maybe Text)
-> (DefaultBookmark -> Maybe Text)
-> Codec DefaultBookmark (Maybe Text)
forall field a object.
Codec field a -> (object -> field) -> Codec object a
.= DefaultBookmark -> Maybe Text
_defaultBookmarkName
bookmarksCodec :: TomlCodec Bookmarks
bookmarksCodec :: TomlCodec Bookmarks
bookmarksCodec = TomlCodec [Bookmark] -> TomlCodec Bookmarks
forall b a. Coercible a b => TomlCodec a -> TomlCodec b
Toml.diwrap (TomlCodec Bookmark -> Key -> TomlCodec [Bookmark]
forall a. TomlCodec a -> Key -> TomlCodec [a]
Toml.list TomlCodec Bookmark
bookmarkCodec Key
"bookmark")
decodeBookmarks :: T.Text -> Either HoyoException Bookmarks
decodeBookmarks :: Text -> Either HoyoException Bookmarks
decodeBookmarks = ([TomlDecodeError] -> HoyoException)
-> Either [TomlDecodeError] Bookmarks
-> Either HoyoException Bookmarks
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first ([Text] -> HoyoException
ParseException ([Text] -> HoyoException)
-> ([TomlDecodeError] -> [Text])
-> [TomlDecodeError]
-> HoyoException
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> [Text])
-> ([TomlDecodeError] -> Text) -> [TomlDecodeError] -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [TomlDecodeError] -> Text
Toml.prettyTomlDecodeErrors)
(Either [TomlDecodeError] Bookmarks
-> Either HoyoException Bookmarks)
-> (Text -> Either [TomlDecodeError] Bookmarks)
-> Text
-> Either HoyoException Bookmarks
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TomlCodec Bookmarks -> Text -> Either [TomlDecodeError] Bookmarks
forall a. TomlCodec a -> Text -> Either [TomlDecodeError] a
Toml.decodeExact TomlCodec Bookmarks
bookmarksCodec
decodeBookmarksFile :: (MonadIO m, MonadCatch m) => FilePath -> m (Either HoyoException Bookmarks)
decodeBookmarksFile :: FilePath -> m (Either HoyoException Bookmarks)
decodeBookmarksFile = (IOException -> m (Either HoyoException Bookmarks))
-> m (Either HoyoException Bookmarks)
-> m (Either HoyoException Bookmarks)
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
(e -> m a) -> m a -> m a
handle IOException -> m (Either HoyoException Bookmarks)
forall (m :: * -> *) a.
Monad m =>
IOException -> m (Either HoyoException a)
catchIOException
(m (Either HoyoException Bookmarks)
-> m (Either HoyoException Bookmarks))
-> (FilePath -> m (Either HoyoException Bookmarks))
-> FilePath
-> m (Either HoyoException Bookmarks)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Either [TomlDecodeError] Bookmarks
-> Either HoyoException Bookmarks)
-> m (Either [TomlDecodeError] Bookmarks)
-> m (Either HoyoException Bookmarks)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([TomlDecodeError] -> HoyoException)
-> Either [TomlDecodeError] Bookmarks
-> Either HoyoException Bookmarks
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first ([Text] -> HoyoException
ParseException ([Text] -> HoyoException)
-> ([TomlDecodeError] -> [Text])
-> [TomlDecodeError]
-> HoyoException
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> [Text])
-> ([TomlDecodeError] -> Text) -> [TomlDecodeError] -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [TomlDecodeError] -> Text
Toml.prettyTomlDecodeErrors))
(m (Either [TomlDecodeError] Bookmarks)
-> m (Either HoyoException Bookmarks))
-> (FilePath -> m (Either [TomlDecodeError] Bookmarks))
-> FilePath
-> m (Either HoyoException Bookmarks)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TomlCodec Bookmarks
-> FilePath -> m (Either [TomlDecodeError] Bookmarks)
forall a (m :: * -> *).
MonadIO m =>
TomlCodec a -> FilePath -> m (Either [TomlDecodeError] a)
Toml.decodeFileExact TomlCodec Bookmarks
bookmarksCodec
encodeBookmarks :: Bookmarks -> T.Text
encodeBookmarks :: Bookmarks -> Text
encodeBookmarks = TomlCodec Bookmarks -> Bookmarks -> Text
forall a. TomlCodec a -> a -> Text
Toml.encode TomlCodec Bookmarks
bookmarksCodec
encodeBookmarksFile :: MonadIO m => FilePath -> Bookmarks -> m ()
encodeBookmarksFile :: FilePath -> Bookmarks -> m ()
encodeBookmarksFile FilePath
fp = m Text -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m Text -> m ()) -> (Bookmarks -> m Text) -> Bookmarks -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TomlCodec Bookmarks -> FilePath -> Bookmarks -> m Text
forall a (m :: * -> *).
MonadIO m =>
TomlCodec a -> FilePath -> a -> m Text
Toml.encodeToFile TomlCodec Bookmarks
bookmarksCodec FilePath
fp
searchBookmarks :: BookmarkSearchTerm -> Bookmarks -> ([Bookmark], [Bookmark])
searchBookmarks :: BookmarkSearchTerm -> Bookmarks -> ([Bookmark], [Bookmark])
searchBookmarks (SearchIndex Int
idx) (Bookmarks [Bookmark]
bms) =
(Bookmark -> Bool) -> [Bookmark] -> ([Bookmark], [Bookmark])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition ((Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
idx) (Int -> Bool) -> (Bookmark -> Int) -> Bookmark -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting Int Bookmark Int -> Bookmark -> Int
forall a s. Getting a s a -> s -> a
view Getting Int Bookmark Int
Lens' Bookmark Int
bookmarkIndex) [Bookmark]
bms
searchBookmarks (SearchName Text
name) (Bookmarks [Bookmark]
bms) =
(Bookmark -> Bool) -> [Bookmark] -> ([Bookmark], [Bookmark])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition ((Maybe Text -> Maybe Text -> Bool)
-> (Maybe Text -> Maybe Text) -> Maybe Text -> Maybe Text -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
on Maybe Text -> Maybe Text -> Bool
forall a. Eq a => a -> a -> Bool
(==) ((Text -> Text) -> Maybe Text -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> Text
T.toLower) (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
name) (Maybe Text -> Bool)
-> (Bookmark -> Maybe Text) -> Bookmark -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting (Maybe Text) Bookmark (Maybe Text)
-> Bookmark -> Maybe Text
forall a s. Getting a s a -> s -> a
view Getting (Maybe Text) Bookmark (Maybe Text)
Lens' Bookmark (Maybe Text)
bookmarkName) [Bookmark]
bms
filterBookmarkByName :: Maybe T.Text -> Bookmark -> Bool
filterBookmarkByName :: Maybe Text -> Bookmark -> Bool
filterBookmarkByName Maybe Text
Nothing = Bool -> Bookmark -> Bool
forall a b. a -> b -> a
const Bool
True
filterBookmarkByName (Just Text
name) = (Maybe Text -> Maybe Text -> Bool)
-> (Maybe Text -> Maybe Text) -> Maybe Text -> Maybe Text -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
on Maybe Text -> Maybe Text -> Bool
forall a. Eq a => a -> a -> Bool
(==) ((Text -> Text) -> Maybe Text -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> Text
T.toLower) (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
name) (Maybe Text -> Bool)
-> (Bookmark -> Maybe Text) -> Bookmark -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting (Maybe Text) Bookmark (Maybe Text)
-> Bookmark -> Maybe Text
forall a s. Getting a s a -> s -> a
view Getting (Maybe Text) Bookmark (Maybe Text)
Lens' Bookmark (Maybe Text)
bookmarkName
filterBookmarkByDirInfix :: Maybe T.Text -> Bookmark -> Bool
filterBookmarkByDirInfix :: Maybe Text -> Bookmark -> Bool
filterBookmarkByDirInfix Maybe Text
Nothing = Bool -> Bookmark -> Bool
forall a b. a -> b -> a
const Bool
True
filterBookmarkByDirInfix (Just Text
pref) =
(Text -> Text -> Bool) -> (Text -> Text) -> Text -> Text -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
on Text -> Text -> Bool
T.isInfixOf ((Char -> Bool) -> Text -> Text
T.dropWhileEnd (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'/')) Text
pref (Text -> Bool) -> (Bookmark -> Text) -> Bookmark -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text
T.pack (FilePath -> Text) -> (Bookmark -> FilePath) -> Bookmark -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting FilePath Bookmark FilePath -> Bookmark -> FilePath
forall a s. Getting a s a -> s -> a
view Getting FilePath Bookmark FilePath
Lens' Bookmark FilePath
bookmarkDirectory
filterBookmarks :: Maybe T.Text -> Maybe T.Text -> Bookmark -> Bool
filterBookmarks :: Maybe Text -> Maybe Text -> Bookmark -> Bool
filterBookmarks Maybe Text
name Maybe Text
dirInfix Bookmark
bm = Maybe Text -> Bookmark -> Bool
filterBookmarkByName Maybe Text
name Bookmark
bm
Bool -> Bool -> Bool
&& Maybe Text -> Bookmark -> Bool
filterBookmarkByDirInfix Maybe Text
dirInfix Bookmark
bm
bookmarksFromDefault :: MonadIO m => [DefaultBookmark] -> m Bookmarks
bookmarksFromDefault :: [DefaultBookmark] -> m Bookmarks
bookmarksFromDefault [DefaultBookmark]
dbms = [Bookmark] -> Bookmarks
Bookmarks ([Bookmark] -> Bookmarks) -> m [Bookmark] -> m Bookmarks
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m [Bookmark]
bms
where
bms :: m [Bookmark]
bms = [(DefaultBookmark, Int)]
-> ((DefaultBookmark, Int) -> m Bookmark) -> m [Bookmark]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM ([DefaultBookmark] -> [Int] -> [(DefaultBookmark, Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip [DefaultBookmark]
dbms [Int
1..]) (((DefaultBookmark, Int) -> m Bookmark) -> m [Bookmark])
-> ((DefaultBookmark, Int) -> m Bookmark) -> m [Bookmark]
forall a b. (a -> b) -> a -> b
$ \(DefaultBookmark FilePath
dir Maybe Text
name, Int
idx) -> do
ZonedTime
zTime <- IO ZonedTime -> m ZonedTime
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO ZonedTime
getZonedTime
Bookmark -> m Bookmark
forall (m :: * -> *) a. Monad m => a -> m a
return (Bookmark -> m Bookmark) -> Bookmark -> m Bookmark
forall a b. (a -> b) -> a -> b
$ FilePath -> Int -> ZonedTime -> Maybe Text -> Bookmark
Bookmark FilePath
dir Int
idx ZonedTime
zTime Maybe Text
name
getBookmarks :: HoyoMonad Bookmarks
getBookmarks :: HoyoMonad Bookmarks
getBookmarks = SimpleGetter Env Bookmarks -> HoyoMonad Bookmarks
forall a (m :: * -> *) b.
MonadReader a m =>
SimpleGetter a b -> m b
asks' SimpleGetter Env Bookmarks
Lens' Env Bookmarks
bookmarks