    {- |
    Module      :  XMonad.Actions.Launcher
    Description :  A set of prompts for XMonad.
    Copyright   :  (C) 2012 Carlos López-Camey
    License     :  None; public domain

    Maintainer  :  <c.lopez@kmels.net>
    Stability   :  unstable

    A set of prompts for XMonad
    -}

    module XMonad.Actions.Launcher(
      -- * Description and use
      -- $description
      defaultLauncherModes
      , ExtensionActions
      , LauncherConfig(..)
      , launcherPrompt
    ) where

    import qualified Data.Map        as M
    import           XMonad          hiding (config)
    import           XMonad.Prelude
    import           XMonad.Prompt
    import           XMonad.Util.Run

    {- $description
        This module exemplifies usage of `XMonad.Prompt.mkXPromptWithModes`. It includes two modes:

           * Hoogle mode: Search for functions using hoogle, choosing a function leads you to documentation in Haddock.

           * Calc: Uses the program calc to do calculations.

        To test it, modify your local .xmonad:

        > import XMonad.Prompt(def)
        > import XMonad.Actions.Launcher

        > ((modm .|. controlMask, xK_l), launcherPrompt def $ defaultLauncherModes launcherConfig)

        A LauncherConfig contains settings for the default modes, modify them accordingly.

        > launcherConfig = LauncherConfig { pathToHoogle = "/home/YOU/.cabal/bin/hoogle" , browser = "firefox"}

    Restart xmonad. Press Ctrl + Your_Modkey + L and the first prompt should pop up.

     If you used the default 'XPConfig', you can change mode with 'xK_grave'. If you are using your own 'XPConfig', define the value for 'changeModeKey'.
     -}

    data HoogleMode = HMode FilePath String --path to hoogle and browser
    data CalculatorMode = CalcMode

    data LauncherConfig = LauncherConfig {
      LauncherConfig -> String
    browser        :: String
      , LauncherConfig -> String
    pathToHoogle :: String
    }

    type ExtensionActions = M.Map String (String -> X())

    -- | Uses the command `calc` to compute arithmetic expressions
    instance XPrompt CalculatorMode where
      showXPrompt :: CalculatorMode -> String
    showXPrompt CalculatorMode
    CalcMode = String
    "calc %s> "
      commandToComplete :: CalculatorMode -> String -> String
    commandToComplete CalculatorMode
    CalcMode = String -> String
    forall a. a -> a
    id --send the whole string to `calc`
      completionFunction :: CalculatorMode -> ComplFunction
    completionFunction CalculatorMode
    CalcMode String
    s = if String -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    s then [String] -> IO [String]
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return [] else
        String -> [String]
    lines (String -> [String]) -> IO String -> IO [String]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> [String] -> String -> IO String
    forall (m :: * -> *).
    MonadIO m =>
    String -> [String] -> String -> m String
    runProcessWithInput String
    "calc" [String
    s] String
    ""
      modeAction :: CalculatorMode -> String -> String -> X ()
    modeAction CalculatorMode
    CalcMode String
    _ String
    _ = () -> X ()
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return () -- do nothing; this might copy the result to the clipboard

    -- | Uses the program `hoogle` to search for functions
    instance XPrompt HoogleMode where
      showXPrompt :: HoogleMode -> String
    showXPrompt HoogleMode
    _ = String
    "hoogle %s> "
      commandToComplete :: HoogleMode -> String -> String
    commandToComplete HoogleMode
    _ = String -> String
    forall a. a -> a
    id
      completionFunction :: HoogleMode -> ComplFunction
    completionFunction (HMode String
    pathToHoogleBin' String
    _) String
    s = String -> [String] -> IO [String]
    completionFunctionWith String
    pathToHoogleBin' [String
    "--count",String
    "8",String
    s]
      -- This action calls hoogle again to find the URL corresponding to the autocompleted item
      modeAction :: HoogleMode -> String -> String -> X ()
    modeAction (HMode String
    pathToHoogleBin'' String
    browser') String
    query String
    result = do
        completionsWithLink <- IO [String] -> X [String]
    forall a. IO a -> X a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO [String] -> X [String]) -> IO [String] -> X [String]
    forall a b. (a -> b) -> a -> b
    $ String -> [String] -> IO [String]
    completionFunctionWith String
    pathToHoogleBin'' [String
    "--count",String
    "5",String
    "--link",String
    query]
        let link = do
              s <- (String -> Bool) -> [String] -> Maybe String
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
    find (Maybe Int -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe Int -> Bool) -> (String -> Maybe Int) -> String -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . \String
    complStr -> String -> String -> Maybe Int
    forall a. Eq a => [a] -> [a] -> Maybe Int
    findSeqIndex String
    complStr String
    result) [String]
    completionsWithLink
              i <- findSeqIndex s "http://"
              return $ drop i s
        case link of
           Just String
    l -> String -> X ()
    forall (m :: * -> *). MonadIO m => String -> m ()
    spawn (String -> X ()) -> String -> X ()
    forall a b. (a -> b) -> a -> b
    $ String
    browser' String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    l
           Maybe String
    _      -> () -> X ()
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
        where
          -- | Receives a sublist and a list. It returns the index where the sublist appears in the list.
          findSeqIndex :: (Eq a) => [a] -> [a] -> Maybe Int
          findSeqIndex :: forall a. Eq a => [a] -> [a] -> Maybe Int
    findSeqIndex [a]
    xs [a]
    xss = ([a] -> Bool) -> [[a]] -> Maybe Int
    forall a. (a -> Bool) -> [a] -> Maybe Int
    findIndex ([a] -> [a] -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    isPrefixOf [a]
    xss) ([[a]] -> Maybe Int) -> [[a]] -> Maybe Int
    forall a b. (a -> b) -> a -> b
    $ [a] -> [[a]]
    forall a. [a] -> [[a]]
    tails [a]
    xs

    -- | Creates an autocompletion function for a programm given the program's name and a list of args to send to the command.
    completionFunctionWith :: String -> [String] -> IO [String]
    completionFunctionWith :: String -> [String] -> IO [String]
    completionFunctionWith String
    cmd [String]
    args = String -> [String]
    lines (String -> [String]) -> IO String -> IO [String]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> [String] -> String -> IO String
    forall (m :: * -> *).
    MonadIO m =>
    String -> [String] -> String -> m String
    runProcessWithInput String
    cmd [String]
    args String
    ""

    -- | Creates a prompt with the given modes
    launcherPrompt :: XPConfig -> [XPMode] -> X()
    launcherPrompt :: XPConfig -> [XPMode] -> X ()
    launcherPrompt XPConfig
    config [XPMode]
    modes = [XPMode] -> XPConfig -> X ()
    mkXPromptWithModes [XPMode]
    modes XPConfig
    config

    -- | Create a list of modes based on :
    -- a list of extensions mapped to actions
    -- the path to hoogle
    defaultLauncherModes :: LauncherConfig -> [XPMode]
    defaultLauncherModes :: LauncherConfig -> [XPMode]
    defaultLauncherModes LauncherConfig
    cnf = let
      ph :: String
    ph           = LauncherConfig -> String
    pathToHoogle LauncherConfig
    cnf
      in [ String -> String -> XPMode
    hoogleMode String
    ph (String -> XPMode) -> String -> XPMode
    forall a b. (a -> b) -> a -> b
    $ LauncherConfig -> String
    browser LauncherConfig
    cnf
         , XPMode
    calcMode]

    hoogleMode :: FilePath -> String -> XPMode
    hoogleMode :: String -> String -> XPMode
    hoogleMode String
    pathToHoogleBin String
    browser' = HoogleMode -> XPMode
    forall p. XPrompt p => p -> XPMode
    XPT (HoogleMode -> XPMode) -> HoogleMode -> XPMode
    forall a b. (a -> b) -> a -> b
    $ String -> String -> HoogleMode
    HMode String
    pathToHoogleBin String
    browser'
    calcMode :: XPMode
    calcMode :: XPMode
    calcMode = CalculatorMode -> XPMode
    forall p. XPrompt p => p -> XPMode
    XPT CalculatorMode
    CalcMode

    {-

      -- ideas for XMonad.Prompt running on mode XPMultipleModes
         * Switch to mode by name of the prompt, 1. ':' at an empty(?) buffer, 2. autocomplete name in buffer should happen, 3. switch to mode with enter (cancel switch with C-g)

         * Support for actions of type String -> X a

      -- ideas for this module

         * Hoogle mode: add a setting in the action to either go to documentation or to the source code (needs hoogle change?)

         * Hoogle mode: add setting to query hoogle at haskell.org instead (with &mode=json)
    -}