{-| The TDisplayFile module provides 'TDisplay.TDTag' definitions and corresponding functions to allow the FSOps elements to be described for "TDisplay" usage. All of the functions here are used to obtain either a set of 'TDisplay.TDOutput' objects or a 'TDisplay.TDOutputsS' showing function representing a filepath; the functions in this module differ primarily in the type of input arguments and the type of the output. -} module FSOps.TDisplayFile ( -- * TDisplay TDTag objects tdTag_filepath, tdTag_filebase, tdTag_filedir, tdTag_filename, -- * TDisplay representation functions -- $filesplit_doc tdFilePath, tdFileInfoPath, tdFileInfoPaths, ) where import Data.List (isPrefixOf) import FSOps.FileBase (pathsplit) import FSOps.FileInfo (FileInfoClass(..)) import TDisplay -- | A TDGroup tag which will contain a filepath broken into components. tdTag_filepath :: TDTag tdTag_filepath = TDTag "filepath" [ "text", "filepath", "group" ] -- | The portion of a filepath that represents the base directory path. tdTag_filebase :: TDTag tdTag_filebase = TDTag "filebase" [ "text" ] -- | The portion of a filepath that represents the subdirectory path under the base. tdTag_filedir :: TDTag tdTag_filedir = TDTag "filedir" [ "text" ] -- | The final name portion of a filepath. tdTag_filename :: TDTag tdTag_filename = TDTag "filename" [ "text", "filename" ] {- $filesplit_doc The functions in this module that create "TDisplay" objects from input parameters attempt to recognize and mark three distinct portions of a filepath: the base portion, the directory portion, and the name portion. At the most basic level, these functions take two or three arguments providing various portions of the file path: 1. The first argument is a filepath base which is to be marked with the 'tdTag_filebase' tag. 2. The second argument is a directory specification which will be marked with the 'tdTag_filedir' tag. * If this argument is a relative path, it is assumed to be relative to the first argument. * If this argument is an absolute path and it begins with the first argument, that latter portion will be removed from the resulting directory specification. * Otherwise, this argument is an absolute path and does not begin with the first argument, in which case the first argument is ignored. 3. The third argument is the file name and will be marked with the 'tdTag_filename' tag. If it contains path portions, those will be appended to the second argument and this argument reduced to only the final component. If the function only takes two arguments then the first is the base and the second is the directory and filename combined. For example, if a tool \"@mytool@\" were invoked as: @ $ mytool \/foo\/bar@ and found a file \"@\/foo\/bar\/cow\/goes\/moo@\", then this function could be called with \"@\/foo\/bar@\" as the first argument, \"@cow\/@\" as the second argument, and \"@goes\/moo@\" as the third argument. The result would be: @ TDGroup tdTag_filepath TDString tdTag_filebase "\/foo\/bar\/" TDString tdTag_filedir "cow\/goes\/" TDString tdTag_filename "moo" @ -} {- The i_tdfilepath is an internal function used to generate a TDOutput object from various input information describing a filepath as described by the $filesplit_doc above. Assumes regularized d and n as might be obtained by pathsplit, although it will handle the case where n begins with a slash. Will NOT handle the case where b is part of n as well as d. -} --kwq: if path or name ends in '/', should there be only a directory portion and no name portion? i_tdfilepath :: String -> String -> String -> TDOutput i_tdfilepath b d n = TDGroup tdTag_filepath $ Left $ map (uncurry TDString) epairs where epairs = zip [tdTag_filebase, tdTag_filedir, tdTag_filename] elements elements = adjust_seps b (rmv_base b d) n rmv_base a f | "" == a = f | isPrefixOf (a ++ "/") f = drop (1 + length a) f | isPrefixOf a f = drop (length a) f | otherwise = f adjust_seps x "" ('/':z) | '/' == last x = adjust_seps x "" z | otherwise = adjust_seps (x ++ "/") "" z adjust_seps "" y ('/':z) | '/' == last y = adjust_seps "" y z | otherwise = adjust_seps "" (y ++ "/") z adjust_seps x "" z | '/' == last x = [x, "", z] | otherwise = [x ++ "/", "", z] adjust_seps "" y z | '/' == last y = ["", y, z] | otherwise = ["", y ++ "/", z] adjust_seps x ('/':y) z | '/' == last x = adjust_seps x y z | otherwise = adjust_seps (x ++ "/") y z adjust_seps x y ('/':z) | '/' == last y = adjust_seps x y z | otherwise = adjust_seps x (y ++ "/") z adjust_seps x y z | '/' == last x && '/' == last y = [x, y, z] | '/' == last x = [x, y ++ "/", z] | '/' == last y = [x ++ "/", y, z] | otherwise = [x,y,z] {- | Creates a 'TDisplay.TDOutput' set of objects representing a file path. The first argument is the base path, and the second argument specifies the filepath, which is broken into path and final name components. -} tdFilePath :: String -> String -> TDOutput tdFilePath b n = let fname = snd . pathsplit fpath = fst . pathsplit in i_tdfilepath b (fpath n) (fname n) {- | Creates a 'TDisplay.TDOutput' set of objects representing a file path. The first argument is the base path and the second argument specifies the 'FSOps.FileInfo.FileInfoClass' object to be represented. -} tdFileInfoPath :: (FileInfoClass a) => String -> a -> TDOutput tdFileInfoPath b n = i_tdfilepath b (path_to n) (name n) {- | Creates a 'TDisplay.TDOutputsS' display function representing a file path. The first argument is the base path and the second argument specifies the 'FSOps.FileInfo.FileInfoClass' object to be represented. -} tdFileInfoPaths :: (FileInfoClass a) => String -> a -> TDOutputsS tdFileInfoPaths b n = (++) [(tdFileInfoPath b n)]