packages feed

yavie-0.0.1: src/Yavie/Tools.hs

module Yavie.Tools (

  const2
, const3
, const4
, const5
, addIfMinus

, ctrl2strN
, ctrl2str
, tab2spaceN
, tab2space

, inFromMToN
, zeroToN
, intoMToN
, intoNToM

, intoLargerEq

, strIndices

, lastIndex

, reverseXY
, findIndexXY
, takeXY
, dropXY

, opfs

, normalizeTwoDot
, mkAbsoluteFilePath

) where

import Data.List        ( isPrefixOf, isInfixOf, findIndex )
import Data.Char        ( isControl, ord )
import System.FilePath  ( normalise, combine )
import System.Directory ( getCurrentDirectory )
import Numeric          ( showHex )
import Text.RegexPR     ( gsubRegexPR )

const2 :: a -> b -> c -> a
const2 = const . const

const3 :: a -> b -> c -> d -> a
const3 = const . const . const

const4 :: a -> b -> c -> d -> e -> a
const4 = const . const . const . const

const5 :: a -> b -> c -> d -> e -> f -> a
const5 = const . const . const . const . const

addIfMinus :: ( Num a, Ord a ) => a -> a -> a
addIfMinus a x | x < 0     = x + a
               | otherwise = x


isCtrl :: Char -> Bool
isCtrl c = isControl c && ( c /= '\t' )

ctrl2str :: String -> String
ctrl2str ""     = ""
ctrl2str ( c : cs )
  | isCtrl c  = '\\' : showHex2 ( ord c ) ++ ctrl2str cs
  | otherwise = c : ctrl2str cs
  where
  showHex2 n = let s = showHex n "" in replicate ( 2 - length s ) '0' ++ s

ctrl2strN :: String -> Int -> Int
ctrl2strN _          0 = 0
ctrl2strN ""         n = n
ctrl2strN ( c : cs ) n
  | isCtrl c  = 3 + ctrl2strN cs ( n - 1 )
  | otherwise = 1 + ctrl2strN cs ( n - 1 )

tab2spaceN :: String -> Int -> Int
tab2spaceN = t2sn 8

t2sn :: Int -> String -> Int -> Int
t2sn _ _             0 = 0
t2sn _ ""            n = n
t2sn i ( '\t' : cs ) n = i + t2sn 8 cs ( n - 1 )
t2sn i ( _    : cs ) n
  | i > 1     = 1 + t2sn ( i - 1 ) cs ( n - 1 )
  | otherwise = 1 + t2sn 8         cs ( n - 1 )

tab2space :: String -> String
tab2space = t2s 8

t2s :: Int -> String -> String
t2s _ ""            = ""
t2s i ( '\t' : cs ) = replicate i ' ' ++ t2s 8 cs
t2s i ( c    : cs )
  | i > 1           = c : t2s ( i - 1 ) cs
  | otherwise       = c : t2s 8         cs

zeroToN :: ( Num a, Ord a ) => a -> a -> a
zeroToN n x | x < 0 && 0 <= n          = 0
            |          0 <= n && n < x = n
            | x < n && n <  0          = n
            |          n <  0 && 0 < x = 0
            | otherwise = x

intoMToN :: ( Num a, Ord a ) => a -> a -> a -> a
intoMToN = intoNToM

intoNToM :: ( Num a, Ord a ) => a -> a -> a -> a
intoNToM n m x | x < n && n <= m          = n
               |          n <= m && m < x = m
               | x < m && m <  n          = m
               |          m <  n && n < x = n
               | otherwise                = x

intoLargerEq :: Ord a => a -> a -> a
intoLargerEq m n | n < m     = m
                 | otherwise = n

strIndices :: Eq a => [ a ] -> [ a ] -> [ Int ]
strIndices _   [ ]                = [ ]
strIndices str field@( _ : next )
  | str `isPrefixOf` field        = 0 : map (+ 1) ( strIndices str next )
  | otherwise                     =     map (+ 1) ( strIndices str next )

inFromMToN :: ( Num a, Ord a ) => a -> a -> a -> a
inFromMToN m n x
  |          m <= n && n < x = n
  | x < m && m <= n          = m
  |          m <= n          = x
  | otherwise                = error "inFromMToN: need m <= n"

lastIndex :: [ a ] -> Int
lastIndex = (+ (-1)) . length

reverseXY :: [ [ a ] ] -> [ [ a ] ]
reverseXY = map reverse . reverse

findIndexXY :: ( a -> Bool ) -> [ [ a ] ] -> Maybe ( Int, Int )
findIndexXY _ [ ]          = Nothing
findIndexXY p ( ln : lns ) =
  case ( findIndex p ln, findIndexXY p lns ) of
       ( Just i, _             ) -> Just ( i, 0     )
       ( _     , Just ( x, y ) ) -> Just ( x, y + 1 )
       _                         -> Nothing

takeXY, dropXY :: Int -> Int -> [ [ a ] ] -> [ [ a ] ]
takeXY xx yy ll = take yy ll ++ [ take xx ( ll !! yy ) ]
dropXY xx yy ll = drop xx ( ll !! yy ) : drop ( yy + 1 ) ll

opfs ::
  ( a -> b -> c ) -> ( a' -> b' -> c' ) -> ( a, a' ) -> ( b, b' ) -> ( c, c' )
opfs opf ops ( x, y ) ( x', y' ) = ( x `opf` x', y `ops` y' )

normalizeTwoDot :: FilePath -> FilePath
normalizeTwoDot fp 
  | ".." `isInfixOf` fp = normalizeTwoDot $ gsubRegexPR "/[^/]+/\\.\\./" "/" fp
  | otherwise           = fp

mkAbsoluteFilePath :: FilePath -> IO FilePath
mkAbsoluteFilePath fp = do
  cd <- getCurrentDirectory
  return $ normalizeTwoDot $ normalise $ cd `combine` fp