aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/app/ListPaths.hs
blob: 5834f1155c428b6b6fd57f5edd7ee6e273e96f27 (plain) (blame)
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
88
89
90
91
92
93
94
95
96
97
98
99
100
-- |
-- Copyright   : (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
-- License     : MIT
-- Maintainer  : Egor.Tensin@gmail.com
-- Stability   : experimental
-- Portability : Windows-only

module Main (main) where

import Control.Monad      (filterM)
import Control.Monad.Trans.Class  (lift)
import Control.Monad.Trans.Except (ExceptT, runExceptT)
import Data.Maybe         (fromMaybe)
import System.Directory   (doesDirectoryExist)
import System.Environment (lookupEnv)
import System.IO.Error    (ioError)

import Options.Applicative

import qualified WindowsEnv

data WhichPaths = All | ExistingOnly | MissingOnly
                deriving (Eq, Show)

shouldListPath :: WhichPaths -> WindowsEnv.VarValue -> IO Bool
shouldListPath All = return . const True
shouldListPath ExistingOnly = doesDirectoryExist
shouldListPath MissingOnly  = fmap not . doesDirectoryExist

data Source = Environment | Registry WindowsEnv.Profile
            deriving (Eq, Show)

data Options = Options
    { optName       :: WindowsEnv.VarName
    , optWhichPaths :: WhichPaths
    , optSource     :: Source
    } deriving (Eq, Show)

optionParser :: Parser Options
optionParser = Options
    <$> optNameDesc
    <*> optWhichPathsDesc
    <*> optSourceDesc
  where
    optNameDesc = strOption
         $ long "name" <> short 'n'
        <> metavar "NAME" <> value "PATH"
        <> help "Variable name ('PATH' by default)"
    optWhichPathsDesc = pure All
        <|> flag' ExistingOnly (long "existing" <> short 'e'
            <> help "List existing paths only")
        <|> flag' MissingOnly (long "missing" <> short 'm'
            <> help "List missing paths only")
    optSourceDesc = pure Environment
        <|> flag' (Registry WindowsEnv.CurrentUser) (long "user" <> short 'u'
            <> help "List current user's paths only")
        <|> flag' (Registry WindowsEnv.AllUsers) (long "global" <> short 'g'
            <> help "List global (all users') paths only")

main :: IO ()
main = execParser parser >>= listPaths
  where
    parser = info (helper <*> optionParser) $
        fullDesc <> progDesc "List directories in your PATH"

data ExpandedPath = ExpandedPath
    { pathOriginal :: WindowsEnv.VarValue
    , pathExpanded :: WindowsEnv.VarValue
    } deriving (Eq, Show)

splitAndExpand :: WindowsEnv.VarValue -> ExceptT IOError IO [ExpandedPath]
splitAndExpand pathValue = do
    expandedOnce <- expandOnce
    zipWith ExpandedPath originalPaths <$>
        if length expandedOnce == length originalPaths
            then return expandedOnce
            else expandEach
  where
    originalPaths = WindowsEnv.pathSplit pathValue
    expandOnce = WindowsEnv.pathSplit <$> WindowsEnv.expand pathValue
    expandEach = mapM WindowsEnv.expand originalPaths

listPaths :: Options -> IO ()
listPaths options = runExceptT doListPaths >>= either ioError return
  where
    varName = optName options
    whichPaths = optWhichPaths options

    query = queryFrom $ optSource options

    queryFrom Environment = lift $ fromMaybe "" <$> lookupEnv varName
    queryFrom (Registry profile) = WindowsEnv.query profile varName

    filterPaths = filterM (shouldListPath whichPaths . pathExpanded)

    doListPaths = do
        paths <- query >>= splitAndExpand
        lift $ do
            pathsToPrint <- filterPaths paths
            mapM_ (putStrLn . pathOriginal) pathsToPrint