packages feed

pandoc-filter-indent-0.2.2.0: src/Render/Debug.hs

{-# LANGUAGE AllowAmbiguousTypes   #-}
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE FlexibleContexts      #-}
-- | Renders alignment to text with alignment markers,
--   for debugging purposes.
module Render.Debug(render, renderInline) where

import Data.Text (Text)
import qualified Data.Text as T
import Prelude hiding(getLine)
import Optics.Core ( view, Field2(..))

import FindColumns ( alignPos, getCol, tableColumns )
import Alignment ( textContent, Align(..), Processed )
import Util ( safeTail )

-- | Insert element at a given index of the list.
insertAt       :: Show a => Int -> a -> [a] -> [a]
insertAt i e ls = case maybeInsertAt i e ls of
                    Nothing -> error $ "Failed in insertAt " <> show i <> " " <> show e <> " " <> show ls
                    Just r  -> r

-- | Insert element at a given index of the list, or return error.
maybeInsertAt :: Int -> a -> [a] -> Maybe [a]
maybeInsertAt 0 e    ls  = pure $ e:ls
maybeInsertAt i e (l:ls) = (l:) <$> maybeInsertAt (i-1) e ls
maybeInsertAt _ _    []  = Nothing

-- | Render text of code blocks
--   with marker columns inserted
--   to indicate alignment boundaries.
render :: [Processed] -> Text
render ps = T.concat $ go ps
  where
    -- | Table columns between starting point of this segment and the next.
    lastColumn  = maximum tColumns + 1
    -- | Translates indices of alignment/table columns to text columns.
    tColumns :: [Int]
    tColumns = fst <$> tableColumns ps
    go  []        = []
    go (tok:toks) = alignMarker:textWithMarkers tColumns nextCol tok
                               :go toks
      where
        nextCol = case toks of
                    []       -> lastColumn
                    (next:_) -> getCol next
        alignMarker :: Text
        alignMarker  = case view alignPos tok of
                         Just (ACenter, _) -> "^"
                         Just _            -> "|"
                         otherwise         -> ""

-- | Text content with markers for markers inside it.
textWithMarkers tColumns nextCol tok = 
    T.pack $ insertMarkers unaccountedMarkers $ T.unpack $ view textContent tok
  where
    insertMarkers []   txt = txt
    insertMarkers mrks txt = foldr insertMarker txt mrks

    insertMarker index = insertAt index '.'
    unaccountedMarkers = fmap (-getCol tok+)
                       $ withoutKnownMarker
                       $ columnsBetween (getCol tok) nextCol
    withoutKnownMarker | Just _ <- view alignPos tok = safeTail
                       | otherwise                   = id
    columnsBetween :: Int -> Int -> [Int]
    columnsBetween colA colB = filter (\c -> c >= colA && c < colB) tColumns

renderInline :: Field2 a a Text Text => [a] -> Text
renderInline = mconcat . map (view _2)