packages feed

marxup 3.0.0.1 → 3.1.0.0

raw patch · 25 files changed

+1027/−1564 lines, 25 filesdep +haskell-src-extsdep +lp-diagramsdep +marxupdep −cubicbezierdep −glpk-hsdep −polynomials-bernsteindep ~basedep ~filepathdep ~lensnew-component:exe:marxupnew-component:exe:marxup-example

Dependencies added: haskell-src-exts, lp-diagrams, marxup

Dependencies removed: cubicbezier, glpk-hs, polynomials-bernstein, typography-geometry, vector

Dependency ranges changed: base, filepath, lens

Files

Config.hs view
@@ -4,8 +4,6 @@ import Data.Configurator import Data.Configurator.Types (Value (..),Configured (..)) import System.IO.Unsafe-import Data.Traversable-import Control.Applicative  data List a = L [a] 
+ Literate.hs view
@@ -0,0 +1,27 @@+module Literate where++import Data.Monoid+import Data.DList hiding (foldr, map)+import MarXupParser+import Data.List (isPrefixOf)+import Output++----------------------------------------------+-- Top-level generation++rHaskells :: [Haskell] -> Doc+rHaskells xs = mconcat $ map rHaskell xs++rHaskell :: Haskell -> DList Char+rHaskell (HaskLn pos) = oPos pos <> text "\n"+rHaskell (Quote xs) = mconcat $ map rMarxup xs+rHaskell _ = mempty++rMarxup :: MarXup -> Doc+rMarxup (Unquote _ [(_,HaskChunk fct),(position,Quote code)]) | "haskell" `isPrefixOf` fct = oPos position <> foldMap rInlineHask code+rMarxup _ = mempty++rInlineHask :: MarXup -> Doc+rInlineHask (TextChunk x) = text x+rInlineHask _ = mempty+
+ Main.hs view
@@ -0,0 +1,35 @@+import Text.ParserCombinators.Parsek.Position++import System.Environment+import Data.Monoid+import Data.DList hiding (foldr, map)+import MarXupParser+import qualified Literate as Lit+import Output++rHaskells :: [Haskell] -> Doc+rHaskells xs = mconcat $ map rHaskell xs++rHaskell :: Haskell -> DList Char+rHaskell (HaskChunk s) = text s+rHaskell (HaskLn pos) = oPos pos+rHaskell (Quote xs) = parens $ oConcat $ map rMarxup xs+rHaskell (List xs) = brackets $ rHaskells xs+rHaskell (Parens xs) = parens $ rHaskells xs+rHaskell (String xs) = doubleQuotes $ text xs++rArg :: (SourcePos, Haskell) -> Doc+rArg (pos,h) = oPos pos <> parens (rHaskell h)++rMarxup :: MarXup -> Doc+rMarxup (TextChunk s) = oText s+rMarxup (Unquote var val) =+  maybe mempty (\(pos,x) -> oPos pos <> text (x <> "<-")) var <>+  text "element" <+> parens (hcat $ map rArg val)+rMarxup (Comment _) = mempty++main :: IO ()+main = do+  x : y : z : _ <- getArgs+  parseFile y $ \res -> writeFile z $ render (rHaskells res <> Lit.rHaskells res)+
− Main3.hs
@@ -1,188 +0,0 @@-{-# LANGUAGE TupleSections, FlexibleInstances, TransformListComp #-}-import Text.ParserCombinators.Parsek.Position--import Data.Char-import Data.List-import System.IO-import System.Environment-import Control.Monad-import Data.DList hiding (map,foldr)-import Data.Monoid-import GHC.Exts (the,groupWith)-import Config---- todo: parse haskell comments----------------------- Simple printing combinators, which do not add nor remove line breaks--type Doc = DList Char--text = fromList-x <+> y =  x <> text " " <> y-oChar = singleton-parens s = oChar '(' <> s <> oChar ')'-braces s = oChar '{' <> s <> oChar '}'-brackets s = oChar '[' <> s <> oChar ']'-doubleQuotes s = oChar '"' <> s <> oChar '"'--int x = text $ show x-hcat :: [Doc] -> Doc-hcat = foldr (<>) mempty-punctuate t = map (<> t)-render :: Doc -> String-render = toList----------------------------------------------- Output combinators--oPos :: SourcePos -> Doc-oPos EOF = mempty-oPos p = text "{-# LINE" <+> int (sourceLine p) <+> text (show (sourceName p)) <+> text "#-}"--oText :: String -> Doc-oText x = text "textual" <+> text (show x)--oMappend :: [Doc] -> Doc-oMappend [] = text "(return ())"-oMappend [x] = parens x-oMappend l = text "do" <+> braces (text "rec" <+> braces (hcat (punctuate (text ";") binds)) <> text ";" <> ret)-  where binds = init l-        ret = last l--------------------------------------------------- Parsing helpers--satisfy' :: (String -> Bool) -> Parser Char-satisfy' p = do-  l <- look-  unless (p l) $-    fail "Unexpected leading string"-  anySymbol--munch',munch1' :: (String -> Bool) -> Parser String-munch' p = scan =<< look- where-  scan (c:cs) | p (c:cs) = (:) <$> anySymbol <*> scan cs-  scan _            = pure []--munch1' p = (:) <$> satisfy' p <*> munch' p---- | A chunck not containing some strings-pChunk' :: [String] -> Parser String-pChunk' stops = munch1' (\l -> not $ any (`isPrefixOf` l) stops)----- | A chunk not containing some chars.-pChunk :: [Char] -> Parser String-pChunk stops = munch1 (not . (`elem` stops))--------------------------------------------------- Parsing combinators--anyQuoteStrings :: [String]-anyQuoteStrings = concatMap (\(x,y) -> [x,y]) quoteStrings--pTextChunk = oText <$> pChunk' ("\n" : commentString : antiQuoteStrings ++ anyQuoteStrings) <?> "Text chunk"-pHaskChunk = text <$> pChunk' (map box "\n\"[]()" ++ map fst quoteStrings) <?> "Haskell chunk"-    -- we keep track of balancing--pWPos :: Parser Doc-pWPos = do-  char '\n'-  pos <- getPosition-  return $ oPos pos <> text "\n"--pHaskLn = pWPos -- before each newline, tell GHC where we are.-pTextLn = (oText "\n" <>) <$> pWPos-  -- add code to output a newline; and insert a newline in the code.--box = (:[])--pString :: Parser Doc-pString = do-  char '"'-  result <- many (string "\\\"" <|> pChunk ['"'])-  char '"'-  return $ doubleQuotes . hcat . map text $ result---- | Parse some Haskell code with markup inside.-pHask :: Parser Doc-pHask =-  (hcat <$> many ((brackets <$> pArg "[]") <|>-                  (parens   <$> pArg "()") <|>-                  (parens   <$> pTextArg ) <|> pString <|> pHaskChunk <|> pHaskLn))---- | Parse a text argument to an element-pTextArg' :: String -> String -> Parser Doc-pTextArg' open close = label "quoted text" $-  string open *>-  (oMappend <$> many (pElement <|> pTextChunk <|> pTextLn <|> pComment))-  <* string close--pTextArg :: Parser Doc-pTextArg = choice $ map (uncurry pTextArg') quoteStrings--pArg :: String -> Parser Doc-pArg [open,close] = char open *> pHask <*  char close--isIdentChar :: Char -> Bool-isIdentChar x = isAlphaNum x || (x `elem` "\'_")--pIdent :: Parser Doc-pIdent = text <$> munch1 isIdentChar <?> "identifier"--pArgument :: Parser Doc-pArgument = (pArg "()" <|> (brackets <$> pArg "[]") <|> pTextArg <|> pString) <?> "argument"--pElement :: Parser Doc-pElement = label "Haskell element" $ do-  choice $ map string $ antiQuoteStrings-  var <- ((<+> text "<-") <$> (pIdent <* string "<-")) <<|> pure mempty-  val <- ((:) <$> pIdent <*> manyGreedy pArgument) <|> (box <$> pArg "()")-  return $ var <> text "element" <+> parens (hcat $ fmap parens val)--commentString :: String-commentString = "%%"--pComment :: Parser Doc-pComment = label "Comment" $ do-  string commentString-  munch (/= '\n')-  string "\n"-  return mempty--main :: IO ()-main = do-  x : y : z : _ <- getArgs-  putStrLn x-  putStrLn y-  putStrLn z-  p <- parseFromFile (pHask <* endOfFile) completeResults y-  case p of-    Left e -> handleErr e-    Right [res] -> writeFile z $ render res-    Right _ -> hPutStrLn stderr "Amibiguous input!"--handleErr e =-   sequence_-          [ hPutStrLn stderr (show $ maybePosToPos $ the pos) >>-            hPutStrLn stderr ("  Expected:" ++ (intercalate " or " $ nub what))-           | (exps,_why) <- e, (what,pos) <- exps, then group by pos using groupWith, then reverse ]--instance Show (DList Char) where-  show x = show $ render x----- Tests-testHask = parse "<interactive>" pHask completeResults "arst « text @z<-fct[x](y) awft"-testHask2 = parse "<interactive>" pHask completeResults "ars(t) « text @z<-fct[x](y) » awft"-testText2 = parse "<interactive>" pTextArg completeResults "« text @fct(x »"-testText3 = parse "<interactive>" pTextArg completeResults "« 1 @x 2 @y 3 @x 4 »"-testElem = parse "<interactive>" pElement completeResults "@x<-fct(x « yop »)[y]"-testChunk = parse "<interactive>" pHaskChunk completeResults "t"-testArg = parse "<interactive>" (pArg "()") completeResults "()"--terr e  = case e of-    Left x -> handleErr x-    Right [res] -> putStrLn $ render res
MarXup/DerivationTrees.hs view
@@ -1,19 +1,15 @@-{-# LANGUAGE DisambiguateRecordFields, NamedFieldPuns, RecordWildCards, PostfixOperators, LiberalTypeSynonyms, TypeOperators, OverloadedStrings, PackageImports #-}+{-# LANGUAGE DisambiguateRecordFields, NamedFieldPuns, RecordWildCards, PostfixOperators, LiberalTypeSynonyms, TypeOperators, OverloadedStrings, PackageImports, ScopedTypeVariables #-}  module MarXup.DerivationTrees ( -- * Basics module Data.Monoid, module Data.LabeledTree, --- * Derivation' building--- axiom, rule, etc, aborted, -emptyDrv, haltDrv, haltDrv', delayPre,-dummy, rule, Derivation, Premise, Rule(..), ---- * Links-LineStyle,defaultLink,Link(..),- -- * Engine+haltDrv,+module Graphics.Diagrams.DerivationTrees,++-- * Frontend derivationTree, derivationTreeD  ) where@@ -21,60 +17,27 @@ -- import DerivationTrees.Basics import Data.List import Control.Monad.Writer -import Control.Applicative  import Data.LabeledTree import Data.Monoid import MarXup (element) import MarXup.Tex hiding (label)-import MarXup.MultiRef-import MarXup.Diagram as D-import qualified Data.Tree as T----------------------- Basics--type LineStyle = PathOptions -> PathOptions--data Link = Link {label :: Tex (), linkStyle :: LineStyle, steps :: Int}  -- ^ Regular link-          | Delayed -- ^ automatic delaying--defaultLink :: Link-defaultLink = Link mempty (denselyDotted . outline "black")  0------------------------data Rule = Rule {ruleStyle :: LineStyle, delimiter :: Tex (), ruleLabel :: Tex (), conclusion :: Tex ()}---  deriving Show--type Premise = Link ::> Derivation-type Derivation = Tree Link Rule------------------------------------------------------- Delay--depth (Link{steps} ::> Node _ ps) = 1 + steps + maximum (0 : map depth ps)--isDelayed :: Premise -> Bool-isDelayed (Delayed{} ::> _) = True-isDelayed _ = False+import Graphics.Diagrams.DerivationTrees+import MarXup.Diagram -delayPre s (Link {..} ::> j) = Link {steps = s, ..} ::> j+----------------------------------------------------------+-- Tikzify -delayD :: Derivation -> Derivation-delayD (Node r ps0) = Node r (map delayP ps)-    where ps = fmap (fmap delayD) ps0-          ps' = filter (not . isDelayed) ps-          delayP (Delayed{..} ::> d) = defaultLink {steps = 1 + maximum (0 : map depth ps')} ::> d-          delayP p = p+derivationTreeD :: Derivation TeX -> TeX+derivationTreeD d = element $ (derivationTreeDiag $ delayD d :: TexDiagram ())  ---------------------------------------------------------- -- TeXify   --- | Render a derivation tree without using metapost drv package (links will not be rendered properly)-derivationTree :: Derivation -> TeX+-- | Render a derivation tree using simple latex only (links will not be rendered properly)+derivationTree :: Derivation TeX -> TeX derivationTree = stringizeTex -stringizeTex :: Derivation -> TeX+stringizeTex :: Derivation TeX -> TeX stringizeTex (Node Rule {..} premises) = braces $ do   cmd0 "displaystyle" -- so that the text does not get smaller   cmdn "frac" [mconcat $@@ -84,145 +47,7 @@   braces $ do cmd0 "small"               ruleLabel -------------------------------------------------------------- Tikzify--derivationTreeD :: Derivation -> Tex ()-derivationTreeD d = element $ derivationTreeDiag $ delayD d--derivationTreeDiag :: Derivation -> Diagram ()-derivationTreeDiag d = do-  [h] <- newVars [ContVar] -- the height of a layer in the tree.-  minimize h-  h >== 1-  tree@(T.Node (_,n,_) _) <- toDiagram h d-  forM_ (T.levels tree) $ \ls ->-    case ls of-      [] -> return ()-      (_:ls') -> forM_ (zip ls ls') $ \((_,_,l),(r,_,_)) ->-        (l + Point 10 0) `westOf` r-  let leftFringe = map head nonNilLevs-      rightFringe = map last nonNilLevs-      nonNilLevs = filter (not . null) $ T.levels tree-  [leftMost,rightMost] <- newVars [ContVar,ContVar]-  forM_ leftFringe $ \(p,_,_) ->-    leftMost <== xpart p-  forM_ rightFringe $ \(_,_,p) ->-    xpart p <== rightMost-  minimize $ 10 *- (rightMost - leftMost)-  n # Center .=. Point 0 0--toDiagPart :: Expr -> Premise -> Diagram (T.Tree (Point,Anchorage,Point))-toDiagPart layerHeight (Link{..} ::> rul)-  | steps == 0 = toDiagram layerHeight rul-  | otherwise = do-    above@(T.Node (_,concl,_) _) <- toDiagram layerHeight rul-    ptObj <- vrule-    let pt = ptObj # S-    pt `eastOf` (concl # W)-    pt `westOf` (concl # E)-    xpart pt =~= xpart (concl # Center)-    let top = ypart (concl # S)-    ypart pt + (fromIntegral steps *- layerHeight) === top-    using linkStyle $ path $ polyline [ptObj # Base,Point (xpart pt) top]-    let embedPt 1 x = T.Node (concl # W,ptObj,concl # E) [x]-        embedPt n x = T.Node (pt,ptObj,pt) [embedPt (n-1) x]-    return $ embedPt steps above---- | @chainBases distance objects@--- - Ensures that all the objects have the same baseline.--- - Separates the objects by the given distance--- - Returns an object encompassing the group, with a the baseline set correctly.--- - Returns the average distance between the objects-   -chainBases :: Expr -> [Anchorage] -> Diagram (Anchorage,Expr)-chainBases _ [] = do-  o <- box-  return (o,0)-chainBases spacing ls = do-  grp <- box-  forM_ [Base,N,S] $ \ anch -> do-    D.align ypart $ map (# anch) (grp:ls)-  dxs <- forM (zip ls (tail ls)) $ \(x,y) -> do-    let dx = xdiff (x # E) (y # W)-    dx >== spacing-    return dx-  D.align xpart [grp # W,head ls # W]-  D.align xpart [grp # E,last ls # E]-  return (grp,avg dxs)---- | Make an horizontally flexible box of glue.-mkHGlue :: Expr -> Expr -> Diagram Anchorage-mkHGlue minimumWidth preferredWidth = do-  g <- box-  width g >== minimumWidth-  width g =~= preferredWidth-  return g---- | Put object in a box of the same vertical extent, and baseline,--- but whose height can be bigger.-relaxHeight o = do-  b <- box-  -- using (outline "green")$ traceBounds o-  D.align xpart [b#W,o#W]-  D.align xpart [b#E,o#E]-  D.align ypart [b#Base,o#Base]-  o `fitsVerticallyIn` b-  return b--toDiagram :: Expr -> Derivation -> Diagram (T.Tree (Point,Anchorage,Point))-toDiagram layerHeight (Node Rule{..} premises) = do-  ps <- mapM (toDiagPart layerHeight) premises-  concl <- relaxHeight =<< extend 1.5 <$> texBox conclusion-  -- using (outline "red")$ traceBounds concl-  lab <- texBox ruleLabel--  -- Grouping-  (psGrp,premisesDist) <- chainBases 10 [p | T.Node (_,p,_) _ <- ps]-  -- using (outline "blue" . denselyDotted) $ traceBounds psGrp-  height psGrp === layerHeight--  -- Sepaartion rule-  separ <- hrule-  separ # N .=. psGrp # S-  align ypart [concl # N,separ # S]-  minimize $ width separ-  psGrp `fitsHorizontallyIn` separ-  concl `fitsHorizontallyIn` separ--  -- rule label-  lab # BaseW .=. separ # E + Point 3 (negate 1)---  -- layout hints (not necessary for "correctness")-  let xd = xdiff (separ # W) (psGrp # W)-  xd   === xdiff (psGrp # E) (separ # E) -  relax 2 $ (2 *- xd) =~= premisesDist-  -- centering of conclusion-  xd' <- absoluteValue $ xdiff (separ # Center) (concl # Center)-  relax 3 $ minimize xd'--  -- draw the rule.-  localPathOptions ruleStyle $ path $ polyline [separ # W,separ # E]-  return $ T.Node (separ # W, concl, lab # E) ps----------------------------rule ruleLabel conclusion = Rule {delimiter = mempty, ruleStyle = outline "black", ..}--dummy :: Rule-dummy = (rule mempty mempty) {ruleStyle = const defaultPathOptions}-emptyDrv = Node dummy []---- abortDrv (Node Rule {..} _) = Node Rule {ruleStyle = Waved, ..} []---- | Used when the rest of the derivation is known.-haltDrv' :: Tex () -> Derivation -> Derivation-haltDrv' tex (Node r _) = Node r {ruleStyle = noOutline}-     [defaultLink {steps = 1, label = tex} ::> emptyDrv]---- | More compact variant-haltDrv :: Tex () -> Derivation -> Derivation+-- -- | More compact variant+haltDrv :: TeX -> Derivation TeX -> Derivation TeX haltDrv t (Node r _) = Node r [defaultLink ::> Node dummy {conclusion = cmd "vdots" nil >> cmd "hspace" (tex "2pt") >> t} []] 
MarXup/Diagram.hs view
@@ -1,7 +1,4 @@ module MarXup.Diagram (module D) where -import MarXup.Diagram.Layout as D-import MarXup.Diagram.Path as D-import MarXup.Diagram.Point  as D-import MarXup.Diagram.Object as D+import Graphics.Diagrams as D import MarXup.Diagram.Tikz as D
− MarXup/Diagram/Graphviz.hs
@@ -1,109 +0,0 @@-{-# LANGUAGE RecordWildCards #-}-module MarXup.Diagram.Graphviz (graph) where--import MarXup.Tex-import MarXup.Diagram.Point as D-import MarXup.Diagram.Object as D-import MarXup.Diagram.Tikz as D-import MarXup.Diagram.Layout-import MarXup.Diagram.Path-import Data.GraphViz as G-import Data.GraphViz.Attributes.Complete as G-import Data.GraphViz.Parsing as G-import qualified Data.GraphViz.Types.Generalised as Gen-import Data.GraphViz.Commands.IO as G--- import qualified Data.Text.Lazy.Internal as T-import qualified Data.Text.Lazy as T-import System.IO.Unsafe (unsafePerformIO)--- import Data.Traversable-import Data.Foldable-import Control.Lens (set)--graph :: (PrintDotRepr g n, ParseDot n, PrintDot n) => GraphvizCommand -> g n -> Dia-graph cmd gr = graphToDiagram $ layout cmd gr--layout :: (PrintDotRepr g n, ParseDot n, PrintDot n) => GraphvizCommand -> g n -> Gen.DotGraph n-layout command input = parseIt' $ unsafePerformIO $ graphvizWithHandle command input DotOutput hGetStrict --pos (Pos p) = Just p-pos _= Nothing--lpos (LPos p) = Just p-lpos _= Nothing--shapeA (Shape s) = Just s-shapeA _ = Nothing--widthA (Width s) = Just s-widthA _ = Nothing--labelA (Label l) = Just l-labelA _ = Nothing--arrowHeadA (ArrowHead a) = Just a-arrowHeadA _ = Nothing--readAttr :: Monad m => (Attribute -> Maybe a) -> [Attribute] -> (a -> m ()) -> m ()-readAttr f as k = readAttr' f as k (return ())--readAttr' :: (Attribute -> Maybe a) -> [Attribute] -> (a -> k) -> k -> k-readAttr' f as k1 k2 = case [x | Just x <- map f as] of-  (x:_) -> k1 x-  _ -> k2---pt' (G.Point x y _z _forced) = D.Point x y-pt = unfreeze . pt'--diaSpline (w:x:y:z:rest) = curveSegment w x y z:diaSpline (z:rest)-diaSpline _ = []---- ToTip | CircleTip | NoTip | StealthTip | LatexTip | ReversedTip LineTip | BracketTip | ParensTip-tipTop def (AType [(_,NoArrow)]) = NoTip-tipTop def (AType [(_,Normal)]) = LatexTip-tipTop def (AType [(_,DotArrow)]) = CircleTip-tipTop def (AType [(_,Vee)]) = StealthTip-tipTop def _ = def--renderLab l p = do-  l' <- labelObj $ tex $ T.unpack $ l-  l' # D.Center .=. pt p--graphToDiagram :: Gen.DotGraph n -> Dia-graphToDiagram (Gen.DotGraph _strict _directed _grIdent stmts) = do-  forM_ stmts $ \ stmt -> case stmt of-    (Gen.DE (DotEdge _from _to attrs)) -> do-      diaRaw $ "%Edge: " ++ show attrs ++ "\n"-      let toTip = readAttr' arrowHeadA attrs (tipTop ToTip) ToTip-      readAttr labelA attrs $ \(StrLabel l) ->-        readAttr lpos attrs $ \p -> -        renderLab l p-      readAttr pos attrs $ \(SplinePos splines) ->-        forM_ splines $ \Spline{..} -> do-          let mid = diaSpline $ map pt' splinePoints-          let beg = case (startPoint,splinePoints) of-                (Just p,q:_) -> [lineSegment (pt' p) (pt' q)]-                _ -> []-          let end = case (endPoint,reverse splinePoints) of-                (Just p,q:_) -> [lineSegment (pt' q) (pt' p)]-                _ -> []-          using (set endTip toTip) $-            draw $ frozenPath $ fromBeziers (beg ++ mid ++ end)--    (Gen.DN (DotNode _nodeIdent attrs)) -> do-      diaRaw $ "%Node: " ++ show attrs ++ "\n"-      readAttr pos   attrs $ \(PointPos p) -> do-        readAttr labelA attrs $ \l -> do-          case l of-            StrLabel l -> renderLab l p-        readAttr widthA attrs $ \w ->-         readAttr shapeA attrs $ \s ->-          case s of-            Circle -> do-              draw $ path $ circle (pt p) (constant $ inch (w/2))-            _ -> return ()-    _ -> return ()--inch x = 72 * x--
− MarXup/Diagram/Layout.hs
@@ -1,203 +0,0 @@-{-# LANGUAGE TypeSynonymInstances, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, RecursiveDo, TypeFamilies, OverloadedStrings, RecordWildCards,UndecidableInstances, PackageImports, TemplateHaskell #-}--module MarXup.Diagram.Layout (module MarXup.Diagram.Layout) where-import Control.Monad.LPMonad-import Prelude hiding (sum,mapM_,mapM,concatMap)-import Control.Monad.RWS hiding (forM,forM_,mapM_,mapM)-import Data.LinearProgram-import Data.LinearProgram.Common as MarXup.Diagram.Layout (VarKind(..)) -import Data.LinearProgram.LinExpr-import Data.Map (Map)-import qualified Data.Map as M-import Control.Lens hiding (element)-import Data.String--- import MarXup-import Data.Traversable-import Data.Foldable-import Control.Applicative-import System.IO.Unsafe-import MarXup.MultiRef-import MarXup.Tex--type LPState = LP Var Constant--type Solution = Map Var Double-type Constant = Double---- | Expressions are linear functions of the variables-type Expr = LinExpr Var Constant--newtype Decoration = Decoration String-data LineTip = ToTip | CircleTip | NoTip | StealthTip | LatexTip | ReversedTip LineTip | BracketTip | ParensTip-type Color = String-data LineCap = ButtCap | RectCap | RoundCap-data LineJoin = MiterJoin | RoundJoin | BevelJoin-type DashPattern = [(Constant,Constant)]-data PathOptions = PathOptions-                     {_drawColor :: Maybe Color-                     ,_fillColor :: Maybe Color-                     ,_lineWidth :: Constant-                     ,_startTip  :: LineTip-                     ,_endTip    :: LineTip-                     ,_lineCap   :: LineCap-                     ,_lineJoin  :: LineJoin-                     ,_dashPattern :: DashPattern-                     ,_decoration :: Decoration-                     }-$(makeLenses ''PathOptions)--data Env = Env {_diaSolution :: Solution-               ,_diaTightness :: Constant -- ^ Multiplicator to minimize constraints-               ,_diaPathOptions :: PathOptions}--$(makeLenses ''Env)--defaultPathOptions :: PathOptions-defaultPathOptions = PathOptions-  {_drawColor = Nothing-  ,_fillColor = Nothing-  ,_lineWidth = 0.4-  ,_startTip  = NoTip-  ,_endTip    = NoTip-  ,_lineCap   = ButtCap-  ,_lineJoin  = MiterJoin-  ,_dashPattern = []-  ,_decoration = Decoration ""-  }--newtype Diagram a = Dia (RWST Env () (Var,LPState) Multi a)-  deriving (Monad, Applicative, Functor, MonadReader Env)--type Dia = Diagram ()--instance MonadState LPState Diagram where-  get = Dia $ snd <$> get-  put y = Dia $ do-    (x,_) <- get-    put (x,y)------------------ Diagrams--runDiagram :: Diagram a -> Multi a-runDiagram (Dia diag) = do-  rec (a,(_,problem),_) <- runRWST diag (Env solution 1 defaultPathOptions)-                                        (Var 0,LP Min M.empty [] M.empty M.empty)-      let solution = case unsafePerformIO $ glpSolveVars simplexDefaults problem of-            (_retcode,Just (_objFunc,s)) -> s-            (retcode,Nothing) -> error $ "ret code = " ++ show retcode-  -- Raw Normal $ "%problem solved: " ++ show problem ++ "\n"-  return a--diaRawTex :: Tex a -> Diagram a-diaRawTex (Tex t) = Dia $ lift t--diaRaw :: String -> Dia-diaRaw = diaRawTex . tex--relax factor = local (over diaTightness (/ factor)) --instance Monoid (Diagram ()) where-  mempty = return ()-  mappend = (>>)--instance IsString (Diagram ()) where-  fromString = diaRawTex . tex------------------- Variables-varValue :: Var -> Diagram Double-varValue v = M.findWithDefault 0 v <$> view diaSolution--rawNewVar :: Diagram Var-rawNewVar = Dia $ do-      (Var x,y) <- get-      put $ (Var (x+1),y)-      return $ Var x--newVars :: [VarKind] -> Diagram [Expr]-newVars kinds = newVars' (zip kinds (repeat Free))--newVars' :: [(VarKind,Bounds Constant)] -> Diagram [Expr]-newVars' kinds = forM kinds $ \(k,b) -> do-  v <- rawNewVar-  setVarKind v k-  setVarBounds v b-  return $ variable v--infix 4 <==,===,>==--------------------- Expressions-instance Fractional Expr where-  fromRational ratio = constant (fromRational ratio)--instance Num Expr where-  fromInteger x = LinExpr M.empty (fromInteger x)-  negate = neg-  (+) = (^+^)-  (-) = (^-^)--valueOf :: Expr -> Diagram Double-valueOf (LinExpr m c) = do-  vs <- forM (M.assocs m) $ \(v,scale) ->-    (scale *) <$> varValue v-  return $ sum $ c:vs--variable :: Var -> Expr-variable v = LinExpr (var v) 0--constant :: Constant -> Expr-constant c = LinExpr M.empty c--(*-) :: Module Constant a => Constant -> a -> a-(*-) = (*^)-infixr 6 *---avg :: Module Constant a => [a] -> a-avg xs = (1/fromIntegral (length xs)) *- gsum xs--absoluteValue :: Expr -> Diagram Expr-absoluteValue x = do-  [t1,t2] <- newVars' [(ContVar,LBound 0),(ContVar,LBound 0)]-  t1 - t2 === x-  return $ t1 + t2--satAll :: (Expr -> a -> Diagram b) -> [a] -> Diagram Expr-satAll p xs = do-  [m] <- newVars [ContVar]-  mapM_ (p m) xs-  return m--maximVar, minimVar :: [Expr] -> Diagram Expr-maximVar = satAll (>==)-minimVar = satAll (<==)------------------- Expression constraints-(>==), (<==) :: Expr -> Expr -> Diagram ()-e1 <== e2 = do-  let LinExpr f c = e1 - e2-  leqTo f (negate c)--(>==) = flip (<==)--(===) :: Expr -> Expr -> Diagram ()-e1 === e2 = do-  let LinExpr f c = e1 - e2-  equalTo f (negate c)---- | minimize the distance between expressions-(=~=) :: Expr -> Expr -> Diagram ()-x =~= y = minimize =<< absoluteValue (x-y)------------------------------ Expression objectives--minimize,maximize :: Expr -> Diagram ()-minimize (LinExpr x _) = do-  tightness <- view diaTightness-  addObjective (tightness *- x)-maximize = minimize . negate--
− MarXup/Diagram/Object.hs
@@ -1,266 +0,0 @@-{-# LANGUAGE DataKinds, KindSignatures, OverloadedStrings, EmptyDataDecls, MultiParamTypeClasses, FlexibleContexts, OverlappingInstances, TypeSynonymInstances, FlexibleInstances   #-}--module MarXup.Diagram.Object where---- import MarXup-import MarXup.Tex-import MarXup.Diagram.Tikz-import MarXup.Diagram.Path-import MarXup.Diagram.Point-import MarXup.Diagram.Layout-import MarXup.MultiRef (BoxSpec(..))-import Control.Monad-import Control.Applicative--- import Data.Algebra--- import Data.List (intersperse)-import Control.Lens (set)--data Anchor = Center | N | NW | W | SW | S | SE | E | NE | BaseW | Base | BaseE-  deriving Show---- | Box-shaped object. (a subtype)-type Box = Object--newtype Anchorage = Anchorage {boxAnchors :: Anchor -> Point}-data Object = Object {objectOutline :: Path, objectAnchorage :: Anchorage}--class Anchored a where-  anchors :: a -> Anchor -> Point-infix 8 #--(#) :: Anchored a => a -> Anchor -> Point-(#) = anchors--instance Anchored Anchorage where-  anchors = boxAnchors--instance Anchored Object where-  anchors = anchors . objectAnchorage--instance Anchored Point where-  anchors p _ = p---- | Horizontal distance between objects-hdist :: Anchored a => a -> a -> Expr-hdist x y = xpart (y # W - x # E)---- | Vertical distance between objects-vdist :: Anchored a => a -> a -> Expr-vdist x y = ypart (y # S - x # N)---- | Extend the box boundaries by the given delta-extend :: Expr -> Anchorage -> Anchorage-extend e o = Anchorage $ \a -> o # a + shiftInDir a e---- | Makes a shift of size 'd' in the given direction.-shiftInDir :: Anchor -> Expr -> Point-shiftInDir N d = 0 `Point` d-shiftInDir S d = 0 `Point` negate d-shiftInDir W d = negate d `Point` 0-shiftInDir E d  = d `Point` 0-shiftInDir NW d = negate d `Point` d-shiftInDir SE d = d `Point` negate d-shiftInDir SW d = negate d `Point` negate d-shiftInDir NE d = d `Point` d-shiftInDir _ _  = 0 `Point` 0---- | Make a label object. This is just some text surrounded by 4--- points of blank.-mkLabel :: TeX -> Diagram Anchorage-mkLabel texCode = extend 4 <$> texBox texCode--labelObj :: TeX -> Diagram Box-labelObj = rectangleShape <=< mkLabel---- | Label a point by a given TeX expression, at the given anchor.-labelPt :: TeX -> Anchor -> Point -> Diagram Box-labelPt labell anchor labeled  = do-  t <- labelObj labell -  t # anchor .=. labeled-  return t---- | A free point-point :: Diagram Point-point = do-  [x,y] <- newVars (replicate 2 ContVar)-  return $ Point x y---- | A point anchorage (similar to a box of zero width and height)-pointBox :: Diagram Anchorage-pointBox = do-  p <- point-  return $ Anchorage $ \a -> case a of _ -> p---- | A box. Anchors are aligned along a grid.-box :: Diagram Anchorage-box = do-  [n,s,e,w,base,midx,midy] <- newVars (replicate 7 ContVar)-  n >== base-  base >== s-  w <== e-  -  midx === avg [w,e]-  midy === avg [n,s]-  let pt = flip Point-  return $ Anchorage $ \anch -> case anch of-    NW     -> pt n    w-    N      -> pt n    midx-    NE     -> pt n    e  -    E      -> pt midy e-    SE     -> pt s    e-    S      -> pt s    midx-    SW     -> pt s    w-    W      -> pt midy w-    Center -> pt midy midx-    Base   -> pt base midx-    BaseE  -> pt base e-    BaseW  -> pt base w---- | A box of zero width-vrule :: Diagram Anchorage-vrule = do-  o <- box-  align xpart [o # W, o #Center, o#E]-  return o---- | A box of zero height-hrule :: Diagram Anchorage-hrule = do-  o <- box-  height o === 0-  return o--height o = ypart (o # N - o # S)-width o = xpart (o # E - o # W)-ascent o = ypart (o # N - o # Base)-descent o = ypart (o # Base - o # S)---- fitsVerticallyIn :: Anchorage -> Anchorage -> Diagram ()-o `fitsVerticallyIn` o' = do-  let dyN = ypart $ o' # N - o # N-      dyS = ypart $ o # S - o' # S-  minimize dyN-  dyN >== 0-  minimize dyS-  dyS >== 0---- fitsHorizontallyIn :: Anchorage -> Anchorage -> Diagram ()-o `fitsHorizontallyIn` o' = do-  let dyW = xpart $ o # W - o' # W-      dyE = xpart $ o' # E - o # E-  minimize dyW-  dyW >== 0-  minimize dyE-  dyE >== 0--a `fitsIn` b = do-  a `fitsHorizontallyIn` b-  a `fitsVerticallyIn` b--circleShape :: Diagram Object-circleShape = do-  anch <- box-  width anch === height anch-  let radius = 0.5 *- width anch-  let p = circle (anch # Center) radius-  path p-  return $ Object p anch---   let k1 :: Constant---       k1 = sqrt 2 / 2---       k = k1 *^ r---       p = circle center r---   return $ Object p $ Anchorage $ \a -> center + case a of---     N -> Point 0 r---     S -> Point 0 (-r)---     E -> Point r 0---     W -> Point (-r) 0---     Center -> Point 0 0---     NE -> Point k k--rectangleShape :: Anchorage -> Diagram Object-rectangleShape l = do-  let p = polygon (map (l #) [NW,NE,SE,SW])-  path p-  return $ Object p l--traceAnchorage :: Anchored a => Color -> a -> Diagram ()-traceAnchorage c l = do-  stroke c $ path $ polygon (map (l #) [NW,NE,SE,SW])-  -- TODO: draw the baseline, etc.---- | Typeset a piece of text and return its bounding box.-texBox :: TeX -> Diagram Anchorage-texBox t = do-  l <- box-  -- traceAnchorage "red" l-  BoxSpec wid h desc <- drawText (l # NW) t--  width   l === constant wid-  descent l === constant desc-  height  l === constant (h + desc)-  return l--data Incidence = Incidence { incidencePoint, incidenceNormal :: Point }-swap :: Incidence -> Incidence-swap (Incidence p v) = Incidence p (negate v)---- | Traces a straight edge between two objects.--- The midpoint is returned, as well as a normal vector.-edge :: Object -> Object -> Diagram Incidence-edge source target = do-  let points@[a,b] = [source # Center,target # Center]-      link = polyline points-      targetArea = objectOutline target-      sourceArea = objectOutline source-  l' <- freeze link-  sa' <- freeze sourceArea-  ta' <- freeze targetArea-  frozenPath $ (l' `cutAfter` ta') `cutBefore` sa'-  return $ Incidence (avg points) (rotate90 (b-a))--(.<.) :: Point -> Point -> Diagram ()-Point x1 y1 .<. Point x2 y2 = do-  x1 <== x2-  y1 <== y2---- | Forces the point to be inside the (bounding box) of the object.-inside :: Point -> Box -> Diagram ()-inside p o = do-  (o # SW) .<. p-  p .<. (o # NE)---- | @autoLabel label i@ Layouts the label at the given incidence--- point.-autoLabel :: Box -> Incidence -> Diagram ()-autoLabel lab (Incidence pt norm) = do-  pt `inside` lab-  minimize =<< orthoDist (lab#Center) (pt + norm)---- | @labeledEdge label source target@-labeledEdge :: Object -> Object -> Box -> Diagram ()-labeledEdge source target lab = autoLabel lab =<< edge source target-------------------------- Even higher-level primitives:-----example:      spread hdist 30 ps--spread f d (x:y:xs) = do-  f x y === d-  spread f d (y:xs)-spread f _ _ = return ()--node lab = do-  l <- extend 4 <$> texBox lab-  c <- draw $ circleShape-  l `fitsIn` c-  l # Center .=. c # Center-  return c--arrow :: Object -> Object -> Diagram Incidence-arrow src trg = using (outline "black" . set endTip LatexTip) $ do-  edge src trg-
− MarXup/Diagram/Path.hs
@@ -1,156 +0,0 @@-{-# LANGUAGE TypeSynonymInstances, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, RecursiveDo, TypeFamilies, OverloadedStrings, RecordWildCards,UndecidableInstances, PackageImports, TemplateHaskell #-}--module MarXup.Diagram.Path where--import MarXup.Diagram.Layout-import MarXup.Diagram.Point-import Data.Traversable-import Data.Foldable-import Data.Algebra--- import Data.Traversable--- import Data.Foldable-import Graphics.Typography.Geometry.Bezier-import Graphics.Typography.Geometry.Bezier as MarXup.Diagram.Point (Curve) -import Control.Applicative-import Data.List (sort,transpose)-import Data.Maybe (listToMaybe)-import Prelude hiding (sum,mapM_,mapM,concatMap,maximum,minimum)-import qualified Data.Vector.Unboxed as V-import Algebra.Polynomials.Bernstein (restriction,Bernsteinp(..))--type Frozen x = x Constant-type FrozenPoint = Frozen Point'-type FrozenPath = Frozen Path'--freeze :: Traversable t => t Expr -> Diagram (t Constant)-freeze = traverse valueOf--unfreeze :: Functor t => t Constant -> t Expr-unfreeze = fmap constant--toBeziers :: FrozenPath -> [Curve]-toBeziers EmptyPath = []-toBeziers (Path start ss) | not (null ss) &&-                            isCycle (last ss) = toBeziers' start (init ss ++ [StraightTo start])-                          | otherwise = toBeziers' start ss--curveSegment (Point xa ya) (Point xb yb) (Point xc yc) (Point xd yd) = bezier3 xa ya xb yb xc yc xd yd-lineSegment (Point xa ya) (Point xb yb) = line xa ya xb yb--toBeziers' :: FrozenPoint -> [Frozen Segment] -> [Curve]-toBeziers' _ [] = []-toBeziers' start (StraightTo next:ss) = curveSegment start mid mid next : toBeziers' next ss-  where mid = avg [start, next]-toBeziers' p (CurveTo c d q:ss) = curveSegment p c d q : toBeziers' q ss--fromBeziers :: [Curve] -> FrozenPath-fromBeziers [] = EmptyPath-fromBeziers (Bezier cx cy t0 t1:bs) = case map toPt $ V.foldr (:) [] cxy of-      [p,c,d,q] -> Path p (CurveTo c d q:rest)-      [p,q] -> Path p (StraightTo q:rest)-  where [cx',cy'] = map (\c -> coefs $ restriction c t0 t1) [cx,cy]-        cxy = V.zip cx' cy'-        toPt (x,y) = Point x y-        rest = pathSegments (fromBeziers bs)--pathSegments :: Path' t -> [Segment t]-pathSegments EmptyPath = []-pathSegments (Path _ ss) = ss--isCycle Cycle = True-isCycle _  = False--frozenPointElim (Point x y) f = f x y--splitBezier (Bezier cx cy t0 t1) (u,v,_,_) = (Bezier cx cy t0 u, Bezier cx cy v t1)--clipOne :: Curve -> [Curve] -> Maybe Curve-clipOne b cutter = fmap firstPart $ listToMaybe $ sort $ concatMap (inter b) cutter-  where firstPart t = fst $ splitBezier b t---- | @cutAfter path area@ cuts the path after its first intersection with the @area@.-cutAfter', cutBefore' :: [Curve] -> [Curve] -> [Curve]-cutAfter' [] _cutter = []-cutAfter' (b:bs) cutter = case clipOne b cutter of-  Nothing -> b:cutAfter' bs cutter-  Just b' -> [b']--revBernstein (Bernsteinp n c) = Bernsteinp n (V.reverse c)-revBeziers :: [Curve] -> [Curve]-revBeziers = reverse . map rev-  where rev (Bezier cx cy t0 t1) = (Bezier (revBernstein cx) (revBernstein cy) (1-t1) (1-t0))--cutBefore' path area = revBeziers $ cutAfter' (revBeziers path) area--onBeziers :: ([Curve] -> [Curve] -> [Curve])-             -> FrozenPath -> FrozenPath -> FrozenPath-onBeziers op p' q' = fromBeziers $ op (toBeziers p') (toBeziers q')---cutAfter :: FrozenPath -> FrozenPath -> FrozenPath-cutAfter = onBeziers cutAfter'--cutBefore :: FrozenPath -> FrozenPath -> FrozenPath-cutBefore = onBeziers cutBefore'--data Segment v = CurveTo (Point' v) (Point' v) (Point' v)-                   | StraightTo (Point' v)-                   | Cycle-                   -- | Rounded (Maybe Constant)-                   -- | HV point | VH point-  deriving (Show,Eq)-instance Functor Segment where-  fmap = fmapDefault-  -instance Foldable Segment where-  foldMap = foldMapDefault-instance Traversable Segment where-  traverse _ Cycle = pure Cycle-  traverse f (StraightTo p) = StraightTo <$> traverse f p-  traverse f (CurveTo c d q) = CurveTo <$> traverse f c <*> traverse f d <*> traverse f q-  ---------------------- Paths--type Path = Path' Expr--data Path' a-  = EmptyPath-  | Path {startingPoint :: Point' a-         ,segments :: [Segment a]}-  deriving Show---- mapPoints :: (Point' a -> Point' b) -> Path' a -> Path' b-instance Functor Path' where-  fmap = fmapDefault--instance Foldable Path' where-  foldMap = foldMapDefault-instance Traversable Path' where-  traverse _ EmptyPath = pure EmptyPath-  traverse f (Path s ss) = Path <$> traverse f s <*> traverse (traverse f) ss---polyline :: [Point] -> Path-polyline [] = EmptyPath-polyline (x:xs) = Path x (map StraightTo xs)--polygon :: [Point] -> Path-polygon [] = EmptyPath-polygon (x:xs) = Path x (map StraightTo xs ++ [Cycle])----- | Circle approximated with 4 cubic bezier curves-circle :: Point -> Expr -> Path-circle center r =      Path (pt r 0)-                         [CurveTo (pt r k) (pt k r) (pt 0 r),-                          CurveTo (pt (-k) r) (pt (-r) k) (pt (-r) 0),-                          CurveTo (pt (-r) (-k)) (pt (-k) (-r)) (pt 0 (-r)),-                          CurveTo (pt k (-r)) (pt r (-k)) (pt r 0),-                          Cycle]- where k1 :: Constant-       k1 = 4 * (sqrt 2 - 1) / 3-       k = k1 *^ r-       pt x y = center ^+^ (Point x y)-
− MarXup/Diagram/Point.hs
@@ -1,96 +0,0 @@-{-# LANGUAGE TypeSynonymInstances, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, RecursiveDo, TypeFamilies, OverloadedStrings, RecordWildCards,UndecidableInstances, PackageImports, TemplateHaskell #-}--module MarXup.Diagram.Point where--import MarXup.Diagram.Layout-import Data.Traversable-import Data.Foldable-import Data.Algebra-import Control.Applicative-import Data.List (transpose)-import Prelude hiding (sum,mapM_,mapM,concatMap,maximum,minimum)--infix 4 .=.-------------------- Points --- | A point in 2d space-data Point' a = Point {xpart :: a, ypart :: a}-  deriving (Eq,Show)--instance Traversable Point' where-  traverse f (Point x y) = Point <$> f x <*> f y--instance Foldable Point' where-  foldMap = foldMapDefault--instance Functor Point' where-  fmap = fmapDefault--  -type Point = Point' Expr-instance Group a => Num (Point' a) where-  negate = neg-  (+) = (^+^)-  (-) = (^-^)--instance Group v => Group (Point' v) where-  zero = Point zero zero-  Point x1 y1 ^+^ Point x2 y2 = Point (x1 ^+^ x2) (y1 ^+^ y2)-  neg (Point x y) = Point (neg x) (neg y)--instance Module Constant v => Module Constant (Point' v) where-  k *^ Point x y = Point (k *^ x) (k *^ y)---- | Orthogonal norm of a vector-orthonorm :: Point -> Diagram Expr-orthonorm (Point x y) =-  (+) <$> absoluteValue x <*> absoluteValue y---- | Orthogonal distance between points.-orthoDist :: Point -> Point -> Diagram Expr-orthoDist p q = orthonorm (q-p)---- | Rotate a vector 90 degres in the trigonometric direction.-rotate90, rotate180 :: Point -> Point-rotate90 (Point x y) = Point (negate y) x--rotate180 = rotate90 . rotate90--xdiff,ydiff :: Point -> Point -> Expr-xdiff p q = xpart (q - p)-ydiff p q = ypart (q - p)---------------------- Point constraints--(.=.),northOf,southOf,westOf,eastOf :: Point -> Point -> Diagram ()-Point x1 y1 .=. Point x2 y2 = do-  x1 === x2-  y1 === y2--northOf (Point _ y1) (Point _ y2) = y2 <== y1-southOf = flip northOf-westOf (Point x1 _) (Point x2 _) = x1 <== x2-eastOf = flip westOf--alignHoriz,alignVert :: [Point] -> Diagram ()-alignHoriz = align ypart-alignVert = align xpart--align :: (a -> Expr) -> [a] -> Diagram ()-align _ [] = return ()-align f (p:ps) = forM_ ps $ \p' -> f p === f p'--alignMatrix :: [[Point]] -> Dia-alignMatrix ls = do-  forM_ ls alignHoriz-  forM_ (transpose ls) alignVert-------------------------- Point objectives--southwards, northwards, westwards, eastwards :: Point -> Diagram ()-southwards (Point _ y) = minimize y-westwards (Point x _) = minimize x-northwards = southwards . negate-eastwards = westwards . negate
MarXup/Diagram/Tikz.hs view
@@ -1,145 +1,67 @@-{-# LANGUAGE TypeSynonymInstances, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, RecursiveDo, TypeFamilies, OverloadedStrings, RecordWildCards,UndecidableInstances, PackageImports, TemplateHaskell #-}+{-# LANGUAGE TypeSynonymInstances, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, RecursiveDo, TypeFamilies, OverloadedStrings, RecordWildCards,UndecidableInstances, PackageImports, TemplateHaskell, RankNTypes #-}  module MarXup.Diagram.Tikz where -import MarXup.Diagram.Layout-import MarXup.Diagram.Point-import MarXup.Diagram.Path-import Control.Lens hiding (element)+import Graphics.Diagrams.Core+import Graphics.Diagrams.Path import Prelude hiding (sum,mapM_,mapM,concatMap)-import Control.Applicative import Data.List (intercalate)-import Data.String import MarXup-import MarXup.MultiRef+import MarXup.MultiRef (newLabel) import MarXup.Tex import Numeric (showFFloat)-import Data.Traversable import Data.Foldable import Data.Monoid-import Control.Monad.Reader -instance Element Expr where-  type Target Expr = Dia-  element x = do-    v <- valueOf x-    diaRaw $ showDistance v+type TexDiagram = Diagram TeX Tex -instance Element (Diagram ()) where-  type Target (Diagram ()) = TeX+instance Element (Diagram TeX Tex ()) where+  type Target (Diagram TeX Tex ()) = TeX   element d = do    texLn "" -- otherwise beamer does not understand where a tikzpicture ends (?!!)    braces $ do-    cmd0 "normalsize"-      -- otherwise the boxes use "normalsize", while tikz inherits-      -- the smaller or bigger size from the current scope. Actually,-      -- every text styling should be reset, but I don't know how to-      -- do that.+    usepkg "tikz" 100 []     env "tikzpicture" $-      Tex $ runDiagram d------------------------- Point rendering-instance Element Point where-  type Target Point = Diagram ()-  element (Point x y) = "(" <> element x <> "," <> element y <> ")"--diaDebug msg = diaRaw $ "\n%DBG:" ++ msg ++ "\n"--instance (Element (Point' v),Monoid (Target (Point' v)), IsString (Target (Point' v))) => Element (Segment v) where-  type Target (Segment v) = Target (Point' v)-  element (StraightTo p) = "--" <> element p-  element (CurveTo c d p) = "..controls" <> element c <> "and" <> element d <> ".." <> element p-  element Cycle = "--cycle"-  -- element (VH p) = "|-" <> element p-  -- element (HV p) = "-|" <> element p-  -- element (Rounded Nothing) = "[sharp corners]"-  -- element (Rounded (Just r)) = "[" <> element (constant r) <> "]"--instance Element Path where-  type Target Path = Diagram ()-  element = path+      runDiagram tikzBackend d -path :: Path -> Dia-path = frozenPath <=< freeze+-- diaDebug msg = diaRaw $ "\n%DBG:" ++ msg ++ "\n"+class Tikz a where+  toTikz :: a -> String -frozenPath :: FrozenPath  -> Dia-frozenPath p  = do-  options <- view diaPathOptions-  diaRaw $ "\\path"-    <> element options-    <> case p of-      EmptyPath -> ""-      (Path start segs) -> element start ++ concatMap element segs-  diaRaw ";\n"+instance Tikz FrozenPoint where+  toTikz (Point x y) =  "(" <> showDistance x <> "," <> showDistance y <> ")" +instance Tikz (Frozen Segment) where+  toTikz (StraightTo p) = "--" <> toTikz p+  toTikz (CurveTo c d p) = "..controls" <> toTikz c <> "and" <> toTikz d <> ".." <> toTikz p+  toTikz Cycle = "--cycle"+  -- toTikz (VH p) = "|-" <> toTikz p+  -- toTikz (HV p) = "-|" <> toTikz p+  -- toTikz (Rounded Nothing) = "[sharp corners]"+  -- toTikz (Rounded (Just r)) = "[" <> toTikz (constant r) <> "]"  showDistance :: Constant -> String showDistance x = showFFloat (Just 4) x tikzUnit     where tikzUnit = "pt" -instance Element FrozenPoint where-  type Target FrozenPoint = String-  element pt = frozenPointElim pt $ \x y -> "(" <> showDistance x <> "," <> showDistance y <> ")"----------------------- Path Options--localPathOptions :: (PathOptions -> PathOptions) -> Diagram a -> Diagram a-localPathOptions f = local (over diaPathOptions f)--instance Show LineTip where-  show t = case t of+instance Tikz LineTip where+  toTikz t = case t of     ToTip -> "to"     StealthTip -> "stealth"     CircleTip -> "o"     NoTip -> ""     LatexTip -> "latex"-    ReversedTip x -> show x ++ " reversed"+    ReversedTip x -> toTikz x ++ " reversed"     BracketTip -> "["     ParensTip -> "(" --ultraThin, veryThin, thin, semiThick, thick, veryThick, ultraThick :: Constant-ultraThin = 0.1-veryThin = 0.2-thin = 0.4-semiThick = 0.6-thick = 0.8-veryThick = 1.2-ultraThick = 1.6-- showDashPat :: DashPattern -> String showDashPat xs = intercalate " " ["on " <> showDistance on <>                                   " off " <> showDistance off | (on,off) <- xs] -solid             o@PathOptions{..} = o { _dashPattern = [] }-dotted            o@PathOptions{..} = o { _dashPattern = [(_lineWidth,2)] }-denselyDotted     o@PathOptions{..} = o { _dashPattern = [(_lineWidth, 1)] }-looselyDotted     o@PathOptions{..} = o { _dashPattern = [(_lineWidth, 4)] }-dashed            o@PathOptions{..} = o { _dashPattern = [(3, 3)] }-denselyDashed     o@PathOptions{..} = o { _dashPattern = [(3, 2)] }-looselyDashed     o@PathOptions{..} = o { _dashPattern = [(3, 6)] }-dashdotted        o@PathOptions{..} = o { _dashPattern = [(3, 2), (_lineWidth, 2)] }-denselyDashdotted o@PathOptions{..} = o { _dashPattern = [(3, 1), (_lineWidth, 1)] }-looselyDashdotted o@PathOptions{..} = o { _dashPattern = [(3, 4), (_lineWidth, 4)] }--using = localPathOptions-stroke color = using (outline color)-draw = stroke "black"--noOutline = set drawColor Nothing-outline color = set drawColor (Just color)-fill color = set fillColor (Just color)--zigzagDecoration = set decoration (Decoration "zigzag")--instance Element PathOptions where-  type Target PathOptions = String-  element PathOptions{..} = "["-    <> show _startTip <> "-" <> show _endTip <> ","+instance Tikz PathOptions where+  toTikz PathOptions{..} = "["+    <> toTikz _startTip <> "-" <> toTikz _endTip <> ","     <> col "draw" _drawColor     <> col "fill" _fillColor     <> "line width=" <> showDistance _lineWidth <> ","@@ -158,15 +80,28 @@     <> "]"     where col attr = maybe "" (\c -> attr <> "=" <> c <> ",") -------------- Text--drawText :: Point -> TeX -> Diagram BoxSpec-drawText point t = do-  diaRawTex $ tex $ "\\node[anchor=north west,inner sep=0] at "-  element point-  (_,box) <- diaRawTex $ inBox $ braces $ t-  diaRawTex $ tex ";\n"-  return box+tikzBackend :: Backend TeX Tex+tikzBackend = Backend {..} where+  _tracePath options p = do+     tex $ "\\path"+       <> toTikz options+       <> case p of+         EmptyPath -> ""+         (Path start segs) -> toTikz start ++ concatMap toTikz segs+     tex ";\n"+  _traceLabel :: Monad x =>+                   (location -> (FrozenPoint -> Tex ()) -> x ()) -> -- freezer+                   (forall a. Tex a -> x a) -> -- embedder+                   location ->+                   Tex () -> -- label specification+                   x BoxSpec+  _traceLabel freezer embedder point lab = do+       bxId <- embedder $ Tex newLabel+       freezer point $ \p' -> do+         tex $ "\\node[anchor=north west,inner sep=0] at " ++ toTikz p'+         fillBox bxId True $ braces $ lab+         tex ";\n"+       embedder $ getBoxFromId bxId  +type Dia = TexDiagram ()
MarXup/Latex.hs view
@@ -3,14 +3,12 @@  import MarXup import MarXup.Verbatim-import Control.Monad (forM_)+import Control.Monad (forM_,when,forM) import MarXup.Tex-import Data.List (intersperse,groupBy,elemIndex,nub)+import Data.List (intersperse,groupBy,elemIndex,nub,intercalate) import Data.Monoid-import Control.Applicative import Data.Function (on) - -- | Separate the arguments with '\\' mkrows,mkcols :: [TeX] -> TeX mkrows ls = sequence_ $ intersperse newline ls@@ -19,35 +17,37 @@ mkcols = sequence_ . intersperse newcol  vspace, hspace :: String -> TeX-vspace = cmd "vspace" . textual-hspace = cmd "hspace" . textual+vspace = cmd "vspace" . tex+hspace = cmd "hspace" . tex++hfill :: TeX hfill = cmd0 "hfill"  title :: TeX -> TeX title = cmd "title" --data ClassFile = Plain | LNCS | SIGPlan | IEEE | EPTCS | Beamer-  deriving Eq type AuthorInfoStyle = ClassFile  data AuthorInfo = AuthorInfo {authorName :: String, authorEmail :: String, authorInst :: String} --- | author info in as triplets name, institution, email-authorinfo :: AuthorInfoStyle -> [AuthorInfo] -> TeX-authorinfo LNCS as = do+authorinfo :: [AuthorInfo] -> Tex ()+authorinfo as = do c<-askClass; authorinfo' c as++-- | author info as triplets name, institution, email+authorinfo' :: AuthorInfoStyle -> [AuthorInfo] -> TeX+authorinfo' LNCS as = do   cmd "author" $ mconcat $ intersperse (cmd0 "and") $ map oneauthor as   cmd "institute" $ mconcat $ intersperse (cmd0 "and") $ map textual $ insts   where oneauthor AuthorInfo{..} = textual authorName <> (if length insts > 1 then cmd "inst" (textual $ show $ 1 + instIdx) else mempty)            where Just instIdx = elemIndex authorInst insts         insts = nub $ map authorInst as -authorinfo SIGPlan as = forM_ (groupBy ((==) `on` authorInst) as) $ \ (g@((AuthorInfo _ _ institution):_)) -> do+authorinfo' SIGPlan as = forM_ (groupBy ((==) `on` authorInst) as) $ \ (g@((AuthorInfo _ _ institution):_)) -> do     let names = map authorName g         emails = mconcat $ intersperse (cmd0 "and") $ map (textual . authorEmail) g     cmdn "authorinfo" [mconcat $ intersperse (cmd0 "and") $ map textual names, textual institution, emails]     return ()-authorinfo EPTCS as = mconcat $ intersperse and' $+authorinfo' EPTCS as = mconcat $ intersperse and' $   flip map (groupBy ((==) `on` authorInst) as) $ \ (g@((AuthorInfo _ _ institution):_)) -> do     cmd "author" $ do       mconcat $ intersperse dquad $ map (textual . authorName) g@@ -56,28 +56,59 @@     return ()   where dquad = cmd0 "quad" <> cmd0 "quad"         and' = cmd0 "and"-authorinfo IEEE as = cmd "author" $ do+authorinfo' Beamer as = do+  cmd "author" $ mconcat $ intersperse (cmd0 "and") $ flip map as $ \a -> do+      textual $ authorName a+      case elemIndex (authorInst a) institutions of+        Nothing -> textual $ "error: could not find " ++ (authorInst a)+        Just idx -> inst idx+      -- No emails in beamer+  cmd "institute" $+      forM_ (zip institutions [0..]) $ \(i,idx) -> do+        inst idx+        textual i+  return ()+  where institutions = nub $ map authorInst $ as+        inst :: Int -> TeX+        inst i = when (length institutions > 1) $ cmd "inst" $ tex $ show (i+1)++authorinfo' IEEE as = cmd "author" $ do   cmd "IEEEauthorblockN" $ mconcat $ intersperse (hspace "1cm") $ map (textual . authorName) as   tex "\n\n" -- for some reason the IEEE class wants a paragraph separation here.   cmd "IEEEauthorblockA" $ mkrows $ [textual inst,"email: " <> textual (mconcat $ intersperse " " $ map authorEmail as)]   where (AuthorInfo {authorInst = inst}:_) = as-authorinfo _ {- Plain, EPTCS, Beamer -} as = cmd "author" $ mconcat $ intersperse (cmd0 "and") $ map oneauthor as+authorinfo' _ {- Plain -} as = cmd "author" $ mconcat $ intersperse (cmd0 "and") $ map oneauthor as   where oneauthor (AuthorInfo name _ institution) = textual name <> newline <> textual institution -keywords :: ClassFile -> [String] -> TeX-keywords LNCS ks = do-  cmd "keywords" $ mconcat $ intersperse ", " $ map textual ks-keywords IEEE ks = env "IEEEkeywords" $ do-  mconcat $ intersperse ", " $ map textual ks-keywords SIGPlan ks = do-  cmd0 "keywords"-  mconcat $ intersperse ", " $ map textual ks-keywords _ _ = return ()+keywords :: [String] -> TeX+keywords ks = do+  classFile <- askClass+  case classFile of+    Plain -> do+      paragraph "keywords"+      mconcat $ intersperse ", " $ map textual ks+      return ()+    LNCS -> do cmd "keywords" $ mconcat $ intersperse ", " $ map textual ks+    IEEE -> env "IEEEkeywords" $ do mconcat $ intersperse ", " $ map textual ks+    SIGPlan -> do cmd0 "keywords"+                  mconcat $ intersperse ", " $ map textual ks+    _ -> return () +acknowledgements :: Tex a -> Tex a+acknowledgements body = do+  classFile <- askClass+  case classFile of+    SIGPlan -> cmd0 "acks" >> body+    _ -> do paragraph "acknowledgements"+            body ++newline :: TeX newline = backslash <> backslash+newcol :: TeX newcol = tex "&"-newpara = texLines ["",""]+newpara :: Tex ()+newpara = texLn "\\par"  maketitle :: Tex () maketitle = cmd "maketitle" $ return ()@@ -86,7 +117,7 @@ ldots = cmd "ldots" (return ())  -- | Sectioning-section,subsection,paragraph :: TeX -> Tex SortedLabel+section,subsection,subsubsection,paragraph :: TeX -> Tex SortedLabel section s = cmd "section" s >> label "Sec." subsection s = cmd "subsection" s >> label "Sec." subsubsection s = cmd "subsubsection" s >> label "Sec."@@ -107,19 +138,45 @@ stdPreamble :: TeX stdPreamble = do   usepackage "graphicx" []+  usepackage "ifxetex" []+  cmd0 "ifxetex"+  usepackage "fontspec" []+  usepackage "newunicodechar" []+  mapM_ texLn ["\\newcommand{\\DeclareUnicodeCharacter}[2]{%"+              ,"\\begingroup\\lccode`|=\\string\"#1\\relax"+              ,"\\lowercase{\\endgroup\\newunicodechar{|}}{#2}%"+              ,"}"]+  cmd0 "else"   usepackage "inputenc" ["utf8"]+  cmd0 "fi"   return () -documentClass :: String -> [String] -> TeX-documentClass docClass options = cmd' "documentclass" options (tex docClass)- ---------- -- Lists +{-# DEPRECATED item, enumerate, itemize "Since Aug 2015. Use itemList, enumList, descList instead "#-} item = cmd0 "item" enumerate = env "enumerate" itemize = env "itemize" +itemList :: [TeX] -> TeX+itemList [] = mempty+itemList xs = env "itemize" $ forM_ xs $ \x -> do+  cmd0 "item"+  x++enumList :: [TeX] -> TeX+enumList [] = mempty+enumList xs = env "enumerate" $ forM_ xs $ \x -> do+  cmd0 "item"+  x++descList :: [(TeX,TeX)] -> TeX+descList [] = mempty+descList xs = env "enumerate" $ forM_ xs $ \(lab,x) -> do+  cmdm "item" [lab] []+  x+ ------------------------ -- Various environments @@ -231,5 +288,4 @@         opt' = tex $ mconcat . intersperse ", "                $ "basicstyle=\\ttfamily" :  opt in     backslash <> "lstinline" <> brackets opt' <> sep <> tex s <> sep- 
MarXup/Latex/Math.hs view
@@ -5,9 +5,9 @@ import MarXup.Tex import MarXup import Data.Monoid-import Data.Ratio import Control.Monad (unless) +align :: [[TeX]] -> Tex () align  = env "align*" . mkrows . map mkcols  array :: [String] -> String -> [[TeX]] -> TeX@@ -30,7 +30,9 @@ mbox = cmd "mbox" fbox :: TeX -> TeX fbox = cmd "fbox"+superscript :: Tex () -> TeX superscript y = tex "^" <> braces y+subscript :: Tex () -> TeX subscript x = tex "_" <> braces x  displayMath = env "displaymath"@@ -38,60 +40,65 @@ mathsf :: Tex a -> Tex a mathsf = cmd "mathsf" -mathpreamble :: ClassFile -> TeX-mathpreamble sty = do-  usepackage "graphicx" []+mathpreamble :: TeX+mathpreamble = do   usepackage "amsmath"  []-  unless (sty == LNCS) $ usepackage "amsthm"   []   usepackage "amssymb"  []   -- extra symbols such as □   usepackage "stmaryrd" [] -- has ⟦ and ⟧-  usepackage "mathpartir" [] -- mathpar environment -  unless (sty == LNCS || sty == Beamer) $ do-    newtheorem "theorem" "Theorem"-    newtheorem "corollary" "Corollary"-    newtheorem "lemma" "Lemma"-    newtheorem "definition" "Definition"-    newtheorem "proposition" "Proposition"  mathpar :: [[TeX]] -> TeX-mathpar = env "mathpar" . mkrows . map mk . filter (not . null)- where mk = foldr1 (\x y -> x <> cmd0 "and" <> y)+mathpar ps = do+   usepkg "mathpartir" 100 []+   env "mathpar" . mkrows . map mk . filter (not . null) $ ps+  where mk = foldr1 (\x y -> x <> cmd0 "and" <> y) +mathbox :: Tex a -> Tex a mathbox = mbox . ensureMath -newtheorem :: String -> TeX -> TeX-newtheorem ident txt = cmd "newtheorem" (tex ident) >> braces txt -deflike :: String -> String -> TeX -> TeX -> Tex SortedLabel-deflike reference nv name statement = env'' nv [] [name] $ do-  statement-  label reference+-- | @deflike referent nv header name statement@:+-- Environement of name @nv@, which should be refered as @referent@.+deflike :: String -> String -> String -> TeX -> TeX -> Tex SortedLabel+deflike referent nv header name statement = do+  newtheorem nv header+  cls <- askClass+  unless (cls == LNCS) $ usepkg "amsthm" 100 []+  let envir body = case cls of+        SIGPlan -> env'' nv [name] [] (hspace "0cm" >> body)+        _ -> env'' nv [] [name] body+  envir $ do+    statement+    label referent -thmlike :: String -> String -> TeX -> TeX -> TeX -> Tex SortedLabel-thmlike reference nv name statement proof = do-  x <- deflike reference nv name statement+thmlike :: String -> String -> String -> TeX -> TeX -> TeX -> Tex SortedLabel+thmlike referent nv header name statement proof = do+  x <- deflike referent nv header name statement   env "proof" proof   return x  theorem,lemma ::  TeX -> TeX -> TeX -> Tex SortedLabel-theorem = thmlike "Thm." "theorem"-lemma = thmlike "Lem." "lemma"+theorem = thmlike "Thm." "theorem" "Theorem"+lemma = thmlike "Lem." "lemma" "Lemma" -definition,corollary :: TeX -> TeX -> Tex SortedLabel-definition = deflike "Def." "definition"-corollary = deflike "Cor." "corollary"-proposition = deflike "Prop." "proposition"-example = deflike "Ex." "example"+definition,corollary,proposition,example :: TeX -> TeX -> Tex SortedLabel+definition = deflike "Def." "definition" "Definition"+corollary = deflike "Cor." "corollary" "Corollary"+proposition = deflike "Prop." "proposition" "Proposition"+example = deflike "Ex." "example" "Example"  -- Other stuff oxford :: Tex a -> Tex a oxford = bigParenthesize (textual "⟦") (textual "⟧") +multiline' :: [TeX] -> Tex () multiline' body = env "multline*" $ mkrows body +frac :: TeX -> TeX -> Tex () frac x y = cmdn_ "frac" [x,y] +centerVertically :: Tex a -> Tex a centerVertically = ensureMath . cmd "vcenter" . cmd "hbox" +qedhere :: Tex () qedhere = cmd0 "qedhere"
+ MarXup/LineUp.hs view
@@ -0,0 +1,111 @@+{-# LANGUAGE RecordWildCards #-}+module MarXup.LineUp (Tok(..),lineup,mkSpaces) where++import Data.List+import Data.Foldable+import Control.Monad (when)+import Data.Monoid+import Data.Maybe (catMaybes)++import MarXup.Tex++data Tok = Tok {+  startCol :: Int,+  endCol :: Int,+  preSpace :: Float, -- max amount of space which should come before this token, in mu+  render :: TeX,+  postSpace :: Float -- max amount of space which should come after this token, in mu+  }+++justIf True x = Just x+justIf _ _ = Nothing++marx True = '!'+marx False = '-'++lineup :: [[Tok]] -> TeX+lineup input = env'' "list" [] [mempty,tex "\\setlength\\leftmargin{1em}"] $ do+  usepkg "polytable" 100 []+  texLn ""+  texLines $ map (("% " ++) . map marx . drop 1 . isIndentTab ) array+  +  texLn "\\item\\relax"+  cmd "ensuremath" $ env "pboxed" $ do+    declColumn Nothing "B"+    forM_ (zip3 allTabStops [(1::Int)..] (drop 1 indentColumns)) $ \(_col,tab,indenting) -> +      declColumn (justIf (indenting) $ tex $ show (tab-1) ++ "em") (show tab)+    declColumn Nothing "E"+    texLn "%"+    sequence_ $ intersperse (texLn "\\\\") $ map printLine array+  where+    showCol 0 = "B"+    showCol n = show n+    declColumn :: Maybe TeX -> String -> TeX+    declColumn dim c = do+      cmdm "column" (catMaybes [dim]) [tex c,tex "@{}>{}l<{}@{}"]+      return ()++    printLine :: [[Tok]] -> TeX+    printLine xs = do+      forM_ (zip xs [(0::Int)..]) $ \(ts,colName) -> do+         when (not $ null ts) $ do+           cmdn' ">" [showCol colName] []+           braces $ forM_ ts $ \t -> do +                render t+      cmdn' "<" ["E"] []+      return ()++    -- The input, grouped in lines and columns+    array :: [[[Tok]]]+    array = map (tabify . mkSpaces) input++    -- Is the token preceded by two spaces or starts a line?+    isAligning :: [Tok] -> [(Bool,Tok)]+    isAligning [] = []+    isAligning (x:xs) = (True,x) :+                        [(startCol t2 > 1 + endCol t1,t2) | (t1,t2) <- zip (x:xs) xs]++    -- | The tabstop possibly beginning an indentation? It cannot be+    -- if it both contains a token and is preceded by stuff.+    isIndentTab :: [[Tok]] -> [Bool]+    isIndentTab xs = zipWith (||) nulls (scanl (&&) True nulls) +      where nulls = map null xs++    -- | Is a tabstop an indentation? (Take the intersection for all lines)+    indentColumns :: [Bool]+    indentColumns = map and $ transpose $ map isIndentTab array++    -- The tab stops in a line+    tabStops :: [Tok] -> [Int]+    tabStops xs = [startCol x | (align,x) <- isAligning xs, align]++    -- all the tab stops+    allTabStops :: [Int]+    allTabStops = sort $ nub $ concatMap tabStops input++    tabify :: [Tok] -> [[Tok]]+    tabify xs = tabify' (isAligning xs) allTabStops++    clearMeta :: [(Bool,Tok)] -> [Tok]+    clearMeta = map snd++    tabify' :: [(Bool,Tok)] -> [Int]-> [[Tok]]+    tabify' [] _ = []+    tabify' xs [] = [clearMeta xs]+    tabify' xs (t:ts) = clearMeta col:tabify' xs' ts+      where (col,xs') = break (\(align,s) -> align && (startCol s >= t)) xs++++--- | Transform a list of tokens to move the spacing info into the TeX+-- field of the tokens (spacing goes after the texts)+mkSpaces :: [Tok] -> [Tok]+mkSpaces [] = []+-- mkSpaces ts = [ Tok startCol endCol+--                 0 (tex (show preSpace) <> render <> tex (show postSpace) <> tex "\\;") 0+--               | Tok{..} <- ts]+mkSpaces ts = [ Tok (startCol l) (endCol l) 0+                (render l <>+                 tex ("\\mskip " ++ show (min (postSpace l) (preSpace r)) ++ "mu" )) 0+              | (l,r) <- zip ts (tail ts) ] ++ [last ts]
+ MarXup/LineUp/Haskell.hs view
@@ -0,0 +1,217 @@+module MarXup.LineUp.Haskell where++import Data.List+import Data.Function+import Language.Haskell.Exts.Lexer+import Language.Haskell.Exts.Parser (ParseResult(..),ParseMode(..),defaultParseMode)+import Language.Haskell.Exts.SrcLoc+import MarXup+import MarXup.LineUp+import MarXup.Tex+import MarXup.Verbatim+import Data.Monoid+import Data.Char (isDigit)++haskell :: Verbatim a -> Tex ()+haskell = haskellCust defaultParseMode printTok++haskellInline :: Verbatim a -> Tex ()+haskellInline = haskellInlineCust defaultParseMode printTok++type PrintTok = Token -> (Float,TeX,Float)++haskellInlineCust :: ParseMode -> (PrintTok) -> Verbatim a -> Tex ()+haskellInlineCust mode custPrintTok v = case lexTokenStreamWithMode mode (fromVerbatim v) of+   ParseOk toks -> mconcat $ map render $ mkSpaces $ map (mkTok custPrintTok) toks+   ParseFailed location err -> textual (show location ++ show err)++mkTok :: (t -> (Float, TeX, Float)) -> Loc t -> Tok+mkTok custPrintTok (Loc l t) = Tok (srcSpanStartColumn l) (srcSpanEndColumn l) before txt after+  where (before,txt,after) = custPrintTok t++haskellCust :: ParseMode -> (PrintTok) -> Verbatim a -> Tex ()+haskellCust mode custPrintTok v = case lexTokenStreamWithMode mode (fromVerbatim v) of+  ParseOk toks -> lineup (map (map (mkTok custPrintTok)) lins)+    where lins = groupBy ((==) `on` (srcSpanStartLine . loc)) toks+  ParseFailed location err -> textual (show location ++ show err)++splitTok :: String -> (String, Maybe String)+splitTok input = (reverse prefix ++ primes, if null numbers then Nothing else Just (reverse numbers))+  where (numbers,prefix) = span isDigit revNonPrimes+        (primes,revNonPrimes) = span (== '\'') revIn+        revIn = reverse input++printTok :: PrintTok+printTok t = let s = textual $ showToken t+                 ident = regular $ case splitTok $ showToken t of+                              (_,Nothing) -> cmd "mathsf" s+                              (pref,Just suff) -> cmd "mathsf" (textual pref) <> tex "_" <> braces (textual suff)+                 unquote = regular $ cmd "mathsf" s+                 quote = regular $ cmd "mathtt" s+                 literal = regular $ cmd "mathrm" s+                 string = regular $ cmd "texttt" s+                 keyword = regular $ cmd "mathbf" s+                 pragma = regular $ cmd "mathrm" s+                 symbol = regular $ cmd "mathnormal" s+                 regular tx = (5,tx,5)+                 leftParen  = (5,cmd "mathnormal" s,0)+                 rightParen = (0,cmd "mathnormal" s,5)+                 special x = regular $ cmd "mathnormal" $ tex x+                 debug = regular $ textual "[" <> ( cmd "mathnormal" $ textual $ show t) <> textual "]"+  in case t of+        -- _ -> cmd "mathrm" $ textual $ show t -- Debug+        VarId _ -> ident+        QVarId _ -> ident+        IDupVarId _ -> ident+        ILinVarId _ -> ident+        ConId _ -> ident+        QConId _ -> ident+        DVarId _ -> ident+        VarSym "==" -> special "\\equiv" -- ≡+        VarSym "=~" -> special "\\cong" -- ≅+        VarSym "<=" -> special "\\leq" -- ≤+        VarSym ">=" -> special "\\geq" -- ≥+        VarSym "<>" -> special "<\\!>"+        VarSym "<|>" -> special "<\\!\\mid\\!>"+        VarSym "<+>" -> special "<{\\mkern-12mu}+{\\mkern-12mu}>"+        VarSym "<*>" -> special "<{\\mkern-12mu}*{\\mkern-12mu}>"+        VarSym "<$>" -> special "<{\\mkern-12mu}\\${\\mkern-12mu}>"+        VarSym "++" -> special "+\\!+"+        VarSym _ -> symbol+        ConSym _ -> ident+        QVarSym _ -> ident+        QConSym _ -> ident+        IntTok _ -> literal+        FloatTok _ -> literal+        Character _ -> string+        StringTok _ -> string+        IntTokHash _ -> literal+        WordTokHash _ -> literal+        FloatTokHash _ -> literal+        DoubleTokHash _ -> literal+        CharacterHash _ -> literal+        StringHash _ -> literal+        LeftParen    -> leftParen+        RightParen -> rightParen+        LeftHashParen  -> symbol+        RightHashParen -> symbol+        SemiColon    -> symbol+        LeftCurly    -> leftParen+        RightCurly   -> rightParen+        VRightCurly -> rightParen+        LeftSquare   -> leftParen+        RightSquare          -> rightParen+        ParArrayLeftSquare   -> leftParen+        ParArrayRightSquare -> rightParen+        Comma -> rightParen+        Underscore -> symbol+        BackQuote -> symbol+        Dot -> symbol+        DotDot -> symbol+        Colon -> symbol+        QuoteColon -> symbol+        DoubleColon -> symbol+        Equals -> symbol+        Backslash -> symbol+        Bar -> symbol+        LeftArrow -> regular $ cmd0 "leftarrow"+        RightArrow -> regular $ cmd0 "rightarrow"+        At -> symbol+        Tilde -> symbol+        DoubleArrow -> regular $ cmd0 "Rightarrow"+        Minus -> symbol+        Exclamation -> symbol+        Star -> symbol+        LeftArrowTail -> symbol+        RightArrowTail -> symbol+        LeftDblArrowTail -> symbol+        RightDblArrowTail -> symbol+        THExpQuote -> symbol+        THPatQuote -> symbol+        THDecQuote -> symbol+        THTypQuote -> symbol+        THCloseQuote -> symbol+        THIdEscape _ -> unquote+        THParenEscape -> symbol+        THVarQuote -> symbol+        THTyQuote -> symbol+        THQuasiQuote _ -> quote+        RPGuardOpen -> symbol+        RPGuardClose -> symbol+        RPCAt -> symbol+        XCodeTagOpen -> symbol+        XCodeTagClose -> symbol+        XStdTagOpen -> symbol+        XStdTagClose -> symbol+        XCloseTagOpen -> symbol+        XEmptyTagClose -> symbol+        XChildTagOpen -> symbol+        XPCDATA _ -> symbol+        XRPatOpen -> symbol+        XRPatClose -> symbol+        PragmaEnd -> symbol+        RULES -> pragma+        INLINE _ -> pragma+        INLINE_CONLIKE -> pragma+        SPECIALISE -> pragma+        SPECIALISE_INLINE _ -> pragma+        SOURCE -> pragma+        DEPRECATED -> pragma+        WARNING -> pragma+        SCC -> pragma+        GENERATED -> pragma+        CORE -> pragma+        UNPACK -> pragma+        OPTIONS _ -> pragma+        LANGUAGE -> pragma+        ANN -> pragma+        MINIMAL -> pragma+        NO_OVERLAP -> pragma+        OVERLAP -> pragma+        INCOHERENT -> pragma+        KW_As -> keyword+        KW_By -> keyword+        KW_Case -> keyword+        KW_Class -> keyword+        KW_Data -> keyword+        KW_Default -> keyword+        KW_Deriving -> keyword+        KW_Do -> keyword+        KW_MDo -> keyword+        KW_Else -> keyword+        KW_Family -> keyword+        KW_Forall -> keyword+        KW_Group -> keyword+        KW_Hiding -> keyword+        KW_If -> keyword+        KW_Import -> keyword+        KW_In -> keyword+        KW_Infix -> keyword+        KW_InfixL -> keyword+        KW_InfixR -> keyword+        KW_Instance -> keyword+        KW_Let -> keyword+        KW_Module -> keyword+        KW_NewType -> keyword+        KW_Of -> keyword+        KW_Proc -> keyword+        KW_Rec -> keyword+        KW_Then -> keyword+        KW_Type -> keyword+        KW_Using -> keyword+        KW_Where -> keyword+        KW_Qualified -> keyword+        KW_Foreign -> keyword+        KW_Export -> keyword+        KW_Safe -> keyword+        KW_Unsafe -> keyword+        KW_Threadsafe -> keyword+        KW_Interruptible -> keyword+        KW_StdCall -> keyword+        KW_CCall -> keyword+        KW_CPlusPlus -> keyword+        KW_DotNet -> keyword+        KW_Jvm -> keyword+        KW_Js -> keyword+        KW_CApi -> keyword+        _ -> debug
MarXup/Math.hs view
@@ -54,6 +54,7 @@ -------------- -- Operators +infixr 1 =: (=:) = binop 0 "="  instance Num Math where@@ -76,6 +77,7 @@     log = fct (cmd "mathnormal" "log")     sin = fct (cmd "mathnormal" "sin")     cos = fct (cmd "mathnormal" "cos")+    tan = fct (cmd "mathnormal" "tan")     asin = fct (cmd "mathnormal" "asin")     acos = fct (cmd "mathnormal" "acos")     atan = fct (cmd "mathnormal" "atan")
MarXup/MultiRef.hs view
@@ -3,48 +3,47 @@ module MarXup.MultiRef where  import Control.Monad.Fix-import "mtl" Control.Monad.RWS.Lazy-import Control.Applicative-import Control.Arrow (first)+import Control.Monad.RWS.Lazy+import Data.Map.Strict (Map,insert)+import qualified Data.Map.Strict as M+import Graphics.Diagrams.Core (BoxSpec, nilBoxSpec)+type MetaData key = Map key String+type BoxSpecs = Map Int BoxSpec -newtype Multi a = Multi {fromMulti :: RWS InterpretMode String (References,[BoxSpec]) a }-  deriving (Functor, Monad, Applicative, MonadWriter String, MonadState (References,[BoxSpec]), MonadFix, MonadReader InterpretMode)+-- FIXME: Move boxspecs to the Read part.+newtype Multi config key a = Multi {fromMulti :: RWS config String (References,BoxSpecs,MetaData key) a }+  deriving (Functor, Monad, MonadReader config, Applicative, MonadWriter String, MonadState (References,BoxSpecs,MetaData key), MonadFix)  ----------------------------------- -- Basic datatype and semantics type Label = Int --- | Size of a box, in points. boxDepth is how far the baseline is--- from the bottom. boxHeight is how far the baseline is from the top.--- (These are TeX meanings)-data BoxSpec = BoxSpec {boxWidth, boxHeight, boxDepth :: Double}-             deriving (Show) -nilBoxSpec :: BoxSpec-nilBoxSpec = BoxSpec 0 0 0 -raw :: String -> Multi ()+raw :: String -> Multi config key () raw s = tell s -getBoxSpec :: Multi BoxSpec-getBoxSpec = do-  (refs,bs) <- get-  case bs of-    [] -> error "display: ran out of boxes!"-    (b:bs') -> do-      put (refs,bs')-      return b- +getBoxSpec :: Int -> Multi config key BoxSpec+getBoxSpec bxId = do+  (_,bs,_) <- get+  return $ case M.lookup bxId bs of+    Nothing -> nilBoxSpec -- TODO: log this error somehow+    Just b -> b +-- | allocate a new label+newLabel :: Multi key config Label -- create a new label+newLabel = do (r,bx,m) <- get+              put (r+1,bx,m)+              return r --- Reference management-newLabel :: Multi Label -- create a new label-newLabel = do x <- fst <$> get;  modify (first (+1)); return x+-- | output some meta data+metaData :: Ord key => key -> String -> Multi config key ()+metaData k val = do+   (r,bx,m) <- get+   put (r,bx,insert k val m)+   return ()  type References = Int -- how many labels have been allocated emptyRefs :: References emptyRefs = 0--type Mode = InterpretMode -> Bool-data InterpretMode = OutsideBox | InsideBox | Regular deriving Eq 
MarXup/PrettyPrint/Core.hs view
@@ -5,7 +5,8 @@ import MarXup (textual) import MarXup.Latex import MarXup.Tex-import MarXup.MultiRef +import MarXup.MultiRef+import Graphics.Diagrams.Core (BoxSpec (..)) import MarXup.Diagram.Tikz (showDistance) import Data.Foldable (forM_) import Control.Applicative
MarXup/Tex.hs view
@@ -3,26 +3,67 @@ module MarXup.Tex where  import MarXup-import "mtl" Control.Monad.Reader-import "mtl" Control.Monad.RWS-import Control.Applicative+import Control.Monad.Reader+import Control.Monad.RWS import GHC.Exts( IsString(..) )-import Data.List (intersperse)+import Data.List (intersperse,intercalate) import MarXup.MultiRef-import System.Process import System.Directory (doesFileExist)+import Data.Char (isSpace)+import Data.Map (assocs, Map)+import qualified Data.Map as Map+import Graphics.Diagrams.Core (BoxSpec (..)) -newtype Tex a = Tex {fromTex :: Multi a}+data ClassFile = Plain | LNCS | SIGPlan | IEEE | EPTCS | Beamer+  deriving Eq+++------------------------------------+-- MetaData++data Key = PreClass String | PrePackage Int String | PreTheorem String String   -- priority+  deriving (Ord,Eq)++newtheorem :: String -> String -> TeX+newtheorem ident txt = do+  sty <- askClass+  unless ((sty == LNCS || sty == Beamer) && ident `elem` ["theorem", "corollary", "lemma", "definition", "proposition"]) $ do+  Tex $ metaData (PreTheorem ident txt) ""++usepkg :: String -> Int -> [String] -> TeX+usepkg ident prio options = Tex $ metaData (PrePackage prio ident) (intercalate "," options)++documentClass :: String -> [String] -> TeX+documentClass docClass options = Tex $ metaData (PreClass docClass) (intercalate "," options)+++renderKey :: Key -> String -> String+renderKey o options = case o of+  PreClass name -> "\\documentclass[" ++ options ++ "]{" ++ name ++ "}"+  PrePackage _ name -> "\\usepackage[" ++ options ++ "]{" ++ name ++ "}"+  PreTheorem ident txt  -> "\\newtheorem{" ++ ident ++ "}{" ++ txt ++ "}"++newtype Tex a = Tex {fromTex :: Multi ClassFile Key a}   deriving (Monad, MonadFix, Applicative, Functor) +++ --------------------------------- -- MarXup interface instance Textual Tex where-    textual s = tex $ concatMap escape s+  textual s = case break (== '\n') s of+    -- The 1st blank line of a MarXup chunk is replaced by a+    -- space. This means that to create a paragraph after an element,+    -- one needs a double blank line.+    (l,'\n':s') | all isSpace l -> tex (' ' : process s')+    _ -> tex $ process s+   where process = concatMap escape  kern :: String -> TeX kern x = braces $ tex $ "\\kern " ++ x +escape :: Char -> [Char] escape '\\' = "\\ensuremath{\\backslash{}}" escape '~' = "\\ensuremath{\\sim{}}" escape '<' = "\\ensuremath{<}"@@ -34,11 +75,8 @@   type Target (Tex a) = Tex a   element = id -texInMode ::  Mode -> String ->TeX-texInMode mode s = whenMode mode $ Tex $ raw s--tex :: String -> TeX-tex = texInMode (`elem` [Regular,InsideBox])+tex ::  String ->TeX+tex = Tex . raw  texComment :: String -> TeX texComment s =@@ -51,7 +89,7 @@ reference l = tex (show l)  instance Monoid (TeX) where-  mempty = textual ""+  mempty = tex ""   mappend = (>>)  instance IsString (TeX) where@@ -99,7 +137,7 @@   when (null args) $ tex "{}" -- so that this does not get glued with the next thing.   return res --- | Command with tex options and many arguments+-- | Command with tex options and several arguments cmdm :: String -> [Tex a] -> [Tex a] -> Tex [a] cmdm cmd options args = do   backslash >> tex cmd@@ -109,6 +147,7 @@   return res  +-- | Command with string options and several arguments; no result cmdn'_ :: String -> [String] -> [TeX] -> Tex () cmdn'_ cmd options args = cmdn' cmd options args >> return () @@ -116,8 +155,9 @@ cmdn :: String -> [Tex a] -> Tex [a] cmdn c args = cmdn' c [] args +-- | Command with n arguments, no result cmdn_ :: String -> [TeX] -> Tex ()-cmdn_ cmd args = cmdn'_ cmd [] args+cmdn_ theCmd args = cmdn'_ theCmd [] args  -- | Environment env :: String -> Tex a -> Tex a@@ -125,13 +165,13 @@  -- | Environment with options env' :: String -> [String] -> Tex a -> Tex a-env' e opts body = env'' e opts [] body+env' e opts body = env'' e (map textual opts) [] body --- | Environment with a tex option-env'' :: String -> [String] -> [TeX] -> Tex a -> Tex a+-- | Environment with tex options and tex arguments+env'' :: String -> [TeX] -> [TeX] -> Tex a -> Tex a env'' e opts args body = do   cmd "begin" $ tex e-  when (not $ null opts) $ brackets $ sequence_ $ map tex $ intersperse "," opts+  when (not $ null opts) $ brackets $ sequence_ $ intersperse (tex ",") opts   mapM_ braces args   x <- body   cmd "end" $ tex e@@ -171,88 +211,80 @@ ----------------- -- Generate boxes -outputAlsoInBoxMode :: Tex a -> Tex a-outputAlsoInBoxMode (Tex a) = Tex $ local moveInBox $ a-         where moveInBox m = case m of-                 OutsideBox -> InsideBox-                 _ -> m -texAlways = texInMode (const True)+inBox :: Tex a -> Tex (a, BoxSpec)+inBox = helpBox True -inBoxComputMode :: String -> TeX-inBoxComputMode = texInMode (`elem` [OutsideBox,InsideBox])+justBox :: Tex a -> Tex BoxSpec+justBox x = snd <$> helpBox False x -whenMode :: Mode -> Tex () -> Tex ()-whenMode mode act = do-  interpretMode <- Tex ask-  when (mode interpretMode) act -inBox :: Tex a -> Tex (a, BoxSpec)-inBox x = do-  inBoxComputMode $ "\n\\savebox{\\marxupbox}{"-  a <- outputAlsoInBoxMode x-  inBoxComputMode $ +helpBox :: Bool -> Tex a -> Tex (a,BoxSpec)+helpBox showBox x = do bxId <- Tex newLabel+                       a <- fillBox bxId showBox x+                       b <- Tex (getBoxSpec bxId)+                       return (a,b)++getBoxFromId :: Int -> Tex BoxSpec+getBoxFromId = Tex . getBoxSpec++fillBox :: Label -> Bool -> Tex a -> Tex a+fillBox bxId showBox x = braces $ do+  tex $ "\\savebox{\\marxupbox}{"+  a <- x+  tex $     "}"+    ++ "\\immediate\\write\\boxesfile{" ++ show bxId ++ "}"     ++ writeBox "wd"     ++ writeBox "ht"     ++ writeBox "dp"-    ++ "\n"-  b <- Tex getBoxSpec+  when showBox $ tex $ "\\box\\marxupbox" -  return (a,b)+  return a   where writeBox l = "\\immediate\\write\\boxesfile{\\number\\"++ l ++"\\marxupbox}" +-- TODO: it would be nice to have:+-- withBox :: Bool -> Tex a -> (Tex a -> Tex a) -> Tex BoxSpec+-- withBox showBox boxContents boxContext = ... -justBox :: Tex a -> Tex BoxSpec-justBox x = do-  whenMode (`elem` [OutsideBox, InsideBox]) $ outputAlsoInBoxMode $ do-    tex "\n\\savebox{\\marxupbox}{"-    x-    tex $ -      "}"-      ++ writeBox "wd"-      ++ writeBox "ht"-      ++ writeBox "dp"-      ++ "\n"-  b <- Tex getBoxSpec+-- however this may require some latex trickery. The idea would be to+-- create the box upfront (and thus we can obtain its boundaries), and+-- invoke it wherever the context calls it. This means that we need a+-- new 'box' for every invokation. It may be that latex does not have+-- infinitely many boxes, and thus we need to reuse (latex-side) box+-- ids. -  return b-  where writeBox l = "\\immediate\\write\\boxesfile{\\number\\"++ l ++"\\marxupbox}"+renderWithBoxes :: ClassFile -> BoxSpecs -> Tex a -> String+renderWithBoxes classFile bs (Tex t) = (preamble ++ doc)+  where (_,(_,_,metaDatum),doc) = runRWS (fromMulti $ t) classFile (0,bs,mempty)+        preamble :: String+        preamble = unlines $ map (uncurry renderKey) $ assocs metaDatum -renderWithBoxes :: [BoxSpec] -> InterpretMode -> Tex a -> String-renderWithBoxes bs mode (Tex t) = doc-  where (_,_,doc) = runRWS (fromMulti $ t) mode (0,bs)+renderSimple :: ClassFile -> Tex a -> String+renderSimple classFile = renderWithBoxes classFile Map.empty -renderSimple :: TeX -> String-renderSimple = renderWithBoxes [] Regular-  -renderTex :: (Bool -> TeX) -> TeX -> IO String-renderTex preamble body = do-  let bxsTex = renderWithBoxes (repeat nilBoxSpec) OutsideBox (wholeDoc True)-      boxesName = "mpboxes"-      boxesTxt = boxesName ++ ".txt"-      wholeDoc inBoxMode = do-        outputAlsoInBoxMode (preamble inBoxMode)-        inBoxComputMode $ "\\newwrite\\boxesfile"-        texAlways "\\begin{document}"-        inBoxComputMode $ "\\immediate\\openout\\boxesfile="++boxesTxt++"\n \\newsavebox{\\marxupbox}"-        body-        inBoxComputMode "\n\\immediate\\closeout\\boxesfile"-        texAlways "\\end{document}"-  writeFile (boxesName ++ ".tex") bxsTex-  system $ "latex " ++ boxesName-  boxes <- do+renderTex :: ClassFile -> String -> TeX -> IO ()+renderTex classFile fname body = do+  let boxesTxt = fname ++ ".boxes"+  boxes <- getBoxInfo . map read . lines <$> do     e <- doesFileExist boxesTxt     if e-      then do-        boxData <- map read . lines <$> readFile boxesTxt-        return $ getBoxInfo boxData-      else return []-  putStrLn $ "Number of boxes found: " ++ show (length boxes)-  return $ renderWithBoxes boxes Regular $ (wholeDoc False)+      then readFile boxesTxt+      else return ""+  putStrLn $ "Found " ++ show (length boxes) ++ " boxes"+  let texSource = renderWithBoxes classFile boxes wholeDoc+      wholeDoc = do+        tex $ "\\newwrite\\boxesfile"+        tex $ "\\immediate\\openout\\boxesfile="++boxesTxt++"\n\\newsavebox{\\marxupbox}"+        body+        tex "\n\\immediate\\closeout\\boxesfile"+  writeFile (fname ++ ".tex") texSource -getBoxInfo :: [Int] -> [BoxSpec]-getBoxInfo [] = []-getBoxInfo (width:height:depth:bs) = BoxSpec (scale width) (scale height) (scale depth):getBoxInfo bs+askClass :: Tex ClassFile+askClass = Tex ask++getBoxInfo :: [Int] -> Map Int BoxSpec+getBoxInfo (ident:width:height:depth:bs) = Map.insert ident (BoxSpec (scale width) (scale height) (scale depth)) (getBoxInfo bs)   where scale x = fromIntegral x / 65536+getBoxInfo _ = Map.empty 
MarXup/Verbatim.hs view
@@ -4,12 +4,18 @@  import MarXup import Control.Monad.Fix+import Control.Monad (ap)+import Control.Applicative  data Verbatim a = Verbatim {fromVerbatim::String, value::a}   deriving Functor  instance Textual Verbatim where     textual s = Verbatim s ()++instance Applicative Verbatim where+    pure = return+    (<*>) = ap  instance Monad Verbatim where     return x = Verbatim "" x
+ MarXupParser.hs view
@@ -0,0 +1,156 @@+{-# LANGUAGE TupleSections, FlexibleInstances, TransformListComp #-}++module MarXupParser (parseFile, Haskell(..), MarXup(..)) where++import Text.ParserCombinators.Parsek.Position+import Data.Char+import Data.List+import System.IO+import Control.Monad+import GHC.Exts (the,groupWith)+import Config++-- todo: parse haskell comments (so that marxup there is not recognized)++------------------+-- Simple printing combinators, which do not add nor remove line breaks++data Haskell = HaskChunk String | HaskLn SourcePos | Quote [MarXup] | List [Haskell] | Parens [Haskell] | String String deriving (Show)+data MarXup = TextChunk String | Unquote (Maybe (SourcePos,String)) [(SourcePos,Haskell)] | Comment String deriving (Show)++----------------------------------------------+-- Parsing combinators++anyQuoteStrings :: [String]+anyQuoteStrings = concatMap (\(x,y) -> [x,y]) quoteStrings++pTextChunk = TextChunk <$> pChunk' (commentString : antiQuoteStrings ++ anyQuoteStrings) <?> "Text chunk"+pHaskChunk = HaskChunk <$> pChunk' (map box "\n\"[]()" ++ map fst quoteStrings) <?> "Haskell chunk"+    -- we keep track of balancing++pWPos :: Parser SourcePos+pWPos = do+  char '\n'+  getPosition++withPos :: Parser a -> Parser (SourcePos,a)+withPos p = do+  pos <- getPosition+  x <- p+  return (pos,x)++pHaskLn = HaskLn <$> pWPos -- before each newline, tell GHC where we are.++box = (:[])++pString :: Parser Haskell+pString = do+  char '"'+  result <- many (string "\\\"" <|> pChunk ['"'])+  char '"'+  return $ String $ concat result++-- | Parse some Haskell code with markup inside.+pHask :: Parser [Haskell]+pHask = many ((List <$> pArg "[]") <|>+              (Parens <$> pArg "()") <|>+              pTextArg  <|>+              pString <|>+              pHaskChunk <|>+              pHaskLn)++-- | Parse a text argument to an element+pTextArg' :: String -> String -> Parser Haskell+pTextArg' open close = Quote <$> (label "quoted text" $+  string open *>+  (many (pElement <|> pTextChunk <|> pComment))+  <* string close)++pTextArg :: Parser Haskell+pTextArg = choice $ map (uncurry pTextArg') quoteStrings++pArg :: String -> Parser [Haskell]+pArg [open,close] = char open *> pHask <*  char close++isIdentChar :: Char -> Bool+isIdentChar x = isAlphaNum x || (x `elem` "\'_")++pIdent :: Parser String+pIdent = munch1 isIdentChar <?> "identifier"++pArgument :: Parser Haskell+pArgument = (Parens <$> pArg "()" <|> (List <$> pArg "[]") <|> pTextArg <|> pString) <?> "argument"++pId :: Parser Haskell+pId = HaskChunk <$> pIdent++pElement :: Parser MarXup+pElement = +  label "Haskell element" $ do+    choice $ map string $ antiQuoteStrings+    var <- (Just <$> (withPos pIdent <* string "<-")) <<|> pure Nothing+    val <- ((:) <$> withPos pId <*> manyGreedy (withPos pArgument)) <|>+           (box <$> withPos (Parens <$> pArg "()"))+    return $ Unquote var val++commentString :: String+commentString = "%%"++pComment :: Parser MarXup+pComment = Comment <$> do+  label "Comment" $ do+    string commentString+    munch (/= '\n')+    string "\n"+    return mempty++parseFile :: String -> ([Haskell] -> IO ()) -> IO ()+parseFile fname k = do+  p <- parseFromFile (pHask <* endOfFile) completeResults fname+  case p of+    Left e -> handleErr e+    Right [res] -> k res+    Right _ -> hPutStrLn stderr "Amibiguous input!"++handleErr e =+   sequence_+          [ hPutStrLn stderr (show $ maybePosToPos $ the pos) >>+            hPutStrLn stderr ("  Expected:" ++ (intercalate " or " $ nub what))+           | (exps,_why) <- e, (what,pos) <- exps, then group by pos using groupWith, then reverse ]++----------------------------------------------+-- Parsing helpers++satisfy' :: (String -> Bool) -> Parser Char+satisfy' p = do+  l <- look+  unless (p l) $+    fail "Unexpected leading string"+  anySymbol++munch',munch1' :: (String -> Bool) -> Parser String+munch' p = scan =<< look+ where+  scan (c:cs) | p (c:cs) = (:) <$> anySymbol <*> scan cs+  scan _            = pure []++munch1' p = (:) <$> satisfy' p <*> munch' p++-- | A chunk not containing some strings+pChunk' :: [String] -> Parser String+pChunk' stops = munch1' (\l -> not $ any (`isPrefixOf` l) stops)+++-- | A chunk not containing some chars.+pChunk :: [Char] -> Parser String+pChunk stops = munch1 (not . (`elem` stops))+++-- Tests+testHask = parse "<interactive>" pHask completeResults "arst « text @z<-fct[x](y) awft"+testHask2 = parse "<interactive>" pHask completeResults "ars(t) « text @z<-fct[x](y) » awft"+testText2 = parse "<interactive>" pTextArg completeResults "« text @fct(x »"+testText3 = parse "<interactive>" pTextArg completeResults "« 1 @x 2 @y 3 @x 4 »"+testElem = parse "<interactive>" pElement completeResults "@x<-fct(x « yop »)[y]"+testChunk = parse "<interactive>" pHaskChunk completeResults "t"+testArg = parse "<interactive>" (pArg "()") completeResults "()"
+ Output.hs view
@@ -0,0 +1,43 @@+module Output where++import Text.ParserCombinators.Parsek.Position++import Data.Monoid+import Data.DList hiding (foldr, map)++------------------+-- Simple printing combinators, which do not add nor remove line breaks++type Doc = DList Char++text = fromList+x <+> y =  x <> text " " <> y+parens s = singleton '(' <> s <> singleton ')'+braces s = singleton '{' <> s <> singleton '}'+brackets s = singleton '[' <> s <> singleton ']'+doubleQuotes s = singleton '"' <> s <> singleton '"'++int x = text $ show x+hcat :: [Doc] -> Doc+hcat = foldr (<>) mempty+punctuate t = map (<> t)+render :: Doc -> String+render = toList++------------------------------------------+-- Output combinators++oPos :: SourcePos -> Doc+oPos EOF = mempty+oPos p = text "\n{-# LINE" <+> int (sourceLine p) <+> text (show (sourceName p)) <+> text "#-}\n" <>+         Data.DList.replicate (sourceCol p) ' '++oText :: String -> Doc+oText x = text "textual" <+> text (show x)++oConcat :: [Doc] -> Doc+oConcat [] = text "return ()"+oConcat [x] = x+oConcat l = text "do" <+> braces (text "rec" <+> braces (hcat (punctuate (text ";") binds)) <> text ";" <> ret)+  where binds = init l+        ret = last l
examples/LaTeX.hs view
@@ -1,28 +1,46 @@-{-# OPTIONS_GHC -XTypeSynonymInstances -XOverloadedStrings -XRecursiveDo -pgmF marxup3 -F #-}+{-# OPTIONS_GHC -XTypeSynonymInstances -XOverloadedStrings -XRecursiveDo -pgmF dist/build/marxup/marxup -F #-}  import MarXup import MarXup.Latex import MarXup.Latex.Math import MarXup.Math import MarXup.Tex+import MarXup.LineUp.Haskell import MarXup.DerivationTrees import MarXup.PrettyPrint as PP hiding (width) import MarXup.PrettyPrint.Core as PC import Control.Applicative import Data.Monoid import Control.Monad (unless)-import MarXup.Diagram-import MarXup.Diagram.Graphviz+import MarXup.Diagram as D+import Graphics.Diagrams.Plot+import Graphics.Diagrams.Graphviz import Control.Lens (set)-import Data.GraphViz+import Data.GraphViz hiding (Plain) import Data.String import Data.Traversable import Data.GraphViz.Attributes.Complete   (Attribute(RankSep,Shape,Label,Margin,Width,Len,RankDir),    Shape(..),Label(StrLabel),DPoint(..),RankDir(..))+import Numeric (showFFloat, showEFloat)  data SExp = Atom String | SX [SExp] +textualS = textual . ($ "")++aPlot :: Dia+aPlot = do+  c@(bx,_) <- simplePlot (Point (textualS . showFFloat (Just 1)) (textualS . showEFloat (Just 0)))+                         (vec (simplLinAxis 0.1,+                               logAxis 10+                               -- simplLinAxis 2000+                              ))+                         (map vec [(0.1,139),(0.35,10035),(0.23,1202)])+  functionPlot c 100 (\x -> 100 + 300000*(x-0.2)^^2)+  width bx === constant 200+  height bx === constant 100+  where vec (x,y) = Point x y+ prettyS :: SExp -> Tex Doc prettyS (Atom x) = PP.text (textual x) prettyS (SX xs) = do@@ -42,23 +60,16 @@   three = SX $ map Atom ["arstarsx","wftwfy","varstw","x","M"]   six = SX [ three , three , three ] -preamble inMP = do+preamble body = do   documentClass "article" []   usepackage "inputenc" ["utf8x"]-  unless inMP $ usepackage "tikz" []   usepackage "graphicx" []---- arrow :: Object -> Object -> Diagram Incidence--- arrow src trg = using (outline "black" . set endTip ToTip) $ do---   edge src trg--autoLab s i = do-  o <- labelObj s-  autoLabel o i+  env "document" body  (▸) = flip (#) -grDiag = graph Dot gr+grDiag :: TexDiagram ()+grDiag = graph tex Dot gr  nod x = DotNode x [Margin (DVal 0),Width 0, Shape Circle, Label $ StrLabel $ fromString x] edg x y z = DotEdge x y [Label $ StrLabel z, Len 0.1]@@ -71,21 +82,22 @@       ,edg "B" "D" "3"       ,edg "D" "A" "4"]) +testDiagram :: TexDiagram () testDiagram = do   -- draw $ path $ circle (Point 0 0) 5-  a   <- labelObj $ ensureMath $ "a"-  b   <- labelObj $ ensureMath $ "b"-  a'  <- draw $ circleShape -- labelObj $ ensureMath $ "c"-  width a' === 15-  b'  <- labelObj $ ensureMath $ "d"-  a'' <- labelObj $ ensureMath $ "."-  b'' <- labelObj $ ensureMath $ "."+  a   <- D.label "a" $ ensureMath $ "a"+  b   <- D.label "b" $ ensureMath $ "b"+  a'  <- draw $ circle "a'" -- label $ ensureMath $ "c"+  width a' === constant 15+  b'  <- D.label "b'" $ ensureMath $ "d"+  a'' <- D.label "a''" $ ensureMath $ "."+  b'' <- D.label "b''" $ ensureMath $ "."    -- c <- texObj $ ensureMath $ "c"   -- Center ▸ c === MP.center [E ▸ a'', E ▸ b''] + (20 +: 0) -  let width = 70-  vdist b a === 30+  let width = constant 70+  vdist b a === constant 30   hdist a a' === width   hdist a' a'' === width   alignMatrix [[Center ▸ a, Center ▸ a',Center ▸ a'']@@ -93,9 +105,9 @@               ]   autoLab "bing" =<< arrow a a'   autoLab "bang" =<< arrow b b'-  autoLab "oops" . swap =<< arrow a b+  autoLab "oops" . turn180 =<< arrow a b   autoLab "pif" =<< arrow a' a''-  autoLab "paf" =<< arrow b' b'' +  autoLab "paf" =<< arrow b' b''    draw $ do     autoLab "equal" =<< edge a'' b''@@ -129,8 +141,11 @@  (≜) = binop 1 "=" -main = writeFile ("LaTeX.tex") =<< renderTex preamble « +main = renderTex Plain "LaTeX" docu++docu = preamble «+ @intro<-section«Intro»  At-syntax is used to call a Haskell function. The result can be bound.@@ -168,20 +183,39 @@ @someTree  @section«Diagrams»--One can also draw diagrams: @testDiagram+One can also draw diagrams:  @section«Graphviz»  There is partial, rudimentary support for layout of graphs using graphviz. -grDiag+@grDiag+%% This is deactivated for now; it requires graphviz to be installed  +@section«Plots»++@aPlot++@cmd0"newpage"+@section«Haskell»++There is simple support for lhs2tex-style stuff.++Another paragaph.+++@haskell«++autoLab :: String -> OVector -> Diagram TeX Tex Object+autoLab s = autoLabel s (textual s)++some text after+ @concl<-section«Conclusion»  Mar@ensureMath«@cmd0"chi"»up is awesome :p .  »-
marxup.cabal view
@@ -1,76 +1,63 @@ name:           marxup-version:        3.0.0.1+version:        3.1.0.0 category:       Text synopsis:       Markup language preprocessor for Haskell description:   Markup syntax preprocessor for Haskell. Steals ideas from the Scribble project (in Scheme).   The package also provides a DSL to output Latex seamlessly from MarXup output.-license:        GPL+license:        GPL-2 license-file:   LICENSE author:         Jean-Philippe Bernardy maintainer:     jeanphilippe.bernardy@gmail.com Cabal-Version:  >= 1.8-tested-with:    GHC==6.12.1-tested-with:    GHC==7.4.1 build-type:     Simple  data-files:      examples/LaTeX.hs ---- executable marxup---   extensions: FlexibleInstances, TupleSections---   main-is: Main.hs---   build-depends: base>=4.2&&<=5---   build-depends: pretty==1.1.*---   build-depends: parsec>=3---   build-depends: dlist>=0.5+Flag example+  Description: Compile example. This will generally not work unless you know what you're doing.+  manual: True+  Default:     False -executable marxup3+executable marxup   extensions: FlexibleInstances, TupleSections-  main-is: Main3.hs+  main-is: Main.hs   build-depends: configurator>=0.2&&<2   build-depends: base>=4.2&&<=58   build-depends: pretty==1.1.*   build-depends: parsek==1.*   build-depends: dlist>=0.7-  other-modules: Config-  +  other-modules: Config, MarXupParser, Literate, Output+ library   extensions: FlexibleInstances, TypeSynonymInstances, GADTs   build-depends: base>=4.2&&<5 --  build-depends: pandoc==1.5.*  (support broken)   build-depends: mtl>=2.1   build-depends: labeled-tree==1.*-  build-depends: filepath==1.3.*+  build-depends: filepath>=1.3 && <2   build-depends: containers>=0.4 &&<1   build-depends: process>=1.1-  build-depends: glpk-hs>=0.3.4-  build-depends: cubicbezier>=0.2   build-depends: lens>=3.10   build-depends: directory>=1.2-  build-depends: typography-geometry-  build-depends: polynomials-bernstein==1.*-  build-depends: vector-  build-depends: graphviz+  build-depends: haskell-src-exts+  build-depends: lp-diagrams   build-depends: text    exposed-modules: MarXup   exposed-modules: MarXup.Tex   exposed-modules: MarXup.Latex   exposed-modules: MarXup.Latex.Math+  exposed-modules: MarXup.LineUp+  exposed-modules: MarXup.LineUp.Haskell   exposed-modules: MarXup.Math   exposed-modules: MarXup.Latex.Bib   exposed-modules: MarXup.Beamer   exposed-modules: MarXup.DerivationTrees   exposed-modules: MarXup.Text   exposed-modules: MarXup.Diagram-  exposed-modules: MarXup.Diagram.Object-  exposed-modules: MarXup.Diagram.Path-  exposed-modules: MarXup.Diagram.Point-  exposed-modules: MarXup.Diagram.Layout   exposed-modules: MarXup.Diagram.Tikz-  exposed-modules: MarXup.Diagram.Graphviz   exposed-modules: MarXup.MultiRef   exposed-modules: MarXup.Verbatim   exposed-modules: MarXup.PrettyPrint.Core@@ -78,3 +65,16 @@    --  exposed-modules: MarXup.Pandoc (broken) +executable marxup-example+   if  flag(example)+     buildable: True+   else+     buildable: False+   hs-source-dirs: examples+   main-is: LaTeX.hs+   build-depends: marxup+   build-depends: lp-diagrams+   build-depends: base+   build-depends: lens+   build-depends: graphviz+