    -----------------------------------------------------------------------------
    -- |
    -- Module      :  XMonad.Prompt.AppendFile
    -- Description :  A prompt for appending a single line of text to a file.
    -- Copyright   :  (c) 2007 Brent Yorgey
    -- License     :  BSD-style (see LICENSE)
    --
    -- Maintainer  :  <byorgey@gmail.com>
    -- Stability   :  stable
    -- Portability :  unportable
    --
    -- A prompt for appending a single line of text to a file.  Useful for
    -- keeping a file of notes, things to remember for later, and so on---
    -- using a keybinding, you can write things down just about as quickly
    -- as you think of them, so it doesn't have to interrupt whatever else
    -- you're doing.
    --
    -- Who knows, it might be useful for other purposes as well!
    --
    -----------------------------------------------------------------------------

    module XMonad.Prompt.AppendFile (
                                     -- * Usage
                                     -- $usage

                                     appendFilePrompt,
                                     appendFilePrompt',
                                     AppendFile,
                                    ) where

    import XMonad.Core
    import XMonad.Prompt
    import XMonad.Prelude (mkAbsolutePath)

    import System.IO

    -- $usage
    --
    -- You can use this module by importing it, along with
    -- "XMonad.Prompt", into your @xmonad.hs@ file:
    --
    -- > import XMonad.Prompt
    -- > import XMonad.Prompt.AppendFile
    --
    -- and adding an appropriate keybinding, for example:
    --
    -- >  , ((modm .|. controlMask, xK_n), appendFilePrompt def "/home/me/NOTES")
    --
    -- Additional notes can be added via regular Haskell or XMonad functions; for
    -- example, to preface notes with the time they were made, one could write a
    -- binding like
    --
    -- > ,  ((modm .|. controlMask, xK_n), do
    -- >            spawn ("date>>"++"/home/me/NOTES")
    -- >            appendFilePrompt def "/home/me/NOTES"
    -- >        )
    --
    -- (Put the spawn on the line after the prompt to append the time instead.)
    --
    -- 'appendFilePrompt'' can be used to transform the string input in the prompt
    -- before saving into the file. Previous example with date can be rewritten as:
    --
    -- > ,  ((modm .|. controlMask, xK_n), do
    -- >            date <- io $ fmap (formatTime defaultTimeLocale "[%Y-%m-%d %H:%M] ") getZonedTime
    -- >            appendFilePrompt' def (date ++) $ "/home/me/NOTES"
    -- >        )
    --
    -- A benefit is that if the prompt is cancelled the date is not output to
    -- the file too.
    --
    -- For detailed instructions on editing your key bindings, see
    -- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.

    newtype AppendFile = AppendFile FilePath

    instance XPrompt AppendFile where
        showXPrompt :: AppendFile -> String
    showXPrompt (AppendFile String
    fn) = String
    "Add to " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    fn String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ": "

    -- | Given an XPrompt configuration and a file path, prompt the user
    --   for a line of text, and append it to the given file.
    appendFilePrompt :: XPConfig -> FilePath -> X ()
    appendFilePrompt :: XPConfig -> String -> X ()
    appendFilePrompt XPConfig
    c = XPConfig -> (String -> String) -> String -> X ()
    appendFilePrompt' XPConfig
    c String -> String
    forall a. a -> a
    id

    -- | Given an XPrompt configuration, string transformation function
    --   and a file path, prompt the user for a line of text, transform it
    --   and append the result to the given file.
    appendFilePrompt' :: XPConfig -> (String -> String) -> FilePath -> X ()
    appendFilePrompt' :: XPConfig -> (String -> String) -> String -> X ()
    appendFilePrompt' XPConfig
    c String -> String
    trans String
    fn = AppendFile -> XPConfig -> ComplFunction -> (String -> X ()) -> X ()
    forall p.
    XPrompt p =>
    p -> XPConfig -> ComplFunction -> (String -> X ()) -> X ()
    mkXPrompt (String -> AppendFile
    AppendFile String
    fn)
                                      XPConfig
    c
                                      (IO [String] -> ComplFunction
    forall a b. a -> b -> a
    const ([String] -> IO [String]
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return []))
                                      ((String -> String) -> String -> String -> X ()
    doAppend String -> String
    trans String
    fn)

    -- | Append a string to a file.
    doAppend :: (String -> String) -> FilePath -> String -> X ()
    doAppend :: (String -> String) -> String -> String -> X ()
    doAppend String -> String
    trans String
    fn String
    s = String -> X String
    forall (m :: * -> *). MonadIO m => String -> m String
    mkAbsolutePath String
    fn X String -> (String -> X ()) -> X ()
    forall a b. X a -> (a -> X b) -> X b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \String
    f -> (IO () -> X ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    io (IO () -> X ()) -> (String -> IO ()) -> String -> X ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> IOMode -> (Handle -> IO ()) -> IO ()
    forall r. String -> IOMode -> (Handle -> IO r) -> IO r
    withFile String
    f IOMode
    AppendMode ((Handle -> IO ()) -> IO ())
    -> (String -> Handle -> IO ()) -> String -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Handle -> String -> IO ()) -> String -> Handle -> IO ()
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Handle -> String -> IO ()
    hPutStrLn (String -> Handle -> IO ())
    -> (String -> String) -> String -> Handle -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> String
    trans) String
    s