zettelkast-0.1.0.0: app/Main.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeApplications #-}
module Main where
import Options.Generic
import GHC.Generics
(Generic)
import System.Process
import System.Environment
import qualified Data.Text.IO as T
import Data.Maybe
(catMaybes, fromMaybe)
import Data.Path
import Data.Zettel
(readZettel, zettels)
import Data.ZettelGraph
import Data.ZettelID
import Data.ZettelMeta
import Data.ZettelPath
import qualified Data.Set as Set
import Data.Foldable
(for_, traverse_)
import Data.List
(sortOn)
import Data.Traversable
(for)
import Control.Lens
(from, (^.))
import Control.Monad.Trans.Maybe
(MaybeT(..), runMaybeT)
import Data.Time
(getCurrentTime, utctDay)
import System.Directory
(createDirectoryIfMissing, setCurrentDirectory)
data Commands
= New
| Graph
| Open Text
| List
deriving (Show, Generic)
instance ParseRecord Commands
getEditor :: IO FilePath
getEditor = fromMaybe "vim" <$> lookupEnv "EDITOR"
getZettelBase :: IO (Path Root Dir)
getZettelBase = fromPosixPath <$> getEnv "ZETTEL_ROOT"
withZettelRoot :: (ZettelRoot -> IO a) -> IO a
withZettelRoot f = do
zettelBase <- getZettelBase
let path = ZettelRoot zettelBase
createDirectoryIfMissing True (toPosixPath zettelBase)
setCurrentDirectory (toPosixPath zettelBase)
f path
createNew :: ZettelRoot -> IO ()
createNew base = do
editor <- getEditor
nextZettel <- createZettelID <$> (concatSet <$> zettels base) <*> (utctDay <$> getCurrentTime)
for_ nextZettel $ \zid ->
callProcess editor [toPosixPath ((base ^. from _ZettelRoot) ./ toPath zid)]
where
concatSet = Set.foldl' (\acc -> maybe acc (`Set.insert` acc)) Set.empty
open :: ZettelRoot -> Text -> IO ()
open base name = for_ (parse name) $ \zid -> do
editor <- getEditor
callProcess editor [toPosixPath ((base ^. from _ZettelRoot) ./ toPath zid)]
createGraph :: ZettelRoot -> IO ()
createGraph base = do
contents <- dot <$> zettelLinks base
T.putStrLn contents
list :: ZettelRoot -> IO ()
list base = do
zs <- zettels @[] base
meta <- for zs $ \mzid -> runMaybeT $ do
zid <- MaybeT (pure mzid)
zettel <- MaybeT (either (const Nothing) pure <$> readZettel base zid)
MaybeT $ pure $ zettelMeta zid zettel
traverse_ (T.putStrLn . format) . sortOn zettelID . catMaybes $ meta
where
format :: ZettelMeta -> Text
format ZettelMeta{..} = render zettelID <> ":\t\t" <> title
main :: IO ()
main = withZettelRoot $ \base ->
getRecord "zettelkast" >>= \case
New -> createNew base
Graph -> createGraph base
Open name -> open base name
List -> list base