Adding NamedActions to xmonad to display all keybindings.

This commit is contained in:
Derek Taylor
2022-06-19 20:05:29 -05:00
parent 780cfcce88
commit dad192b689
2 changed files with 516 additions and 513 deletions
+38 -36
View File
@@ -389,7 +389,10 @@ myShowWNameTheme = def
} }
-- The layout hook -- The layout hook
myLayoutHook = avoidStruts $ mouseResize $ windowArrange $ T.toggleLayouts floats myLayoutHook = avoidStruts
$ mouseResize
$ windowArrange
$ T.toggleLayouts floats
$ mkToggle (NBFULL ?? NOBORDERS ?? EOT) myDefaultLayout $ mkToggle (NBFULL ?? NOBORDERS ?? EOT) myDefaultLayout
where where
myDefaultLayout = withBorder myBorderWidth tall myDefaultLayout = withBorder myBorderWidth tall
@@ -500,14 +503,13 @@ I am using the Xmonad.Util.EZConfig module which allows keybindings to be writte
#+BEGIN_SRC haskell #+BEGIN_SRC haskell
showKeybindings :: [((KeyMask, KeySym), NamedAction)] -> NamedAction showKeybindings :: [((KeyMask, KeySym), NamedAction)] -> NamedAction
showKeybindings x = addName "Show Keybindings" $ io $ do showKeybindings x = addName "Show Keybindings" $ io $ do
h <- spawnPipe $ "yad --text-info --fontname=" ++ myFont ++ " --width 800 --height 600 --center --title \"XMonad keybindings\"" h <- spawnPipe $ "yad --text-info --fontname=\"SauceCodePro Nerd Font Mono 12\" --width 800 --height 600 --center --title \"XMonad keybindings\""
hPutStr h (unlines $ showKm x) hPutStr h (unlines $ showKm x)
hClose h hClose h
return () return ()
myKeys :: XConfig l0 -> [((KeyMask, KeySym), NamedAction)] myKeys :: XConfig l0 -> [((KeyMask, KeySym), NamedAction)]
myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $ myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $
-- KB_GROUP Xmonad -- KB_GROUP Xmonad
[ ("M-C-r", addName "Recompile XMonad" $ spawn "xmonad --recompile") [ ("M-C-r", addName "Recompile XMonad" $ spawn "xmonad --recompile")
, ("M-S-r", addName "Restart XMonad" $ spawn "xmonad --restart") , ("M-S-r", addName "Restart XMonad" $ spawn "xmonad --restart")
@@ -568,31 +570,31 @@ myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $
, ("C-g b", addName "Bring selected window" $ bringSelected $ mygridConfig myColorizer) , ("C-g b", addName "Bring selected window" $ bringSelected $ mygridConfig myColorizer)
-- KB_GROUP Windows navigation -- KB_GROUP Windows navigation
, ("M-m", addName "" $ windows W.focusMaster) -- Move focus to the master window , ("M-m", addName "Move focus to master window" $ windows W.focusMaster)
, ("M-j", addName "" $ windows W.focusDown) -- Move focus to the next window , ("M-j", addName "Move focus to next window" $ windows W.focusDown)
, ("M-k", addName "" $ windows W.focusUp) -- Move focus to the prev window , ("M-k", addName "Move focus to prev window" $ windows W.focusUp)
, ("M-S-m", addName "" $ windows W.swapMaster) -- Swap the focused window and the master window , ("M-S-m", addName "Swap focused window with master window" $ windows W.swapMaster)
, ("M-S-j", addName "" $ windows W.swapDown) -- Swap focused window with next window , ("M-S-j", addName "Swap focused window with next window" $ windows W.swapDown)
, ("M-S-k", addName "" $ windows W.swapUp) -- Swap focused window with prev window , ("M-S-k", addName "Swap focused window with prev window" $ windows W.swapUp)
, ("M-<Backspace>", addName "" $ promote) -- Moves focused window to master, others maintain order , ("M-<Backspace>", addName "Move focused window to master" $ promote)
, ("M-S-<Tab>", addName "" $ rotSlavesDown) -- Rotate all windows except master and keep focus in place , ("M-S-<Tab>", addName "Rotate all windows except master" $ rotSlavesDown)
, ("M-C-<Tab>", addName "" $ rotAllDown) -- Rotate all the windows in the current stack , ("M-C-<Tab>", addName "Rotate all windows current stack" $ rotAllDown)
-- KB_GROUP Layouts -- KB_GROUP Layouts
, ("M-<Tab>", addName "" $ sendMessage NextLayout) -- Switch to next layout , ("M-<Tab>", addName "Switch to next layout" $ sendMessage NextLayout)
, ("M-<Space>", addName "" $ sendMessage (MT.Toggle NBFULL) >> sendMessage ToggleStruts) -- Toggles noborder/full , ("M-<Space>", addName "Toggle noborders/full" $ sendMessage (MT.Toggle NBFULL) >> sendMessage ToggleStruts)
-- KB_GROUP Increase/decrease windows in the master pane or the stack -- KB_GROUP Increase/decrease windows in the master pane or the stack
, ("M-S-<Up>", addName "" $ sendMessage (IncMasterN 1)) -- Increase # of clients master pane , ("M-S-<Up>", addName "Increase clients in master pane" $ sendMessage (IncMasterN 1))
, ("M-S-<Down>", addName "" $ sendMessage (IncMasterN (-1))) -- Decrease # of clients master pane , ("M-S-<Down>", addName "Decrease clients in master pane" $ sendMessage (IncMasterN (-1)))
, ("M-C-<Up>", addName "" $ increaseLimit) -- Increase # of windows , ("M-C-<Up>", addName "Increase # of windows" $ increaseLimit)
, ("M-C-<Down>", addName "" $ decreaseLimit) -- Decrease # of windows , ("M-C-<Down>", addName "Decrease # of windows" $ decreaseLimit)
-- KB_GROUP Window resizing -- KB_GROUP Window resizing
, ("M-h", addName "Shrink window" $ sendMessage Shrink) -- Shrink horiz window width , ("M-h", addName "Shrink window" $ sendMessage Shrink)
, ("M-l", addName "Expand window" $ sendMessage Expand) -- Expand horiz window width , ("M-l", addName "Expand window" $ sendMessage Expand)
, ("M-M1-j", addName "Shrink window vertically" $ sendMessage MirrorShrink) -- Shrink vert window width , ("M-M1-j", addName "Shrink window vertically" $ sendMessage MirrorShrink)
, ("M-M1-k", addName "Expand window vertically" $ sendMessage MirrorExpand) -- Expand vert window width , ("M-M1-k", addName "Expand window vertically" $ sendMessage MirrorExpand)
-- KB_GROUP Sublayouts -- KB_GROUP Sublayouts
-- This is used to push windows to tabbed sublayouts, or pull them out of it. -- This is used to push windows to tabbed sublayouts, or pull them out of it.
@@ -610,9 +612,9 @@ myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $
-- Toggle show/hide these programs. They run on a hidden workspace. -- Toggle show/hide these programs. They run on a hidden workspace.
-- When you toggle them to show, it brings them to your current workspace. -- When you toggle them to show, it brings them to your current workspace.
-- Toggle them to hide and it sends them back to hidden workspace (NSP). -- Toggle them to hide and it sends them back to hidden workspace (NSP).
, ("M-s t", addName "" $ namedScratchpadAction myScratchPads "terminal") , ("M-s t", addName "Toggle scratchpad terminal" $ namedScratchpadAction myScratchPads "terminal")
, ("M-s m", addName "" $ namedScratchpadAction myScratchPads "mocp") , ("M-s m", addName "Toggle scratchpad mocp" $ namedScratchpadAction myScratchPads "mocp")
, ("M-s c", addName "" $ namedScratchpadAction myScratchPads "calculator") , ("M-s c", addName "Toggle scratchpad calculator" $ namedScratchpadAction myScratchPads "calculator")
-- KB_GROUP Controls for mocp music player (SUPER-u followed by a key) -- KB_GROUP Controls for mocp music player (SUPER-u followed by a key)
, ("M-u p", addName "" $ spawn "mocp --play") , ("M-u p", addName "" $ spawn "mocp --play")
@@ -621,16 +623,16 @@ myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $
, ("M-u <Space>", addName "" $ spawn "mocp --toggle-pause") , ("M-u <Space>", addName "" $ spawn "mocp --toggle-pause")
-- KB_GROUP Emacs (SUPER-e followed by a key) -- KB_GROUP Emacs (SUPER-e followed by a key)
, ("M-e e", addName "" $ spawn (myEmacs ++ ("--eval '(dashboard-refresh-buffer)'"))) -- emacs dashboard , ("M-e e", addName "Emacsclient Dashboard" $ spawn (myEmacs ++ ("--eval '(dashboard-refresh-buffer)'"))) -- emacs dashboard
, ("M-e b", addName "" $ spawn (myEmacs ++ ("--eval '(ibuffer)'"))) -- list buffers , ("M-e b", addName "Emacsclient Ibuffer" $ spawn (myEmacs ++ ("--eval '(ibuffer)'"))) -- list buffers
, ("M-e d", addName "" $ spawn (myEmacs ++ ("--eval '(dired nil)'"))) -- dired , ("M-e d", addName "Emacsclient Dired" $ spawn (myEmacs ++ ("--eval '(dired nil)'"))) -- dired
, ("M-e i", addName "" $ spawn (myEmacs ++ ("--eval '(erc)'"))) -- erc irc client , ("M-e i", addName "Emacsclient ERC (IRC)" $ spawn (myEmacs ++ ("--eval '(erc)'"))) -- erc irc client
, ("M-e n", addName "" $ spawn (myEmacs ++ ("--eval '(elfeed)'"))) -- elfeed rss , ("M-e n", addName "Emacsclient Elfeed (RSS)" $ spawn (myEmacs ++ ("--eval '(elfeed)'"))) -- elfeed rss
, ("M-e s", addName "" $ spawn (myEmacs ++ ("--eval '(eshell)'"))) -- eshell , ("M-e s", addName "Emacsclient Eshell" $ spawn (myEmacs ++ ("--eval '(eshell)'"))) -- eshell
, ("M-e t", addName "" $ spawn (myEmacs ++ ("--eval '(mastodon)'"))) -- mastodon.el , ("M-e t", addName "Emacsclient Mastodon" $ spawn (myEmacs ++ ("--eval '(mastodon)'"))) -- mastodon.el
, ("M-e v", addName "" $ spawn (myEmacs ++ ("--eval '(+vterm/here nil)'"))) -- vterm if on Doom Emacs , ("M-e v", addName "Emacsclient Vterm" $ spawn (myEmacs ++ ("--eval '(+vterm/here nil)'"))) -- vterm if on Doom Emacs
, ("M-e w", addName "" $ spawn (myEmacs ++ ("--eval '(doom/window-maximize-buffer(eww \"distro.tube\"))'"))) -- eww browser if on Doom Emacs , ("M-e w", addName "Emacsclient EWW browser" $ spawn (myEmacs ++ ("--eval '(doom/window-maximize-buffer(eww \"distro.tube\"))'"))) -- eww browser if on Doom Emacs
, ("M-e a", addName "" $ spawn (myEmacs ++ ("--eval '(emms)' --eval '(emms-play-directory-tree \"~/Music/\")'"))) , ("M-e a", addName "Emacsclient EMMS (music)" $ spawn (myEmacs ++ ("--eval '(emms)' --eval '(emms-play-directory-tree \"~/Music/\")'")))
-- KB_GROUP Multimedia Keys -- KB_GROUP Multimedia Keys
, ("<XF86AudioPlay>", addName "" $ spawn "mocp --play") , ("<XF86AudioPlay>", addName "" $ spawn "mocp --play")
@@ -649,7 +651,7 @@ myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $
-- The following lines are needed for named scratchpads. -- The following lines are needed for named scratchpads.
where nonNSP = WSIs (return (\ws -> W.tag ws /= "NSP")) where nonNSP = WSIs (return (\ws -> W.tag ws /= "NSP"))
nonEmptyNonNSP = WSIs (return (\ws -> isJust (W.stack ws) && W.tag ws /= "NSP")) nonEmptyNonNSP = WSIs (return (\ws -> isJust (W.stack ws) && W.tag ws /= "NSP"))
-- END_KEYS
#+END_SRC #+END_SRC
* Main * Main
+37 -36
View File
@@ -311,7 +311,10 @@ myShowWNameTheme = def
} }
-- The layout hook -- The layout hook
myLayoutHook = avoidStruts $ mouseResize $ windowArrange $ T.toggleLayouts floats myLayoutHook = avoidStruts
$ mouseResize
$ windowArrange
$ T.toggleLayouts floats
$ mkToggle (NBFULL ?? NOBORDERS ?? EOT) myDefaultLayout $ mkToggle (NBFULL ?? NOBORDERS ?? EOT) myDefaultLayout
where where
myDefaultLayout = withBorder myBorderWidth tall myDefaultLayout = withBorder myBorderWidth tall
@@ -368,14 +371,13 @@ dmenuSound = soundDir ++ "menu-01.mp3"
showKeybindings :: [((KeyMask, KeySym), NamedAction)] -> NamedAction showKeybindings :: [((KeyMask, KeySym), NamedAction)] -> NamedAction
showKeybindings x = addName "Show Keybindings" $ io $ do showKeybindings x = addName "Show Keybindings" $ io $ do
h <- spawnPipe $ "yad --text-info --fontname=" ++ myFont ++ " --width 800 --height 600 --center --title \"XMonad keybindings\"" h <- spawnPipe $ "yad --text-info --fontname=\"SauceCodePro Nerd Font Mono 12\" --width 800 --height 600 --center --title \"XMonad keybindings\""
hPutStr h (unlines $ showKm x) hPutStr h (unlines $ showKm x)
hClose h hClose h
return () return ()
myKeys :: XConfig l0 -> [((KeyMask, KeySym), NamedAction)] myKeys :: XConfig l0 -> [((KeyMask, KeySym), NamedAction)]
myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $ myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $
-- KB_GROUP Xmonad -- KB_GROUP Xmonad
[ ("M-C-r", addName "Recompile XMonad" $ spawn "xmonad --recompile") [ ("M-C-r", addName "Recompile XMonad" $ spawn "xmonad --recompile")
, ("M-S-r", addName "Restart XMonad" $ spawn "xmonad --restart") , ("M-S-r", addName "Restart XMonad" $ spawn "xmonad --restart")
@@ -436,31 +438,31 @@ myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $
, ("C-g b", addName "Bring selected window" $ bringSelected $ mygridConfig myColorizer) , ("C-g b", addName "Bring selected window" $ bringSelected $ mygridConfig myColorizer)
-- KB_GROUP Windows navigation -- KB_GROUP Windows navigation
, ("M-m", addName "" $ windows W.focusMaster) -- Move focus to the master window , ("M-m", addName "Move focus to master window" $ windows W.focusMaster)
, ("M-j", addName "" $ windows W.focusDown) -- Move focus to the next window , ("M-j", addName "Move focus to next window" $ windows W.focusDown)
, ("M-k", addName "" $ windows W.focusUp) -- Move focus to the prev window , ("M-k", addName "Move focus to prev window" $ windows W.focusUp)
, ("M-S-m", addName "" $ windows W.swapMaster) -- Swap the focused window and the master window , ("M-S-m", addName "Swap focused window with master window" $ windows W.swapMaster)
, ("M-S-j", addName "" $ windows W.swapDown) -- Swap focused window with next window , ("M-S-j", addName "Swap focused window with next window" $ windows W.swapDown)
, ("M-S-k", addName "" $ windows W.swapUp) -- Swap focused window with prev window , ("M-S-k", addName "Swap focused window with prev window" $ windows W.swapUp)
, ("M-<Backspace>", addName "" $ promote) -- Moves focused window to master, others maintain order , ("M-<Backspace>", addName "Move focused window to master" $ promote)
, ("M-S-<Tab>", addName "" $ rotSlavesDown) -- Rotate all windows except master and keep focus in place , ("M-S-<Tab>", addName "Rotate all windows except master" $ rotSlavesDown)
, ("M-C-<Tab>", addName "" $ rotAllDown) -- Rotate all the windows in the current stack , ("M-C-<Tab>", addName "Rotate all windows current stack" $ rotAllDown)
-- KB_GROUP Layouts -- KB_GROUP Layouts
, ("M-<Tab>", addName "" $ sendMessage NextLayout) -- Switch to next layout , ("M-<Tab>", addName "Switch to next layout" $ sendMessage NextLayout)
, ("M-<Space>", addName "" $ sendMessage (MT.Toggle NBFULL) >> sendMessage ToggleStruts) -- Toggles noborder/full , ("M-<Space>", addName "Toggle noborders/full" $ sendMessage (MT.Toggle NBFULL) >> sendMessage ToggleStruts)
-- KB_GROUP Increase/decrease windows in the master pane or the stack -- KB_GROUP Increase/decrease windows in the master pane or the stack
, ("M-S-<Up>", addName "" $ sendMessage (IncMasterN 1)) -- Increase # of clients master pane , ("M-S-<Up>", addName "Increase clients in master pane" $ sendMessage (IncMasterN 1))
, ("M-S-<Down>", addName "" $ sendMessage (IncMasterN (-1))) -- Decrease # of clients master pane , ("M-S-<Down>", addName "Decrease clients in master pane" $ sendMessage (IncMasterN (-1)))
, ("M-C-<Up>", addName "" $ increaseLimit) -- Increase # of windows , ("M-C-<Up>", addName "Increase # of windows" $ increaseLimit)
, ("M-C-<Down>", addName "" $ decreaseLimit) -- Decrease # of windows , ("M-C-<Down>", addName "Decrease # of windows" $ decreaseLimit)
-- KB_GROUP Window resizing -- KB_GROUP Window resizing
, ("M-h", addName "Shrink window" $ sendMessage Shrink) -- Shrink horiz window width , ("M-h", addName "Shrink window" $ sendMessage Shrink)
, ("M-l", addName "Expand window" $ sendMessage Expand) -- Expand horiz window width , ("M-l", addName "Expand window" $ sendMessage Expand)
, ("M-M1-j", addName "Shrink window vertically" $ sendMessage MirrorShrink) -- Shrink vert window width , ("M-M1-j", addName "Shrink window vertically" $ sendMessage MirrorShrink)
, ("M-M1-k", addName "Expand window vertically" $ sendMessage MirrorExpand) -- Expand vert window width , ("M-M1-k", addName "Expand window vertically" $ sendMessage MirrorExpand)
-- KB_GROUP Sublayouts -- KB_GROUP Sublayouts
-- This is used to push windows to tabbed sublayouts, or pull them out of it. -- This is used to push windows to tabbed sublayouts, or pull them out of it.
@@ -478,9 +480,9 @@ myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $
-- Toggle show/hide these programs. They run on a hidden workspace. -- Toggle show/hide these programs. They run on a hidden workspace.
-- When you toggle them to show, it brings them to your current workspace. -- When you toggle them to show, it brings them to your current workspace.
-- Toggle them to hide and it sends them back to hidden workspace (NSP). -- Toggle them to hide and it sends them back to hidden workspace (NSP).
, ("M-s t", addName "" $ namedScratchpadAction myScratchPads "terminal") , ("M-s t", addName "Toggle scratchpad terminal" $ namedScratchpadAction myScratchPads "terminal")
, ("M-s m", addName "" $ namedScratchpadAction myScratchPads "mocp") , ("M-s m", addName "Toggle scratchpad mocp" $ namedScratchpadAction myScratchPads "mocp")
, ("M-s c", addName "" $ namedScratchpadAction myScratchPads "calculator") , ("M-s c", addName "Toggle scratchpad calculator" $ namedScratchpadAction myScratchPads "calculator")
-- KB_GROUP Controls for mocp music player (SUPER-u followed by a key) -- KB_GROUP Controls for mocp music player (SUPER-u followed by a key)
, ("M-u p", addName "" $ spawn "mocp --play") , ("M-u p", addName "" $ spawn "mocp --play")
@@ -489,16 +491,16 @@ myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $
, ("M-u <Space>", addName "" $ spawn "mocp --toggle-pause") , ("M-u <Space>", addName "" $ spawn "mocp --toggle-pause")
-- KB_GROUP Emacs (SUPER-e followed by a key) -- KB_GROUP Emacs (SUPER-e followed by a key)
, ("M-e e", addName "" $ spawn (myEmacs ++ ("--eval '(dashboard-refresh-buffer)'"))) -- emacs dashboard , ("M-e e", addName "Emacsclient Dashboard" $ spawn (myEmacs ++ ("--eval '(dashboard-refresh-buffer)'"))) -- emacs dashboard
, ("M-e b", addName "" $ spawn (myEmacs ++ ("--eval '(ibuffer)'"))) -- list buffers , ("M-e b", addName "Emacsclient Ibuffer" $ spawn (myEmacs ++ ("--eval '(ibuffer)'"))) -- list buffers
, ("M-e d", addName "" $ spawn (myEmacs ++ ("--eval '(dired nil)'"))) -- dired , ("M-e d", addName "Emacsclient Dired" $ spawn (myEmacs ++ ("--eval '(dired nil)'"))) -- dired
, ("M-e i", addName "" $ spawn (myEmacs ++ ("--eval '(erc)'"))) -- erc irc client , ("M-e i", addName "Emacsclient ERC (IRC)" $ spawn (myEmacs ++ ("--eval '(erc)'"))) -- erc irc client
, ("M-e n", addName "" $ spawn (myEmacs ++ ("--eval '(elfeed)'"))) -- elfeed rss , ("M-e n", addName "Emacsclient Elfeed (RSS)" $ spawn (myEmacs ++ ("--eval '(elfeed)'"))) -- elfeed rss
, ("M-e s", addName "" $ spawn (myEmacs ++ ("--eval '(eshell)'"))) -- eshell , ("M-e s", addName "Emacsclient Eshell" $ spawn (myEmacs ++ ("--eval '(eshell)'"))) -- eshell
, ("M-e t", addName "" $ spawn (myEmacs ++ ("--eval '(mastodon)'"))) -- mastodon.el , ("M-e t", addName "Emacsclient Mastodon" $ spawn (myEmacs ++ ("--eval '(mastodon)'"))) -- mastodon.el
, ("M-e v", addName "" $ spawn (myEmacs ++ ("--eval '(+vterm/here nil)'"))) -- vterm if on Doom Emacs , ("M-e v", addName "Emacsclient Vterm" $ spawn (myEmacs ++ ("--eval '(+vterm/here nil)'"))) -- vterm if on Doom Emacs
, ("M-e w", addName "" $ spawn (myEmacs ++ ("--eval '(doom/window-maximize-buffer(eww \"distro.tube\"))'"))) -- eww browser if on Doom Emacs , ("M-e w", addName "Emacsclient EWW browser" $ spawn (myEmacs ++ ("--eval '(doom/window-maximize-buffer(eww \"distro.tube\"))'"))) -- eww browser if on Doom Emacs
, ("M-e a", addName "" $ spawn (myEmacs ++ ("--eval '(emms)' --eval '(emms-play-directory-tree \"~/Music/\")'"))) , ("M-e a", addName "Emacsclient EMMS (music)" $ spawn (myEmacs ++ ("--eval '(emms)' --eval '(emms-play-directory-tree \"~/Music/\")'")))
-- KB_GROUP Multimedia Keys -- KB_GROUP Multimedia Keys
, ("<XF86AudioPlay>", addName "" $ spawn "mocp --play") , ("<XF86AudioPlay>", addName "" $ spawn "mocp --play")
@@ -517,7 +519,6 @@ myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $
-- The following lines are needed for named scratchpads. -- The following lines are needed for named scratchpads.
where nonNSP = WSIs (return (\ws -> W.tag ws /= "NSP")) where nonNSP = WSIs (return (\ws -> W.tag ws /= "NSP"))
nonEmptyNonNSP = WSIs (return (\ws -> isJust (W.stack ws) && W.tag ws /= "NSP")) nonEmptyNonNSP = WSIs (return (\ws -> isJust (W.stack ws) && W.tag ws /= "NSP"))
-- END_KEYS
main :: IO () main :: IO ()
main = do main = do