add swapLeft and swapRight

This commit is contained in:
bobstopper
2007-05-22 05:00:08 +00:00
parent 0df8dffc78
commit bcf305cd1e
4 changed files with 80 additions and 35 deletions

View File

@@ -160,6 +160,9 @@ keys = M.fromList $
, ((modMask, xK_j ), focusRight) , ((modMask, xK_j ), focusRight)
, ((modMask, xK_k ), focusLeft) , ((modMask, xK_k ), focusLeft)
, ((modMask, xK_Left ), swapLeft)
, ((modMask, xK_Right ), swapRight)
, ((modMask, xK_h ), sendMessage Shrink) , ((modMask, xK_h ), sendMessage Shrink)
, ((modMask, xK_l ), sendMessage Expand) , ((modMask, xK_l ), sendMessage Expand)
@@ -172,7 +175,7 @@ keys = M.fromList $
, ((modMask .|. shiftMask .|. controlMask, xK_q ), restart Nothing False) , ((modMask .|. shiftMask .|. controlMask, xK_q ), restart Nothing False)
-- Cycle the current tiling order -- Cycle the current tiling order
, ((modMask, xK_Return), swap) , ((modMask, xK_Return), swapMaster)
] ++ ] ++
-- Keybindings to get to each workspace: -- Keybindings to get to each workspace:

View File

@@ -51,13 +51,15 @@ unmanage :: Window -> X ()
unmanage = windows . W.delete unmanage = windows . W.delete
-- | focus. focus window to the left or right. -- | focus. focus window to the left or right.
focusLeft, focusRight :: X () focusLeft, focusRight, swapLeft, swapRight :: X ()
focusLeft = windows W.focusLeft focusLeft = windows W.focusLeft
focusRight = windows W.focusRight focusRight = windows W.focusRight
swapLeft = windows W.swapLeft
swapRight = windows W.swapRight
-- | swap. Move the currently focused window into the master frame -- | swapMaster. Move the currently focused window into the master frame
swap :: X () swapMaster :: X ()
swap = windows W.swap swapMaster = windows W.swapMaster
-- | shift. Move a window to a new workspace, 0 indexed. -- | shift. Move a window to a new workspace, 0 indexed.
shift :: WorkspaceId -> X () shift :: WorkspaceId -> X ()

View File

@@ -77,8 +77,8 @@
module StackSet ( module StackSet (
StackSet(..), Workspace(..), Screen(..), Stack(..), StackSet(..), Workspace(..), Screen(..), Stack(..),
new, view, lookupWorkspace, peek, index, focusLeft, focusRight, new, view, lookupWorkspace, peek, index, focusLeft, focusRight,
focusWindow, member, findIndex, insertLeft, delete, swap, shift, focusWindow, member, findIndex, insertLeft, delete, shift,
modify -- needed by users swapMaster, swapLeft, swapRight, modify -- needed by users
) where ) where
import Data.Maybe (listToMaybe) import Data.Maybe (listToMaybe)
@@ -92,10 +92,11 @@ import qualified Data.List as L (delete,find,genericSplitAt)
-- index, -- index,
-- peek, -- was: peek/peekStack -- peek, -- was: peek/peekStack
-- focusLeft, focusRight, -- was: rotate -- focusLeft, focusRight, -- was: rotate
-- swapLeft, swapRight
-- focus -- was: raiseFocus -- focus -- was: raiseFocus
-- insertLeft, -- was: insert/push -- insertLeft, -- was: insert/push
-- delete, -- delete,
-- swap, -- was: promote -- swapMaster, -- was: promote/swap
-- member, -- member,
-- shift, -- shift,
-- lookupWorkspace, -- was: workspace -- lookupWorkspace, -- was: workspace
@@ -239,12 +240,18 @@ index = with [] $ \(Node t l r) -> reverse l ++ t : r
-- let is = t : r ++ reverse l in take (length is) (dropWhile (/= m) (cycle is)) -- let is = t : r ++ reverse l in take (length is) (dropWhile (/= m) (cycle is))
-- --
-- /O(1), O(w) on the wrapping case/. Move the window focus left or -- /O(1), O(w) on the wrapping case/.
--
-- focusLeft, focusRight. Move the window focus left or
-- right, wrapping if we reach the end. The wrapping should model a -- right, wrapping if we reach the end. The wrapping should model a
-- 'cycle' on the current stack. The 'master' window, and window order, -- 'cycle' on the current stack. The 'master' window, and window order,
-- are unaffected by movement of focus. -- are unaffected by movement of focus.
-- --
focusLeft, focusRight :: StackSet i a s -> StackSet i a s -- swapLeft, swapRight. Swap the focused window with its left or right
-- neighbour in the stack ordering, wrapping if we reach the end. Again
-- the wrapping model should 'cycle' on the current stack.
--
focusLeft, focusRight, swapLeft, swapRight :: StackSet i a s -> StackSet i a s
focusLeft = modify Empty $ \c -> case c of focusLeft = modify Empty $ \c -> case c of
Node _ [] [] -> c Node _ [] [] -> c
Node t (l:ls) rs -> Node l ls (t:rs) Node t (l:ls) rs -> Node l ls (t:rs)
@@ -255,6 +262,16 @@ focusRight = modify Empty $ \c -> case c of
Node t ls (r:rs) -> Node r (t:ls) rs Node t ls (r:rs) -> Node r (t:ls) rs
Node t ls [] -> Node x [] (xs ++ [t]) where (x:xs) = reverse ls Node t ls [] -> Node x [] (xs ++ [t]) where (x:xs) = reverse ls
swapLeft = modify Empty $ \c -> case c of
Node _ [] [] -> c
Node t (l:ls) rs -> Node t ls (l:rs)
Node t [] rs -> Node t (reverse rs) []
swapRight = modify Empty $ \c -> case c of
Node _ [] [] -> c
Node t ls (r:rs) -> Node t (r:ls) rs
Node t ls [] -> Node t [] (reverse ls)
-- --
-- | /O(1) on current window, O(n) in general/. Focus the window 'w', -- | /O(1) on current window, O(n) in general/. Focus the window 'w',
-- and set its workspace as current. -- and set its workspace as current.
@@ -342,8 +359,8 @@ delete w s | Just w == peek s = remove s -- common case.
-- /O(s)/. Set the master window to the focused window. -- /O(s)/. Set the master window to the focused window.
-- The old master window is swapped in the tiling order with the focused window. -- The old master window is swapped in the tiling order with the focused window.
-- Focus stays with the item moved. -- Focus stays with the item moved.
swap :: StackSet i a s -> StackSet i a s swapMaster :: StackSet i a s -> StackSet i a s
swap = modify Empty $ \c -> case c of swapMaster = modify Empty $ \c -> case c of
Node _ [] _ -> c -- already master. Node _ [] _ -> c -- already master.
Node t ls rs -> Node t [] (ys ++ x : rs) where (x:ys) = reverse ls Node t ls rs -> Node t [] (ys ++ x : rs) where (x:ys) = reverse ls

View File

@@ -155,7 +155,12 @@ prop_delete_I (x :: T) = invariant $
Nothing -> x Nothing -> x
Just i -> delete i x Just i -> delete i x
prop_swap_I (x :: T) = invariant $ swap x prop_swap_master_I (x :: T) = invariant $ swapMaster x
prop_swap_left_I (n :: NonNegative Int) (x :: T) =
invariant $ foldr (const swapLeft ) x [1..n]
prop_swap_right_I (n :: NonNegative Int) (x :: T) =
invariant $ foldr (const swapRight) x [1..n]
prop_shift_I (n :: NonNegative Int) (x :: T) = prop_shift_I (n :: NonNegative Int) (x :: T) =
fromIntegral n < size x ==> invariant $ shift (fromIntegral n) x fromIntegral n < size x ==> invariant $ shift (fromIntegral n) x
@@ -349,8 +354,8 @@ prop_insert_peek (n :: Positive Int) (m :: Positive Int) (NonEmptyNubList is) =
-- --
prop_insert_delete n x = not (member n x) ==> delete n (insertLeft n y) == (y :: T) prop_insert_delete n x = not (member n x) ==> delete n (insertLeft n y) == (y :: T)
where where
y = swap x -- sets the master window to the current focus. y = swapMaster x -- sets the master window to the current focus.
-- otherwise, we don't have a rule for where master goes. -- otherwise, we don't have a rule for where master goes.
-- inserting n elements increases current stack size by n -- inserting n elements increases current stack size by n
prop_size_insert is (n :: Positive Int) (m :: Positive Int) = prop_size_insert is (n :: Positive Int) (m :: Positive Int) =
@@ -379,7 +384,7 @@ prop_delete_insert (x :: T) =
Nothing -> True Nothing -> True
Just n -> insertLeft n (delete n y) == y Just n -> insertLeft n (delete n y) == y
where where
y = swap x y = swapMaster x
-- delete should be local -- delete should be local
prop_delete_local (x :: T) = prop_delete_local (x :: T) =
@@ -388,20 +393,11 @@ prop_delete_local (x :: T) =
Just i -> hidden_spaces x == hidden_spaces (delete i x) Just i -> hidden_spaces x == hidden_spaces (delete i x)
-- --------------------------------------------------------------------- -- ---------------------------------------------------------------------
-- swap: setting the master window -- swapLeft, swapRight, swapMaster: reordiring windows
-- prop_swap_reversible a b xs = swap a b (swap a b ys) == ys
-- where ys = nub xs :: [Int]
-- swap doesn't change focus
prop_swap_focus (x :: T)
= case peek x of
Nothing -> True
Just f -> focus (stack (workspace $ current (swap x))) == f
-- swap is local
prop_swap_local (x :: T) = hidden_spaces x == hidden_spaces (swap x)
-- swap is trivially reversible
prop_swap_left (x :: T) = (swapLeft (swapRight x)) == x
prop_swap_right (x :: T) = (swapRight (swapLeft x)) == x
-- TODO swap is reversible -- TODO swap is reversible
-- swap is reversible, but involves moving focus back the window with -- swap is reversible, but involves moving focus back the window with
-- master on it. easy to do with a mouse... -- master on it. easy to do with a mouse...
@@ -414,7 +410,26 @@ prop_promote_reversible x b = (not . null . fromMaybe [] . flip index x . curren
(Just (z:_)) = flip index x . current $ x (Just (z:_)) = flip index x . current $ x
-} -}
prop_swap_idempotent (x :: T) = swap (swap x) == swap x -- swap doesn't change focus
prop_swap_master_focus (x :: T) = peek x == (peek $ swapMaster x)
-- = case peek x of
-- Nothing -> True
-- Just f -> focus (stack (workspace $ current (swap x))) == f
prop_swap_left_focus (x :: T) = peek x == (peek $ swapLeft x)
prop_swap_right_focus (x :: T) = peek x == (peek $ swapRight x)
-- swap is local
prop_swap_master_local (x :: T) = hidden_spaces x == hidden_spaces (swapMaster x)
prop_swap_left_local (x :: T) = hidden_spaces x == hidden_spaces (swapLeft x)
prop_swap_right_local (x :: T) = hidden_spaces x == hidden_spaces (swapRight x)
-- rotation through the height of a stack gets us back to the start
prop_swap_all_l (x :: T) = (foldr (const swapLeft) x [1..n]) == x
where n = length (index x)
prop_swap_all_r (x :: T) = (foldr (const swapRight) x [1..n]) == x
where n = length (index x)
prop_swap_master_idempotent (x :: T) = swapMaster (swapMaster x) == swapMaster x
-- --------------------------------------------------------------------- -- ---------------------------------------------------------------------
-- shift -- shift
@@ -429,7 +444,7 @@ prop_shift_reversible (r :: Int) (x :: T) =
Nothing -> True Nothing -> True
Just _ -> normal ((view n . shift n . view i . shift i) y) == normal y Just _ -> normal ((view n . shift n . view i . shift i) y) == normal y
where where
y = swap x y = swapMaster x
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- some properties for layouts: -- some properties for layouts:
@@ -523,10 +538,18 @@ main = do
,("delete is reversible", mytest prop_delete_insert) ,("delete is reversible", mytest prop_delete_insert)
,("delete is local" , mytest prop_delete_local) ,("delete is local" , mytest prop_delete_local)
,("swap: invariant " , mytest prop_swap_I) ,("swapMaster: invariant", mytest prop_swap_master_I)
,("swap id on focus" , mytest prop_swap_focus) ,("swapLeft: invariant" , mytest prop_swap_left_I)
,("swap is idempotent" , mytest prop_swap_idempotent) ,("swapRight: invariant", mytest prop_swap_right_I)
,("swap is local" , mytest prop_swap_local) ,("swapMaster id on focus", mytest prop_swap_master_focus)
,("swapLeft id on focus", mytest prop_swap_left_focus)
,("swapRight id on focus", mytest prop_swap_right_focus)
,("swapMaster is idempotent", mytest prop_swap_master_idempotent)
,("swap all left " , mytest prop_swap_all_l)
,("swap all right " , mytest prop_swap_all_r)
,("swapMaster is local" , mytest prop_swap_master_local)
,("swapLeft is local" , mytest prop_swap_left_local)
,("swapRight is local" , mytest prop_swap_right_local)
,("shift: invariant" , mytest prop_shift_I) ,("shift: invariant" , mytest prop_shift_I)
,("shift is reversible" , mytest prop_shift_reversible) ,("shift is reversible" , mytest prop_shift_reversible)