1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
diff --git a/src/XMonad/Core.hs b/src/XMonad/Core.hs
index 69ddb2a..15eb97f 100644
--- a/src/XMonad/Core.hs
+++ b/src/XMonad/Core.hs
@@ -523,35 +523,61 @@ type Directories = Directories' FilePath
 -- always assumed to be in @cfgDir@.
 --
 getDirectories :: IO Directories
-getDirectories = xmEnvDirs <|> xmDirs <|> xdgDirs
+getDirectories = do
+    dataDir <- mma xmEnvDataDir xmDataDir xdgDataDir
+    cfgDir <- mma xmEnvCfgDir xmCfgDir xdgCfgDir
+    cacheDir <- mma xmEnvCacheDir xmCacheDir xdgCacheDir
+    pure $ Directories { dataDir, cfgDir, cacheDir}
+
   where
+    mma fa fb fc = fa >>= \case
+        Just a -> pure a
+        Nothing -> fb >>= \case
+          Just b -> pure b
+          Nothing -> fc
+
     -- | Check for xmonad's environment variables first
-    xmEnvDirs :: IO Directories
-    xmEnvDirs = do
-        let xmEnvs = Directories{ dataDir  = "XMONAD_DATA_DIR"
-                                , cfgDir   = "XMONAD_CONFIG_DIR"
-                                , cacheDir = "XMONAD_CACHE_DIR"
-                                }
-        maybe empty pure . sequenceA =<< traverse getEnv xmEnvs
+    xmEnvDataDir, xmEnvCfgDir, xmEnvCacheDir :: IO (Maybe FilePath)
+    xmEnvDataDir  = getEnv "XMONAD_DATA_DIR"
+    xmEnvCfgDir   = getEnv "XMONAD_CONFIG_DIR"
+    xmEnvCacheDir = getEnv "XMONAD_CACHE_DIR"
+
+    -- this is a tiny bit inefficient, but it's not worth the extra complexity
 
     -- | Check whether the config file or a build script is in the
-    -- @~\/.xmonad@ directory
-    xmDirs :: IO Directories
-    xmDirs = do
+    xmDataDir, xmCfgDir, xmCacheDir :: IO (Maybe FilePath)
+    xmCfgDir = do
         xmDir <- getAppUserDataDirectory "xmonad"
         conf  <- doesFileExist $ xmDir </> "xmonad.hs"
-        build <- doesFileExist $ xmDir </> "build"
+        pure $ if conf then Just xmDir else Nothing
 
-        -- Place *everything* in ~/.xmonad if yes
-        guard $ conf || build
-        pure Directories{ dataDir = xmDir, cfgDir = xmDir, cacheDir = xmDir }
+    xmCacheDir = do
+        xmDir <- getAppUserDataDirectory "xmonad"
+        build <- doesFileExist $ xmDir </> "build"
+        pure $ if build then Just xmDir else Nothing
+
+    xmDataDir = do
+        cfgDir <- xmCfgDir
+        cacheDir <- xmCacheDir
+        -- only set it if one of the other two exist
+        if isJust cfgDir || isJust cacheDir
+            then Just <$> getAppUserDataDirectory "xmonad"
+            else pure Nothing
+
+    xdgDataDir, xdgCfgDir, xdgCacheDir :: IO FilePath
+    xdgDataDir = do
+        dataDir <- getXdgDirectory XdgData "xmonad"
+        createDirectoryIfMissing True dataDir
+        pure  dataDir
+    xdgCfgDir = do
+        cfgDir <- getXdgDirectory XdgConfig "xmonad"
+        createDirectoryIfMissing True cfgDir
+        pure cfgDir
+    xdgCacheDir = do
+        cacheDir <- getXdgDirectory XdgCache "xmonad"
+        createDirectoryIfMissing True cacheDir
+        pure cacheDir
 
-    -- | Use XDG directories as a fallback
-    xdgDirs :: IO Directories
-    xdgDirs =
-        for Directories{ dataDir = XdgData, cfgDir = XdgConfig, cacheDir = XdgCache }
-            $ \dir -> do d <- getXdgDirectory dir "xmonad"
-                         d <$ createDirectoryIfMissing True d
 
 -- | Return the path to the xmonad configuration directory.
 getXMonadDir :: X String