Ansi2Html (empty) → 0.1
raw patch · 5 files changed
+341/−0 lines, 5 filesdep +basedep +mtldep +parsecsetup-changed
Dependencies added: base, mtl, parsec, xhtml
Files
- Ansi2Html.cabal +16/−0
- Ansi2Html.hs +237/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- ansi2html.css +56/−0
+ Ansi2Html.cabal view
@@ -0,0 +1,16 @@+Name: Ansi2Html+Version: 0.1+Synopsis: Convert ANSI Terminal Sequences to nice HTML markup+Description: Particularly with xterm in mind, this software enables integration of terminal screen state in html pages. See project homepage for hints on how to setup xterm for it.+Homepage: http://janzzstimmpfle.de/~jens/software/Ansi2Html/+License: BSD3+License-file: LICENSE+Author: Jens Stimpfle+Maintainer: jens@janzzstimmpfle.de+Category: Web+Build-type: Simple+Extra-source-files: ansi2html.css+Cabal-version: >=1.2+Executable ansi2html+ Main-is: Ansi2Html.hs+ Build-depends: parsec, mtl, base < 5, xhtml
+ Ansi2Html.hs view
@@ -0,0 +1,237 @@+import Text.ParserCombinators.Parsec+import System.Environment+import System.IO+import System.Exit+import Control.Applicative ((<$>))+import Data.Char+import Data.Maybe+import Text.XHtml as X+import Control.Monad+import Control.Monad.State as S++-- the (Integer,Integer) state holds an (couner,columns) state+type MyParser = GenParser Char (Integer,Integer)++data ANSIEnv = AnsiEnv { ansiBrightOrBold :: Bool+ , ansiFaint :: Bool+ , ansiItalic :: Bool+ , ansiUnderline :: Bool+ , ansiReverse :: Bool+ , ansiFontNumber :: Int+ , ansiFramed :: Bool+ , ansiEncircled :: Bool+ , ansiOverlined :: Bool+ , ansiFGColor :: ANSIColor+ , ansiBGColor :: ANSIColor+ }++defaultEnv :: ANSIEnv+defaultEnv = AnsiEnv False False False False False 0 False False False AnsiWhite AnsiBlack++modifyEnv :: ANSIEnv -> ANSIToken -> ANSIEnv+modifyEnv env ctl = if (finalByte ctl /= 'm')+ then env+ else foldl (flip ($)) env modifiers+ where modifiers = flip map (optParms ctl)+ (\parm -> case parm of+ 0 -> \_ -> defaultEnv+ 1 -> \e -> e { ansiBrightOrBold = True }+ 2 -> \e -> e { ansiFaint = True }+ 3 -> \e -> e { ansiItalic = True }+ 4 -> \e -> e { ansiUnderline = True }+ 7 -> \e -> e { ansiReverse = True }+ 10 -> \e -> e { ansiFontNumber = 0 }+ 11 -> \e -> e { ansiFontNumber = 1 }+ 12 -> \e -> e { ansiFontNumber = 2 }+ 13 -> \e -> e { ansiFontNumber = 3 }+ 14 -> \e -> e { ansiFontNumber = 4 }+ 15 -> \e -> e { ansiFontNumber = 5 }+ 16 -> \e -> e { ansiFontNumber = 6 }+ 17 -> \e -> e { ansiFontNumber = 7 }+ 18 -> \e -> e { ansiFontNumber = 8 }+ 19 -> \e -> e { ansiFontNumber = 9 }+ 21 -> \e -> e { ansiBrightOrBold = False }+ 22 -> \e -> e { ansiBrightOrBold = False+ , ansiFaint = False+ }+ 23 -> \e -> e { ansiItalic = False }+ 24 -> \e -> e { ansiUnderline = False }+ 26 -> \e -> e { ansiUnderline = False }+ 27 -> \e -> e { ansiReverse = False }+ 30 -> \e -> e { ansiFGColor = AnsiBlack }+ 31 -> \e -> e { ansiFGColor = AnsiRed }+ 32 -> \e -> e { ansiFGColor = AnsiGreen }+ 33 -> \e -> e { ansiFGColor = AnsiYellow }+ 34 -> \e -> e { ansiFGColor = AnsiBlue }+ 35 -> \e -> e { ansiFGColor = AnsiMagenta }+ 36 -> \e -> e { ansiFGColor = AnsiCyan }+ 37 -> \e -> e { ansiFGColor = AnsiWhite }+ 40 -> \e -> e { ansiBGColor = AnsiBlack }+ 41 -> \e -> e { ansiBGColor = AnsiRed }+ 42 -> \e -> e { ansiBGColor = AnsiGreen }+ 43 -> \e -> e { ansiBGColor = AnsiYellow }+ 44 -> \e -> e { ansiBGColor = AnsiBlue }+ 45 -> \e -> e { ansiBGColor = AnsiMagenta }+ 46 -> \e -> e { ansiBGColor = AnsiCyan }+ 47 -> \e -> e { ansiBGColor = AnsiWhite }+ 51 -> \e -> e { ansiFramed = True }+ 52 -> \e -> e { ansiEncircled = True }+ 53 -> \e -> e { ansiOverlined = True }+ 54 -> \e -> e { ansiFramed = False+ , ansiEncircled = False+ }+ 55 -> \e -> e { ansiOverlined = False }+ _ -> id)+++data ANSIColor = AnsiBlack+ | AnsiRed+ | AnsiGreen+ | AnsiYellow+ | AnsiBlue+ | AnsiMagenta+ | AnsiCyan+ | AnsiWhite+ deriving Eq++envAttrs :: ANSIEnv -> [HtmlAttr]+envAttrs e =+ let r = ansiReverse env+ env = reverseEnv r e+ bob = when' (ansiBrightOrBold env) ("bold")+ italic = when' (ansiItalic env) ("italic")+ underline = when' (ansiUnderline env) ("underline")+ fontnum = when' (ansiFontNumber env /= 0) ("fontNum" ++ (show $ ansiFontNumber env))+ framed = when' (ansiFramed env) ("framed")+ fgcolor = when' (ansiFGColor env /= AnsiBlack) ("fg" ++ (show $ ansiFGColor env))+ bgcolor = when' (ansiBGColor env /= AnsiBlack) ("bg" ++ (show $ ansiBGColor env))+ classes = map ("ansi2html-"++) $ catMaybes [bob, italic, underline, fontnum, framed, fgcolor, bgcolor]+ joined = foldl (\a b -> if null a then b else a ++ " " ++ b) "" classes+ in [theclass joined]+ where+ when' x y = if x then Just y else Nothing+ -- TODO+ reverseEnv = flip const++instance Show ANSIColor where+ show color = case color of+ AnsiBlack -> "black"+ AnsiRed -> "red"+ AnsiGreen -> "green"+ AnsiYellow -> "yellow"+ AnsiBlue -> "blue"+ AnsiMagenta -> "magenta"+ AnsiCyan -> "cyan"+ AnsiWhite -> "white"++data ANSIToken = AnsiText String+ | CtlSeq { privModeChars :: String+ , optParms :: [Int]+ , interMedChars :: String+ , finalByte :: Char+ }+ deriving Show++ansiParser :: MyParser [ANSIToken]+ansiParser = do+ result <- many ansiToken+ eof+ return result++ansiToken :: MyParser ANSIToken+ansiToken = do+ {- xterm prints a strange file with each line prefixed by '\ESC#5'+ - Let's simply remove those prefixes -}+ try (string "\ESC#5") <|> return ""+ try ctlSeq <|> ansiText++ansiText :: MyParser ANSIToken+ansiText = do+ strings <- many1 nonControlChar+ column <- getState+ return $ AnsiText $ concat strings++nonControlChar :: MyParser String+nonControlChar = do+ -- filter out \CR+ try (char '\CR') <|> return ' '+ (counter,columns) <- getState+ r <- satisfy (/='\ESC')+ implicitbreak <- if counter == columns && r /= '\n'+ then do+ updateState (mapFst (const 0))+ return "\n"+ else return ""+ rr <- if (r == '\n')+ then do+ updateState (mapFst (const 0))+ return $ replicate (fromInteger (columns - counter)) ' ' ++ "\n"+ else do+ updateState (mapFst (+1))+ return [r]+ return $ implicitbreak ++ rr+ where mapFst f (a,b) = (f a,b)++ctlSeq :: MyParser ANSIToken+ctlSeq = do+ csiCode+ parms <- number `sepBy` char ';'+ iMBs <- interMedBytes+ l <- letter+ return $ CtlSeq "" parms iMBs l++number :: MyParser Int+number = do{ ds <- many1 digit+ ; return (read ds)+ }+ <?> "number"++interMedBytes :: MyParser String+interMedBytes = return ""++csiCode :: MyParser ()+csiCode = do+ escapeChar+ char '['+ return ()++escapeChar :: MyParser ()+escapeChar = do+ char '\ESC'+ return ()++ansiToken2Html :: ANSIToken -> S.State ANSIEnv X.Html+ansiToken2Html tok = do+ env <- S.get+ case tok of+ AnsiText t -> let html = (linesToHtml $ lines t) +++ (if last t == '\n' then X.br else X.noHtml)+ in return $ (X.thespan ! envAttrs env) << html+ ctlseq -> do+ S.put $ modifyEnv env ctlseq+ return X.noHtml++ansi2Html :: [ANSIToken] -> X.Html+ansi2Html toks = foldl (+++) noHtml htmls+ where htmls = evalState (mapM ansiToken2Html toks) defaultEnv++makeHtml :: X.Html -> X.Html+makeHtml content = X.thespan ! [theclass "ansi2html"] << content++printUsage :: IO ()+printUsage = do+ hPutStrLn stderr "Usage: ansi2html <columns>"+ hFlush stderr++main = do+ args <- getArgs+ columns <- case args of+ [] -> return 80+ x:xs -> case reads x :: [(Integer,String)] of+ [(c,[])] -> return c+ _ -> printUsage >> exitFailure+ contents <- getContents+ tokens <- case runParser ansiParser (0,columns) "" contents of+ Left err -> do+ error $ "parse error at " ++ show err+ Right x -> return x+ print . makeHtml $ ansi2Html tokens
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2011, Jens Stimpfle++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Jens Stimpfle nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ ansi2html.css view
@@ -0,0 +1,56 @@+span.ansi2html {+ font-family: monospace;+ background-color: black;+}++/* foreground colors */+.ansi2html-fgblack {+ color: #000;+}+.ansi2html-fgcyan {+ color: #00cdcd;+}+.ansi2html-fgblue {+ color: #0000ee;+}+.ansi2html-fggreen {+ color: #00cd00;+}+.ansi2html-fgmagenta {+ color: #cd00cd;+}+.ansi2html-fgred {+ color: #cd0000;+}+.ansi2html-fgwhite {+ color: #e5e5e5;+}+.ansi2html-fgyellow {+ color: #cdcd00;+}++/* Background background-colors */+.ansi2html-bgblack {+ background-color: #000;+}+.ansi2html-bgcyan {+ background-color: #00cdcd;+}+.ansi2html-bgblue {+ background-color: #0000ee;+}+.ansi2html-bggreen {+ background-color: #00cd00;+}+.ansi2html-bgmagenta {+ background-color: #cd00cd;+}+.ansi2html-bgred {+ background-color: #cd0000;+}+.ansi2html-bgwhite {+ background-color: #e5e5e5;+}+.ansi2html-bgyellow {+ background-color: #cdcd00;+}