    -----------------------------------------------------------------------------
    -- |
    -- Module      :  XMonad.Util.Dmenu
    -- Description :  Convenient bindings to dmenu.
    -- Copyright   :  (c) Spencer Janssen <spencerjanssen@gmail.com>
    -- License     :  BSD-style (see LICENSE)
    --
    -- Maintainer  :  Spencer Janssen <spencerjanssen@gmail.com>
    -- Stability   :  unstable
    -- Portability :  unportable
    --
    -- A convenient binding to dmenu.
    --
    -- Requires the process-1.0 package
    --
    -----------------------------------------------------------------------------

    module XMonad.Util.Dmenu (
                    -- * Usage
                    -- $usage
                    dmenu, dmenuXinerama, dmenuMap, menu, menuArgs, menuMap, menuMapArgs
                   ) where

    import XMonad
    import qualified XMonad.StackSet as W
    import qualified Data.Map as M
    import XMonad.Util.Run

    -- $usage
    -- You can use this module with the following in your Config.hs file:
    --
    -- > import XMonad.Util.Dmenu
    --
    -- These functions block xmonad's event loop until dmenu exits; this means that
    -- programs will not be able to open new windows and you will not be able to
    -- change workspaces or input focus until you have responded to the prompt one
    -- way or another.

    -- %import XMonad.Util.Dmenu

    -- | Starts dmenu on the current screen. Requires this patch to dmenu:
    -- <http://www.jcreigh.com/dmenu/dmenu-3.2-xinerama.patch>
    dmenuXinerama :: [String] -> X String
    dmenuXinerama :: [String] -> X String
    dmenuXinerama [String]
    opts = do
        Int
    curscreen <-
          ScreenId -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (ScreenId -> Int)
    -> (StackSet String (Layout Window) Window ScreenId ScreenDetail
        -> ScreenId)
    -> StackSet String (Layout Window) Window ScreenId ScreenDetail
    -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Screen String (Layout Window) Window ScreenId ScreenDetail
    -> ScreenId
    forall i l a sid sd. Screen i l a sid sd -> sid
    W.screen (Screen String (Layout Window) Window ScreenId ScreenDetail
     -> ScreenId)
    -> (StackSet String (Layout Window) Window ScreenId ScreenDetail
        -> Screen String (Layout Window) Window ScreenId ScreenDetail)
    -> StackSet String (Layout Window) Window ScreenId ScreenDetail
    -> ScreenId
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . StackSet String (Layout Window) Window ScreenId ScreenDetail
    -> Screen String (Layout Window) Window ScreenId ScreenDetail
    forall i l a sid sd. StackSet i l a sid sd -> Screen i l a sid sd
    W.current (StackSet String (Layout Window) Window ScreenId ScreenDetail
     -> Int)
    -> X (StackSet String (Layout Window) Window ScreenId ScreenDetail)
    -> X Int
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (XState
     -> StackSet String (Layout Window) Window ScreenId ScreenDetail)
    -> X (StackSet String (Layout Window) Window ScreenId ScreenDetail)
    forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
    gets XState
    -> StackSet String (Layout Window) Window ScreenId ScreenDetail
    windowset :: X Int
        String
    _ <-
          String -> [String] -> String -> X String
    forall (m :: * -> *).
    MonadIO m =>
    String -> [String] -> String -> m String
    runProcessWithInput String
    "dmenu" [String
    "-xs", Int -> String
    forall a. Show a => a -> String
    show (Int
    curscreenInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    1)] ([String] -> String
    unlines [String]
    opts)
        String -> [String] -> [String] -> X String
    forall (m :: * -> *).
    MonadIO m =>
    String -> [String] -> [String] -> m String
    menuArgs String
    "dmenu" [String
    "-xs", Int -> String
    forall a. Show a => a -> String
    show (Int
    curscreenInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    1)] [String]
    opts

    -- | Run dmenu to select an option from a list.
    dmenu :: MonadIO m => [String] -> m String
    dmenu :: forall (m :: * -> *). MonadIO m => [String] -> m String
    dmenu = String -> [String] -> m String
    forall (m :: * -> *). MonadIO m => String -> [String] -> m String
    menu String
    "dmenu"

    -- | like 'dmenu' but also takes the command to run.
    menu :: MonadIO m => String -> [String] -> m String
    menu :: forall (m :: * -> *). MonadIO m => String -> [String] -> m String
    menu String
    menuCmd = String -> [String] -> [String] -> m String
    forall (m :: * -> *).
    MonadIO m =>
    String -> [String] -> [String] -> m String
    menuArgs String
    menuCmd []

    -- | Like 'menu' but also takes a list of command line arguments.
    menuArgs :: MonadIO m => String -> [String] -> [String] -> m String
    menuArgs :: forall (m :: * -> *).
    MonadIO m =>
    String -> [String] -> [String] -> m String
    menuArgs String
    menuCmd [String]
    args [String]
    opts = (Char -> Bool) -> String -> String
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    /=Char
    '\n') (String -> String) -> m String -> m String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$>
      String -> [String] -> String -> m String
    forall (m :: * -> *).
    MonadIO m =>
    String -> [String] -> String -> m String
    runProcessWithInput String
    menuCmd [String]
    args ([String] -> String
    unlines [String]
    opts)

    -- | Like 'dmenuMap' but also takes the command to run.
    menuMap :: MonadIO m => String -> M.Map String a -> m (Maybe a)
    menuMap :: forall (m :: * -> *) a.
    MonadIO m =>
    String -> Map String a -> m (Maybe a)
    menuMap String
    menuCmd = String -> [String] -> Map String a -> m (Maybe a)
    forall (m :: * -> *) a.
    MonadIO m =>
    String -> [String] -> Map String a -> m (Maybe a)
    menuMapArgs String
    menuCmd []

    -- | Like 'menuMap' but also takes a list of command line arguments.
    menuMapArgs :: MonadIO m => String -> [String] -> M.Map String a ->
                   m (Maybe a)
    menuMapArgs :: forall (m :: * -> *) a.
    MonadIO m =>
    String -> [String] -> Map String a -> m (Maybe a)
    menuMapArgs String
    menuCmd [String]
    args Map String a
    selectionMap = do
      String
    selection <- [String] -> m String
    menuFunction (Map String a -> [String]
    forall k a. Map k a -> [k]
    M.keys Map String a
    selectionMap)
      Maybe a -> m (Maybe a)
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe a -> m (Maybe a)) -> Maybe a -> m (Maybe a)
    forall a b. (a -> b) -> a -> b
    $ String -> Map String a -> Maybe a
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup String
    selection Map String a
    selectionMap
          where
            menuFunction :: [String] -> m String
    menuFunction = String -> [String] -> [String] -> m String
    forall (m :: * -> *).
    MonadIO m =>
    String -> [String] -> [String] -> m String
    menuArgs String
    menuCmd [String]
    args

    -- | Run dmenu to select an entry from a map based on the key.
    dmenuMap :: MonadIO m => M.Map String a -> m (Maybe a)
    dmenuMap :: forall (m :: * -> *) a. MonadIO m => Map String a -> m (Maybe a)
    dmenuMap = String -> Map String a -> m (Maybe a)
    forall (m :: * -> *) a.
    MonadIO m =>
    String -> Map String a -> m (Maybe a)
    menuMap String
    "dmenu"