Skip to content

Instantly share code, notes, and snippets.

@ThoNohT
Last active August 13, 2021 12:48
Show Gist options
  • Save ThoNohT/1301b6cf8eb9123288fef729b166db06 to your computer and use it in GitHub Desktop.
Save ThoNohT/1301b6cf8eb9123288fef729b166db06 to your computer and use it in GitHub Desktop.

Assuming you use XMonad.Util.EZConfig to configure your key mappings, this code allows you to print those mappings in a nice format and let them be visualized in multiple ways.

Starting from the latest darcs template xmonad.hs, but the key map configuration already replaced with XMonad.Util.EZConfig, I need the following imports extra imports:

import Data.Foldable
import qualified Data.List as L

This is the code containing the types used for formatting the input, and the actual formatting code.

data KeyMapCategory = MkCat { name :: String, mappings :: [ KeyMapKey ] }
unwrapCategory :: KeyMapCategory -> [ ( String, X () )]
unwrapCategory MkCat { mappings = m } = map unwrapKey m

data KeyMapKey = MkKey { binding :: String, action :: X (), catDescription :: String }
unwrapKey :: KeyMapKey -> ( String, X () )
unwrapKey MkKey { binding = b, action = a } = ( b, a )

categoryListFormat :: [ KeyMapCategory ] -> String
categoryListFormat = L.intercalate "\n\n\n" . map formatCategory
    where
        formatCategory MkCat { mappings = m, name = n } = L.intercalate "\n" $ n : "" : map formatBinding m
        formatBinding MkKey { binding = b, catDescription = d } = L.intercalate "\n" [ b, d ]

categoryTextFormat :: [ KeyMapCategory ] -> String
categoryTextFormat = L.intercalate "\n\n" . map formatCategory
    where
        formatCategory MkCat { mappings = m, name = n } = L.intercalate "\n" $  n : map (formatBinding width) m
            where width = foldl max 0 $ map (length . binding) m
        formatBinding width MkKey { binding = b, catDescription = d } = padRight width b ++ " : " ++ d
        padRight width str = if length str < width then padRight width (str ++ " ") else str

Now the key mapping can be defined as follows:

myKeyMap :: [ KeyMapCategory ]
myKeyMap =
    [ MkCat "App launching"
      [ MkKey "M-S-<Return>"
          (spawn myTerminal)
          "Launch a terminal"
      , MkKey "M-p"
          (spawn "rofi -show drun")
          "Launch rofi"
      -- etc, more keys in a category...
      ]
      -- etc, more categories...
    ]

I came up with three ways to display this:

  • In yad as a list
  • In yad as text
  • In rofi as text

These are the bindings I made for them:

      , MkKey "M-S-/"
          (spawn $ unwords
            ["yad"
            , "--list"
            , "--no-markup"
            , "--column Binding"
            , "--column Action"
            , "--title=Keybindings"
            , "--geometry=500x775"
            , "--no-buttons"
            , "--undecorated"
            , "--text=<<EOF\n" ++ categoryListFormat myKeyMap ++ "\nEOF"
            ])
          "Show the key bindings (list)"
      , MkKey "M-C-S-/"
          (spawn $ unwords
            ["yad"
            , "--text-info"
            , "--no-markup"
            , "--title=Keybindings"
            , "--geometry=650x825"
            , "--no-buttons"
            , "--undecorated"
            , "--fontname=\"Source Code Pro 12\""
            , "--text=<<EOF\n" ++ categoryTextFormat myKeyMap ++ "\nEOF"
            ])
          "Show the key bindings (textual)"
      , MkKey "M-C-/"
          (spawn $ "cat <<EOF | rofi -p Bindings -columns 1 -dmenu\n" ++ categoryTextFormat myKeyMap ++ "\nEOF")
          "Show the key bindings (rofi)"

Now all that needs to be done is actually convert the new type of my myKeyMap to something xmonad understands: Change

} `additionalKeysP` myKeyMap

to

} `additionalKeysP` L.concatMap unwrapCategory myKeyMap
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment