-
-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
doc: XMonad.Layout.Inspect #2
base: layout-inspect
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,15 +8,17 @@ | |
|
||
-- | | ||
-- Module : XMonad.Layout.Inspect | ||
-- Description : Inspect layout data. | ||
-- Copyright : (c) 2020 Tomáš Janoušek <[email protected]> | ||
-- License : BSD3 | ||
-- | ||
-- Maintainer : Tomáš Janoušek <[email protected]> | ||
-- Stability : experimental | ||
-- Portability : unknown | ||
-- | ||
-- TODO | ||
-- | ||
-- Inspect a workspace's layout data. Useful for accessing data contained in | ||
-- layout modifiers. | ||
|
||
module XMonad.Layout.Inspect ( | ||
-- * Usage | ||
-- $usage | ||
|
@@ -36,23 +38,58 @@ import XMonad | |
import qualified XMonad.StackSet as W | ||
|
||
-- $usage | ||
-- This module provides a way for layout authors to make workspace layout data | ||
-- accessible to end-users. | ||
-- | ||
-- Best explained by example, suppose you've written a layout modifier: | ||
-- | ||
-- > newtype Foo a = Foo String deriving (Read, Show) | ||
-- > instance LayoutModifier Foo a | ||
-- > foo :: LayoutClass l a => String -> l a -> ModifiedLayout Foo l a | ||
-- > foo = ModifiedLayout . Foo | ||
-- | ||
-- To allow users to inspect the string contained in a given workspace's layout, | ||
-- first import this module: | ||
-- | ||
-- > import XMonad.Layout.Inspect | ||
-- | ||
-- Then define instances for 'InspectResult' and 'InspectLayout', and implement | ||
-- getFoo in terms of 'inspectWorkspace': | ||
-- | ||
-- > data GetFoo = GetFoo | ||
-- > type instance InspectResult GetFoo = Alt Maybe String | ||
-- > | ||
-- > instance InspectLayout GetFoo Foo a where | ||
-- > inspectLayout GetFoo (Foo s) = pure s | ||
-- > | ||
-- > getFoo :: (LayoutClass l Window, InspectLayout GetFoo l Window) | ||
-- > => l Window -> WindowSpace -> Maybe String | ||
-- > getFoo l = getAlt . inspectWorkspace l GetFoo | ||
-- | ||
-- An end-user can then call getFoo by passing it the appropriate layout and a | ||
-- given workspace: | ||
-- | ||
-- TODO: help for users | ||
-- > xFoo :: WindowSpace -> X () | ||
-- > xFoo wsp = do | ||
-- > l <- asks (layoutHook . config) | ||
-- > case getFoo l wsp of | ||
-- > Nothing -> pure () | ||
-- > Just s -> xmessage s | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @liskin @mislavzanic I encountered some unexpected behavior while testing this. I captured my test setup here, and the most relevant part is this section. In brief, I created a simple layout modifier: newtype Foo a = Foo String deriving (Read, Show)
instance LayoutModifier Foo a
foo :: LayoutClass l a => String -> l a -> ModifiedLayout Foo l a
foo = ModifiedLayout . Foo
data GetFoo = GetFoo
type instance InspectResult GetFoo = Alt Maybe String
instance InspectLayout GetFoo Foo a where
inspectLayout GetFoo (Foo s) = pure s
getFoo :: (LayoutClass l Window, InspectLayout GetFoo l Window)
=> l Window -> WindowSpace -> Maybe String
getFoo l = getAlt . inspectWorkspace l GetFoo and used it in a myLayoutHook = foo "test" (Tall nmaster delta ratio)
where
nmaster = 1
ratio = 1/2
delta = 3/100
main = xmonad $ def { keys = myKeys, layoutHook = myLayoutHook } If I pass do
wsp <- withWindowSet (pure . W.workspace . W.current)
getFoo myLayoutHook wsp
-- => Just "test" However, if I retrieve the layout hook by other means, such as do
wsp <- withWindowSet (pure . W.workspace . W.current)
l <- asks (layoutHook . config)
getFoo l wsp
-- => Nothing Any idea what I'm missing? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That explains it, thanks 👍 I can update the usage documentation accordingly (see below). I'd be interested to know if there's another way to call this correctly. diff --git a/XMonad/Layout/Inspect.hs b/XMonad/Layout/Inspect.hs
index 18b93eb8..ddea14a0 100644
--- a/XMonad/Layout/Inspect.hs
+++ b/XMonad/Layout/Inspect.hs
@@ -69,10 +69,11 @@ import qualified XMonad.StackSet as W
-- An end-user can then call getFoo by passing it the appropriate layout and a
-- given workspace:
--
+-- > myLayoutHook = ...
+-- >
-- > xFoo :: WindowSpace -> X ()
-- > xFoo wsp = do
--- > l <- asks (layoutHook . config)
--- > case getFoo l wsp of
+-- > case getFoo myLayoutHook wsp of
-- > Nothing -> pure ()
-- > Just s -> xmessage s There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably not, as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's present in the main = xmonad $ inspectableLayout $ \il -> def{ layoutHook = myLayoutHook, … } That might be marginally less error-prone, as some There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I really think you'd want to be capturing the layout type immediately before -- > main = xmonadIL \i@Inspect{current,tag,workspace} ->
-- > ...
xmonadIL
:: (LayoutClass l Window, Read (l Window))
=> (Inspect l -> XConfig l) -> IO ()
xmonadIL = xmonad . inspectableLayout
-- > main = xmonad $ inspectableLayout \i@Inspect{current,tag,workspace} ->
-- > ...
inspectableLayout
:: forall l. Typeable l
=> (Inspect l -> XConfig l) -> XConfig l
inspectableLayout k = k (makeInspect (Proxy @l))
data Inspect l = Inspect
{ current :: forall i. InspectLayout i l Window
=> i -> X ( InspectResult i )
, tag :: forall i. InspectLayout i l Window
=> i -> WorkspaceId -> X (Maybe (InspectResult i))
, workspace :: forall i. InspectLayout i l Window
=> i -> WindowSpace -> InspectResult i
}
makeInspect :: Typeable l => proxy l -> Inspect l
makeInspect p = Inspect
{ current = inspectCurrentP p
, tag = inspectTagP p
, workspace = inspectWorkspaceP p
} where inspectCurrentP :: (Typeable l, InspectLayout i l Window)
=> proxy l -> i -> X (InspectResult i)
inspectCurrentP p i = gets (inspectWorkspaceP p i . w)
where w = W.workspace . W.current . windowset
inspectTagP :: (Typeable l, InspectLayout i l Window)
=> proxy l -> i -> WorkspaceId
-> X (Maybe (InspectResult i))
inspectTagP p i t = gets (fmap (inspectWorkspaceP p i) . mw)
where mw = find ((t==) . W.tag) . W.workspaces . windowset
inspectWorkspaceP :: (Typeable l, InspectLayout i l Window)
=> proxy l -> i -> WindowSpace -> InspectResult i
inspectWorkspaceP p i = inspectLayout i . asLayout p . W.layout
asLayout :: (Typeable l, Typeable a) => proxy l -> Layout a -> l a
asLayout _ (Layout l) = cast' l and inspectCurrent :: forall l i. (Typeable l, InspectLayout i l Window)
=> l Window -> i -> X (InspectResult i)
inspectCurrent _ = inspectCurrentP (Proxy @l)
inspectTag :: forall l i. (Typeable l, InspectLayout i l Window)
=> l Window -> i -> WorkspaceId
-> X (Maybe (InspectResult i))
inspectTag _ = inspectTagP (Proxy @l)
inspectWorkspace :: forall l i. (Typeable l, InspectLayout i l Window)
=> l Window -> i -> WindowSpace -> InspectResult i
inspectWorkspace _ = inspectWorkspaceP (Proxy @l) It can't really be helped that main = xmonad myConfig
myConfig = ewmh . ... $ def
{ ...
} and use e.g. main = makeMyConfig >>= xmonad
makeMyConfig :: IO (XConfig L)
makeMyConfig = do
... using |
||
|
||
-- | TODO | ||
-- | Inspect the layout of the currently focused workspace. | ||
inspectCurrent :: (LayoutClass l Window, InspectLayout i l Window) | ||
=> l Window -> i -> X (InspectResult i) | ||
inspectCurrent l i = gets (inspectWorkspace l i . w) | ||
where w = W.workspace . W.current . windowset | ||
|
||
-- | TODO | ||
-- | Inspect the layout of the workspace with a specified tag. | ||
inspectTag :: (LayoutClass l Window, InspectLayout i l Window) | ||
=> l Window -> i -> WorkspaceId | ||
-> X (Maybe (InspectResult i)) | ||
inspectTag l i t = gets (fmap (inspectWorkspace l i) . mw) | ||
where mw = find ((t==) . W.tag) . W.workspaces . windowset | ||
|
||
-- | TODO | ||
-- | Inspect the layout of a specified workspace. | ||
inspectWorkspace :: (LayoutClass l Window, InspectLayout i l Window) | ||
=> l Window -> i -> WindowSpace -> InspectResult i | ||
inspectWorkspace l i = inspectLayout i . asLayout l . W.layout | ||
|
@@ -69,7 +106,12 @@ cast' x | Just HRefl <- ta `eqTypeRep` tb = x | |
|
||
type family InspectResult i | ||
|
||
-- | TODO: for layout/modifier authors | ||
-- | A typeclass defining 'inspectLayout' over monoidal @InspectResult@ types. | ||
-- An overlappable instance provides sensible default behavior, returning | ||
-- 'mempty'. (Specific @InspectResult@ instances may override this by defining | ||
-- their own instance of 'InspectLayout'.) Additionally, an instance is provided | ||
-- for layouts using 'Choose', provided that all the layouts in the 'Choose' are | ||
-- capable of being inspected. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These should perhaps be documentation of the respective instances? Although I guess the |
||
class Monoid (InspectResult i) => InspectLayout i l a where | ||
inspectLayout :: i -> l a -> InspectResult i | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps
s/data/state
(here and in other places)? Data sounds very static, but the main point seems to be that we want access to runtime information