Hello community,

here is the log from the commit of package ghc-xmonad-contrib for 
openSUSE:Factory checked in at 2018-10-25 08:19:36
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-xmonad-contrib (Old)
 and      /work/SRC/openSUSE:Factory/.ghc-xmonad-contrib.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ghc-xmonad-contrib"

Thu Oct 25 08:19:36 2018 rev:2 rq:642908 version:0.15

Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-xmonad-contrib/ghc-xmonad-contrib.changes    
2018-08-04 21:53:49.005323870 +0200
+++ 
/work/SRC/openSUSE:Factory/.ghc-xmonad-contrib.new/ghc-xmonad-contrib.changes   
    2018-10-25 08:19:38.507983800 +0200
@@ -1,0 +2,42 @@
+Thu Oct  4 09:42:58 UTC 2018 - psim...@suse.com
+
+- Update xmonad-contrib to version 0.15.
+  ## unknown
+
+  ## 0.15
+
+  ### Breaking Changes
+
+    * `XMonad.Layout.Groups` & `XMonad.Layout.Groups.Helpers`
+      The layout will no longer perform refreshes inside of its message 
handling.
+      If you have been relying on it to in your xmonad.hs, you will need to 
start
+      sending its messages in a manner that properly handles refreshing, e.g. 
with
+      `sendMessage`.
+
+  ### New Modules
+
+    * `XMonad.Util.Purex`
+
+      Unlike the opaque `IO` actions that `X` actions can wrap, regular reads 
from
+      the `XConf` and modifications to the `XState` are fundamentally pure --
+      contrary to the current treatment of such actions in most xmonad code. 
Pure
+      modifications to the `WindowSet` can be readily composed, but due to the
+      need for those modifications to be properly handled by `windows`, other 
pure
+      changes to the `XState` cannot be interleaved with those changes to the
+      `WindowSet` without superfluous refreshes, hence breaking composability.
+
+      This module aims to rectify that situation by drawing attention to it and
+      providing `PureX`: a pure type with the same monadic interface to state 
as
+      `X`. The `XLike` typeclass enables writing actions generic over the two
+      monads; if pure, existing `X` actions can be generalised with only a 
change
+      to the type signature. Various other utilities are provided, in 
particular
+      the `defile` function which is needed by end-users.
+
+  ### Bug Fixes and Minor Changes
+
+    * Add support for GHC 8.6.1.
+
+    * `XMonad.Actions.MessageHandling`
+      Refresh-performing functions updated to better reflect the new 
`sendMessage`.
+
+-------------------------------------------------------------------
@@ -5 +46,0 @@
-

Old:
----
  xmonad-contrib-0.14.tar.gz

New:
----
  xmonad-contrib-0.15.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ghc-xmonad-contrib.spec ++++++
--- /var/tmp/diff_new_pack.pESICg/_old  2018-10-25 08:19:40.003983137 +0200
+++ /var/tmp/diff_new_pack.pESICg/_new  2018-10-25 08:19:40.007983135 +0200
@@ -12,13 +12,13 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
 
 %global pkg_name xmonad-contrib
 Name:           ghc-%{pkg_name}
-Version:        0.14
+Version:        0.15
 Release:        0
 Summary:        Third party extensions for xmonad
 License:        BSD-3-Clause

++++++ xmonad-contrib-0.14.tar.gz -> xmonad-contrib-0.15.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmonad-contrib-0.14/CHANGES.md 
new/xmonad-contrib-0.15/CHANGES.md
--- old/xmonad-contrib-0.14/CHANGES.md  2018-07-31 15:53:27.000000000 +0200
+++ new/xmonad-contrib-0.15/CHANGES.md  1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +1,43 @@
 # Change Log / Release Notes
 
+## unknown
+
+## 0.15
+
+### Breaking Changes
+
+  * `XMonad.Layout.Groups` & `XMonad.Layout.Groups.Helpers`
+    The layout will no longer perform refreshes inside of its message handling.
+    If you have been relying on it to in your xmonad.hs, you will need to start
+    sending its messages in a manner that properly handles refreshing, e.g. 
with
+    `sendMessage`.
+
+### New Modules
+
+  * `XMonad.Util.Purex`
+
+    Unlike the opaque `IO` actions that `X` actions can wrap, regular reads 
from
+    the `XConf` and modifications to the `XState` are fundamentally pure --
+    contrary to the current treatment of such actions in most xmonad code. Pure
+    modifications to the `WindowSet` can be readily composed, but due to the
+    need for those modifications to be properly handled by `windows`, other 
pure
+    changes to the `XState` cannot be interleaved with those changes to the
+    `WindowSet` without superfluous refreshes, hence breaking composability.
+
+    This module aims to rectify that situation by drawing attention to it and
+    providing `PureX`: a pure type with the same monadic interface to state as
+    `X`. The `XLike` typeclass enables writing actions generic over the two
+    monads; if pure, existing `X` actions can be generalised with only a change
+    to the type signature. Various other utilities are provided, in particular
+    the `defile` function which is needed by end-users.
+
+### Bug Fixes and Minor Changes
+
+  * Add support for GHC 8.6.1.
+
+  * `XMonad.Actions.MessageHandling`
+    Refresh-performing functions updated to better reflect the new 
`sendMessage`.
+
 ## 0.14
 
 ### Breaking Changes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/xmonad-contrib-0.14/XMonad/Actions/MessageFeedback.hs 
new/xmonad-contrib-0.15/XMonad/Actions/MessageFeedback.hs
--- old/xmonad-contrib-0.14/XMonad/Actions/MessageFeedback.hs   2018-07-31 
15:53:27.000000000 +0200
+++ new/xmonad-contrib-0.15/XMonad/Actions/MessageFeedback.hs   1970-01-01 
01:00:00.000000000 +0100
@@ -52,10 +52,10 @@
 import XMonad               ( Window )
 import XMonad.Core          ( X(), Message, SomeMessage(..), LayoutClass(..), 
windowset, catchX, WorkspaceId, Layout, whenJust )
 import XMonad.StackSet      ( Workspace, current, workspace, layout, tag )
-import XMonad.Operations    ( updateLayout, refresh, windows )
+import XMonad.Operations    ( updateLayout, windowBracket, modifyWindowSet )
 
 import Data.Maybe           ( isJust )
-import Control.Monad        ( when, void )
+import Control.Monad        ( void )
 import Control.Monad.State  ( gets )
 import Control.Applicative  ( (<$>), liftA2 )
 
@@ -107,11 +107,11 @@
 -- for efficiency this is pretty much an exact copy of the
 -- 'XMonad.Operations.sendMessage' code - foregoes the O(n) 'updateLayout'.
 sendSomeMessageB :: SomeMessage -> X Bool
-sendSomeMessageB m = do
+sendSomeMessageB m = windowBracket id $ do
     w  <- workspace . current <$> gets windowset
     ml <- handleMessage (layout w) m `catchX` return Nothing
     whenJust ml $ \l ->
-        windows $ \ws -> ws { current = (current ws)
+        modifyWindowSet $ \ws -> ws { current = (current ws)
                                 { workspace = (workspace $ current ws)
                                     { layout = l }}}
     return $ isJust ml
@@ -178,9 +178,9 @@
 -- that would have otherwise used 'XMonad.Operations.sendMessage' while
 -- minimizing refreshes, use this.
 sendSomeMessagesB :: [SomeMessage] -> X [Bool]
-sendSomeMessagesB m
-    =   mapM sendSomeMessageWithNoRefreshToCurrentB m
-    >>= liftA2 (>>) (flip when refresh . or) return
+sendSomeMessagesB
+    = windowBracket or
+    . mapM sendSomeMessageWithNoRefreshToCurrentB
 
 -- | Variant of 'sendSomeMessagesB' that discards the results.
 sendSomeMessages :: [SomeMessage] -> X ()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/xmonad-contrib-0.14/XMonad/Actions/PhysicalScreens.hs 
new/xmonad-contrib-0.15/XMonad/Actions/PhysicalScreens.hs
--- old/xmonad-contrib-0.14/XMonad/Actions/PhysicalScreens.hs   2018-07-31 
15:53:27.000000000 +0200
+++ new/xmonad-contrib-0.15/XMonad/Actions/PhysicalScreens.hs   1970-01-01 
01:00:00.000000000 +0100
@@ -63,7 +63,7 @@
 > --
 > [((modm .|. mask, key), f sc)
 >     | (key, sc) <- zip [xK_w, xK_e, xK_r] [0..]
->     , (f, mask) <- [(viewScreen, 0), (sendToScreen def, shiftMask)]]
+>     , (f, mask) <- [(viewScreen def, 0), (sendToScreen def, shiftMask)]]
 
 For detailed instructions on editing your key bindings, see
 "XMonad.Doc.Extending#Editing_key_bindings".
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmonad-contrib-0.14/XMonad/Hooks/DebugEvents.hs 
new/xmonad-contrib-0.15/XMonad/Hooks/DebugEvents.hs
--- old/xmonad-contrib-0.14/XMonad/Hooks/DebugEvents.hs 2018-07-31 
15:53:27.000000000 +0200
+++ new/xmonad-contrib-0.15/XMonad/Hooks/DebugEvents.hs 1970-01-01 
01:00:00.000000000 +0100
@@ -34,6 +34,7 @@
 import           Control.Monad.State
 import           Control.Monad.Reader
 import           Data.Char                                   (isDigit)
+import           Data.Maybe                                  (fromJust)
 import           Data.List                                   (genericIndex
                                                              ,genericLength
                                                              ,unfoldr
@@ -696,30 +697,31 @@
 dumpString :: Decoder Bool
 dumpString =  do
   fmt <- asks pType
-  [cOMPOUND_TEXT,uTF8_STRING] <- inX $ mapM getAtom 
["COMPOUND_TEXT","UTF8_STRING"]
-  case () of
-    () | fmt == cOMPOUND_TEXT -> guardSize 16 (...)
-       | fmt == sTRING        -> guardSize  8 $ do
-                                   vs <- gets value
-                                   modify (\r -> r {value = []})
-                                   let ss = flip unfoldr (map twiddle vs) $
-                                            \s -> if null s
-                                                  then Nothing
-                                                  else let (w,s'') = break (== 
'\NUL') s
-                                                           s'      = if null 
s''
-                                                                     then s''
-                                                                     else tail 
s''
-                                                        in Just (w,s')
-                                   case ss of
-                                     [s] -> append $ show s
-                                     ss' -> let go (s:ss'') c = append c       
 >>
-                                                                append (show 
s) >>
-                                                                go ss'' ","
-                                                go []       _ = append "]"
-                                             in append "[" >> go ss' ""
-       | fmt == uTF8_STRING   -> dumpUTF -- duplicate type test instead of 
code :)
-       | otherwise            -> (inX $ atomName fmt) >>=
-                                 failure . ("unrecognized string type " ++)
+  x <- inX $ mapM getAtom ["COMPOUND_TEXT","UTF8_STRING"]
+  case x of
+    [cOMPOUND_TEXT,uTF8_STRING] -> case () of
+      () | fmt == cOMPOUND_TEXT -> guardSize 16 (...)
+         | fmt == sTRING        -> guardSize  8 $ do
+                                     vs <- gets value
+                                     modify (\r -> r {value = []})
+                                     let ss = flip unfoldr (map twiddle vs) $
+                                              \s -> if null s
+                                                    then Nothing
+                                                    else let (w,s'') = break 
(== '\NUL') s
+                                                             s'      = if null 
s''
+                                                                       then s''
+                                                                       else 
tail s''
+                                                          in Just (w,s')
+                                     case ss of
+                                       [s] -> append $ show s
+                                       ss' -> let go (s:ss'') c = append c     
   >>
+                                                                  append (show 
s) >>
+                                                                  go ss'' ","
+                                                  go []       _ = append "]"
+                                               in append "[" >> go ss' ""
+         | fmt == uTF8_STRING   -> dumpUTF -- duplicate type test instead of 
code :)
+         | otherwise            -> (inX $ atomName fmt) >>=
+                                   failure . ("unrecognized string type " ++)
 
 -- show who owns a selection
 dumpSelection :: Decoder Bool
@@ -917,7 +919,7 @@
     let w = (length (value sp) - length vs) * 8
     -- now we get to reparse again so we get our copy of it
     put sp
-    Just v <- getInt' w
+    v <- fmap fromJust (getInt' w)
     -- and after all that, we can process the exception list
     dumpExcept' xs that v
 
@@ -1176,20 +1178,23 @@
 -- @@@@@@@@@ evil beyond evil.  there *has* to be a better way
 inhale    :: Int -> Decoder Integer
 inhale  8 =  do
-               [b] <- eat 1
-               return $ fromIntegral b
+               x <- eat 1
+               case x of
+                 [b] -> return $ fromIntegral b
 inhale 16 =  do
-               [b0,b1] <- eat 2
-               io $ allocaArray 2 $ \p -> do
-                 pokeArray p [b0,b1]
-                 [v] <- peekArray 1 (castPtr p :: Ptr Word16)
-                 return $ fromIntegral v
+               x <- eat 2
+               case x of
+                 [b0,b1] -> io $ allocaArray 2 $ \p -> do
+                              pokeArray p [b0,b1]
+                              [v] <- peekArray 1 (castPtr p :: Ptr Word16)
+                              return $ fromIntegral v
 inhale 32 =  do
-               [b0,b1,b2,b3] <- eat 4
-               io $ allocaArray 4 $ \p -> do
-                 pokeArray p [b0,b1,b2,b3]
-                 [v] <- peekArray 1 (castPtr p :: Ptr Word32)
-                 return $ fromIntegral v
+               x <- eat 4
+               case x of
+                 [b0,b1,b2,b3] -> io $ allocaArray 4 $ \p -> do
+                                    pokeArray p [b0,b1,b2,b3]
+                                    [v] <- peekArray 1 (castPtr p :: Ptr 
Word32)
+                                    return $ fromIntegral v
 inhale  b =  error $ "inhale " ++ show b
 
 eat   :: Int -> Decoder Raw
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmonad-contrib-0.14/XMonad/Layout/Fullscreen.hs 
new/xmonad-contrib-0.15/XMonad/Layout/Fullscreen.hs
--- old/xmonad-contrib-0.14/XMonad/Layout/Fullscreen.hs 2018-07-31 
15:53:27.000000000 +0200
+++ new/xmonad-contrib-0.15/XMonad/Layout/Fullscreen.hs 1970-01-01 
01:00:00.000000000 +0100
@@ -30,17 +30,19 @@
     ,FullscreenFloat, FullscreenFocus, FullscreenFull
     ) where
 
-import XMonad
-import XMonad.Layout.LayoutModifier
-import XMonad.Util.WindowProperties
-import XMonad.Hooks.ManageHelpers (isFullscreen)
-import qualified XMonad.StackSet as W
-import Data.List
-import Data.Maybe
-import Data.Monoid
-import qualified Data.Map as M
-import Control.Monad
-import Control.Arrow (second)
+import           XMonad
+import           XMonad.Layout.LayoutModifier
+import           XMonad.Hooks.ManageHelpers     (isFullscreen)
+import           XMonad.Util.WindowProperties
+import qualified XMonad.Util.Rectangle          as R
+import qualified XMonad.StackSet                as W
+
+import           Data.List
+import           Data.Maybe
+import           Data.Monoid
+import qualified Data.Map                       as M
+import           Control.Monad
+import           Control.Arrow                  (second)
 
 -- $usage
 -- Provides a ManageHook and an EventHook that sends layout messages
@@ -107,9 +109,12 @@
     _ -> Nothing
 
   pureModifier (FullscreenFull frect fulls) rect _ list =
-    (map (flip (,) rect') visfulls ++ rest, Nothing)
-    where visfulls = intersect fulls $ map fst list
-          rest = filter (not . (flip elem visfulls `orP` covers rect')) list
+    (visfulls' ++ rest', Nothing)
+    where (visfulls,rest) = partition (flip elem fulls . fst) list
+          visfulls' = map (second $ const rect') visfulls
+          rest' = if null visfulls'
+                  then rest
+                  else filter (not . R.supersetOf rect' . snd) rest
           rect' = scaleRationalRect rect frect
 
 instance LayoutModifier FullscreenFocus Window where
@@ -122,7 +127,7 @@
   pureModifier (FullscreenFocus frect fulls) rect (Just (W.Stack {W.focus = 
f})) list
      | f `elem` fulls = ((f, rect') : rest, Nothing)
      | otherwise = (list, Nothing)
-     where rest = filter (not . ((== f) `orP` covers rect')) list
+     where rest = filter (not . orP (== f) (R.supersetOf rect')) list
            rect' = scaleRationalRect rect frect
   pureModifier _ _ Nothing list = (list, Nothing)
 
@@ -240,15 +245,6 @@
     sendMessageWithNoRefresh FullscreenChanged cw
   idHook
 
--- | True iff one rectangle completely contains another.
-covers :: Rectangle -> Rectangle -> Bool
-(Rectangle x1 y1 w1 h1) `covers` (Rectangle x2 y2 w2 h2) =
-  let fi = fromIntegral
-      in x1 <= x2 &&
-         y1 <= y2 &&
-         x1 + fi w1 >= x2 + fi w2 &&
-         y1 + fi h1 >= y2 + fi h2
-
 -- | Applies a pair of predicates to a pair of operands, combining them with 
||.
 orP :: (a -> Bool) -> (b -> Bool) -> (a, b) -> Bool
 orP f g (x, y) = f x || g y
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmonad-contrib-0.14/XMonad/Layout/Groups/Helpers.hs 
new/xmonad-contrib-0.15/XMonad/Layout/Groups/Helpers.hs
--- old/xmonad-contrib-0.14/XMonad/Layout/Groups/Helpers.hs     2018-07-31 
15:53:27.000000000 +0200
+++ new/xmonad-contrib-0.15/XMonad/Layout/Groups/Helpers.hs     1970-01-01 
01:00:00.000000000 +0100
@@ -45,7 +45,7 @@
 
 import qualified XMonad.Layout.Groups as G
 
-import XMonad.Actions.MessageFeedback
+import XMonad.Actions.MessageFeedback (sendMessageB)
 
 import Control.Monad (unless)
 import qualified Data.Map as M
@@ -92,7 +92,7 @@
 alt f g = alt2 (G.Modify f) $ windows g
 
 alt2 :: G.GroupsMessage -> X () -> X ()
-alt2 m x = do b <- send m
+alt2 m x = do b <- sendMessageB m
               unless b x
 
 -- | Swap the focused window with the previous one
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmonad-contrib-0.14/XMonad/Layout/Groups.hs 
new/xmonad-contrib-0.15/XMonad/Layout/Groups.hs
--- old/xmonad-contrib-0.14/XMonad/Layout/Groups.hs     2018-07-31 
15:53:27.000000000 +0200
+++ new/xmonad-contrib-0.15/XMonad/Layout/Groups.hs     1970-01-01 
01:00:00.000000000 +0100
@@ -61,8 +61,8 @@
 import Data.Maybe (isJust, isNothing, fromMaybe, catMaybes, fromJust)
 import Data.List ((\\))
 import Control.Arrow ((>>>))
-import Control.Applicative ((<$>))
-import Control.Monad (forM)
+import Control.Applicative ((<$>),(<|>),(<$))
+import Control.Monad (forM,void)
 
 -- $usage
 -- This module provides a layout combinator that allows you
@@ -311,12 +311,12 @@
               Just (ToGroup i sm') -> do mg's <- handleOnIndex i sm' z
                                          return $ maybeMakeNew l Nothing mg's
               Just (Modify spec) -> case applySpec spec l of
-                                      Just l' -> refocus l' >> return (Just l')
-                                      Nothing -> return $ Just l
-              Just (ModifyX spec) -> applySpecX spec l >>= \case
-                                      Just l' -> refocus l' >> return (Just l')
-                                      Nothing -> return $ Just l
-              Just Refocus -> refocus l >> return (Just l)
+                                      Just l' -> refocus l'
+                                      Nothing -> return Nothing
+              Just (ModifyX spec) -> do ml' <- applySpecX spec l
+                                        whenJust ml' (void . refocus)
+                                        return (ml' <|> Just l)
+              Just Refocus -> refocus l
               Just _ -> return Nothing
               Nothing -> handleMessage l $ SomeMessage (ToFocused sm)
             where handleOnFocused sm z = mapZM step $ Just z
@@ -343,10 +343,10 @@
 maybeMakeNew _ Nothing ml's | all isNothing ml's = Nothing
 maybeMakeNew g mpart' ml's = justMakeNew g mpart' ml's
 
-refocus :: Groups l l2 Window -> X ()
-refocus g = case getFocusZ $ gZipper $ W.focus $ groups g
-            of Just w -> focus w
-               Nothing -> return ()
+refocus :: Groups l l2 Window -> X (Maybe (Groups l l2 Window))
+refocus g =
+  let mw = (getFocusZ . gZipper . W.focus . groups) g
+  in  g <$ mw <$ whenJust mw (modifyWindowSet . W.focusWindow)
 
 -- ** ModifySpec type
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmonad-contrib-0.14/XMonad/Prompt.hs 
new/xmonad-contrib-0.15/XMonad/Prompt.hs
--- old/xmonad-contrib-0.14/XMonad/Prompt.hs    2018-07-31 15:53:27.000000000 
+0200
+++ new/xmonad-contrib-0.15/XMonad/Prompt.hs    1970-01-01 01:00:00.000000000 
+0100
@@ -1215,7 +1215,7 @@
 -- name satisfies the given predicate.
 historyCompletionP :: (String -> Bool) -> ComplFunction
 historyCompletionP p x = fmap (toComplList . M.filterWithKey (const . p)) 
readHistory
-    where toComplList = deleteConsecutive . filter (isInfixOf x) . M.fold (++) 
[]
+    where toComplList = deleteConsecutive . filter (isInfixOf x) . M.foldr 
(++) []
 
 -- | Sort a list and remove duplicates. Like 'deleteAllDuplicates', but trades 
off
 --   laziness and stability for efficiency.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmonad-contrib-0.14/XMonad/Util/ExtensibleState.hs 
new/xmonad-contrib-0.15/XMonad/Util/ExtensibleState.hs
--- old/xmonad-contrib-0.14/XMonad/Util/ExtensibleState.hs      2018-07-31 
15:53:27.000000000 +0200
+++ new/xmonad-contrib-0.15/XMonad/Util/ExtensibleState.hs      1970-01-01 
01:00:00.000000000 +0100
@@ -27,6 +27,7 @@
 import Data.Typeable (typeOf,cast)
 import qualified Data.Map as M
 import XMonad.Core
+import XMonad.Util.PureX
 import qualified Control.Monad.State as State
 import Data.Maybe (fromMaybe)
 
@@ -75,27 +76,29 @@
 --
 
 -- | Modify the map of state extensions by applying the given function.
-modifyStateExts :: (M.Map String (Either String StateExtension)
-                   -> M.Map String (Either String StateExtension))
-                -> X ()
+modifyStateExts
+  :: XLike m
+  => (M.Map String (Either String StateExtension)
+  -> M.Map String (Either String StateExtension))
+  -> m ()
 modifyStateExts f = State.modify $ \st -> st { extensibleState = f 
(extensibleState st) }
 
 -- | Apply a function to a stored value of the matching type or the initial 
value if there
 -- is none.
-modify :: ExtensionClass a => (a -> a) -> X ()
+modify :: (ExtensionClass a, XLike m) => (a -> a) -> m ()
 modify f = put . f =<< get
 
 -- | Add a value to the extensible state field. A previously stored value with 
the same
 -- type will be overwritten. (More precisely: A value whose string 
representation of its type
 -- is equal to the new one's)
-put :: ExtensionClass a => a -> X ()
+put :: (ExtensionClass a, XLike m) => a -> m ()
 put v = modifyStateExts . M.insert (show . typeOf $ v) . Right . extensionType 
$ v
 
 -- | Try to retrieve a value of the requested type, return an initial value if 
there is no such value.
-get :: ExtensionClass a => X a
+get :: (ExtensionClass a, XLike m) => m a
 get = getState' undefined -- `trick' to avoid needing -XScopedTypeVariables
   where toValue val = maybe initialValue id $ cast val
-        getState' :: ExtensionClass a => a -> X a
+        getState' :: (ExtensionClass a, XLike m) => a -> m a
         getState' k = do
           v <- State.gets $ M.lookup (show . typeOf $ k) . extensibleState
           case v of
@@ -110,14 +113,14 @@
                          [(x,"")] -> Just x
                          _ -> Nothing
 
-gets :: ExtensionClass a => (a -> b) -> X b
+gets :: (ExtensionClass a, XLike m) => (a -> b) -> m b
 gets = flip fmap get
 
 -- | Remove the value from the extensible state field that has the same type 
as the supplied argument
-remove :: ExtensionClass a => a -> X ()
+remove :: (ExtensionClass a, XLike m) => a -> m ()
 remove wit = modifyStateExts $ M.delete (show . typeOf $ wit)
 
-modified :: (ExtensionClass a, Eq a) => (a -> a) -> X Bool
+modified :: (ExtensionClass a, Eq a, XLike m) => (a -> a) -> m Bool
 modified f = do
     v <- get
     case f v of
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmonad-contrib-0.14/XMonad/Util/PureX.hs 
new/xmonad-contrib-0.15/XMonad/Util/PureX.hs
--- old/xmonad-contrib-0.14/XMonad/Util/PureX.hs        1970-01-01 
01:00:00.000000000 +0100
+++ new/xmonad-contrib-0.15/XMonad/Util/PureX.hs        1970-01-01 
01:00:00.000000000 +0100
@@ -0,0 +1,276 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleContexts #-}
+
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  XMonad.Util.PureX
+-- Copyright   :  L. S. Leary 2018
+-- License     :  BSD3-style (see LICENSE)
+--
+-- Maintainer  :  L. S. Leary
+-- Stability   :  unstable
+-- Portability :  not portable
+--
+-- Unlike the opaque @IO@ actions that @X@ actions can wrap, regular reads from
+-- the 'XConf' and modifications to the 'XState' are fundamentally 
pure—contrary
+-- to the current treatment of such actions in most xmonad code. Pure
+-- modifications to the 'WindowSet' can be readily composed, but due to the 
need
+-- for those modifications to be properly handled by 'windows', other pure
+-- changes to the @XState@ cannot be interleaved with those changes to the
+-- @WindowSet@ without superfluous refreshes, hence breaking composability.
+--
+-- This module aims to rectify that situation by drawing attention to it and
+-- providing 'PureX': a pure type with the same monadic interface to state as
+-- @X@. The 'XLike' typeclass enables writing actions generic over the two
+-- monads; if pure, existing @X@ actions can be generalised with only a change
+-- to the type signature. Various other utilities are provided, in particular
+-- the 'defile' function which is needed by end-users.
+--
+-----------------------------------------------------------------------------
+
+-- --< Imports & Exports >-- {{{
+
+module XMonad.Util.PureX (
+  -- * Usage
+  -- $Usage
+  PureX, XLike(..), defile,
+  windowBracket', handlingRefresh,
+  runPureX, toXLike,
+  -- * Utility
+  -- ** Generalised when* functions
+  when', whenM', whenJust',
+  -- ** Infix operators
+  (<?), (&>),
+  -- ** @WindowSet@ operations
+  withWindowSet', withFocii,
+  modify'', modifyWindowSet',
+  getStack, putStack, peek,
+  view, greedyView, invisiView,
+  shift, curScreen, curWorkspace,
+  curTag, curScreenId,
+) where
+
+-- xmonad
+import XMonad
+import qualified XMonad.StackSet as W
+
+-- mtl
+import Control.Monad.State
+import Control.Monad.Reader
+
+-- base
+import Data.Semigroup (Semigroup(..), Any(..))
+import Control.Applicative (liftA2)
+
+-- }}}
+
+-- --< Usage >-- {{{
+
+-- $Usage
+--
+-- The suggested pattern of usage for this module is to write composable, pure
+-- actions as @XLike m => m Any@ or @PureX Any@ values, where the encapsulated
+-- @Any@ value encodes whether or not a refresh is needed to properly institute
+-- changes. These values can then be combined monoidally (i.e. with '<>' AKA
+-- '<+>') or with operators such as '<*', '*>', '<?' and '&>' to build seamless
+-- new actions. The end user can run and handle the effects of the pure actions
+-- in the @X@ monad by applying the @defile@ function, which you may want to
+-- re-export. Alternatively, if an action does not make stackset changes that
+-- need to be handled by @windows@, it can be written with as an
+-- @XLike m => m ()@ and used directly.
+--
+-- Unfortunately since layouts must handle messages in the @X@ monad, this
+-- approach does not quite apply to actions involving them. However a 
relatively
+-- direct translation to impure actions is possible: you can write composable,
+-- refresh-tracking actions as @X Any@ values, making sure to eschew
+-- refresh-inducing functions like @windows@ and @sendMessage@ in favour of
+-- 'modifyWindowSet' and utilities provided by 
"XMonad.Actions.MessageFeedback".
+-- The 'windowBracket_' function recently added to "XMonad.Operations" is the
+-- impure analogue of @defile@. Note that @PureX Any@ actions can be composed
+-- into impure ones after applying 'toX'; don't use @defile@ for this. E.g.
+--
+-- > windowBracket_ (composableImpureAction <> toX composablePureAction)
+--
+-- Although both @X@ and @PureX@ have Monoid instances over monoidal values,
+-- @(XLike m, Monoid a)@ is not enough to infer @Monoid (m a)@ (due to the
+-- open-world assumption). Hence a @Monoid (m Any)@ constraint may need to be
+-- used when working with @XLike m => m Any@ where no context is forcing @m@ to
+-- unify with @X@ or @PureX@. This can also be avoided by working with
+-- @PureX Any@ values and generalising them with 'toXLike' where necessary.
+--
+-- @PureX@ also enables a more monadic style when writing windowset operations;
+-- see the implementation of the utilities in this module for examples.
+-- For an example of a whole module written in terms of this one, see
+-- "XMonad.Hooks.RefocusLast".
+--
+
+-- }}}
+
+-- --< Core >-- {{{
+
+-- | The @PureX@ newtype over @ReaderT XConf (State XState) a@.
+newtype PureX a = PureX (ReaderT XConf (State XState) a)
+  deriving (Functor, Applicative, Monad, MonadReader XConf, MonadState XState)
+
+instance Semigroup a => Semigroup (PureX a) where
+  (<>) = liftA2 (<>)
+
+instance Monoid a => Monoid (PureX a) where
+  mappend = liftA2 mappend
+  mempty  = return mempty
+
+-- | The @XLike@ typeclass over monads reading @XConf@ values and tracking
+--   @XState@ state.
+class (MonadReader XConf m, MonadState XState m) => XLike m where
+  toX :: m a -> X a
+
+instance XLike X where
+  toX = id
+
+instance XLike PureX where
+  toX = toXLike
+
+-- | Consume a @PureX a@.
+runPureX :: PureX a -> XConf -> XState -> (a, XState)
+runPureX (PureX m) = runState . runReaderT m
+
+-- | Despite appearing less general, @PureX a@ is actually isomorphic to
+--   @XLike m => m a@.
+toXLike :: XLike m => PureX a -> m a
+toXLike pa = state =<< runPureX pa <$> ask
+
+-- | A generalisation of 'windowBracket'. Handles refreshing for an action that
+--   __performs no refresh of its own__ but can indicate that it needs one
+--   through a return value that's tested against the supplied predicate. The
+--   action can interleave changes to the @WindowSet@ with @IO@ or changes to
+--   the @XState@.
+windowBracket' :: XLike m => (a -> Bool) -> m a -> X a
+windowBracket' p = windowBracket p . toX
+
+-- | A version of @windowBracket'@ specialised to take a @PureX Any@ action and
+--   handle windowset changes with a refresh when the @Any@ holds @True@.
+--   Analogous to 'windowBracket_'. Don't bake this into your action; it's for
+--   the end-user.
+defile :: PureX Any -> X ()
+defile = void . windowBracket' getAny
+
+-- | A version of @windowBracket@ specialised to take an @X ()@ action and
+--   perform a refresh handling any changes it makes.
+handlingRefresh :: X () -> X ()
+handlingRefresh = windowBracket (\_ -> True)
+
+-- }}}
+
+-- --< Utility >-- {{{
+
+-- | A 'when' that accepts a monoidal return value.
+when' :: (Monad m, Monoid a) => Bool -> m a -> m a
+when' b ma = if b then ma else return mempty
+
+-- | A @whenX@/@whenM@ that accepts a monoidal return value.
+whenM' :: (Monad m, Monoid a) => m Bool -> m a -> m a
+whenM' mb m = when' <$> mb >>= ($ m)
+
+-- | A 'whenJust' that accepts a monoidal return value.
+whenJust' :: (Monad m, Monoid b) => Maybe a -> (a -> m b) -> m b
+whenJust' = flip $ maybe (return mempty)
+
+-- | Akin to @<*@. Discarding the wrapped value in the second argument either
+--   way, keep its effects iff the first argument returns @Any True@.
+(<?) :: Monad m => m Any -> m a -> m Any
+ifthis <? thenthis = do
+  Any b <- ifthis
+  when' b (Any b <$ thenthis)
+infixl 4 <?
+
+-- | Akin to a low precedence @<>@. Combines applicative effects left-to-right
+--   and wrapped @Bool@s with @&&@ (instead of @||@).
+(&>) :: Applicative f => f Any -> f Any -> f Any
+(&>) = liftA2 $ \(Any b1) (Any b2) -> Any (b1 && b2)
+infixl 1 &>
+
+-- | A generalisation of 'withWindowSet'.
+withWindowSet' :: XLike m => (WindowSet -> m a) -> m a
+withWindowSet' = (=<< gets windowset)
+
+-- | If there is a current tag and a focused window, perform an operation with
+--   them, otherwise return mempty.
+withFocii :: (XLike m, Monoid a) => (WorkspaceId -> Window -> m a) -> m a
+withFocii f = join $ (whenJust' <$> peek) <*> (f <$> curTag)
+
+-- | A generalisation of 'modifyWindowSet'.
+modifyWindowSet' :: XLike m => (WindowSet -> WindowSet) -> m ()
+modifyWindowSet' f = modify $ \xs -> xs { windowset = f (windowset xs) }
+
+-- | A variant of @W.modify@ and @W.modify'@ handling the @Nothing@ and @Just@
+--   cases uniformly.
+modify''
+  :: (Maybe (W.Stack a) -> Maybe (W.Stack a))
+  -> (W.StackSet i l a s sd -> W.StackSet i l a s sd)
+modify'' f = W.modify (f Nothing) (f . Just)
+
+-- | Get the stack from the current workspace.
+getStack :: XLike m => m (Maybe (W.Stack Window))
+getStack = W.stack <$> curWorkspace
+
+-- | Set the stack on the current workspace.
+putStack :: XLike m => Maybe (W.Stack Window) -> m ()
+putStack mst = modifyWindowSet' . modify'' $ \_ -> mst
+
+-- | Get the focused window if there is one.
+peek :: XLike m => m (Maybe Window)
+peek = withWindowSet' (return . W.peek)
+
+-- | Get the current screen.
+curScreen
+  :: XLike m
+  => m (W.Screen WorkspaceId (Layout Window) Window ScreenId ScreenDetail)
+curScreen = withWindowSet' (return . W.current)
+
+-- | Get the current workspace.
+curWorkspace :: XLike m => m WindowSpace
+curWorkspace = W.workspace <$> curScreen
+
+-- | Get the current tag.
+curTag :: XLike m => m WorkspaceId
+curTag = W.tag <$> curWorkspace
+
+-- | Get the current @ScreenId@.
+curScreenId :: XLike m => m ScreenId
+curScreenId = W.screen <$> curScreen
+
+-- | Internal. Refresh-tracking logic of view operations.
+viewWith
+  :: XLike m => (WorkspaceId -> WindowSet -> WindowSet) -> WorkspaceId -> m Any
+viewWith viewer tag = do
+  itag <- curTag
+  when' (tag /= itag) $ do
+    modifyWindowSet' (viewer tag)
+    Any . (tag ==) <$> curTag
+
+-- | A version of @W.view@ that tracks the need to refresh.
+view :: XLike m => WorkspaceId -> m Any
+view = viewWith W.view
+
+-- | A version of @W.greedyView@ that tracks the need to refresh.
+greedyView :: XLike m => WorkspaceId -> m Any
+greedyView = viewWith W.greedyView
+
+-- | View a workspace if it's not visible. An alternative to @view@ and
+--   @greedyView@ that—rather than changing the current screen or affecting
+--   another—opts not to act.
+invisiView :: XLike m => WorkspaceId -> m Any
+invisiView = viewWith $ \tag ws ->
+  if   tag `elem` (W.tag . W.workspace <$> W.current ws : W.visible ws)
+  then W.view tag ws
+  else ws
+
+-- | A refresh-tracking version of @W.Shift@.
+shift :: XLike m => WorkspaceId -> m Any
+shift tag = withFocii $ \ctag fw ->
+  when' (tag /= ctag) $ do
+    modifyWindowSet' (W.shiftWin tag fw)
+    mfw' <- peek
+    return (Any $ Just fw /= mfw')
+
+-- }}}
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmonad-contrib-0.14/xmonad-contrib.cabal 
new/xmonad-contrib-0.15/xmonad-contrib.cabal
--- old/xmonad-contrib-0.14/xmonad-contrib.cabal        2018-07-31 
15:53:27.000000000 +0200
+++ new/xmonad-contrib-0.15/xmonad-contrib.cabal        1970-01-01 
01:00:00.000000000 +0100
@@ -1,5 +1,5 @@
 name:               xmonad-contrib
-version:            0.14
+version:            0.15
 homepage:           http://xmonad.org/
 synopsis:           Third party extensions for xmonad
 description:
@@ -36,7 +36,7 @@
 build-type:         Simple
 bug-reports:        https://github.com/xmonad/xmonad-contrib/issues
 
-tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.1, GHC==8.2.2, GHC==8.4.3
+tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.1, GHC==8.2.2, GHC==8.4.3, 
GHC==8.6.1
 
 source-repository head
   type:     git
@@ -54,7 +54,7 @@
 library
     build-depends: base >= 4.5 && < 5,
                    bytestring >= 0.10 && < 0.11,
-                   containers >= 0.5 && < 0.6,
+                   containers >= 0.5 && < 0.7,
                    directory,
                    extensible-exceptions,
                    filepath,
@@ -65,7 +65,7 @@
                    mtl >= 1 && < 3,
                    unix,
                    X11>=1.6.1 && < 1.10,
-                   xmonad>=0.14   && < 0.15,
+                   xmonad >= 0.15 && < 0.16,
                    utf8-string,
                    semigroups
 
@@ -329,6 +329,7 @@
                         XMonad.Util.NoTaskbar
                         XMonad.Util.Paste
                         XMonad.Util.PositionStore
+                        XMonad.Util.PureX
                         XMonad.Util.Rectangle
                         XMonad.Util.RemoteWindows
                         XMonad.Util.Replace


Reply via email to