{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE ViewPatterns          #-}
{-# LANGUAGE ExplicitForAll        #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE FlexibleContexts      #-}
-- | Find alignment columns.
module FindColumns(findColumns, getLine, getCol, getLineCol, alignPos, tableColumns) where

import Text.Pandoc.JSON
import Text.Pandoc.Definition ()
import Data.Function  (on)
import Data.String    (fromString, IsString)
import Data.Text      (Text)
import Data.List      (groupBy, sortBy, sort, group, elemIndex)
import Prelude hiding (getLine)
import Optics.Core
import Data.Tuple.Optics

import Token
import Token.Haskell
import Tuples
import Alignment
import Util
import Debug.Trace

-- | Records tokenized and converted to common token format.
type Unanalyzed = (MyTok, MyLoc, Text
                  , Maybe Int -- Indent for entire line
                  )

-- | Records aligned, but without column numbers yet.
type Aligned   = (MyTok       -- token type
                 ,MyLoc       -- text start location
                 ,Text        -- text content
                 ,Maybe Int   -- indent in this column
                 ,Maybe Align -- alignment
                 )

-- * Definitions of fields accessible at many stages
getCol, getLine :: Field2 a a MyLoc MyLoc => a -> Int
getCol :: forall a. Field2 a a MyLoc MyLoc => a -> Int
getCol  = Optic' A_Lens NoIx a Int -> a -> Int
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view (Optic' A_Lens NoIx a Int -> a -> Int)
-> Optic' A_Lens NoIx a Int -> a -> Int
forall a b. (a -> b) -> a -> b
$ Lens a a MyLoc MyLoc
forall s t a b. Field2 s t a b => Lens s t a b
_2 Lens a a MyLoc MyLoc
-> Optic A_Lens NoIx MyLoc MyLoc Int Int
-> Optic' A_Lens NoIx a Int
forall k l m (is :: IxList) (js :: IxList) (ks :: IxList) s t u v a
       b.
(JoinKinds k l m, AppendIndices is js ks) =>
Optic k is s t u v -> Optic l js u v a b -> Optic m ks s t a b
% Optic A_Lens NoIx MyLoc MyLoc Int Int
col
getLine :: forall a. Field2 a a MyLoc MyLoc => a -> Int
getLine = Optic' A_Lens NoIx a Int -> a -> Int
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view (Optic' A_Lens NoIx a Int -> a -> Int)
-> Optic' A_Lens NoIx a Int -> a -> Int
forall a b. (a -> b) -> a -> b
$ Lens a a MyLoc MyLoc
forall s t a b. Field2 s t a b => Lens s t a b
_2 Lens a a MyLoc MyLoc
-> Optic A_Lens NoIx MyLoc MyLoc Int Int
-> Optic' A_Lens NoIx a Int
forall k l m (is :: IxList) (js :: IxList) (ks :: IxList) s t u v a
       b.
(JoinKinds k l m, AppendIndices is js ks) =>
Optic k is s t u v -> Optic l js u v a b -> Optic m ks s t a b
% Optic A_Lens NoIx MyLoc MyLoc Int Int
line

align :: Field5 a a (Maybe b) (Maybe b) => Lens' a (Maybe b)
align :: forall a b. Field5 a a (Maybe b) (Maybe b) => Lens' a (Maybe b)
align  = Lens a a (Maybe b) (Maybe b)
forall s t a b. Field5 s t a b => Lens s t a b
_5

-- | From a record with alignment option, select this option.
alignPos :: Field5 a a (Maybe (Align, Int)) (Maybe (Align, Int)) => Lens' a (Maybe (Align, Int))
alignPos :: forall a.
Field5 a a (Maybe (Align, Int)) (Maybe (Align, Int)) =>
Lens' a (Maybe (Align, Int))
alignPos  = Lens a a (Maybe (Align, Int)) (Maybe (Align, Int))
forall s t a b. Field5 s t a b => Lens s t a b
_5

-- | Find columns from tokens.
findColumns :: [Tokenized] -> [Processed]
findColumns :: [Tokenized] -> [Processed]
findColumns =
      ([Aligned], [(Int, Maybe Align)]) -> [Processed]
forall b. ([Aligned], [(Int, b)]) -> [Processed]
columnIndices
    (([Aligned], [(Int, Maybe Align)]) -> [Processed])
-> ([Tokenized] -> ([Aligned], [(Int, Maybe Align)]))
-> [Tokenized]
-> [Processed]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Aligned] -> ([Aligned], [(Int, Maybe Align)])
forall {a}.
(Field2 a a MyLoc MyLoc, Field5 a a (Maybe Align) (Maybe Align)) =>
[a] -> ([a], [(Int, Maybe Align)])
withExtraColumns
    ([Aligned] -> ([Aligned], [(Int, Maybe Align)]))
-> ([Tokenized] -> [Aligned])
-> [Tokenized]
-> ([Aligned], [(Int, Maybe Align)])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Aligned -> Aligned -> Ordering) -> [Aligned] -> [Aligned]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy ((Int, Int) -> (Int, Int) -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ((Int, Int) -> (Int, Int) -> Ordering)
-> (Aligned -> (Int, Int)) -> Aligned -> Aligned -> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Aligned -> (Int, Int)
forall a. Field2 a a MyLoc MyLoc => a -> (Int, Int)
getLineCol)
    ([Aligned] -> [Aligned])
-> ([Tokenized] -> [Aligned]) -> [Tokenized] -> [Aligned]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Unanalyzed] -> [Aligned]) -> [[Unanalyzed]] -> [Aligned]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap [Unanalyzed] -> [Aligned]
markBoundaries
    ([[Unanalyzed]] -> [Aligned])
-> ([Tokenized] -> [[Unanalyzed]]) -> [Tokenized] -> [Aligned]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Unanalyzed -> Int) -> [Unanalyzed] -> [[Unanalyzed]]
forall k a. Ord k => (a -> k) -> [a] -> [[a]]
grouping Unanalyzed -> Int
forall a. Field2 a a MyLoc MyLoc => a -> Int
getCol
    ([Unanalyzed] -> [[Unanalyzed]])
-> ([Tokenized] -> [Unanalyzed]) -> [Tokenized] -> [[Unanalyzed]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Tokenized] -> [Unanalyzed]) -> [[Tokenized]] -> [Unanalyzed]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap [Tokenized] -> [Unanalyzed]
addLineIndent
    ([[Tokenized]] -> [Unanalyzed])
-> ([Tokenized] -> [[Tokenized]]) -> [Tokenized] -> [Unanalyzed]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Tokenized -> Int) -> [Tokenized] -> [[Tokenized]]
forall k a. Ord k => (a -> k) -> [a] -> [[a]]
grouping Tokenized -> Int
forall a. Field2 a a MyLoc MyLoc => a -> Int
getLine

-- | Extract both line and column where a token starts.
getLineCol :: Field2 a a MyLoc MyLoc => a -> (Int, Int)
getLineCol :: forall a. Field2 a a MyLoc MyLoc => a -> (Int, Int)
getLineCol a
x = (a -> Int
forall a. Field2 a a MyLoc MyLoc => a -> Int
getLine a
x, a -> Int
forall a. Field2 a a MyLoc MyLoc => a -> Int
getCol a
x)

-- | Mark alignment boundaries.
markBoundaries :: [Unanalyzed] -> [Aligned]
markBoundaries :: [Unanalyzed] -> [Aligned]
markBoundaries = (Aligned -> Aligned) -> [Aligned] -> [Aligned]
forall a b. (a -> b) -> [a] -> [b]
map Aligned -> Aligned
markIndent
               -- . (\b -> trace ("ALIGNED: " <> show b) b)
               ([Aligned] -> [Aligned])
-> ([Unanalyzed] -> [Aligned]) -> [Unanalyzed] -> [Aligned]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Unanalyzed] -> [Aligned]) -> [[Unanalyzed]] -> [Aligned]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap [Unanalyzed] -> [Aligned]
alignBlock
               -- . (\b -> trace ("BLOCKS: " <> show b) b)
               ([[Unanalyzed]] -> [Aligned])
-> ([Unanalyzed] -> [[Unanalyzed]]) -> [Unanalyzed] -> [Aligned]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Unanalyzed] -> [[Unanalyzed]]
blocks
               ([Unanalyzed] -> [[Unanalyzed]])
-> ([Unanalyzed] -> [Unanalyzed]) -> [Unanalyzed] -> [[Unanalyzed]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Unanalyzed -> Unanalyzed -> Ordering)
-> [Unanalyzed] -> [Unanalyzed]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Int -> Int -> Ordering)
-> (Unanalyzed -> Int) -> Unanalyzed -> Unanalyzed -> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Unanalyzed -> Int
forall {a} {c} {d}. (a, MyLoc, c, d) -> Int
getLine)
  where
    getLine :: (a, MyLoc, c, d) -> Int
getLine (a
tok, MyLoc Int
line Int
col Bool
_, c
_, d
_) = Int
line

-- | If first indented token is yet unmarked, mark it as boundary.
--   FIXME: remove boundaries from not `mark`s.
markIndent :: Aligned -> Aligned
markIndent :: Aligned -> Aligned
markIndent (MyTok
TBlank, myLoc :: MyLoc
myLoc@(MyLoc Int
_ Int
1 Bool
_), Text
txt, Just Int
indent, Maybe Align
_) =
           (MyTok
TBlank, MyLoc
myLoc              , Text
txt, Int -> Maybe Int
forall a. a -> Maybe a
Just Int
indent, Align -> Maybe Align
forall a. a -> Maybe a
Just Align
AIndent)
markIndent (MyTok
myTok,  myLoc :: MyLoc
myLoc@(MyLoc Int
_ Int
col Bool
True), Text
txt, Just Int
indent, Maybe Align
_) | Int
indent Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
col =
           (MyTok
myTok,  MyLoc
myLoc                   , Text
txt, Int -> Maybe Int
forall a. a -> Maybe a
Just Int
indent, Align -> Maybe Align
forall a. a -> Maybe a
Just Align
ALeft)
markIndent Aligned
other                                                               = Aligned
other

-- | Append alignment option to unanalyzed token record.
withAlign :: Maybe Align -> Unanalyzed -> Aligned
withAlign :: Maybe Align -> Unanalyzed -> Aligned
withAlign  = (Unanalyzed -> Maybe Align -> Aligned)
-> Maybe Align -> Unanalyzed -> Aligned
forall a b c. (a -> b -> c) -> b -> a -> c
flip Unanalyzed -> Maybe Align -> Aligned
forall c b a. Annex c b a => b -> a -> c
annex

-- | Given a list of unanalyzed token records in a single column,
--   check the alignment option that applies to this column.
alignBlock :: [Unanalyzed] -> [Aligned]
alignBlock :: [Unanalyzed] -> [Aligned]
alignBlock [Unanalyzed
a]                            = Maybe Align -> Unanalyzed -> Aligned
withAlign  Maybe Align
forall a. Maybe a
Nothing       (Unanalyzed -> Aligned) -> [Unanalyzed] -> [Aligned]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Unanalyzed
a]
alignBlock [Unanalyzed]
opList | (Unanalyzed -> Bool) -> [Unanalyzed] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Unanalyzed -> Bool
forall {b} {c} {d}. (MyTok, b, c, d) -> Bool
isOperator ((Unanalyzed -> Bool) -> [Unanalyzed] -> [Unanalyzed]
forall a. (a -> Bool) -> [a] -> [a]
filter Unanalyzed -> Bool
forall {a} {c} {d}. (a, MyLoc, c, d) -> Bool
isMarked [Unanalyzed]
opList) =
              (Unanalyzed -> Aligned) -> [Unanalyzed] -> [Aligned]
forall {f :: * -> *} {a} {b} {a}.
(Functor f, Field2 a a MyLoc MyLoc, Annex b a (Maybe a)) =>
(a -> b) -> f a -> f b
withMarked (Maybe Align -> Unanalyzed -> Aligned
withAlign (Maybe Align -> Unanalyzed -> Aligned)
-> Maybe Align -> Unanalyzed -> Aligned
forall a b. (a -> b) -> a -> b
$ Align -> Maybe Align
forall a. a -> Maybe a
Just Align
ACenter) [Unanalyzed]
opList
  where
    isOperator :: (MyTok, b, c, d) -> Bool
isOperator (MyTok
TOperator, b
_,   c
_, d
_) = Bool
True
    isOperator  (MyTok, b, c, d)
_                     = Bool
False
    isMarked :: (a, MyLoc, c, d) -> Bool
isMarked (a
_, MyLoc Int
_ Int
_ Bool
True, c
_, d
_) = Bool
True
    isMarked (a
_, MyLoc
_,              c
_, d
_) = Bool
False
alignBlock [Unanalyzed]
aList                          =
              (Unanalyzed -> Aligned) -> [Unanalyzed] -> [Aligned]
forall {f :: * -> *} {a} {b} {a}.
(Functor f, Field2 a a MyLoc MyLoc, Annex b a (Maybe a)) =>
(a -> b) -> f a -> f b
withMarked (Maybe Align -> Unanalyzed -> Aligned
withAlign (Maybe Align -> Unanalyzed -> Aligned)
-> Maybe Align -> Unanalyzed -> Aligned
forall a b. (a -> b) -> a -> b
$ Align -> Maybe Align
forall a. a -> Maybe a
Just Align
ALeft  ) [Unanalyzed]
aList

withMarked :: (a -> b) -> f a -> f b
withMarked a -> b
f f a
aList = a -> b
apply (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> f a
aList
  where
    apply :: a -> b
apply entry :: a
entry@(Optic' A_Lens NoIx a MyLoc -> a -> MyLoc
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view Optic' A_Lens NoIx a MyLoc
forall s t a b. Field2 s t a b => Lens s t a b
_2 -> MyLoc Int
_ Int
_ Bool
True) = a -> b
f a
entry
    apply a
entry                             = a
entry a -> Maybe a -> b
forall c b a. Annex c b a => b -> a -> c
`annex` Maybe a
forall a. Maybe a
Nothing

-- | Compute all alignment columns existing and their positions in the text column space.
--   Note: Deduplicates by text column position only (not by alignment type)
--   to ensure consistency with tableColumns and avoid gaps in table column indices.
extraColumns :: Field2 a a  MyLoc         MyLoc
             => Field5 a a (Maybe Align) (Maybe Align)
             => [a] -> [(Int, Maybe Align)]
extraColumns :: forall a.
(Field2 a a MyLoc MyLoc, Field5 a a (Maybe Align) (Maybe Align)) =>
[a] -> [(Int, Maybe Align)]
extraColumns =
    ((Int, Maybe Align) -> (Int, Maybe Align) -> Ordering)
-> [(Int, Maybe Align)] -> [(Int, Maybe Align)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
nubSortedBy (Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Int -> Int -> Ordering)
-> ((Int, Maybe Align) -> Int)
-> (Int, Maybe Align)
-> (Int, Maybe Align)
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (Int, Maybe Align) -> Int
forall a b. (a, b) -> a
fst)  -- Deduplicate by text column position only
  ([(Int, Maybe Align)] -> [(Int, Maybe Align)])
-> ([a] -> [(Int, Maybe Align)]) -> [a] -> [(Int, Maybe Align)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Int, Maybe Align) -> Bool)
-> [(Int, Maybe Align)] -> [(Int, Maybe Align)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int, Maybe Align) -> Bool
forall {a} {a}. (a, Maybe a) -> Bool
hasAlignment
  ([(Int, Maybe Align)] -> [(Int, Maybe Align)])
-> ([a] -> [(Int, Maybe Align)]) -> [a] -> [(Int, Maybe Align)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> (Int, Maybe Align)) -> [a] -> [(Int, Maybe Align)]
forall a b. (a -> b) -> [a] -> [b]
map a -> (Int, Maybe Align)
forall {s} {b}.
(Field2 s s MyLoc MyLoc, Field5 s s (Maybe b) (Maybe b)) =>
s -> (Int, Maybe b)
extract
  where
    extract :: s -> (Int, Maybe b)
extract s
x = (s -> Int
forall a. Field2 a a MyLoc MyLoc => a -> Int
getCol s
x, Optic' A_Lens NoIx s (Maybe b) -> s -> Maybe b
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view Optic' A_Lens NoIx s (Maybe b)
forall a b. Field5 a a (Maybe b) (Maybe b) => Lens' a (Maybe b)
align s
x)
    hasAlignment :: (a, Maybe a) -> Bool
hasAlignment (a
_, Maybe a
Nothing) = Bool
False
    hasAlignment (a
_, Just a
_)  = Bool
True

withExtraColumns :: [a] -> ([a], [(Int, Maybe Align)])
withExtraColumns [a]
x = ([a]
x, [a] -> [(Int, Maybe Align)]
forall a.
(Field2 a a MyLoc MyLoc, Field5 a a (Maybe Align) (Maybe Align)) =>
[a] -> [(Int, Maybe Align)]
extraColumns [a]
x)

-- | Compute all alignment columns existing and their positions in the text column space.
-- TEST: check that we always have correct number of columns
-- FIXME: known bug that may be caused by this one
tableColumns :: Field2 a a  MyLoc     MyLoc
             => Field5 a a (Maybe b) (Maybe b)
             => [a]
             -> [(Int, Maybe b)]
tableColumns :: forall a b.
(Field2 a a MyLoc MyLoc, Field5 a a (Maybe b) (Maybe b)) =>
[a] -> [(Int, Maybe b)]
tableColumns  =
    ((Int, Maybe b) -> (Int, Maybe b) -> Ordering)
-> [(Int, Maybe b)] -> [(Int, Maybe b)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
nubSortedBy (Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Int -> Int -> Ordering)
-> ((Int, Maybe b) -> Int)
-> (Int, Maybe b)
-> (Int, Maybe b)
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (Int, Maybe b) -> Int
forall a b. (a, b) -> a
fst)
  ([(Int, Maybe b)] -> [(Int, Maybe b)])
-> ([a] -> [(Int, Maybe b)]) -> [a] -> [(Int, Maybe b)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Int, Maybe b) -> Bool) -> [(Int, Maybe b)] -> [(Int, Maybe b)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int, Maybe b) -> Bool
forall {a} {a}. (a, Maybe a) -> Bool
hasAlignment
  ([(Int, Maybe b)] -> [(Int, Maybe b)])
-> ([a] -> [(Int, Maybe b)]) -> [a] -> [(Int, Maybe b)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> (Int, Maybe b)) -> [a] -> [(Int, Maybe b)]
forall a b. (a -> b) -> [a] -> [b]
map a -> (Int, Maybe b)
forall {s} {b}.
(Field2 s s MyLoc MyLoc, Field5 s s (Maybe b) (Maybe b)) =>
s -> (Int, Maybe b)
extract
  where
    extract :: s -> (Int, Maybe b)
extract s
x                 = (s -> Int
forall a. Field2 a a MyLoc MyLoc => a -> Int
getCol s
x, Optic' A_Lens NoIx s (Maybe b) -> s -> Maybe b
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view Optic' A_Lens NoIx s (Maybe b)
forall a b. Field5 a a (Maybe b) (Maybe b) => Lens' a (Maybe b)
align s
x)
    hasAlignment :: (a, Maybe a) -> Bool
hasAlignment (a
_, Maybe a
Nothing) = Bool
False
    hasAlignment (a
_, Just a
_)  = Bool
True

-- | Extract information about depth of indent in a line where token is.
getIndent :: Unanalyzed -> Maybe Int
getIndent = Optic' A_Lens NoIx Unanalyzed (Maybe Int)
-> Unanalyzed -> Maybe Int
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view Optic' A_Lens NoIx Unanalyzed (Maybe Int)
forall s t a b. Field4 s t a b => Lens s t a b
_4

-- | Detect uninterrupted stretches that cover consecutive columns.
--   NOTE: replacing with `groupBy` would not work due to comparison of consecutive only
blocks :: [Unanalyzed] -> [[Unanalyzed]]
blocks :: [Unanalyzed] -> [[Unanalyzed]]
blocks (Unanalyzed
b:[Unanalyzed]
bs) = [Unanalyzed] -> [Unanalyzed] -> [[Unanalyzed]]
go [Unanalyzed
b] [Unanalyzed]
bs
  where
    go :: [Unanalyzed] -> [Unanalyzed] -> [[Unanalyzed]]
go currentBlock :: [Unanalyzed]
currentBlock@((Unanalyzed -> Maybe Int
getIndent -> Maybe Int
Nothing):[Unanalyzed]
_) (b :: Unanalyzed
b@(Unanalyzed -> Int
forall a. Field2 a a MyLoc MyLoc => a -> Int
getLine -> Int
nextLine):[Unanalyzed]
bs) =
        [Unanalyzed] -> [Unanalyzed] -> [[Unanalyzed]]
go (Unanalyzed
bUnanalyzed -> [Unanalyzed] -> [Unanalyzed]
forall a. a -> [a] -> [a]
:[Unanalyzed]
currentBlock)         [Unanalyzed]
bs
    go currentBlock :: [Unanalyzed]
currentBlock@((Unanalyzed -> Int
forall a. Field2 a a MyLoc MyLoc => a -> Int
getLine -> Int
lastLine):[Unanalyzed]
_) (b :: Unanalyzed
b@(Unanalyzed -> Int
forall a. Field2 a a MyLoc MyLoc => a -> Int
getLine -> Int
nextLine):[Unanalyzed]
bs)
      | Int
nextLine Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
lastLine Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 = -- add ignoring of unindented (Nothing)
        [Unanalyzed] -> [Unanalyzed] -> [[Unanalyzed]]
go (Unanalyzed
bUnanalyzed -> [Unanalyzed] -> [Unanalyzed]
forall a. a -> [a] -> [a]
:[Unanalyzed]
currentBlock)         [Unanalyzed]
bs
    go (Unanalyzed
c:[Unanalyzed]
currentBlock)                         (blank :: Unanalyzed
blank@(Unanalyzed -> Maybe Int
getIndent -> Maybe Int
Nothing):[Unanalyzed]
bs) =
        [Unanalyzed] -> [Unanalyzed] -> [[Unanalyzed]]
go (Unanalyzed
cUnanalyzed -> [Unanalyzed] -> [Unanalyzed]
forall a. a -> [a] -> [a]
:Unanalyzed
blankUnanalyzed -> [Unanalyzed] -> [Unanalyzed]
forall a. a -> [a] -> [a]
:[Unanalyzed]
currentBlock)   [Unanalyzed]
bs
    go [Unanalyzed]
currentBlock                             (Unanalyzed
b                     :[Unanalyzed]
bs) =
        [Unanalyzed] -> [Unanalyzed]
forall a. [a] -> [a]
reverse [Unanalyzed]
currentBlock[Unanalyzed] -> [[Unanalyzed]] -> [[Unanalyzed]]
forall a. a -> [a] -> [a]
:[Unanalyzed] -> [Unanalyzed] -> [[Unanalyzed]]
go [Unanalyzed
b] [Unanalyzed]
bs
    go [Unanalyzed]
currentBlock                             []                          =
       [[Unanalyzed] -> [Unanalyzed]
forall a. [a] -> [a]
reverse [Unanalyzed]
currentBlock]

-- | Add line indent to each token in line.
addLineIndent :: [Tokenized] -> [Unanalyzed]
addLineIndent :: [Tokenized] -> [Unanalyzed]
addLineIndent [Tokenized]
aLine = (Tokenized -> Maybe Int -> Unanalyzed
forall c b a. Annex c b a => b -> a -> c
`annex` Maybe Int
indentColumn) (Tokenized -> Unanalyzed) -> [Tokenized] -> [Unanalyzed]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Tokenized]
aLine
  where
    indentColumn :: Maybe Int
    indentColumn :: Maybe Int
indentColumn = [Tokenized] -> Maybe Int
forall {a} {c}. [(a, MyLoc, c)] -> Maybe Int
extractColumn ([Tokenized] -> Maybe Int) -> [Tokenized] -> Maybe Int
forall a b. (a -> b) -> a -> b
$ (Tokenized -> Bool) -> [Tokenized] -> [Tokenized]
forall a. (a -> Bool) -> [a] -> [a]
filter Tokenized -> Bool
forall {b} {c}. (MyTok, b, c) -> Bool
notBlank [Tokenized]
aLine
    notBlank :: (MyTok, b, c) -> Bool
notBlank       (MyTok
TBlank, b
_, c
_)                 = Bool
False
    notBlank        (MyTok, b, c)
_                             = Bool
True
    extractColumn :: [(a, MyLoc, c)] -> Maybe Int
extractColumn  []                             = Maybe Int
forall a. Maybe a
Nothing
    extractColumn  ((a
_,   MyLoc Int
line Int
col Bool
_, c
_):[(a, MyLoc, c)]
_) = Int -> Maybe Int
forall a. a -> Maybe a
Just Int
col
    -- FIXME: is it only for `mark` columns?

-- | Given a list of aligned records, and a list of marker columns,
--   add table column indices to each record.
columnIndices :: ([Aligned], [(Int, b)]) -> [Processed]
columnIndices :: forall b. ([Aligned], [(Int, b)]) -> [Processed]
columnIndices ([Aligned]
allAligned, ((Int, b) -> Int) -> [(Int, b)] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int, b) -> Int
forall a b. (a, b) -> a
fst -> [Int]
markerColumns) = (Aligned -> Processed) -> [Aligned] -> [Processed]
forall a b. (a -> b) -> [a] -> [b]
map Aligned -> Processed
addIndex [Aligned]
allAligned
  where
    addIndex :: Aligned -> Processed
    addIndex :: Aligned -> Processed
addIndex Aligned
aligned = (Lens Aligned Processed (Maybe Align) (Maybe (Align, Int))
forall s t a b. Field5 s t a b => Lens s t a b
_5 Lens Aligned Processed (Maybe Align) (Maybe (Align, Int))
-> (Maybe Align -> Maybe (Align, Int)) -> Aligned -> Processed
forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
`over` Maybe Align -> Maybe (Align, Int)
mod) Aligned
aligned
      where
        mod :: Maybe Align -> Maybe (Align, Int)
        mod :: Maybe Align -> Maybe (Align, Int)
mod Maybe Align
Nothing   = Maybe (Align, Int)
forall a. Maybe a
Nothing
        mod (Just  Align
a) =
             (Align, Int) -> Maybe (Align, Int)
forall a. a -> Maybe a
Just (Align
a, Int
colIndex)
          where
            colIndex :: Int
colIndex = case Int -> [Int] -> Maybe Int
forall a. Eq a => a -> [a] -> Maybe Int
elemIndex (Aligned -> Int
forall a. Field2 a a MyLoc MyLoc => a -> Int
getCol Aligned
aligned) [Int]
markerColumns of
                         Maybe Int
Nothing -> [Char] -> Int
forall a. HasCallStack => [Char] -> a
error ([Char] -> Int) -> [Char] -> Int
forall a b. (a -> b) -> a -> b
$ [Char]
"Did not find the index for column " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> Int -> [Char]
forall a. Show a => a -> [Char]
show (Aligned -> Int
forall a. Field2 a a MyLoc MyLoc => a -> Int
getCol Aligned
aligned) [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
" within " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Int] -> [Char]
forall a. Show a => a -> [Char]
show [Int]
markerColumns
                         Just Int
i  -> Int
i