From 461fc783c74f706a9c692d0a28ee48a8139056c1 Mon Sep 17 00:00:00 2001 From: ndwarshuis Date: Sat, 19 Jun 2021 15:06:02 -0400 Subject: [PATCH] ENH distinguish between required and optional deps --- bin/xmonad.hs | 4 +-- lib/XMonad/Internal/Command/DMenu.hs | 4 +-- lib/XMonad/Internal/Command/Desktop.hs | 12 +++---- lib/XMonad/Internal/Shell.hs | 45 +++++++++++++++++--------- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/bin/xmonad.hs b/bin/xmonad.hs index 51d4611..1a80564 100644 --- a/bin/xmonad.hs +++ b/bin/xmonad.hs @@ -468,8 +468,8 @@ filterExternal = fmap go where go k@KeyGroup { kgBindings = bs } = k { kgBindings = mapMaybe go' bs } - go' k@KeyBinding { kbAction = Installed x } = Just $ k { kbAction = x } - go' _ = Nothing + go' k@KeyBinding { kbAction = Installed x _ } = Just $ k { kbAction = x } + go' _ = Nothing externalBindings :: ThreadState -> [KeyGroup (IO MaybeX)] externalBindings ts = diff --git a/lib/XMonad/Internal/Command/DMenu.hs b/lib/XMonad/Internal/Command/DMenu.hs index 2fe1694..fc8f91a 100644 --- a/lib/XMonad/Internal/Command/DMenu.hs +++ b/lib/XMonad/Internal/Command/DMenu.hs @@ -62,7 +62,7 @@ myDmenuMatchingArgs = ["-i"] -- case insensitivity -- | Exported Commands runDevMenu :: IO MaybeX -runDevMenu = runIfInstalled [myDmenuDevices] $ do +runDevMenu = runIfInstalled [Required myDmenuDevices] $ do c <- io $ getXdgDirectory XdgConfig "rofi/devices.yml" spawnCmd myDmenuDevices $ ["-c", c] @@ -70,7 +70,7 @@ runDevMenu = runIfInstalled [myDmenuDevices] $ do ++ myDmenuMatchingArgs runBwMenu :: IO MaybeX -runBwMenu = runIfInstalled [myDmenuPasswords] $ +runBwMenu = runIfInstalled [Required myDmenuPasswords] $ spawnCmd myDmenuPasswords $ ["-c", "--"] ++ themeArgs "#bb6600" ++ myDmenuMatchingArgs -- TODO what to do with this if rofi doesn't exist? diff --git a/lib/XMonad/Internal/Command/Desktop.hs b/lib/XMonad/Internal/Command/Desktop.hs index fce7c30..2a7b058 100644 --- a/lib/XMonad/Internal/Command/Desktop.hs +++ b/lib/XMonad/Internal/Command/Desktop.hs @@ -91,7 +91,7 @@ runTerm :: IO MaybeX runTerm = spawnIfInstalled myTerm runTMux :: IO MaybeX -runTMux = runIfInstalled [myTerm, "tmux", "bash"] cmd +runTMux = runIfInstalled [Required myTerm, Required "tmux", Required "bash"] cmd where cmd = spawn $ "tmux has-session" @@ -101,7 +101,7 @@ runTMux = runIfInstalled [myTerm, "tmux", "bash"] cmd msg = "could not connect to tmux session" runCalc :: IO MaybeX -runCalc = runIfInstalled [myTerm, "R"] $ spawnCmd myTerm ["-e", "R"] +runCalc = runIfInstalled [Required myTerm, Required "R"] $ spawnCmd myTerm ["-e", "R"] runBrowser :: IO MaybeX runBrowser = spawnIfInstalled myBrowser @@ -144,7 +144,7 @@ runVolumeMute = spawnSound volumeChangeSound (void toggleMute) $ return () -- | System commands runToggleBluetooth :: IO MaybeX -runToggleBluetooth = runIfInstalled [myBluetooth] $ spawn +runToggleBluetooth = runIfInstalled [Required myBluetooth] $ spawn $ myBluetooth ++ " show | grep -q \"Powered: no\"" #!&& "a=on" #!|| "a=off" @@ -167,7 +167,7 @@ runToggleDPMS :: X () runToggleDPMS = io $ void callToggle runToggleEthernet :: IO MaybeX -runToggleEthernet = runIfInstalled ["nmcli"] $ spawn +runToggleEthernet = runIfInstalled [Required "nmcli"] $ spawn $ "nmcli -g GENERAL.STATE device show " ++ ethernetIface ++ " | grep -q disconnected" #!&& "a=connect" #!|| "a=disconnect" @@ -225,7 +225,7 @@ getCaptureDir = do fallback = ( ".local/share") <$> getHomeDirectory runFlameshot :: String -> IO MaybeX -runFlameshot mode = runIfInstalled [myCapture] $ do +runFlameshot mode = runIfInstalled [Required myCapture] $ do ssDir <- io getCaptureDir spawnCmd myCapture $ mode : ["-p", ssDir] @@ -243,6 +243,6 @@ runScreenCapture :: IO MaybeX runScreenCapture = runFlameshot "screen" runCaptureBrowser :: IO MaybeX -runCaptureBrowser = runIfInstalled [myImageBrowser] $ do +runCaptureBrowser = runIfInstalled [Required myImageBrowser] $ do dir <- io getCaptureDir spawnCmd myImageBrowser [dir] diff --git a/lib/XMonad/Internal/Shell.hs b/lib/XMonad/Internal/Shell.hs index 5702411..a273d44 100644 --- a/lib/XMonad/Internal/Shell.hs +++ b/lib/XMonad/Internal/Shell.hs @@ -3,6 +3,7 @@ module XMonad.Internal.Shell ( MaybeExe(..) + , Dependency(..) , MaybeX , IOMaybeX , runIfInstalled @@ -25,45 +26,57 @@ module XMonad.Internal.Shell import Control.Monad (filterM) import Control.Monad.IO.Class -import Data.Maybe (isNothing) +import Data.Maybe (isJust) -import System.FilePath.Posix import System.Directory (findExecutable) +import System.FilePath.Posix -import XMonad.Core (getXMonadDir, X) +import XMonad.Core (X, getXMonadDir) import XMonad.Internal.Process -------------------------------------------------------------------------------- -- | Gracefully handling missing binaries -data MaybeExe m = Installed (m ()) | Missing [String] | Noop +data Dependency = Required String | Optional String deriving (Eq, Show) + +data MaybeExe m = Installed (m ()) [String] | Missing [Dependency] | Ignore type MaybeX = MaybeExe X type IOMaybeX = IO MaybeX -runIfInstalled :: MonadIO m => [String] -> m () -> IO (MaybeExe m) -runIfInstalled exes x = do - missing <- filterM (fmap isNothing . findExecutable) exes - return $ case missing of - [] -> Installed x - ms -> Missing ms +exeInstalled :: String -> IO Bool +exeInstalled x = isJust <$> findExecutable x + +depInstalled :: Dependency -> IO Bool +depInstalled (Required d) = exeInstalled d +depInstalled (Optional d) = exeInstalled d + +filterMissing :: [Dependency] -> IO [Dependency] +filterMissing = filterM (fmap not . depInstalled) + +runIfInstalled :: MonadIO m => [Dependency] -> m () -> IO (MaybeExe m) +runIfInstalled ds x = do + missing <- filterMissing ds + return $ if null [m | Required m <- missing] + then Installed x [m | Optional m <- missing] + else Missing missing spawnIfInstalled :: MonadIO m => String -> IO (MaybeExe m) -spawnIfInstalled exe = runIfInstalled [exe] $ spawn exe +spawnIfInstalled exe = runIfInstalled [Required exe] $ spawn exe spawnCmdIfInstalled :: MonadIO m => String -> [String] -> IO (MaybeExe m) -spawnCmdIfInstalled exe args = runIfInstalled [exe] $ spawnCmd exe args +spawnCmdIfInstalled exe args = runIfInstalled [Required exe] $ spawnCmd exe args whenInstalled :: Monad m => MaybeExe m -> m () -whenInstalled (Installed x) = x -whenInstalled _ = return () +whenInstalled (Installed x _) = x +whenInstalled _ = return () skip :: Monad m => m () skip = return () noCheck :: Monad m => a () -> m (MaybeExe a) -noCheck = return . Installed +noCheck = return . flip Installed [] -------------------------------------------------------------------------------- -- | Opening subshell @@ -78,7 +91,7 @@ soundDir :: FilePath soundDir = "sound" spawnSound :: MonadIO m => FilePath -> m () -> m () -> IO (MaybeExe m) -spawnSound file pre post = runIfInstalled ["paplay"] +spawnSound file pre post = runIfInstalled [Required "paplay"] $ pre >> playSound file >> post playSound :: MonadIO m => FilePath -> m ()