{- |
Module      :  Text.XML.Basic.Position

Maintainer  :  tagsoup@henning-thielemann.de
Stability   :  provisional
Portability :  portable

Position in a file.

Cf. to Text.ParserCombinators.Parsec.Pos
-}

module Text.XML.Basic.Position (
    T, FileName, Row, Column,
    new, initialize,
    row, column, fileName,
    updateOnChar, updateOnString,
    toReportText,
   ) where

import qualified Data.Accessor.Basic as Accessor
-- import Data.Accessor.Basic ((^=), )

import Data.List (foldl')


type FileName = String
type Row      = Int
type Column   = Int

{- |
Position in a file consisting of file name, row and column coordinates.
Upper left is (0,0), but show routines can display this with different offsets.
-}
data T =
   Cons {
      T -> FileName
fileName_ :: FileName,
      T -> Row
row_      :: !Row,
      T -> Row
column_   :: !Column
   } deriving (T -> T -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: T -> T -> Bool
$c/= :: T -> T -> Bool
== :: T -> T -> Bool
$c== :: T -> T -> Bool
Eq,Eq T
T -> T -> Bool
T -> T -> Ordering
T -> T -> T
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: T -> T -> T
$cmin :: T -> T -> T
max :: T -> T -> T
$cmax :: T -> T -> T
>= :: T -> T -> Bool
$c>= :: T -> T -> Bool
> :: T -> T -> Bool
$c> :: T -> T -> Bool
<= :: T -> T -> Bool
$c<= :: T -> T -> Bool
< :: T -> T -> Bool
$c< :: T -> T -> Bool
compare :: T -> T -> Ordering
$ccompare :: T -> T -> Ordering
Ord)


new :: FileName -> Row -> Column -> T
new :: FileName -> Row -> Row -> T
new = FileName -> Row -> Row -> T
Cons

initialize :: FileName -> T
initialize :: FileName -> T
initialize FileName
fn = FileName -> Row -> Row -> T
new FileName
fn Row
0 Row
0


-- * access functions

fileName :: Accessor.T T FileName
fileName :: T T FileName
fileName = forall a r. (a -> r -> r) -> (r -> a) -> T r a
Accessor.fromSetGet (\FileName
fn T
p -> T
p{fileName_ :: FileName
fileName_ = FileName
fn}) T -> FileName
fileName_

row :: Accessor.T T Row
row :: T T Row
row = forall a r. (a -> r -> r) -> (r -> a) -> T r a
Accessor.fromSetGet (\Row
n T
p -> T
p{row_ :: Row
row_ = Row
n}) T -> Row
row_

column :: Accessor.T T Column
column :: T T Row
column = forall a r. (a -> r -> r) -> (r -> a) -> T r a
Accessor.fromSetGet (\Row
n T
p -> T
p{column_ :: Row
column_ = Row
n}) T -> Row
column_


-- * update position according to read characters

updateOnString :: T -> String -> T
updateOnString :: T -> FileName -> T
updateOnString T
pos FileName
string =
   forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (forall a b c. (a -> b -> c) -> b -> a -> c
flip Char -> T -> T
updateOnChar) T
pos FileName
string

updateOnChar   :: Char -> T -> T
updateOnChar :: Char -> T -> T
updateOnChar Char
char (Cons FileName
name Row
r Row
c) =
   let (Row
newRow, Row
newColumn) =
          case Char
char of
            Char
'\n' -> (forall a. Enum a => a -> a
succ Row
r, Row
0)
            Char
'\t' -> (Row
r, Row
c forall a. Num a => a -> a -> a
+ Row
8 forall a. Num a => a -> a -> a
- forall a. Integral a => a -> a -> a
mod Row
c Row
8)
            Char
_    -> (Row
r, forall a. Enum a => a -> a
succ Row
c)
   in  FileName -> Row -> Row -> T
Cons FileName
name Row
newRow Row
newColumn
--   in  (row ^= newRow) $ (column ^= newColumn) $ pos


-- * update position according to read characters

{- |
Convert the file position to a format
that development environments can understand.
-}
toReportText :: T -> String
toReportText :: T -> FileName
toReportText (Cons FileName
name Row
r Row
c) =
   forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (forall a. [a] -> [a] -> [a]
++FileName
":") [FileName
name, forall a. Show a => a -> FileName
show (Row
rforall a. Num a => a -> a -> a
+Row
1), forall a. Show a => a -> FileName
show (Row
cforall a. Num a => a -> a -> a
+Row
1)]

instance Show T where
  showsPrec :: Row -> T -> FileName -> FileName
showsPrec Row
p (Cons FileName
name Row
r Row
c) =
     Bool -> (FileName -> FileName) -> FileName -> FileName
showParen (Row
p forall a. Ord a => a -> a -> Bool
> Row
10)
        (FileName -> FileName -> FileName
showString forall a b. (a -> b) -> a -> b
$ [FileName] -> FileName
unwords forall a b. (a -> b) -> a -> b
$
            FileName
"Position.new" forall a. a -> [a] -> [a]
: forall a. Show a => a -> FileName
show FileName
name forall a. a -> [a] -> [a]
: forall a. Show a => a -> FileName
show Row
r forall a. a -> [a] -> [a]
: forall a. Show a => a -> FileName
show Row
c forall a. a -> [a] -> [a]
: [])