vimus-0.2.0: src/Vimus/Util.hs
module Vimus.Util where
import Control.Applicative
import Data.List (isPrefixOf)
import Data.Char as Char
import Data.Maybe (fromJust)
import System.FilePath ((</>))
import System.Environment (getEnvironment)
import Network.MPD (MonadMPD, PlaylistName, Id)
import qualified Network.MPD as MPD
-- | Remove leading and trailing whitespace
strip :: String -> String
strip = dropWhile Char.isSpace . reverse . dropWhile Char.isSpace . reverse
data MatchResult = None | Match String | Ambiguous [String]
deriving (Eq, Show)
match :: String -> [String] -> MatchResult
match s l = case filter (isPrefixOf s) l of
[] -> None
[x] -> Match x
xs -> if s `elem` xs then Match s else Ambiguous xs
-- | Get longest common prefix of a list of strings.
--
-- >>> commonPrefix ["foobar", "foobaz", "foosomething"]
-- "foo"
commonPrefix :: [String] -> String
commonPrefix [] = ""
commonPrefix xs = foldr1 go xs
where
go (y:ys) (z:zs)
| y == z = y : go ys zs
go _ _ = []
-- | Add a song which is inside a playlist, returning its id.
addPlaylistSong :: MonadMPD m => PlaylistName -> Int -> m Id
addPlaylistSong plist index = do
current <- MPD.playlistInfo Nothing
MPD.load plist
new <- MPD.playlistInfo Nothing
let (first, this:rest) = splitAt index . map (fromJust . MPD.sgId) $ drop (length current) new
mapM_ MPD.deleteId $ first ++ rest
return this
-- | A copy of `System.Process.Internals.translate`.
posixEscape :: String -> String
posixEscape str = '\'' : foldr escape "'" str
where escape '\'' = showString "'\\''"
escape c = showChar c
-- | Expand a tilde at the start of a string to the users home directory.
--
-- Expansion is only performed if the tilde is either followed by a slash or
-- the only character in the string.
expandHome :: FilePath -> IO (Either String FilePath)
expandHome path = do
home <- maybe err Right . lookup "HOME" <$> getEnvironment
case path of
"~" -> return home
'~' : '/' : xs -> return $ (</> xs) `fmap` home
xs -> return (Right xs)
where
err = Left ("expansion of " ++ show path ++ " failed: $HOME is not defined")
-- | Confine a number to an interval.
--
-- The result will be greater or equal to a given lower bound and (if still
-- possible) smaller than a given upper bound.
clamp :: Int -- ^ lower bound (inclusive)
-> Int -- ^ upper bound (exclusive)
-> Int
-> Int
clamp lower upper n = max lower $ min (pred upper) n
-- | Emit ANSI sequence to change the console window title.
setTitle :: String -> IO ()
setTitle title = putStrLn $ "\ESC]0;" ++ filter (/= '\007') title ++ "\007"