packages feed

neuron-0.4.0.0: src/app/Neuron/CLI/New.hs

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Neuron.CLI.New
  ( newZettelFile,
  )
where

import qualified Data.Set as Set
import Data.Some
import Data.Text (strip)
import qualified Data.Text as T
import Development.Shake (Action)
import Neuron.CLI.Types
import qualified Neuron.Zettelkasten.Graph as G
import Neuron.Zettelkasten.ID (ZettelID, zettelIDSourceFileName)
import qualified Neuron.Zettelkasten.ID.Scheme as IDScheme
import Neuron.Zettelkasten.Zettel (zettelID)
import Options.Applicative
import Relude
import qualified Rib
import System.FilePath
import qualified System.Posix.Env as Env
import System.Posix.Process

-- | Create a new zettel file and open it in editor if requested
--
-- As well as print the path to the created file.
newZettelFile :: NewCommand -> Action ()
newZettelFile NewCommand {..} = do
  zettels <- G.loadZettels
  mzid <- withSome idScheme $ \scheme -> do
    val <- liftIO $ IDScheme.genVal scheme
    pure $ IDScheme.nextAvailableZettelID (Set.fromList $ fmap zettelID zettels) val scheme
  case mzid of
    Left e -> die $ show e
    Right zid -> do
      path <- zettelPath zid
      liftIO $ do
        fileAction :: FilePath -> IO () <-
          bool (pure showAction) mkEditActionFromEnv edit
        writeFileText path $
          T.intercalate
            "\n"
            [ "---",
              "title: " <> title,
              "date: " <> show day,
              "---",
              "",
              ""
            ]
        fileAction path
  where
    mkEditActionFromEnv :: IO (FilePath -> IO ())
    mkEditActionFromEnv =
      getEnvNonEmpty "EDITOR" >>= \case
        Nothing ->
          die "\n-e option can only be used with EDITOR environment variable set"
        Just editorExe ->
          pure $ editAction editorExe
    editAction editorExe path = do
      -- Show it first in case the editor launch fails
      showAction path
      executeFile editorExe True [path] Nothing
    showAction =
      putStrLn
    getEnvNonEmpty name =
      Env.getEnv name >>= \case
        Nothing -> pure Nothing
        Just (toString . strip . toText -> v) ->
          if null v then pure Nothing else pure (Just v)

zettelPath :: ZettelID -> Action FilePath
zettelPath zid = do
  notesDir <- Rib.ribInputDir
  pure $ notesDir </> zettelIDSourceFileName zid