{-# LANGUAGE CPP #-}

------------------------------------------------------------------------------
-- |
-- Module: Utils
-- Copyright: (c) 2010, 2018, 2020, 2022 Jose Antonio Ortega Ruiz
-- License: BSD3-style (see LICENSE)
--
-- Maintainer: Jose A Ortega Ruiz <jao@gnu.org>
-- Stability: unstable
-- Portability: unportable
-- Created: Sat Dec 11, 2010 20:55
--
--
-- Miscellaneous utility functions
--
------------------------------------------------------------------------------


module Xmobar.System.Utils
  ( expandHome
  , changeLoop
  , safeIndex
  , forkThread
  ) where

import Control.Monad
import Control.Concurrent.STM
import Control.Exception (handle, SomeException(..))

#ifdef THREADED_RUNTIME
import Control.Concurrent (forkOS)
#else
import Control.Concurrent (forkIO)
#endif

import qualified Data.List.NonEmpty as NE
import Data.Maybe (fromMaybe)

import System.Environment
import System.FilePath

expandHome :: FilePath -> IO FilePath
expandHome :: FilePath -> IO FilePath
expandHome (Char
'~':Char
'/':FilePath
path) = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (FilePath -> FilePath -> FilePath
</> FilePath
path) (FilePath -> IO FilePath
getEnv FilePath
"HOME")
expandHome FilePath
p = forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
p

forkThread :: String -> IO () -> IO ()
forkThread :: FilePath -> IO () -> IO ()
forkThread FilePath
name IO ()
action = do
#ifdef THREADED_RUNTIME
    _ <- forkOS (handle (onError name) action)
#else
    ThreadId
_ <- IO () -> IO ThreadId
forkIO (forall e a. Exception e => (e -> IO a) -> IO a -> IO a
handle (FilePath -> SomeException -> IO ()
onError FilePath
name) IO ()
action)
#endif
    forall (m :: * -> *) a. Monad m => a -> m a
return ()
  where
    onError :: FilePath -> SomeException -> IO ()
onError FilePath
thing (SomeException e
e) =
      forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ FilePath -> IO ()
putStrLn (FilePath
"Thread " forall a. [a] -> [a] -> [a]
++ FilePath
thing forall a. [a] -> [a] -> [a]
++ FilePath
" failed: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> FilePath
show e
e)

changeLoop :: Eq a => STM a -> (a -> IO ()) -> IO ()
changeLoop :: forall a. Eq a => STM a -> (a -> IO ()) -> IO ()
changeLoop STM a
s a -> IO ()
f = forall a. STM a -> IO a
atomically STM a
s forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall {b}. a -> IO b
go
 where
    go :: a -> IO b
go a
old = do
        a -> IO ()
f a
old
        a -> IO b
go forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall a. STM a -> IO a
atomically (do
            a
new <- STM a
s
            forall (f :: * -> *). Alternative f => Bool -> f ()
guard (a
new forall a. Eq a => a -> a -> Bool
/= a
old)
            forall (m :: * -> *) a. Monad m => a -> m a
return a
new)

(!!?) :: [a] -> Int -> Maybe a
!!? :: forall a. [a] -> Int -> Maybe a
(!!?) [a]
xs Int
i
    | Int
i forall a. Ord a => a -> a -> Bool
< Int
0     = forall a. Maybe a
Nothing
    | Bool
otherwise = forall a. Int -> [a] -> Maybe a
go Int
i [a]
xs
  where
    go :: Int -> [a] -> Maybe a
    go :: forall a. Int -> [a] -> Maybe a
go Int
0 (a
x:[a]
_)  = forall a. a -> Maybe a
Just a
x
    go Int
j (a
_:[a]
ys) = forall a. Int -> [a] -> Maybe a
go (Int
j forall a. Num a => a -> a -> a
- Int
1) [a]
ys
    go Int
_ []     = forall a. Maybe a
Nothing
{-# INLINE (!!?) #-}

safeIndex :: NE.NonEmpty a -> Int -> a
safeIndex :: forall a. NonEmpty a -> Int -> a
safeIndex NonEmpty a
xs Int
index = forall a. a -> Maybe a -> a
fromMaybe (forall a. NonEmpty a -> a
NE.head NonEmpty a
xs) (forall a. NonEmpty a -> [a]
NE.toList NonEmpty a
xs forall a. [a] -> Int -> Maybe a
!!? Int
index)