XMonad.Util.ExtensibleConf

xmonad-contrib-0.18.1: Community-maintained extensions for xmonad

Copyright | (c) 2021 Tomáš Janoušek <tomi@nomi.cz>
License | BSD3
Maintainer | Tomáš Janoušek <tomi@nomi.cz>
Safe Haskell | None
Language | Haskell2010

XMonad.Util.ExtensibleConf

Contents

- Usage
- High-level idioms based on Semigroup
- High-level idioms based on Default
- Low-level primitivies

Description

Extensible and composable configuration for contrib modules.

This is the configuration counterpart of XMonad.Util.ExtensibleState. It allows contrib modules to store custom configuration values inside `XConfig`. This lets them create custom hooks, ensure they hook into xmonad core only once, and possibly more.

Synopsis

- with :: (MonadReader XConf m, Typeable a, Monoid b) => (a -> m b) -> m b
- add :: forall a (l :: Type -> Type). (Semigroup a, Typeable a) => a -> XConfig l -> XConfig l
- once :: forall a (l :: Type -> Type). (Semigroup a, Typeable a) => (XConfig l -> XConfig l) -> a -> XConfig l -> XConfig l
- onceM :: forall a (l :: Type -> Type) m. (Applicative m, Semigroup a, Typeable a) => (XConfig l -> m (XConfig l)) -> a -> XConfig l -> m (XConfig l)
- withDef :: (MonadReader XConf m, Typeable a, Default a) => (a -> m b) -> m b
- modifyDef :: forall a (l :: Type -> Type). (Default a, Typeable a) => (a -> a) -> XConfig l -> XConfig l
- modifyDefM :: forall a (l :: Type -> Type) m. (Applicative m, Default a, Typeable a) => (a -> m a) -> XConfig l -> m (XConfig l)
- ask :: (MonadReader XConf m, Typeable a) => m (Maybe a)
- lookup :: forall a (l :: Type -> Type). Typeable a => XConfig l -> Maybe a
- alter :: forall a (l :: Type -> Type). Typeable a => (Maybe a -> Maybe a) -> XConfig l -> XConfig l
- alterF :: forall a (l :: Type -> Type) f. (Typeable a, Functor f) => (Maybe a -> f (Maybe a)) -> XConfig l -> f (XConfig l)

# Usage

To utilize this feature in a contrib module, create a data type for the configuration, then use the helper functions provided here to implement a user-friendly composable interface for your contrib module.

Example:

    import qualified XMonad.Util.ExtensibleConf as XC

    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    newtype MyConf = MyConf{ fromMyConf :: [Int] } deriving Semigroup

    customLogger :: Int -> XConfig l -> XConfig l
    customLogger i = XC.once (\c -> c{ logHook = logHook c <> lh }) (MyConf [i])
      where
        lh :: X ()
        lh = XC.with $ io . print . fromMyConf

The above defines an xmonad configuration combinator that can be applied any number of times like so:

    main = xmonad $ … . customLogger 1 . ewmh . customLogger 2 . … $ def{…}

and will always result in just one `print` invocation in `logHook`.

# High-level idioms based on Semigroup

with :: (MonadReader XConf m, Typeable a, Monoid b) => (a -> m b) -> m b #

Run-time: Run a monadic action with the value of the custom configuration, if set.

add #

Arguments

:: forall a (l :: Type -> Type). (Semigroup a, Typeable a) |
=> a | configuration to add
-> XConfig l |
-> XConfig l |

Config-time: Add (append) a piece of custom configuration to an `XConfig` using the `Semigroup` instance of the configuration type.

once #

Arguments

:: forall a (l :: Type -> Type). (Semigroup a, Typeable a) |
=> (XConfig l -> XConfig l) | `XConfig` modification done only once
-> a | configuration to add
-> XConfig l |
-> XConfig l |

Config-time: `add` a piece of custom configuration, and if it's the first piece of this type, also modify the `XConfig` using the provided function.

This can be used to implement a composable interface for modules that must only hook into xmonad core once.

(The piece of custom configuration is the last argument as it's expected to come from the user.)

onceM #

Arguments

:: forall a (l :: Type -> Type) m. (Applicative m, Semigroup a, Typeable a) |
=> (XConfig l -> m (XConfig l)) | `XConfig` modification done only once
-> a | configuration to add
-> XConfig l |
-> m (XConfig l) |

Config-time: Applicative (monadic) variant of `once`, useful if the `XConfig` modification needs to do some `IO` (e.g. create an `IORef`).

# High-level idioms based on Default

withDef :: (MonadReader XConf m, Typeable a, Default a) => (a -> m b) -> m b #

Run-time: Run a monadic action with the value of the custom configuration, or the `Default` value thereof, if absent.

modifyDef #

Arguments

:: forall a (l :: Type -> Type). (Default a, Typeable a) |
=> (a -> a) | modification of configuration
-> XConfig l |
-> XConfig l |

Config-time: Modify a configuration value in `XConfig`, initializing it to its `Default` value first if absent. This is an alternative to `add` for when a `Semigroup` instance is unavailable or unsuitable.

Note that this must not be used together with any variant of `once`!

modifyDefM #

Arguments

:: forall a (l :: Type -> Type) m. (Applicative m, Default a, Typeable a) |
=> (a -> m a) | modification of configuration
-> XConfig l |
-> m (XConfig l) |

Config-time: Applicative (monadic) variant of `modifyDef`, useful if the configuration value modification needs to do some `IO` (e.g. create an `IORef`).

Note that this must not be used together with any variant of `once`!

# Low-level primitivies

ask :: (MonadReader XConf m, Typeable a) => m (Maybe a) #

Run-time: Retrieve a configuration value of the requested type.

lookup :: forall a (l :: Type -> Type). Typeable a => XConfig l -> Maybe a #

Config-time: Retrieve a configuration value of the requested type.

alter :: forall a (l :: Type -> Type). Typeable a => (Maybe a -> Maybe a) -> XConfig l -> XConfig l #

Config-time: Alter a configuration value, or absence thereof.

alterF :: forall a (l :: Type -> Type) f. (Typeable a, Functor f) => (Maybe a -> f (Maybe a)) -> XConfig l -> f (XConfig l) #

Config-time: Functor variant of `alter`, useful if the configuration modifications needs to do some `IO`.