-----------------------------------------------------------------------------
-- |
-- Module      :  XMonad.Actions.SwapWorkspaces
-- Description :  Swap workspace tags without having to move individual windows.
-- Copyright   :  (c) Devin Mullins <me@twifkak.com>
-- License     :  BSD3-style (see LICENSE)
--
-- Maintainer  :  Devin Mullins <me@twifkak.com>
-- Stability   :  unstable
-- Portability :  unportable
--
-- Lets you swap workspace tags, so you can keep related ones next to
-- each other, without having to move individual windows.
--
-----------------------------------------------------------------------------

module XMonad.Actions.SwapWorkspaces (
                                     -- * Usage
                                     -- $usage
                                     swapWithCurrent,
                                     swapTo,
                                     swapWorkspaces,
                                     Direction1D(..)
                                    ) where

import XMonad (windows, X())
import XMonad.StackSet
import XMonad.Actions.CycleWS
import XMonad.Util.WorkspaceCompare


-- $usage
-- Add this import to your @xmonad.hs@:
--
-- > import XMonad.Actions.SwapWorkspaces
--
-- Then throw something like this in your keys definition:
--
-- > ++
-- > [((modm .|. controlMask, k), windows $ swapWithCurrent i)
-- >     | (i, k) <- zip workspaces [xK_1 ..]]
--
-- After installing this update, if you're on workspace 1, hitting mod-ctrl-5
-- will swap workspaces 1 and 5.
--
-- For detailed instructions on editing your key bindings, see
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.

-- | Swaps the currently focused workspace with the given workspace tag, via
--   @swapWorkspaces@.
swapWithCurrent :: Eq i => i -> StackSet i l a s sd -> StackSet i l a s sd
swapWithCurrent :: forall i l a s sd.
Eq i =>
i -> StackSet i l a s sd -> StackSet i l a s sd
swapWithCurrent i
t StackSet i l a s sd
s = i -> i -> StackSet i l a s sd -> StackSet i l a s sd
forall i l a s sd.
Eq i =>
i -> i -> StackSet i l a s sd -> StackSet i l a s sd
swapWorkspaces i
t (StackSet i l a s sd -> i
forall i l a s sd. StackSet i l a s sd -> i
currentTag StackSet i l a s sd
s) StackSet i l a s sd
s

-- | Say @swapTo Next@ or @swapTo Prev@ to move your current workspace.
-- This is an @X ()@ so can be hooked up to your keybindings directly.
swapTo :: Direction1D -> X ()
swapTo :: Direction1D -> X ()
swapTo Direction1D
dir = X WorkspaceSort -> Direction1D -> WSType -> Int -> X WorkspaceId
findWorkspace X WorkspaceSort
getSortByIndex Direction1D
dir WSType
anyWS Int
1 X WorkspaceId -> (WorkspaceId -> 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
>>= (WindowSet -> WindowSet) -> X ()
windows ((WindowSet -> WindowSet) -> X ())
-> (WorkspaceId -> WindowSet -> WindowSet) -> WorkspaceId -> X ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WorkspaceId -> WindowSet -> WindowSet
forall i l a s sd.
Eq i =>
i -> StackSet i l a s sd -> StackSet i l a s sd
swapWithCurrent

-- | Takes two workspace tags and an existing XMonad.StackSet and returns a new
--   one with the two corresponding workspaces' tags swapped.
swapWorkspaces :: Eq i => i -> i -> StackSet i l a s sd -> StackSet i l a s sd
swapWorkspaces :: forall i l a s sd.
Eq i =>
i -> i -> StackSet i l a s sd -> StackSet i l a s sd
swapWorkspaces i
t1 i
t2 = (Workspace i l a -> Workspace i l a)
-> StackSet i l a s sd -> StackSet i l a s sd
forall i l a s sd.
(Workspace i l a -> Workspace i l a)
-> StackSet i l a s sd -> StackSet i l a s sd
mapWorkspace Workspace i l a -> Workspace i l a
forall {l} {a}. Workspace i l a -> Workspace i l a
swap
    where swap :: Workspace i l a -> Workspace i l a
swap Workspace i l a
w
            | Workspace i l a -> i
forall i l a. Workspace i l a -> i
tag Workspace i l a
w i -> i -> Bool
forall a. Eq a => a -> a -> Bool
== i
t1 = Workspace i l a
w { tag = t2 }
            | Workspace i l a -> i
forall i l a. Workspace i l a -> i
tag Workspace i l a
w i -> i -> Bool
forall a. Eq a => a -> a -> Bool
== i
t2 = Workspace i l a
w { tag = t1 }
            | Bool
otherwise = Workspace i l a
w