-- imports import XMonad import qualified XMonad.StackSet as W import XMonad.Actions.TopicSpace (TopicConfig (..), TopicItem (..), noAction, tiDirs, tiActions, currentTopicDir, switchNthLastFocusedByScreen, switchTopic, topicNames) import XMonad.Actions.Search (SearchEngine, openstreetmap, hackage, wikipedia, youtube, searchEngine, promptSearch, selectSearch) import XMonad.Hooks.DynamicLog (PP(..), dynamicLogWithPP, filterOutWsPP, xmobarPP, xmobarColor, wrap, shorten) import XMonad.Hooks.ManageDocks (ToggleStruts(..), avoidStruts, docks) import XMonad.Hooks.DynamicProperty (dynamicPropertyChange) import XMonad.Hooks.SetWMName (setWMName) import XMonad.Hooks.WorkspaceHistory (workspaceHistoryHook) import XMonad.Layout.Spacing (Spacing, spacingRaw, Border (..)) import XMonad.Layout.LayoutModifier (ModifiedLayout) import XMonad.Layout.Renamed (renamed, Rename (..)) import XMonad.Layout.NoBorders (noBorders, smartBorders) import XMonad.Util.WorkspaceCompare ( getSortByIndex, filterOutWs ) import XMonad.Util.NamedScratchpad (NamedScratchpad (NS), customFloating, defaultFloating, namedScratchpadAction, namedScratchpadManageHook) import XMonad.Util.Run (proc, inProgram, termInDir, (>-$), (>->), execute, spawnPipe, spawnExternalProcess, hPutStrLn) import XMonad.Util.Cursor (setDefaultCursor) import XMonad.Util.SpawnOnce (spawnOnce) import XMonad.Util.EZConfig (additionalKeysP) import XMonad.Prompt (XPConfig (..), mkXPrompt, mkComplFunFromList', XPPosition (..)) import XMonad.Prompt.Workspace (Wor(..)) import XMonad.Prompt.FuzzyMatch (fuzzyMatch, fuzzySort) import XMonad.Prompt.Shell (shellPrompt, unsafePrompt) import Text.Regex.Posix ((=~)) -- variables myTerminal = "alacritty" myBrowser = "librewolf" myBorderWidth = 1 myModMask = mod4Mask white = "#dcdccc" yellow = "#efef8f" orange = "#ffcfaf" red = "#dca3a3" blue = "#8cd0d3" darkBlue = "#8c8cbc" green = "#7f9f7f" grey = "#3f3f3f" darkGrey = "#262626" -- scratchpads myScratchpads :: [NamedScratchpad] myScratchpads = [ NS "cmus" "alacritty -n cmus -e cmus" (resource =? "cmus") (customFloating $ W.RationalRect (1/6) (1/6) (4/6) (4/6)) , NS "nnn" "alacritty -t nnn -e run_in_bash n" (title =? "nnn") (customFloating $ W.RationalRect (1/4) (1/6) (2/4) (4/6)) , NS "aerc" "alacritty -t aerc -e aerc" (title =? "aerc") (customFloating $ W.RationalRect (1/10) (1/10) (8/10) (8/10)) , NS "vimwiki" "alacritty -t vimwiki -e run_in_bash vw" (title =? "vimwiki") (customFloating $ W.RationalRect (1/6) (1/6) (2/3) (2/3)) , NS "dino" "dino" (title =? "Dino") (customFloating $ W.RationalRect (1/10) (1/10) (8/10) (8/10)) , NS "keepassxc" "keepassxc ~/dokumente/Database.kdbx" (title =? "Database.kdbx - KeePassXC" <||> title =? "Database.kdbx [Gesperrt] - KeePassXC") defaultFloating , NS "qalculate" "qalculate-gtk" (title =? "Qalculate!") (customFloating $ W.RationalRect (3/6) (1/6) (1/6) (1/6)) , NS "pavucontrol" "pavucontrol" (title =? "Lautstärkeregler") (customFloating $ W.RationalRect (1/6) (1/6) (2/3) (2/3)) ] -- topic space topicItems :: [TopicItem] topicItems = [ noAction "1" "~/" , noAction "2" "~/" , noAction "3" "~/" , noAction "4" "~/" , noAction "5" "~/" , TI "recipes" "~/projekte/recipes" (switchToLayout "Programming" *> spawnShellAndExecute "hugo server" *> proc (inProgram myBrowser) *> spawnEditor) , TI "alkaa" "~/projekte/alkaa" (switchToLayout "Programming" *> spawnShell *> spawnEditor) , TI "steam" "~" (switchToLayout "Steam" *> spawn "steam") , TI "game" "~" (switchToLayout "Full") , TI "micro" "~/projekte/microcontroller" (switchToLayout "Programming" *> spawnShell *> spawnEditor) , TI "aoc" "~/projekte/aoc" (switchToLayout "Programming" *> spawnShell *> spawnEditor) , TI "brass" "~/projekte/brass" (switchToLayout "Programming" *> spawnShell *> spawnEditor) , TI "infra" "~/projekte/infrastruktuuri" (switchToLayout "Programming" *> spawnShell *> spawnEditor) ] myTopicConfig :: TopicConfig myTopicConfig = def { topicDirs = tiDirs topicItems , topicActions = tiActions topicItems , defaultTopicAction = const (pure ()) , defaultTopic = "1" } spawnShell :: X () spawnShell = proc $ termInDir >-$ currentTopicDir myTopicConfig spawnEditor :: X () spawnEditor = proc $ (termInDir >-$ currentTopicDir myTopicConfig) >-> execute "nvim" switchToLayout :: String -> X () switchToLayout = sendMessage . JumpToLayout spawnShellAndExecute :: String -> X () spawnShellAndExecute cmd = proc $ (termInDir >-$ currentTopicDir myTopicConfig) >-> execute cmd toggleTopic :: X () toggleTopic = switchNthLastFocusedByScreen myTopicConfig 1 myWorkSpacePrompt :: XPConfig -> (String -> X ()) -> X () myWorkSpacePrompt c job = do ws <- gets (W.workspaces . windowset) sort <- getSortByIndex let filter = filterOutWs ["1", "2", "3", "4", "5", "NSP"] let ts = map W.tag $ filter ws mkXPrompt (Wor "") c (mkComplFunFromList' c ts) job topicPrompt :: XPConfig topicPrompt = def { historySize = 0 , fgColor = white , fgHLight = grey , bgHLight = red , alwaysHighlight = True , font = "xft:Iosevka-11" , height = 25 , position = CenteredAt 0.45 0.3 , promptBorderWidth = myBorderWidth , borderColor = red , maxComplRows = Just 10 , maxComplColumns = Just 1 , searchPredicate = fuzzyMatch , sorter = fuzzySort } -- search searx :: SearchEngine searx = searchEngine "searx" "https://search.tfld.de/search?q=" wiktionary :: SearchEngine wiktionary = searchEngine "wiktionary" "https://wiktionary.org/w/index.php?search=" searchList :: [(String, SearchEngine)] searchList = [ ("o", openstreetmap) , ("h", hackage) , ("w", wikipedia) , ("y", youtube) , ("s", searx) , ("t", wiktionary) ] -- keybindings myAdditionalKeys :: [(String, X ())] myAdditionalKeys = -- xmonad specific [ ("M-q", spawn "xmonad --recompile; xmonad --restart") , ("M-S-c", kill) , ("M-j", windows W.focusDown) , ("M-k", windows W.focusUp) , ("M-S-j", windows W.swapDown) , ("M-S-k", windows W.swapUp) , ("M-h", sendMessage Shrink) , ("M-l", sendMessage Expand) , ("M-,", sendMessage (IncMasterN 1)) , ("M-S-,", sendMessage (IncMasterN (-1))) , ("M-.", sendMessage ToggleStruts) -- dmenu prompts , ("M-", spawn "dmenu_run") , ("M-p s", spawn "dmenu_screenshot") , ("M-p k", spawn "dmenu_kill") -- scratchpads , ("M-s c", namedScratchpadAction myScratchpads "cmus") , ("M-s m", namedScratchpadAction myScratchpads "aerc") , ("M-s v", namedScratchpadAction myScratchpads "vimwiki") , ("M-s d", namedScratchpadAction myScratchpads "dino") , ("M-S-a", namedScratchpadAction myScratchpads "keepassxc") , ("M-n", namedScratchpadAction myScratchpads "nnn") , ("M-s a", namedScratchpadAction myScratchpads "pavucontrol") , ("M-s q", namedScratchpadAction myScratchpads "qalculate") -- some shortcuts for prorgrams , ("M-S-", spawnShell) , ("M-b", spawn myBrowser) -- layout , ("M-t t", switchToLayout "Tall") , ("M-t p", switchToLayout "Programming") , ("M-t f", switchToLayout "Full") , ("M-S-f", withFocused $ windows . W.sink) -- media keys , ("", spawn "pamixer -t") , ("", spawn "pamixer -d 5") , ("", spawn "pamixer -i 5") , ("", spawn "pamixer --default-source -t") -- lock screen , ("M-S-l", spawn "slock") -- workspace switching , ("M-", toggleTopic) , ("M-", myWorkSpacePrompt topicPrompt (switchTopic myTopicConfig)) , ("M-S-", myWorkSpacePrompt topicPrompt (windows . W.shift)) ] ++ -- use 1-5 for switching (Shift Mod shifts into) workspaces 1-5 [ ("M-" ++ m ++ k, f i) | (i, k) <- zip (topicNames topicItems) (map show [1 .. 5 :: Int]) , (f, m) <- [(switchTopic myTopicConfig, ""), (windows . W.shift, "S-")] ] -- Search commands ++ [("M-d " ++ k, promptSearch topicPrompt f) | (k,f) <- searchList ] ++ [("M-S-d " ++ k, selectSearch f) | (k,f) <- searchList ] -- Layouts mySpacing :: Integer -> l a -> ModifiedLayout Spacing l a mySpacing i = spacingRaw True (Border i i i i) True (Border i i i i) True myLayout = avoidStruts $ tiling ||| hacking ||| full ||| steam where tiling = renamed [Replace "Tall"] $ smartBorders $ mySpacing 6 $ Tall 1 (3/100) (1/2) hacking = renamed [Replace "Programming"] $ smartBorders $ mySpacing 6 $ Tall 1 (3/100) (5/8) full = noBorders Full steam = renamed [Replace "Steam"] $ noBorders $ mySpacing 3 $ Tall 1 (3/100) (6/8) -- Regex lifted up to use in manageHook (*!?) :: Functor f => f String -> String -> f Bool q *!? x = fmap (=~ x) q -- window rules myManageHook = composeAll . concat $ [ [ resource =? "desktop_window" --> doIgnore ] , [ resource =? "kdesktop" --> doIgnore ] , [ ( className =? "LibreWolf" <&&> role =? "Organizer" ) --> doFloat ] -- Steam and games , [ (className =? "steam" <||> className =? "steamwebhelper") --> doShift "steam" ] , [ (title *!? "Friends List" <||> title *!? "News" ) --> doF W.swapDown ] , [ title =? "Steam" --> doF W.shiftMaster ] , [ title =? t <&&> title *!? t --> doShift "game" | t <- myGames ] -- float specific classes , [ className =? c --> doFloat | c <- myFloatingClasses ] -- scratchpads , [ namedScratchpadManageHook myScratchpads ] ] where role = stringProperty "WM_WINDOW_ROLE" myFloatingClasses = ["Gimp", "Origin"] myGames = ["Grim Dawn", "Der Herr der Ringe Online™", "Dota 2", "Project Zomboid", "Valheim", "Factorio", "Path of Exile", "Paradox Launcher", "Europa Universalis IV", "Bannerlord"] myEventHook = dynamicPropertyChange "WM_NAME" (title =? "Database.kdbx - KeePassXC" <||> title =? "Database.kdbx [Gesperrt] - KeePassXC" --> floating) where floating = customFloating $ W.RationalRect (1/8) (1/8) (3/4) (3/4) -- Startup hook myStartupHook = do setWMName "LG3D" setDefaultCursor xC_left_ptr spawnOnce "redshift -c /home/max/.config/redshift/redshiftrc" spawnOnce "feh --bg-fill ~/bilder/bg.jpg" spawnOnce "/usr/bin/syncthing -no-browser -logfile=default" spawnOnce "autorandr -c" -- Main main = do xmproc <- spawnPipe "xmobar /home/max/.config/xmobar/xmobarrc" xmonad $ spawnExternalProcess def $ docks $ def { terminal = myTerminal, borderWidth = myBorderWidth, modMask = myModMask, workspaces = topicNames topicItems, normalBorderColor = white, focusedBorderColor = red, layoutHook = myLayout, manageHook = myManageHook, handleEventHook = myEventHook, logHook = workspaceHistoryHook >> dynamicLogWithPP (filterOutWsPP ["NSP"] $ xmobarPP { ppCurrent = xmobarColor red "" . wrap "[ " " ]", ppHidden = xmobarColor blue "", ppLayout = xmobarColor darkBlue "", ppTitle = xmobarColor orange "" . shorten 90, ppSep = " | ", ppOutput = hPutStrLn xmproc }), startupHook = myStartupHook } `additionalKeysP` myAdditionalKeys