-- Author: Andy Stewart -- Maintainer: Andy Stewart -- -- Copyright (C) 2010 Andy Stewart, all rights reserved. -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . module Manatee.Toolkit.General.FilePath where import Data.Array import Data.List import Manatee.Toolkit.General.List import System.FilePath import System.Process import Text.Regex.TDFA -- | Intersect two file path from end. fileIntersectEnd :: FilePath -> FilePath -> FilePath fileIntersectEnd xs ys = -- Remove otiose characters before path separator -- if have previous directory. case findIndex (== pathSeparator) zs of Just i -> drop (succ i) zs Nothing -> zs -- Get common string from end. where zs = intersectEnd xs ys -- | Get upper directory name. getUpperDirectoryName :: FilePath -> FilePath getUpperDirectoryName = takeFileName . dropTrailingPathSeparator . dropFileName -- | Get upper directory path. getUpperDirectory :: FilePath -> FilePath getUpperDirectory = dropFileName . dropTrailingPathSeparator -- | Try to expand file path that start with backtick. -- Just return original one when file path not start with backtick. expandBacktickFilePath :: FilePath -> IO FilePath expandBacktickFilePath filepath | filepath =~ "^~.*" :: Bool = expandFilePath filepath | otherwise = return filepath -- | Expand file name, -- including expand backtick and fill blank in filepath. expandFileName :: FilePath -> IO FilePath expandFileName = expandBacktickFilePath . fillFilePathBlank -- | Expand file path. expandFilePath :: FilePath -> IO FilePath expandFilePath filepath = fmap (head . lines) (readProcess "bash" ["-c", "echo " ++ filepath] []) -- | Fill blank in filepath with `\\ `. fillFilePathBlank :: FilePath -> FilePath fillFilePathBlank filepath = replaceRegex filepath "[^\\][ ]+" "\\ " where -- Replace regex match string with target string. replaceRegex string regex target = do -- Test match. let matchTextList = string =~ regex :: [MatchText String] if null matchTextList then -- Return original string if match nothing. string else do -- Replace regex match sting with target string. let indexList = map (snd . head . elems) matchTextList replaceMatchText indexList target string -- Replace match text. replaceMatchText indexList target string -- Return current string when list null. | null indexList = string -- Continue replace. | otherwise = matchBefore ++ newMatch ++ replaceMatchText newList target matchAfter where (matchOffset, matchLength) = head indexList (matchBefore, afterString) = splitAt matchOffset string (match, matchAfter) = splitAt matchLength afterString newMatch = head match : target adjust = matchOffset + matchLength newList = map (\(a,b) -> (a - adjust, b)) $ tail indexList -- | Filter dot directory. filterDotDirectory :: [FilePath] -> [FilePath] filterDotDirectory = filter notDotDirectory -- | Filter dot directory apply list. filterDotDirectoryApply :: (a -> FilePath) -> [a] -> [a] filterDotDirectoryApply = filter . (notDotDirectory .) -- | File not directory. notDotDirectory :: FilePath -> Bool notDotDirectory = (`notElem` [".", ".."]) -- | Like takeFileName, but won't return empty when filepath is root path '/' -- Instead return '/'. takeFileNameExceptRoot :: FilePath -> FilePath takeFileNameExceptRoot filepath | filepath == "/" = filepath | otherwise = takeFileName filepath