{-# LANGUAGE CPP #-}
module Agda.Interaction.Highlighting.LaTeX.Base
( LaTeXOptions(..)
, generateLaTeXIO
, prepareCommonAssets
, MonadLogLaTeX(logLaTeX)
, LogMessage(..)
, logMsgToText
) where
import Prelude hiding (log)
import Data.Bifunctor (second)
import Data.Char
import Data.Maybe
import Data.Function (on)
import Data.Foldable (toList)
import Control.Exception.Base (IOException, try)
import Control.Monad.Trans.Reader as R ( ReaderT(runReaderT))
import Control.Monad.RWS.Strict
( RWST(runRWST)
, MonadReader(..), asks
, MonadState(..), gets, modify
, lift, tell
)
import Control.Monad.IO.Class
( MonadIO(..)
)
import System.Directory
import System.FilePath
import System.Process ( readProcess )
import Data.Text (Text)
import qualified Data.Text as T
#ifdef COUNT_CLUSTERS
import qualified Data.Text.ICU as ICU
#endif
import qualified Data.Text.Lazy as L
import qualified Data.Text.Lazy.Encoding as E
import qualified Data.ByteString.Lazy as BS
import Data.HashSet (HashSet)
import qualified Data.HashSet as Set
import qualified Data.IntMap as IntMap
import qualified Data.List as List
import Agda.Syntax.Common
import Agda.Syntax.Parser.Literate (literateTeX, LayerRole, atomizeLayers)
import qualified Agda.Syntax.Parser.Literate as L
import Agda.Syntax.Position (RangeFile, startPos')
import Agda.Syntax.TopLevelModuleName
(TopLevelModuleName, moduleNameParts)
import Agda.Interaction.Highlighting.Precise hiding (toList)
import Agda.TypeChecking.Monad (Interface(..))
import Agda.Setup ( getDataFileName )
import Agda.Utils.Function (applyWhen)
import Agda.Utils.Functor ((<&>))
import Agda.Utils.List (last1, updateHead, updateLast)
import Agda.Utils.Maybe (whenJust)
import Agda.Utils.Monad
import qualified Agda.Utils.List1 as List1
import Agda.Utils.Impossible
class Monad m => MonadLogLaTeX m where
logLaTeX :: LogMessage -> m ()
data LogMessage = LogMessage Debug Text [Text] deriving Int -> LogMessage -> ShowS
[LogMessage] -> ShowS
LogMessage -> [Char]
(Int -> LogMessage -> ShowS)
-> (LogMessage -> [Char])
-> ([LogMessage] -> ShowS)
-> Show LogMessage
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> LogMessage -> ShowS
showsPrec :: Int -> LogMessage -> ShowS
$cshow :: LogMessage -> [Char]
show :: LogMessage -> [Char]
$cshowList :: [LogMessage] -> ShowS
showList :: [LogMessage] -> ShowS
Show
type LaTeXT = RWST Env [Output] State
type LaTeX a = forall m. MonadLogLaTeX m => LaTeXT m a
data Output
= Text !Text
| MaybeColumn !AlignmentColumn
deriving Int -> Output -> ShowS
[Output] -> ShowS
Output -> [Char]
(Int -> Output -> ShowS)
-> (Output -> [Char]) -> ([Output] -> ShowS) -> Show Output
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Output -> ShowS
showsPrec :: Int -> Output -> ShowS
$cshow :: Output -> [Char]
show :: Output -> [Char]
$cshowList :: [Output] -> ShowS
showList :: [Output] -> ShowS
Show
data Kind
= Indentation
| Alignment
deriving (Kind -> Kind -> Bool
(Kind -> Kind -> Bool) -> (Kind -> Kind -> Bool) -> Eq Kind
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Kind -> Kind -> Bool
== :: Kind -> Kind -> Bool
$c/= :: Kind -> Kind -> Bool
/= :: Kind -> Kind -> Bool
Eq, Int -> Kind -> ShowS
[Kind] -> ShowS
Kind -> [Char]
(Int -> Kind -> ShowS)
-> (Kind -> [Char]) -> ([Kind] -> ShowS) -> Show Kind
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Kind -> ShowS
showsPrec :: Int -> Kind -> ShowS
$cshow :: Kind -> [Char]
show :: Kind -> [Char]
$cshowList :: [Kind] -> ShowS
showList :: [Kind] -> ShowS
Show)
type IndentationColumnId = Int
data AlignmentColumn = AlignmentColumn
{ AlignmentColumn -> Int
columnCodeBlock :: !Int
, AlignmentColumn -> Int
columnColumn :: !Int
, AlignmentColumn -> Maybe Int
columnKind :: Maybe IndentationColumnId
} deriving Int -> AlignmentColumn -> ShowS
[AlignmentColumn] -> ShowS
AlignmentColumn -> [Char]
(Int -> AlignmentColumn -> ShowS)
-> (AlignmentColumn -> [Char])
-> ([AlignmentColumn] -> ShowS)
-> Show AlignmentColumn
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AlignmentColumn -> ShowS
showsPrec :: Int -> AlignmentColumn -> ShowS
$cshow :: AlignmentColumn -> [Char]
show :: AlignmentColumn -> [Char]
$cshowList :: [AlignmentColumn] -> ShowS
showList :: [AlignmentColumn] -> ShowS
Show
type TextWidthEstimator = Text -> Int
data Env = Env
{ Env -> TextWidthEstimator
estimateTextWidth :: !TextWidthEstimator
, Env -> [Debug]
debugs :: [Debug]
}
data State = State
{ State -> Int
codeBlock :: !Int
, State -> Int
column :: !Int
, State -> [AlignmentColumn]
columns :: [AlignmentColumn]
, State -> [AlignmentColumn]
columnsPrev :: [AlignmentColumn]
, State -> Int
nextId :: !IndentationColumnId
, State -> HashSet Int
usedColumns :: HashSet IndentationColumnId
}
type Tokens = [Token]
data Token = Token
{ Token -> Text
text :: !Text
, Token -> Aspects
info :: Aspects
}
deriving Int -> Token -> ShowS
[Token] -> ShowS
Token -> [Char]
(Int -> Token -> ShowS)
-> (Token -> [Char]) -> ([Token] -> ShowS) -> Show Token
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Token -> ShowS
showsPrec :: Int -> Token -> ShowS
$cshow :: Token -> [Char]
show :: Token -> [Char]
$cshowList :: [Token] -> ShowS
showList :: [Token] -> ShowS
Show
withTokenText :: (Text -> Text) -> Token -> Token
withTokenText :: (Text -> Text) -> Token -> Token
withTokenText Text -> Text
f tok :: Token
tok@Token{text :: Token -> Text
text = Text
t} = Token
tok{text = f t}
data Debug = MoveColumn | NonCode | Code | Spaces | Output | FileSystem
deriving (Debug -> Debug -> Bool
(Debug -> Debug -> Bool) -> (Debug -> Debug -> Bool) -> Eq Debug
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Debug -> Debug -> Bool
== :: Debug -> Debug -> Bool
$c/= :: Debug -> Debug -> Bool
/= :: Debug -> Debug -> Bool
Eq, Int -> Debug -> ShowS
[Debug] -> ShowS
Debug -> [Char]
(Int -> Debug -> ShowS)
-> (Debug -> [Char]) -> ([Debug] -> ShowS) -> Show Debug
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Debug -> ShowS
showsPrec :: Int -> Debug -> ShowS
$cshow :: Debug -> [Char]
show :: Debug -> [Char]
$cshowList :: [Debug] -> ShowS
showList :: [Debug] -> ShowS
Show)
runLaTeX :: MonadLogLaTeX m =>
LaTeXT m a -> Env -> State -> m (a, State, [Output])
runLaTeX :: forall (m :: * -> *) a.
MonadLogLaTeX m =>
LaTeXT m a -> Env -> State -> m (a, State, [Output])
runLaTeX = RWST Env [Output] State m a
-> Env -> State -> m (a, State, [Output])
forall r w s (m :: * -> *) a.
RWST r w s m a -> r -> s -> m (a, s, w)
runRWST
emptyState :: State
emptyState :: State
emptyState = State
{ codeBlock :: Int
codeBlock = Int
0
, column :: Int
column = Int
0
, columns :: [AlignmentColumn]
columns = []
, columnsPrev :: [AlignmentColumn]
columnsPrev = []
, nextId :: Int
nextId = Int
0
, usedColumns :: HashSet Int
usedColumns = HashSet Int
forall a. HashSet a
Set.empty
}
emptyEnv
:: TextWidthEstimator
-> Env
emptyEnv :: TextWidthEstimator -> Env
emptyEnv TextWidthEstimator
twe = TextWidthEstimator -> [Debug] -> Env
Env TextWidthEstimator
twe []
size :: Text -> LaTeX Int
size :: Text -> LaTeX Int
size Text
t = (Env -> TextWidthEstimator)
-> RWST Env [Output] State m TextWidthEstimator
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Env -> TextWidthEstimator
estimateTextWidth RWST Env [Output] State m TextWidthEstimator
-> (TextWidthEstimator -> Int) -> RWST Env [Output] State m Int
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (TextWidthEstimator -> TextWidthEstimator
forall a b. (a -> b) -> a -> b
$ Text
t)
isSpaces :: Text -> Bool
isSpaces :: Text -> Bool
isSpaces = (Char -> Bool) -> Text -> Bool
T.all Char -> Bool
isSpace
isSpaceNotNewline :: Char -> Bool
isSpaceNotNewline :: Char -> Bool
isSpaceNotNewline Char
c = Char -> Bool
isSpace Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\n'
replaceSpaces :: Text -> Text
replaceSpaces :: Text -> Text
replaceSpaces = (Char -> Char) -> Text -> Text
T.map (\Char
c -> if Char -> Bool
isSpaceNotNewline Char
c then Char
' ' else Char
c)
moveColumnForToken :: Token -> LaTeX ()
moveColumnForToken :: Token -> LaTeX ()
moveColumnForToken Token{ text :: Token -> Text
text = Text
t } = do
Bool
-> RWST Env [Output] State m () -> RWST Env [Output] State m ()
forall b (m :: * -> *). (IsBool b, Monad m) => b -> m () -> m ()
unless (Text -> Bool
isSpaces Text
t) do
Debug -> Text -> LaTeX ()
log Debug
MoveColumn Text
t
Int -> RWST Env [Output] State m ()
forall (m :: * -> *). MonadLogLaTeX m => Int -> LaTeXT m ()
moveColumn (Int -> RWST Env [Output] State m ())
-> RWST Env [Output] State m Int -> RWST Env [Output] State m ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Text -> LaTeX Int
size Text
t
resetColumn :: LaTeX ()
resetColumn :: LaTeX ()
resetColumn = (State -> State) -> RWST Env [Output] State m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((State -> State) -> RWST Env [Output] State m ())
-> (State -> State) -> RWST Env [Output] State m ()
forall a b. (a -> b) -> a -> b
$ \State
s ->
State
s { column = 0
, columnsPrev = mergeCols (columns s) (columnsPrev s)
, columns = []
}
where
mergeCols :: [AlignmentColumn] -> [AlignmentColumn] -> [AlignmentColumn]
mergeCols [] [AlignmentColumn]
old = [AlignmentColumn]
old
mergeCols new :: [AlignmentColumn]
new@(AlignmentColumn
n:[AlignmentColumn]
ns) [AlignmentColumn]
old = [AlignmentColumn]
new [AlignmentColumn] -> [AlignmentColumn] -> [AlignmentColumn]
forall a. [a] -> [a] -> [a]
++ (AlignmentColumn -> Bool) -> [AlignmentColumn] -> [AlignmentColumn]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
leastNew) (Int -> Bool)
-> (AlignmentColumn -> Int) -> AlignmentColumn -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AlignmentColumn -> Int
columnColumn) [AlignmentColumn]
old
where
leastNew :: Int
leastNew = AlignmentColumn -> Int
columnColumn (AlignmentColumn -> [AlignmentColumn] -> AlignmentColumn
forall a. a -> [a] -> a
last1 AlignmentColumn
n [AlignmentColumn]
ns)
moveColumn :: MonadLogLaTeX m => Int -> LaTeXT m ()
moveColumn :: forall (m :: * -> *). MonadLogLaTeX m => Int -> LaTeXT m ()
moveColumn Int
i = (State -> State) -> RWST Env [Output] State m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify \ State
s -> State
s { column = i + column s }
registerColumn :: Kind -> LaTeX AlignmentColumn
registerColumn :: Kind -> LaTeX AlignmentColumn
registerColumn Kind
kind = do
column <- (State -> Int) -> RWST Env [Output] State m Int
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets State -> Int
column
codeBlock <- gets codeBlock
colKind <- case kind of
Kind
Alignment -> Maybe Int -> RWST Env [Output] State m (Maybe Int)
forall a. a -> RWST Env [Output] State m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Int
forall a. Maybe a
Nothing
Kind
Indentation -> do
nextId <- (State -> Int) -> RWST Env [Output] State m Int
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets State -> Int
nextId
modify $ \State
s -> State
s { nextId = succ nextId }
return (Just nextId)
let c = AlignmentColumn { columnColumn :: Int
columnColumn = Int
column
, columnCodeBlock :: Int
columnCodeBlock = Int
codeBlock
, columnKind :: Maybe Int
columnKind = Maybe Int
colKind
}
modify $ \State
s -> State
s { columns = c : columns s }
return c
useColumn :: AlignmentColumn -> LaTeX ()
useColumn :: AlignmentColumn -> LaTeX ()
useColumn AlignmentColumn
c = Maybe Int
-> (Int -> RWST Env [Output] State m ())
-> RWST Env [Output] State m ()
forall (m :: * -> *) a. Monad m => Maybe a -> (a -> m ()) -> m ()
whenJust (AlignmentColumn -> Maybe Int
columnKind AlignmentColumn
c) ((Int -> RWST Env [Output] State m ())
-> RWST Env [Output] State m ())
-> (Int -> RWST Env [Output] State m ())
-> RWST Env [Output] State m ()
forall a b. (a -> b) -> a -> b
$ \ Int
i ->
(State -> State) -> RWST Env [Output] State m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((State -> State) -> RWST Env [Output] State m ())
-> (State -> State) -> RWST Env [Output] State m ()
forall a b. (a -> b) -> a -> b
$ \ State
s -> State
s { usedColumns = Set.insert i (usedColumns s) }
columnZero :: LaTeX AlignmentColumn
columnZero :: LaTeX AlignmentColumn
columnZero = do
codeBlock <- (State -> Int) -> RWST Env [Output] State m Int
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets State -> Int
codeBlock
return $ AlignmentColumn { columnColumn = 0
, columnCodeBlock = codeBlock
, columnKind = Nothing
}
registerColumnZero :: LaTeX ()
registerColumnZero :: LaTeX ()
registerColumnZero = do
c <- LaTeXT m AlignmentColumn
LaTeX AlignmentColumn
columnZero
modify $ \State
s -> State
s { columns = [c] }
enterCode :: LaTeX ()
enterCode :: LaTeX ()
enterCode = do
LaTeXT m ()
LaTeX ()
resetColumn
(State -> State) -> LaTeXT m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((State -> State) -> LaTeXT m ())
-> (State -> State) -> LaTeXT m ()
forall a b. (a -> b) -> a -> b
$ \State
s -> State
s { codeBlock = codeBlock s + 1 }
leaveCode :: LaTeX ()
leaveCode :: LaTeX ()
leaveCode = () -> RWST Env [Output] State m ()
forall a. a -> RWST Env [Output] State m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
tshow :: Show a => a -> Text
tshow :: forall a. Show a => a -> Text
tshow = [Char] -> Text
T.pack ([Char] -> Text) -> (a -> [Char]) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> [Char]
forall a. Show a => a -> [Char]
show
logMsgToText :: LogMessage -> Text
logMsgToText :: LogMessage -> Text
logMsgToText (LogMessage Debug
messageLabel Text
text [Text]
extra) = [Text] -> Text
T.concat ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$
[ Debug -> Text
forall a. Show a => a -> Text
tshow Debug
messageLabel, Text
": '", Text
text, Text
"' "
] [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ if [Text] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Text]
extra then [] else [Text
"(", [Text] -> Text
T.unwords [Text]
extra, Text
")"]
logHelper :: Debug -> Text -> [Text] -> LaTeX ()
logHelper :: Debug -> Text -> [Text] -> LaTeX ()
logHelper Debug
debug Text
text [Text]
extra = do
logLevels <- Env -> [Debug]
debugs (Env -> [Debug])
-> RWST Env [Output] State m Env
-> RWST Env [Output] State m [Debug]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RWST Env [Output] State m Env
forall r (m :: * -> *). MonadReader r m => m r
ask
when (debug `elem` logLevels) $ do
lift $ logLaTeX (LogMessage debug text extra)
log :: Debug -> Text -> LaTeX ()
log :: Debug -> Text -> LaTeX ()
log Debug
MoveColumn Text
text = do
cols <- (State -> [AlignmentColumn])
-> RWST Env [Output] State m [AlignmentColumn]
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets State -> [AlignmentColumn]
columns
logHelper MoveColumn text ["columns=", tshow cols]
log Debug
Code Text
text = do
cols <- (State -> [AlignmentColumn])
-> RWST Env [Output] State m [AlignmentColumn]
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets State -> [AlignmentColumn]
columns
col <- gets column
logHelper Code text ["columns=", tshow cols, "col=", tshow col]
log Debug
debug Text
text = Debug -> Text -> [Text] -> LaTeX ()
logHelper Debug
debug Text
text []
output :: MonadLogLaTeX m => Output -> LaTeXT m ()
output :: forall (m :: * -> *). MonadLogLaTeX m => Output -> LaTeXT m ()
output Output
item = do
Debug -> Text -> LaTeX ()
log Debug
Output (Text -> LaTeX ()) -> Text -> LaTeX ()
forall a b. (a -> b) -> a -> b
$ Output -> Text
forall a. Show a => a -> Text
tshow Output
item
[Output] -> LaTeXT m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell [Output
item]
nl :: Text
nl :: Text
nl = Text
"%\n"
agdaSpace :: Text
agdaSpace :: Text
agdaSpace = Text
cmdPrefix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"Space" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
cmdArg Text
T.empty Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nl
columnName :: AlignmentColumn -> Text
columnName :: AlignmentColumn -> Text
columnName AlignmentColumn
c = [Char] -> Text
T.pack ([Char] -> Text) -> [Char] -> Text
forall a b. (a -> b) -> a -> b
$ case AlignmentColumn -> Maybe Int
columnKind AlignmentColumn
c of
Maybe Int
Nothing -> Int -> [Char]
forall a. Show a => a -> [Char]
show (AlignmentColumn -> Int
columnColumn AlignmentColumn
c)
Just Int
i -> Int -> [Char]
forall a. Show a => a -> [Char]
show Int
i [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
"I"
ptOpen' :: Text -> Text
ptOpen' :: Text -> Text
ptOpen' Text
name = Text
"\\>[" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
name Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"]"
ptOpen :: AlignmentColumn -> Text
ptOpen :: AlignmentColumn -> Text
ptOpen AlignmentColumn
c = Text -> Text
ptOpen' (AlignmentColumn -> Text
columnName AlignmentColumn
c)
ptOpenBeginningOfLine :: Text
ptOpenBeginningOfLine :: Text
ptOpenBeginningOfLine = Text -> Text
ptOpen' Text
"." Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"[@{}l@{}]"
ptOpenIndent
:: AlignmentColumn
-> Int
-> Text
ptOpenIndent :: AlignmentColumn -> Int -> Text
ptOpenIndent AlignmentColumn
c Int
delta =
AlignmentColumn -> Text
ptOpen AlignmentColumn
c Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"[@{}l@{"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
cmdPrefix
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"Indent"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
cmdArg ([Char] -> Text
T.pack ([Char] -> Text) -> [Char] -> Text
forall a b. (a -> b) -> a -> b
$ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
delta)
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"}]"
ptClose :: Text
ptClose :: Text
ptClose = Text
"\\<"
ptClose' :: AlignmentColumn -> Text
ptClose' :: AlignmentColumn -> Text
ptClose' AlignmentColumn
c =
Text
ptClose Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"[" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> AlignmentColumn -> Text
columnName AlignmentColumn
c Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"]"
ptNL :: Text
ptNL :: Text
ptNL = Text
nl Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\\\\\n"
ptEmptyLine :: Text
ptEmptyLine :: Text
ptEmptyLine =
Text
nl Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\\\\["
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
cmdPrefix
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"EmptyExtraSkip"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"]%\n"
cmdPrefix :: Text
cmdPrefix :: Text
cmdPrefix = Text
"\\Agda"
cmdArg :: Text -> Text
cmdArg :: Text -> Text
cmdArg Text
x = Text
"{" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"}"
processLayers :: MonadLogLaTeX m => [(LayerRole, Tokens)] -> LaTeXT m ()
processLayers :: forall (m :: * -> *).
MonadLogLaTeX m =>
[(LayerRole, [Token])] -> LaTeXT m ()
processLayers = ((LayerRole, [Token]) -> RWST Env [Output] State m ())
-> [(LayerRole, [Token])] -> RWST Env [Output] State m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ \ (LayerRole
layerRole, [Token]
toks) -> do
case LayerRole
layerRole of
LayerRole
L.Markup -> [Token] -> RWST Env [Output] State m ()
forall (m :: * -> *). MonadLogLaTeX m => [Token] -> LaTeXT m ()
processMarkup [Token]
toks
LayerRole
L.Comment -> [Token] -> RWST Env [Output] State m ()
forall (m :: * -> *). MonadLogLaTeX m => [Token] -> LaTeXT m ()
processComment [Token]
toks
LayerRole
L.Code -> [Token] -> LaTeX ()
processCode [Token]
toks
processMarkup :: MonadLogLaTeX m => Tokens -> LaTeXT m ()
processMarkup :: forall (m :: * -> *). MonadLogLaTeX m => [Token] -> LaTeXT m ()
processMarkup = (Token -> RWST Env [Output] State m ())
-> [Token] -> RWST Env [Output] State m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ \ Token
t -> do
Token -> LaTeX ()
moveColumnForToken Token
t
Output -> RWST Env [Output] State m ()
forall (m :: * -> *). MonadLogLaTeX m => Output -> LaTeXT m ()
output (Output -> RWST Env [Output] State m ())
-> Output -> RWST Env [Output] State m ()
forall a b. (a -> b) -> a -> b
$ Text -> Output
Text (Text -> Output) -> Text -> Output
forall a b. (a -> b) -> a -> b
$ Token -> Text
text Token
t
processComment :: MonadLogLaTeX m => Tokens -> LaTeXT m ()
= (Token -> RWST Env [Output] State m ())
-> [Token] -> RWST Env [Output] State m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ \ Token
t -> do
let t' :: Text
t' = Token -> Text
text Token
t
Bool
-> RWST Env [Output] State m () -> RWST Env [Output] State m ()
forall b (m :: * -> *). (IsBool b, Monad m) => b -> m () -> m ()
unless (Text
"%" Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> Text -> Text
T.take Int
1 (Text -> Text
T.stripStart Text
t')) (RWST Env [Output] State m () -> RWST Env [Output] State m ())
-> RWST Env [Output] State m () -> RWST Env [Output] State m ()
forall a b. (a -> b) -> a -> b
$ do
Token -> LaTeX ()
moveColumnForToken Token
t
Output -> RWST Env [Output] State m ()
forall (m :: * -> *). MonadLogLaTeX m => Output -> LaTeXT m ()
output (Output -> RWST Env [Output] State m ())
-> Output -> RWST Env [Output] State m ()
forall a b. (a -> b) -> a -> b
$ Text -> Output
Text Text
t'
processCode :: Tokens -> LaTeX ()
processCode :: [Token] -> LaTeX ()
processCode [Token]
toks' = do
Output -> LaTeXT m ()
forall (m :: * -> *). MonadLogLaTeX m => Output -> LaTeXT m ()
output (Output -> LaTeXT m ()) -> Output -> LaTeXT m ()
forall a b. (a -> b) -> a -> b
$ Text -> Output
Text Text
nl
LaTeXT m ()
LaTeX ()
enterCode
(Token -> LaTeXT m ()) -> [Token] -> LaTeXT m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Token -> LaTeXT m ()
forall {m :: * -> *}.
MonadLogLaTeX m =>
Token -> RWST Env [Output] State m ()
go [Token]
toks'
Int -> LaTeXT m ()
forall {m :: * -> *} {a}.
(Eq a, Num a, MonadLogLaTeX m) =>
a -> RWST Env [Output] State m ()
ptOpenWhenColumnZero (Int -> LaTeXT m ())
-> RWST Env [Output] State m Int -> LaTeXT m ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (State -> Int) -> RWST Env [Output] State m Int
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets State -> Int
column
Output -> LaTeXT m ()
forall (m :: * -> *). MonadLogLaTeX m => Output -> LaTeXT m ()
output (Output -> LaTeXT m ()) -> Output -> LaTeXT m ()
forall a b. (a -> b) -> a -> b
$ Text -> Output
Text (Text -> Output) -> Text -> Output
forall a b. (a -> b) -> a -> b
$ Text
ptClose Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nl
LaTeXT m ()
LaTeX ()
leaveCode
where
go :: Token -> RWST Env [Output] State m ()
go tok' :: Token
tok'@Token{ text :: Token -> Text
text = Text
tok } = do
col <- (State -> Int) -> RWST Env [Output] State m Int
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets State -> Int
column
moveColumnForToken tok'
log Code tok
unless (T.null tok) $
if (isSpaces tok) then do
spaces $ T.group $ replaceSpaces tok
else do
ptOpenWhenColumnZero col
output $ Text $
foldr (\[Char]
c Text
t -> Text
cmdPrefix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Char] -> Text
T.pack [Char]
c Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
cmdArg Text
t)
(escape tok)
$ map fromOtherAspect (toList $ otherAspects $ info tok') ++
concatMap fromAspect (toList $ aspect $ info tok')
ptOpenWhenColumnZero :: a -> RWST Env [Output] State m ()
ptOpenWhenColumnZero a
col =
Bool
-> RWST Env [Output] State m () -> RWST Env [Output] State m ()
forall b (m :: * -> *). (IsBool b, Monad m) => b -> m () -> m ()
when (a
col a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0) (RWST Env [Output] State m () -> RWST Env [Output] State m ())
-> RWST Env [Output] State m () -> RWST Env [Output] State m ()
forall a b. (a -> b) -> a -> b
$ do
RWST Env [Output] State m ()
LaTeX ()
registerColumnZero
Output -> RWST Env [Output] State m ()
forall (m :: * -> *). MonadLogLaTeX m => Output -> LaTeXT m ()
output (Output -> RWST Env [Output] State m ())
-> (AlignmentColumn -> Output)
-> AlignmentColumn
-> RWST Env [Output] State m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Output
Text (Text -> Output)
-> (AlignmentColumn -> Text) -> AlignmentColumn -> Output
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AlignmentColumn -> Text
ptOpen (AlignmentColumn -> RWST Env [Output] State m ())
-> RWST Env [Output] State m AlignmentColumn
-> RWST Env [Output] State m ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< RWST Env [Output] State m AlignmentColumn
LaTeX AlignmentColumn
columnZero
fromOtherAspect :: OtherAspect -> String
fromOtherAspect :: OtherAspect -> [Char]
fromOtherAspect = OtherAspect -> [Char]
forall a. Show a => a -> [Char]
show
fromAspect :: Aspect -> [String]
fromAspect :: Aspect -> [[Char]]
fromAspect Aspect
a = let s :: [[Char]]
s = [Aspect -> [Char]
forall a. Show a => a -> [Char]
show Aspect
a] in case Aspect
a of
Aspect
Comment -> [[Char]]
s
Aspect
Keyword -> [[Char]]
s
Aspect
Hole -> [[Char]]
s
Aspect
String -> [[Char]]
s
Aspect
Number -> [[Char]]
s
Aspect
Symbol -> [[Char]]
s
Aspect
PrimitiveType -> [[Char]]
s
Aspect
Pragma -> [[Char]]
s
Aspect
Background -> [[Char]]
s
Aspect
Markup -> [[Char]]
s
Name Maybe NameKind
Nothing Bool
isOp -> Aspect -> [[Char]]
fromAspect (Maybe NameKind -> Bool -> Aspect
Name (NameKind -> Maybe NameKind
forall a. a -> Maybe a
Just NameKind
Postulate) Bool
isOp)
Name (Just NameKind
kind) Bool
isOp ->
(\[Char]
c -> if Bool
isOp then [[Char]
"Operator", [Char]
c] else [[Char]
c]) ([Char] -> [[Char]]) -> [Char] -> [[Char]]
forall a b. (a -> b) -> a -> b
$
case NameKind
kind of
NameKind
Bound -> [Char]
sk
NameKind
Generalizable -> [Char]
sk
Constructor Induction
Inductive -> [Char]
"InductiveConstructor"
Constructor Induction
CoInductive -> [Char]
"CoinductiveConstructor"
NameKind
Datatype -> [Char]
sk
NameKind
Field -> [Char]
sk
NameKind
Function -> [Char]
sk
NameKind
Module -> [Char]
sk
NameKind
Postulate -> [Char]
sk
NameKind
Primitive -> [Char]
sk
NameKind
Record -> [Char]
sk
NameKind
Argument -> [Char]
sk
NameKind
Macro -> [Char]
sk
where
sk :: [Char]
sk = NameKind -> [Char]
forall a. Show a => a -> [Char]
show NameKind
kind
escape :: Text -> Text
escape :: Text -> Text
escape (Text -> Maybe (Char, Text)
T.uncons -> Maybe (Char, Text)
Nothing) = Text
T.empty
escape (Text -> Maybe (Char, Text)
T.uncons -> Just (Char
c, Text
s)) = [Char] -> Text
T.pack (Char -> [Char]
replace Char
c) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
escape Text
s
where
replace :: Char -> String
replace :: Char -> [Char]
replace Char
char = case Char
char of
Char
'_' -> [Char]
"\\AgdaUnderscore{}"
Char
'{' -> [Char]
"\\{"
Char
'}' -> [Char]
"\\}"
Char
'#' -> [Char]
"\\#"
Char
'$' -> [Char]
"\\$"
Char
'&' -> [Char]
"\\&"
Char
'%' -> [Char]
"\\%"
Char
'~' -> [Char]
"\\textasciitilde{}"
Char
'^' -> [Char]
"\\textasciicircum{}"
Char
'\\' -> [Char]
"\\textbackslash{}"
Char
' ' -> [Char]
"\\ "
Char
_ -> [ Char
char ]
#if __GLASGOW_HASKELL__ < 810
escape _ = __IMPOSSIBLE__
#endif
spaces :: [Text] -> LaTeX ()
spaces :: [Text] -> LaTeX ()
spaces [] = () -> RWST Env [Output] State m ()
forall a. a -> RWST Env [Output] State m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
spaces (s :: Text
s@(Text -> Maybe (Char, Text)
T.uncons -> Just (Char
'\n', Text
_)) : [Text]
ss) = do
col <- (State -> Int) -> RWST Env [Output] State m Int
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets State -> Int
column
when (col == 0) do
output . Text . ptOpen =<< columnZero
output $ Text $ ptClose <> ptNL <>
T.replicate (T.length s - 1) ptEmptyLine
resetColumn
spaces ss
spaces (Text
_ : ss :: [Text]
ss@(Text
_ : [Text]
_)) = [Text] -> LaTeX ()
spaces [Text]
ss
spaces [ Text
s ] = do
col <- (State -> Int) -> RWST Env [Output] State m Int
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets State -> Int
column
let len = TextWidthEstimator
T.length Text
s
kind = if Int
col Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0 Bool -> Bool -> Bool
&& Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1
then Kind
Indentation
else Kind
Alignment
moveColumn len
column <- registerColumn kind
if col /= 0
then log Spaces "col /= 0"
else do
columns <- gets columnsPrev
codeBlock <- gets codeBlock
log Spaces $
"col == 0: " <> T.pack (show (len, columns))
case filter ((<= len) . columnColumn) columns of
AlignmentColumn
c : [AlignmentColumn]
_ | AlignmentColumn -> Int
columnColumn AlignmentColumn
c Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
len, Maybe Int -> Bool
forall a. Maybe a -> Bool
isJust (AlignmentColumn -> Maybe Int
columnKind AlignmentColumn
c) -> do
AlignmentColumn -> LaTeX ()
useColumn AlignmentColumn
c
Output -> RWST Env [Output] State m ()
forall (m :: * -> *). MonadLogLaTeX m => Output -> LaTeXT m ()
output (Output -> RWST Env [Output] State m ())
-> Output -> RWST Env [Output] State m ()
forall a b. (a -> b) -> a -> b
$ Text -> Output
Text (Text -> Output) -> Text -> Output
forall a b. (a -> b) -> a -> b
$ Text
ptOpenBeginningOfLine
Output -> RWST Env [Output] State m ()
forall (m :: * -> *). MonadLogLaTeX m => Output -> LaTeXT m ()
output (Output -> RWST Env [Output] State m ())
-> Output -> RWST Env [Output] State m ()
forall a b. (a -> b) -> a -> b
$ Text -> Output
Text (Text -> Output) -> Text -> Output
forall a b. (a -> b) -> a -> b
$ AlignmentColumn -> Text
ptClose' AlignmentColumn
c
AlignmentColumn
c : [AlignmentColumn]
_ | AlignmentColumn -> Int
columnColumn AlignmentColumn
c Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
len -> do
AlignmentColumn -> LaTeX ()
useColumn AlignmentColumn
c
Output -> RWST Env [Output] State m ()
forall (m :: * -> *). MonadLogLaTeX m => Output -> LaTeXT m ()
output (Output -> RWST Env [Output] State m ())
-> Output -> RWST Env [Output] State m ()
forall a b. (a -> b) -> a -> b
$ Text -> Output
Text (Text -> Output) -> Text -> Output
forall a b. (a -> b) -> a -> b
$ AlignmentColumn -> Int -> Text
ptOpenIndent AlignmentColumn
c (Int
codeBlock Int -> Int -> Int
forall a. Num a => a -> a -> a
- AlignmentColumn -> Int
columnCodeBlock AlignmentColumn
c)
[AlignmentColumn]
_ -> () -> RWST Env [Output] State m ()
forall a. a -> RWST Env [Output] State m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
output $ MaybeColumn column
stringLiteral :: Token -> Tokens
stringLiteral :: Token -> [Token]
stringLiteral Token
t | Aspects -> Maybe Aspect
aspect (Token -> Aspects
info Token
t) Maybe Aspect -> Maybe Aspect -> Bool
forall a. Eq a => a -> a -> Bool
== Aspect -> Maybe Aspect
forall a. a -> Maybe a
Just Aspect
String =
(Text -> Token) -> [Text] -> [Token]
forall a b. (a -> b) -> [a] -> [b]
map (\ Text
x -> Token
t { text = x })
([Text] -> [Token]) -> [Text] -> [Token]
forall a b. (a -> b) -> a -> b
$ (Text -> [Text]) -> [Text] -> [Text]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Text -> [Text]
leadingSpaces
([Text] -> [Text]) -> [Text] -> [Text]
forall a b. (a -> b) -> a -> b
$ Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
List.intersperse Text
"\n"
([Text] -> [Text]) -> [Text] -> [Text]
forall a b. (a -> b) -> a -> b
$ Text -> [Text]
T.lines (Token -> Text
text Token
t)
where
leadingSpaces :: Text -> [Text]
leadingSpaces :: Text -> [Text]
leadingSpaces Text
tok = [Text
pre, Text
suf]
where (Text
pre , Text
suf) = (Char -> Bool) -> Text -> (Text, Text)
T.span Char -> Bool
isSpaceNotNewline Text
tok
stringLiteral Token
t = [Token
t]
multiLineComment :: Token -> Tokens
Token{ text :: Token -> Text
text = Text
s, info :: Token -> Aspects
info = Aspects
i } | Aspects -> Maybe Aspect
aspect Aspects
i Maybe Aspect -> Maybe Aspect -> Bool
forall a. Eq a => a -> a -> Bool
== Aspect -> Maybe Aspect
forall a. a -> Maybe a
Just Aspect
Comment =
(Text -> Token) -> [Text] -> [Token]
forall a b. (a -> b) -> [a] -> [b]
map (Text -> Aspects -> Token
`Token` Aspects
i)
([Text] -> [Token]) -> [Text] -> [Token]
forall a b. (a -> b) -> a -> b
$ Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
List.intersperse Text
"\n"
([Text] -> [Text]) -> [Text] -> [Text]
forall a b. (a -> b) -> a -> b
$ Text -> [Text]
T.lines Text
s
multiLineComment Token
t = [Token
t]
latexDataDir :: FilePath
latexDataDir :: [Char]
latexDataDir = [Char]
"latex"
defaultStyFile :: String
defaultStyFile :: [Char]
defaultStyFile = [Char]
"agda.sty"
data LaTeXOptions = LaTeXOptions
{ LaTeXOptions -> [Char]
latexOptOutDir :: FilePath
, LaTeXOptions -> Maybe RangeFile
latexOptSourceFileName :: Maybe RangeFile
, LaTeXOptions -> Bool
latexOptCountClusters :: Bool
}
getTextWidthEstimator :: Bool -> TextWidthEstimator
getTextWidthEstimator :: Bool -> TextWidthEstimator
getTextWidthEstimator Bool
_countClusters =
#ifdef COUNT_CLUSTERS
if Bool
_countClusters
then [Break ()] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Break ()] -> Int) -> (Text -> [Break ()]) -> TextWidthEstimator
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Breaker () -> Text -> [Break ()]
forall a. Breaker a -> Text -> [Break a]
ICU.breaks (LocaleName -> Breaker ()
ICU.breakCharacter LocaleName
ICU.Root))
else TextWidthEstimator
T.length
#else
T.length
#endif
prepareCommonAssets :: (MonadLogLaTeX m, MonadIO m) => FilePath -> m ()
prepareCommonAssets :: forall (m :: * -> *).
(MonadLogLaTeX m, MonadIO m) =>
[Char] -> m ()
prepareCommonAssets [Char]
dir = do
dirExisted <- IO Bool -> m Bool
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> IO Bool -> m Bool
forall a b. (a -> b) -> a -> b
$ [Char] -> IO Bool
doesDirectoryExist [Char]
dir
unless dirExisted $
liftIO $ createDirectoryIfMissing True dir
texFindsSty <- liftIO $ try $
readProcess
"kpsewhich"
(applyWhen dirExisted (("--path=" ++ dir) :) [defaultStyFile])
""
case texFindsSty of
Right [Char]
_ -> () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Left (IOException
e :: IOException) -> do
let agdaSty :: [Char]
agdaSty = [Char]
dir [Char] -> ShowS
</> [Char]
defaultStyFile
m Bool -> m () -> m ()
forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
unlessM (Bool -> m Bool
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
dirExisted m Bool -> m Bool -> m Bool
forall (m :: * -> *). Monad m => m Bool -> m Bool -> m Bool
`and2M` IO Bool -> m Bool
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO ([Char] -> IO Bool
doesFileExist [Char]
agdaSty)) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ do
LogMessage -> m ()
forall (m :: * -> *). MonadLogLaTeX m => LogMessage -> m ()
logLaTeX (LogMessage -> m ()) -> LogMessage -> m ()
forall a b. (a -> b) -> a -> b
$ Debug -> Text -> [Text] -> LogMessage
LogMessage Debug
FileSystem
([Char] -> Text
T.pack ([Char] -> Text) -> [Char] -> Text
forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
unwords [[Char]
defaultStyFile, [Char]
"was not found. Copying a default version of", [Char]
defaultStyFile, [Char]
"into", [Char]
dir])
[]
IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ do
styFile <- [Char] -> IO [Char]
getDataFileName ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$
[Char]
latexDataDir [Char] -> ShowS
</> [Char]
defaultStyFile
copyFile styFile agdaSty
generateLaTeXIO :: (MonadLogLaTeX m, MonadIO m) => LaTeXOptions -> Interface -> m ()
generateLaTeXIO :: forall (m :: * -> *).
(MonadLogLaTeX m, MonadIO m) =>
LaTeXOptions -> Interface -> m ()
generateLaTeXIO LaTeXOptions
opts Interface
i = do
let textWidthEstimator :: TextWidthEstimator
textWidthEstimator = Bool -> TextWidthEstimator
getTextWidthEstimator (LaTeXOptions -> Bool
latexOptCountClusters LaTeXOptions
opts)
let baseDir :: [Char]
baseDir = LaTeXOptions -> [Char]
latexOptOutDir LaTeXOptions
opts
let outPath :: [Char]
outPath = [Char]
baseDir [Char] -> ShowS
</>
TopLevelModuleName -> [Char]
latexOutRelativeFilePath (Interface -> TopLevelModuleName
iTopLevelModuleName Interface
i)
latex <- Text -> ByteString
E.encodeUtf8 (Text -> ByteString) -> m Text -> m ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Env -> Maybe RangeFile -> Text -> HighlightingInfo -> m Text
forall (m :: * -> *).
MonadLogLaTeX m =>
Env -> Maybe RangeFile -> Text -> HighlightingInfo -> m Text
toLaTeX
(TextWidthEstimator -> Env
emptyEnv TextWidthEstimator
textWidthEstimator)
(LaTeXOptions -> Maybe RangeFile
latexOptSourceFileName LaTeXOptions
opts)
(Interface -> Text
iSource Interface
i)
(Interface -> HighlightingInfo
iHighlighting Interface
i)
liftIO $ do
createDirectoryIfMissing True (takeDirectory outPath)
BS.writeFile outPath latex
latexOutRelativeFilePath :: TopLevelModuleName -> FilePath
latexOutRelativeFilePath :: TopLevelModuleName -> [Char]
latexOutRelativeFilePath TopLevelModuleName
m =
[Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
List.intercalate [Char
pathSeparator]
((Item TopLevelModuleNameParts -> [Char])
-> [Item TopLevelModuleNameParts] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map Item TopLevelModuleNameParts -> [Char]
Text -> [Char]
T.unpack ([Item TopLevelModuleNameParts] -> [[Char]])
-> [Item TopLevelModuleNameParts] -> [[Char]]
forall a b. (a -> b) -> a -> b
$ TopLevelModuleNameParts -> [Item TopLevelModuleNameParts]
forall l. IsList l => l -> [Item l]
List1.toList (TopLevelModuleNameParts -> [Item TopLevelModuleNameParts])
-> TopLevelModuleNameParts -> [Item TopLevelModuleNameParts]
forall a b. (a -> b) -> a -> b
$ TopLevelModuleName -> TopLevelModuleNameParts
forall range. TopLevelModuleName' range -> TopLevelModuleNameParts
moduleNameParts TopLevelModuleName
m) [Char] -> ShowS
<.>
[Char]
"tex"
toLaTeX
:: MonadLogLaTeX m
=> Env
-> Maybe RangeFile
-> L.Text
-> HighlightingInfo
-> m L.Text
toLaTeX :: forall (m :: * -> *).
MonadLogLaTeX m =>
Env -> Maybe RangeFile -> Text -> HighlightingInfo -> m Text
toLaTeX Env
env Maybe RangeFile
path Text
source HighlightingInfo
hi =
Env -> [(LayerRole, [Token])] -> m Text
forall (m :: * -> *).
MonadLogLaTeX m =>
Env -> [(LayerRole, [Token])] -> m Text
processTokens Env
env
([(LayerRole, [Token])] -> m Text)
-> ([Char] -> [(LayerRole, [Token])]) -> [Char] -> m Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((LayerRole, List1 (Maybe Aspects, Char)) -> (LayerRole, [Token]))
-> [(LayerRole, List1 (Maybe Aspects, Char))]
-> [(LayerRole, [Token])]
forall a b. (a -> b) -> [a] -> [b]
map
( ( \(LayerRole
role, [Token]
tokens) ->
(LayerRole
role,) ([Token] -> (LayerRole, [Token]))
-> [Token] -> (LayerRole, [Token])
forall a b. (a -> b) -> a -> b
$
( Bool -> ([Token] -> [Token]) -> [Token] -> [Token]
forall b a. IsBool b => b -> (a -> a) -> a -> a
applyWhen (LayerRole -> Bool
L.isCode LayerRole
role) (([Token] -> [Token]) -> [Token] -> [Token])
-> ([Token] -> [Token]) -> [Token] -> [Token]
forall a b. (a -> b) -> a -> b
$
([Token] -> [Token]) -> [Token] -> [Token]
forall a. ([a] -> [a]) -> [a] -> [a]
whenMoreThanOne
( (Token -> Token) -> [Token] -> [Token]
forall a. (a -> a) -> [a] -> [a]
updateLast
((Token -> Token) -> [Token] -> [Token])
-> (Token -> Token) -> [Token] -> [Token]
forall a b. (a -> b) -> a -> b
$ (Text -> Text) -> Token -> Token
withTokenText
((Text -> Text) -> Token -> Token)
-> (Text -> Text) -> Token -> Token
forall a b. (a -> b) -> a -> b
$ \Text
suf ->
Text -> (Text -> Text) -> Maybe Text -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
Text
suf
((Char -> Bool) -> Text -> Text
T.dropWhileEnd Char -> Bool
isSpaceNotNewline)
(Text -> Text -> Maybe Text
T.stripSuffix Text
"\n" Text
suf)
)
([Token] -> [Token]) -> ([Token] -> [Token]) -> [Token] -> [Token]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Token -> Token) -> [Token] -> [Token]
forall a. (a -> a) -> [a] -> [a]
updateLast ((Text -> Text) -> Token -> Token
withTokenText ((Text -> Text) -> Token -> Token)
-> (Text -> Text) -> Token -> Token
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Text -> Text
T.dropWhileEnd Char -> Bool
isSpaceNotNewline)
([Token] -> [Token]) -> ([Token] -> [Token]) -> [Token] -> [Token]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Token -> Token) -> [Token] -> [Token]
forall a. (a -> a) -> [a] -> [a]
updateHead
( (Text -> Text) -> Token -> Token
withTokenText ((Text -> Text) -> Token -> Token)
-> (Text -> Text) -> Token -> Token
forall a b. (a -> b) -> a -> b
$
\Text
pre ->
Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
pre (Maybe Text -> Text) -> Maybe Text -> Text
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Maybe Text
T.stripPrefix Text
"\n" (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$
(Char -> Bool) -> Text -> Text
T.dropWhile
Char -> Bool
isSpaceNotNewline
Text
pre
)
)
[Token]
tokens
) ((LayerRole, [Token]) -> (LayerRole, [Token]))
-> ((LayerRole, List1 (Maybe Aspects, Char))
-> (LayerRole, [Token]))
-> (LayerRole, List1 (Maybe Aspects, Char))
-> (LayerRole, [Token])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ( (List1 (Maybe Aspects, Char) -> [Token])
-> (LayerRole, List1 (Maybe Aspects, Char)) -> (LayerRole, [Token])
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second
(
(Token -> [Token]) -> [Token] -> [Token]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Token -> [Token]
stringLiteral
([Token] -> [Token])
-> (List1 (Maybe Aspects, Char) -> [Token])
-> List1 (Maybe Aspects, Char)
-> [Token]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Token -> [Token]) -> [Token] -> [Token]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Token -> [Token]
multiLineComment
([Token] -> [Token])
-> (List1 (Maybe Aspects, Char) -> [Token])
-> List1 (Maybe Aspects, Char)
-> [Token]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty Token -> [Item (NonEmpty Token)]
NonEmpty Token -> [Token]
forall l. IsList l => l -> [Item l]
List1.toList
(NonEmpty Token -> [Token])
-> (List1 (Maybe Aspects, Char) -> NonEmpty Token)
-> List1 (Maybe Aspects, Char)
-> [Token]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Maybe Aspects, List1 Char) -> Token)
-> NonEmpty (Maybe Aspects, List1 Char) -> NonEmpty Token
forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\ (Maybe Aspects
mi, List1 Char
cs) -> Token
{ text :: Text
text = [Char] -> Text
T.pack ([Char] -> Text) -> [Char] -> Text
forall a b. (a -> b) -> a -> b
$ List1 Char -> [Item (List1 Char)]
forall l. IsList l => l -> [Item l]
List1.toList List1 Char
cs
, info :: Aspects
info = Aspects -> Maybe Aspects -> Aspects
forall a. a -> Maybe a -> a
fromMaybe Aspects
forall a. Monoid a => a
mempty Maybe Aspects
mi
}
)
(NonEmpty (Maybe Aspects, List1 Char) -> NonEmpty Token)
-> (List1 (Maybe Aspects, Char)
-> NonEmpty (Maybe Aspects, List1 Char))
-> List1 (Maybe Aspects, Char)
-> NonEmpty Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. List1 (Maybe Aspects, Char) -> NonEmpty (Maybe Aspects, List1 Char)
forall a b. Eq a => List1 (a, b) -> List1 (a, List1 b)
List1.groupByFst1
)
)
)
([(LayerRole, List1 (Maybe Aspects, Char))]
-> [(LayerRole, [Token])])
-> ([Char] -> [(LayerRole, List1 (Maybe Aspects, Char))])
-> [Char]
-> [(LayerRole, [Token])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(LayerRole, (Maybe Aspects, Char))]
-> [(LayerRole, List1 (Maybe Aspects, Char))]
forall a b. Eq a => [(a, b)] -> [(a, List1 b)]
List1.groupByFst
([(LayerRole, (Maybe Aspects, Char))]
-> [(LayerRole, List1 (Maybe Aspects, Char))])
-> ([Char] -> [(LayerRole, (Maybe Aspects, Char))])
-> [Char]
-> [(LayerRole, List1 (Maybe Aspects, Char))]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> (LayerRole, Char) -> (LayerRole, (Maybe Aspects, Char)))
-> [Int]
-> [(LayerRole, Char)]
-> [(LayerRole, (Maybe Aspects, Char))]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\Int
pos (LayerRole
role, Char
char) -> (LayerRole
role, (Int -> IntMap Aspects -> Maybe Aspects
forall a. Int -> IntMap a -> Maybe a
IntMap.lookup Int
pos IntMap Aspects
infoMap, Char
char)))
[Int
1..]
([(LayerRole, Char)] -> [(LayerRole, (Maybe Aspects, Char))])
-> ([Char] -> [(LayerRole, Char)])
-> [Char]
-> [(LayerRole, (Maybe Aspects, Char))]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Layers -> [(LayerRole, Char)]
atomizeLayers
(Layers -> [(LayerRole, Char)])
-> ([Char] -> Layers) -> [Char] -> [(LayerRole, Char)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Processor
literateTeX (() -> Position' ()
forall a. a -> Position' a
startPos' ())
([Char] -> m Text) -> [Char] -> m Text
forall a b. (a -> b) -> a -> b
$ Text -> [Char]
L.unpack Text
source
where
infoMap :: IntMap Aspects
infoMap = HighlightingInfo -> IntMap Aspects
forall a m. IsBasicRangeMap a m => m -> IntMap a
toMap HighlightingInfo
hi
whenMoreThanOne :: ([a] -> [a]) -> [a] -> [a]
whenMoreThanOne :: forall a. ([a] -> [a]) -> [a] -> [a]
whenMoreThanOne [a] -> [a]
f xs :: [a]
xs@(a
_:a
_:[a]
_) = [a] -> [a]
f [a]
xs
whenMoreThanOne [a] -> [a]
_ [a]
xs = [a]
xs
processTokens
:: MonadLogLaTeX m
=> Env
-> [(LayerRole, Tokens)]
-> m L.Text
processTokens :: forall (m :: * -> *).
MonadLogLaTeX m =>
Env -> [(LayerRole, [Token])] -> m Text
processTokens Env
env [(LayerRole, [Token])]
ts = do
((), s, os) <- LaTeXT m () -> Env -> State -> m ((), State, [Output])
forall (m :: * -> *) a.
MonadLogLaTeX m =>
LaTeXT m a -> Env -> State -> m (a, State, [Output])
runLaTeX ([(LayerRole, [Token])] -> LaTeXT m ()
forall (m :: * -> *).
MonadLogLaTeX m =>
[(LayerRole, [Token])] -> LaTeXT m ()
processLayers [(LayerRole, [Token])]
ts) Env
env State
emptyState
return $ L.fromChunks $ map (render s) os
where
render :: State -> Output -> Text
render State
_ (Text Text
s) = Text
s
render State
s (MaybeColumn AlignmentColumn
c)
| Just Int
i <- AlignmentColumn -> Maybe Int
columnKind AlignmentColumn
c,
Bool -> Bool
not (Int
i Int -> HashSet Int -> Bool
forall a. (Eq a, Hashable a) => a -> HashSet a -> Bool
`Set.member` State -> HashSet Int
usedColumns State
s) = Text
agdaSpace
| Bool
otherwise = Text
nl Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> AlignmentColumn -> Text
ptOpen AlignmentColumn
c