{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
-- | Render analyzed input into LaTeX table.
module Render.Latex(latexFromColSpans, latexInline, latexPackages, subscripts) where
import Data.Text(Text)
import qualified Data.Text as T
import Data.Char(isAlpha)
import Text.LaTeX.Base.Syntax(protectText)
import Alignment ( Align(..) )
import Render.Common(TokensWithColSpan)
import Token(MyTok(..))
import Util(unbrace)
-- | Given a number of table columns,
-- and a list of lists of colspans for each table row,
-- return raw LaTeX code.
latexFromColSpans :: Int -> [[TokensWithColSpan]] -> Text
latexFromColSpans cols =
wrapTable cols
. T.unlines
. fmap ( (<> "\\\\")
. T.intercalate " & "
. fmap renderColSpan )
-- | Render a single colspan as LaTeX \multicolumn.
renderColSpan :: TokensWithColSpan -> Text
renderColSpan ([(TBlank, txt)], colSpan, AIndent) = -- indentation
T.concat [ "\\multicolumn{", T.pack $ show colSpan
, "}{p{", T.pack $ show $ T.length txt
, "ex}}{", protectText txt
, "\\,}" ]
renderColSpan (toks, colSpan, alignment) =
T.concat [ "\\multicolumn{", T.pack $ show colSpan
, "}{", alignMark alignment
, "}{$", latexInline toks
, "$}" ]
where
alignMark ACenter = "c"
alignMark ALeft = "l"
alignMark AIndent = "l"
-- | Wrap a LaTeX table content into \begin{tabular} environment.
wrapTable :: Int -> Text -> Text
wrapTable cols txt =
mconcat [-- "\\newlength{\\tabcolsepBACKUP}\n"
-- ,"\\setlength{\\tabcolsepBACKUP}{\\tabcolsep}"
"\\setlength{\\tabcolsep}{1pt}\n"
, "\\begin{tabular}{"
, T.replicate (cols+1) "l" -- FIXME: tests for correct number of columns
, "}\n"
, txt, "\n\\end{tabular}"
--,"\\setlength{\\tabcolsep}{\\tabcolsepBACKUP}"
]
-- Decrease column spacing: \\setlength{\\tabcolsep}{1ex}
-- TODO: braced operators
-- | Preprocesses functions converted to operator syntax and joins them into a single token.
-- FIXME: deduplicate
preformatTokens [] = []
preformatTokens ((TOperator,"`"):(TVar, "elem"):(TOperator, "`"):rest) = (TOperator, "elem"):preformatTokens rest
preformatTokens (a :rest) = a :preformatTokens rest
-- | Format a list of tokens within a colspan.
-- Preprocesses then and calls `formatToken` for each.
latexInline :: [(MyTok, Text)] -> Text
latexInline = T.concat
. fmap formatToken
. preformatTokens
-- | Add subscripts and superscripts to variable names.
-- `_` is subscript, and `__` is superscript.vim
subscripts :: Text -> Text
subscripts "" = " "
subscripts "_" = "\\_"
subscripts t = segments t
where
segments = foldr1 addSubscript . T.splitOn "_"
-- | Tags the second argument with superscript "^" or subscript "_"
addSubscript :: Text -> Text -> Text
addSubscript t tsub = mconcat [t, "\\textsubscript{", tsub, "}"]
-- Workaround with joinEscapedOperators til w consider spaces only.
-- | Render a simple token.
formatToken :: (MyTok, Text) -> Text
formatToken (TOperator,unbrace -> Just op) = "(" <> formatToken (TOperator, op) <> ")"
formatToken (TKeyword, "forall") = mathop "forall"
--formatToken (TVar, "mempty") = mathop "emptyset"
formatToken (TVar, "bottom") = mathop "bot"
formatToken (TVar, "undefined") = mathop "perp"
formatToken (TVar, "top" ) = mathop "top"
formatToken (TVar, "not" ) = mathop "neg"
--formatToken (TOperator,">>=" ) = mathop "mathbin{>\\!\\!\\!>\\!\\!=}" -- from lhs2TeX, Neil Mitchell's
formatToken (TOperator,">>=" ) = mathop "mathbin{\\gg\\!\\!=}" -- from lhs2TeX, Neil Mitchell's
formatToken (TOperator,"=<<" ) = mathop "mathbin{=\\!\\!<\\!\\!\\!<}" -- from lhs2TeX, Neil Mitchell's
formatToken (TOperator,">=>" ) = mathop "mathbin{>\\!\\!=\\!\\!\\!>}"
formatToken (TOperator,"|-" ) = mathop "vdash"
formatToken (TOperator,"/\\" ) = mathop "lor"
formatToken (TOperator,"\\/" ) = mathop "land"
formatToken (TOperator,"\\|/" ) = mathop "downarrow"
formatToken (TOperator,"\\||/" ) = mathop "Downarrow"
formatToken (TOperator,"~>" ) = mathop "leadsto"
formatToken (TOperator,"|=" ) = mathop "models"
formatToken (TCons ,"Natural") = "\\mathbb{N}"
formatToken (TCons ,"Integer") = "\\mathbb{Z}"
formatToken (TOperator,"|" ) = mathop "alt"
formatToken (TOperator,"||" ) = mathop "parallel"
formatToken (TOperator,"|>" ) = mathop "triangleright"
--formatToken (TOperator,">>" ) = mathop "mathbin{>\\!\\!\\!>}" -- gg
--formatToken (TOperator,">>>" ) = mathop "mathbin{>\\!\\!\\!>\\!\\!\\!>}" -- gg
formatToken (TOperator,">>" ) = mathop "gg"
formatToken (TOperator,">>>" ) = mathop "ggg"
formatToken (TOperator,"<<" ) = mathop "ll"
formatToken (TOperator,"<<<" ) = mathop "lll"
formatToken (TOther, "λ" ) = mathop "lambda" -- Haskell only?
--formatToken (TOperator,"-<" ) = mathop "prec"
formatToken (TOther, "-<" ) = mathop "prec"
formatToken (TOther, ">-" ) = mathop "succ"
formatToken (TOperator,"\\\\" ) = mathop "setminus"
formatToken (TOther ,"<-" ) = mathop "gets"
formatToken (TOperator,">=" ) = mathop "geq"
formatToken (TOperator,"<=" ) = mathop "leq"
formatToken (TOperator,"!=" ) = mathop "ne"
formatToken (TOperator,"<->" ) = mathop "leftrightarrow"
--formatToken (TOperator,"->" ) = mathop "to"
formatToken (TOther, "->" ) = mathop "to"
formatToken (TOther, "=>" ) = mathop "Rightarrow"
formatToken (TOperator,"==>" ) = mathop "implies"
formatToken (TOperator,"|->" ) = mathop "mapsto"
formatToken (TOperator,"|=>" ) = mathop "Mapsto" -- requires stmaryrd
formatToken (TOperator,"<>" ) = mathop "diamond"
formatToken (TOperator,"<$>" ) = mathop "mathbin{\\ooalign{\\raise.29ex\\hbox{$\\scriptscriptstyle\\$$}\\cr\\hss$\\!\\lozenge$\\hss}}"
formatToken (TOperator,"<*>" ) = mathop "mathbin{\\ooalign{\\raise.37ex\\hbox{$\\scriptscriptstyle{*}$}\\cr\\hss$\\!\\lozenge$\\hss}}"
formatToken (TOperator,"elem" ) = mathop "in"
formatToken (TOperator,"~" ) = mathop "sim"
formatToken (TOperator,"~=" ) = mathop "approx"
formatToken (TVar, "a" ) = mathop "alpha"
formatToken (TVar, "b" ) = mathop "beta"
formatToken (TVar, "c" ) = mathop "gamma"
formatToken (TVar, "d" ) = mathop "delta"
formatToken (TVar, "eps" ) = mathop "epsilon"
formatToken (TVar, "k" ) = mathop "kappa"
formatToken (TVar, "n" ) = mathop "nu"
formatToken (TVar, "m" ) = mathop "mu"
formatToken (TVar, "s" ) = mathop "sigma"
formatToken (TVar, "o" ) = mathop "omega"
formatToken (TVar, "pi" ) = mathop "pi"
formatToken (TVar, "tau" ) = mathop "tau"
formatToken (TVar, "rho" ) = mathop "rho"
formatToken (TVar , txt ) | T.any isAlpha txt = "\\textit{" <> subscripts txt <> "}"
formatToken (TVar, txt ) = "\\textit{" <> protectText txt <> "}"
formatToken (TNum , kwd ) = protectText kwd
formatToken (TKeyword, kwd ) = "\\textbf{" <> protectText kwd <> "}"
formatToken (TCons, cons ) = "\\textsc{" <> subscripts cons <> "}"
--formatToken (TOperator,"\\" ) = mathop "lambda"
formatToken (TTikz mark,_ ) = mathop $ "tikzMark{" <> mark <> "}"
--formatToken (TOther, "`" ) = mathop "textasciigrave"
formatToken (TOther, "`" ) = protectText "`"
formatToken (TOther, "'" ) = mathop "prime"
formatToken (TOther, "\"" ) = protectText "\""
formatToken (TOther, "(" ) = protectText "("
formatToken (TOther, ")" ) = protectText ")"
formatToken (TOther, "]" ) = protectText "]"
formatToken (TOther, "[" ) = protectText "["
formatToken (TOther, "}" ) = protectText "}"
formatToken (TOther, "{" ) = protectText "{"
-- formatToken (TBlank, txt ) = "\\textit{\\textcolor{gray}{" <> protectText txt <> "}}"
formatToken (_, txt ) = "\\textrm{" <> protectText txt <> "}"
mathop :: Text -> Text
mathop code = "\\" <> code
prologue :: Text
prologue = T.concat ["\\usepackage{amssymb}"]
latexPackages :: [Text]
latexPackages = ["amssymb", "amsmath", "stmaryrd"]