diff --git a/ihaskell-display/ihaskell-blaze/IHaskell/Display/Blaze.hs b/ihaskell-display/ihaskell-blaze/IHaskell/Display/Blaze.hs
index 2875fc58..5ca1a7c0 100644
--- a/ihaskell-display/ihaskell-blaze/IHaskell/Display/Blaze.hs
+++ b/ihaskell-display/ihaskell-blaze/IHaskell/Display/Blaze.hs
@@ -2,6 +2,7 @@
module IHaskell.Display.Blaze () where
+import IHaskell.CSS (ihaskellCSS)
import IHaskell.Display
import Text.Printf
@@ -15,4 +16,4 @@ instance IHaskellDisplay (MarkupM a) where
where
str = renderMarkup (void val)
stringDisplay = plain str
- htmlDisplay = html str
+ htmlDisplay = html' (Just ihaskellCSS) str
diff --git a/ihaskell-display/ihaskell-diagrams/IHaskell/Display/Diagrams/Animation.hs b/ihaskell-display/ihaskell-diagrams/IHaskell/Display/Diagrams/Animation.hs
index 840ddad7..3ea5310b 100644
--- a/ihaskell-display/ihaskell-diagrams/IHaskell/Display/Diagrams/Animation.hs
+++ b/ihaskell-display/ihaskell-diagrams/IHaskell/Display/Diagrams/Animation.hs
@@ -7,8 +7,8 @@ module IHaskell.Display.Diagrams.Animation
, ManuallySampled, withAnimFps
) where
-import qualified Data.Text as T
import qualified Data.ByteString.Char8 as CBS
+import qualified Data.Text as T
import GHC.Generics (Generic)
import Data.Maybe (fromMaybe)
@@ -41,8 +41,7 @@ withAnimFps fps = withSamplingSpec (Just fps)
instance IHaskellDisplay (ManuallySized (ManuallySampled (QAnimation Cairo V2 Double Any))) where
display renderable = do
gif <- animationData renderable
- return $ Display [html $ ""]
+ return $ Display [html' Nothing $ "
"]
animationData :: ManuallySized (ManuallySampled (Animation Cairo V2 Double)) -> IO String
diff --git a/ihaskell-display/ihaskell-magic/IHaskell/Display/Magic.hs b/ihaskell-display/ihaskell-magic/IHaskell/Display/Magic.hs
index 09821f22..e354e07f 100644
--- a/ihaskell-display/ihaskell-magic/IHaskell/Display/Magic.hs
+++ b/ihaskell-display/ihaskell-magic/IHaskell/Display/Magic.hs
@@ -2,21 +2,23 @@
module IHaskell.Display.Magic () where
-import IHaskell.Display
-import Magic
import qualified Data.ByteString as B
-import qualified Data.ByteString.Unsafe as B
import qualified Data.ByteString.Base64 as Base64
import qualified Data.ByteString.Char8 as Char
+import Data.ByteString.UTF8
import qualified Data.ByteString.UTF8 as B
-
-import Text.Read
+import qualified Data.ByteString.Unsafe as B
import Data.Char
-
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
+import Text.Read
+
+import Magic
+
+import IHaskell.CSS (ihaskellCSS)
+import IHaskell.Display
import IHaskell.IPython.Types (MimeType(MimeSvg))
-import Data.ByteString.UTF8
+
instance IHaskellDisplay T.Text where
display = display . T.encodeUtf8
@@ -35,7 +37,7 @@ withClass :: MagicClass -> B.ByteString -> DisplayData
withClass SVG = DisplayData MimeSvg . T.decodeUtf8
withClass (PNG w h) = png w h . T.decodeUtf8 . Base64.encode
withClass JPG = jpg 400 300 . T.decodeUtf8 . Base64.encode
-withClass HTML = html . B.toString
+withClass HTML = html' (Just ihaskellCSS) . B.toString
withClass LaTeX = latex . B.toString
withClass _ = plain . B.toString
diff --git a/ihaskell.cabal b/ihaskell.cabal
index dc840bb7..31e09f23 100644
--- a/ihaskell.cabal
+++ b/ihaskell.cabal
@@ -63,38 +63,39 @@ library
ghc-options: -Wpartial-fields
build-depends:
- base >=4.9 && <4.19,
- binary ,
- containers ,
- directory ,
- bytestring ,
- exceptions ,
- filepath ,
- ghc >=8.0 && <9.7,
- ghc-boot ,
- haskeline ,
- parsec ,
- process ,
- random ,
- stm ,
- text ,
- time ,
- transformers ,
- unix ,
- aeson >=1.0,
- base64-bytestring >=1.0,
- cmdargs >=0.10,
- ghc-parser >=0.2.1,
- ghc-paths >=0.1,
- http-client >=0.4,
- http-client-tls >=0.2,
- shelly >=1.5,
- split >=0.2,
- strict >=0.3,
- unordered-containers -any,
- utf8-string -any,
- vector -any,
- ipython-kernel >=0.10.2.0
+ base >=4.9 && <4.19,
+ binary ,
+ containers ,
+ directory ,
+ bytestring ,
+ exceptions ,
+ filepath ,
+ ghc >=8.0 && <9.7,
+ ghc-boot ,
+ ghc-syntax-highlighter,
+ haskeline ,
+ parsec ,
+ process ,
+ random ,
+ stm ,
+ text ,
+ time ,
+ transformers ,
+ unix ,
+ aeson >=1.0,
+ base64-bytestring >=1.0,
+ cmdargs >=0.10,
+ ghc-parser >=0.2.1,
+ ghc-paths >=0.1,
+ http-client >=0.4,
+ http-client-tls >=0.2,
+ shelly >=1.5,
+ split >=0.2,
+ strict >=0.3,
+ unordered-containers -any,
+ utf8-string -any,
+ vector -any,
+ ipython-kernel >=0.10.2.0
exposed-modules: IHaskell.Display
IHaskell.Convert
@@ -104,6 +105,7 @@ library
IHaskell.Eval.Completion
IHaskell.Eval.Inspect
IHaskell.Eval.Evaluate
+ IHaskell.Eval.Evaluate.HTML
IHaskell.Eval.Info
IHaskell.Eval.Parser
IHaskell.Eval.Hoogle
diff --git a/ipython-kernel/src/IHaskell/IPython/Types.hs b/ipython-kernel/src/IHaskell/IPython/Types.hs
index f65dc091..3ef38d4c 100644
--- a/ipython-kernel/src/IHaskell/IPython/Types.hs
+++ b/ipython-kernel/src/IHaskell/IPython/Types.hs
@@ -40,13 +40,13 @@ module IHaskell.IPython.Types (
import Data.Aeson
import Data.Aeson.Types (typeMismatch)
+import Data.Binary
import Data.ByteString (ByteString)
import Data.List (find)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (fromMaybe)
import Data.Semigroup (Semigroup)
-import Data.Binary
import Data.Text (Text, pack)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
@@ -920,7 +920,7 @@ replyType _ = Nothing
-- | Data for display: a string with associated MIME type.
data DisplayData = DisplayData MimeType Text
- deriving (Typeable, Generic)
+ deriving (Typeable, Eq, Generic)
-- We can't print the actual data, otherwise this will be printed every time it gets computed
-- because of the way the evaluator is structured. See how `displayExpr` is computed.
diff --git a/main/Main.hs b/main/Main.hs
index 44c94edd..5161b4dc 100644
--- a/main/Main.hs
+++ b/main/Main.hs
@@ -5,9 +5,9 @@
-- Chans to communicate with the ZeroMQ sockets.
module Main (main) where
-import IHaskellPrelude
-import qualified Data.Text as T
import qualified Data.ByteString.Lazy as LBS
+import qualified Data.Text as T
+import IHaskellPrelude
-- Standard library imports.
import Control.Concurrent.Chan
@@ -97,6 +97,10 @@ parseKernelArgs = foldl' addFlag defaultKernelSpecOptions
kernelSpecOpts { kernelSpecDebug = True }
addFlag kernelSpecOpts (CodeMirror codemirror) =
kernelSpecOpts { kernelSpecCodeMirror = codemirror }
+ addFlag kernelSpecOpts (HtmlCodeWrapperClass clazz) =
+ kernelSpecOpts { kernelSpecHtmlCodeWrapperClass = Just clazz }
+ addFlag kernelSpecOpts (HtmlCodeTokenPrefix prefix) =
+ kernelSpecOpts { kernelSpecHtmlCodeTokenPrefix = prefix }
addFlag kernelSpecOpts (GhcLibDir libdir) =
kernelSpecOpts { kernelSpecGhcLibdir = libdir }
addFlag kernelSpecOpts (KernelName name) =
@@ -151,7 +155,7 @@ runKernel kOpts profileSrc = do
interface <- serveProfile profile debug
-- Create initial state in the directory the kernel *should* be in.
- state <- initialKernelState
+ state <- initialKernelState kOpts
modifyMVar_ state $ \kernelState -> return $
kernelState { kernelDebug = debug }
@@ -169,7 +173,7 @@ runKernel kOpts profileSrc = do
noWidget s _ = return s
evaluator line = void $ do
-- Create a new state each time.
- stateVar <- liftIO initialKernelState
+ stateVar <- liftIO $ initialKernelState kOpts
st <- liftIO $ takeMVar stateVar
evaluate st line noPublish noWidget
@@ -229,8 +233,12 @@ runKernel kOpts profileSrc = do
(key, _:val) -> setEnv key val
-- Initial kernel state.
-initialKernelState :: IO (MVar KernelState)
-initialKernelState = newMVar defaultKernelState
+initialKernelState :: KernelSpecOptions -> IO (MVar KernelState)
+initialKernelState kOpts = newMVar (
+ defaultKernelState {
+ htmlCodeWrapperClass = kernelSpecHtmlCodeWrapperClass kOpts
+ , htmlCodeTokenPrefix = kernelSpecHtmlCodeTokenPrefix kOpts
+ })
-- | Create a new message header, given a parent message header.
createReplyHeader :: MessageHeader -> Interpreter MessageHeader
diff --git a/release-9.4.nix b/release-9.4.nix
index 0b26b252..0e125f50 100644
--- a/release-9.4.nix
+++ b/release-9.4.nix
@@ -34,6 +34,15 @@ let
'';
});
ghc-parser = self.callCabal2nix "ghc-parser" (builtins.path { path = ./ghc-parser; name = "ghc-parser-src"; }) {};
+ ghc-syntax-highlighter = let
+ src = nixpkgs.fetchFromGitHub {
+ owner = "mrkkrp";
+ repo = "ghc-syntax-highlighter";
+ rev = "bbc049904524aae08e6431494f41fe2a288f6259";
+ sha256 = "sha256-w7AxGsUfqGhh7wrSPppQ2+gPwjvb4mwExJdDOcasAZ4=";
+ };
+ in
+ self.callCabal2nix "ghc-syntax-highlighter" src {};
ipython-kernel = self.callCabal2nix "ipython-kernel" (builtins.path { path = ./ipython-kernel; name = "ipython-kernel-src"; }) {};
hlint = super.hlint_3_5;
diff --git a/release-9.6.nix b/release-9.6.nix
index 2ab3bba5..97750630 100644
--- a/release-9.6.nix
+++ b/release-9.6.nix
@@ -37,6 +37,15 @@ let
hlint = null;
});
ghc-parser = self.callCabal2nix "ghc-parser" (builtins.path { path = ./ghc-parser; name = "ghc-parser-src"; }) {};
+ ghc-syntax-highlighter = let
+ src = nixpkgs.fetchFromGitHub {
+ owner = "mrkkrp";
+ repo = "ghc-syntax-highlighter";
+ rev = "71ff751eaa6034d4aef254d6bc5a8be4f6595344";
+ sha256 = "14yahxi4pnjbvcd9r843kn7b36jsjaixd99jswsrh9n8xd59c2f1";
+ };
+ in
+ self.callCabal2nix "ghc-syntax-highlighter" src {};
ipython-kernel = self.callCabal2nix "ipython-kernel" (builtins.path { path = ./ipython-kernel; name = "ipython-kernel-src"; }) {};
zeromq4-haskell = nixpkgs.haskell.lib.addPkgconfigDepend super.zeromq4-haskell nixpkgs.libsodium;
diff --git a/src/IHaskell/CSS.hs b/src/IHaskell/CSS.hs
index 161261a0..2e72158f 100644
--- a/src/IHaskell/CSS.hs
+++ b/src/IHaskell/CSS.hs
@@ -1,11 +1,24 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+
module IHaskell.CSS (ihaskellCSS) where
+import Data.Text as T
import IHaskellPrelude
-ihaskellCSS :: String
+ihaskellCSS :: Text
ihaskellCSS =
- unlines
+ T.unlines
+ [
+ hoogleCSS
+ , basicCSS
+ , highlightCSS
+ , hlintCSS
+ ]
+
+hoogleCSS :: Text
+hoogleCSS =
+ T.unlines
[
-- Custom IHaskell CSS
"/* Styles used for the Hoogle display in the pager */"
@@ -43,7 +56,13 @@ ihaskellCSS =
, ".hoogle-class {"
, "font-weight: bold;"
, "}"
- ,
+ ]
+
+
+basicCSS :: Text
+basicCSS =
+ T.unlines
+ [
-- Styles used for basic displays
".get-type {"
, "color: green;"
@@ -76,14 +95,23 @@ ihaskellCSS =
, ".err-msg.in.collapse {"
, "padding-top: 0.7em;"
, "}"
- ,
+ ]
+
+highlightCSS :: Text
+highlightCSS =
+ T.unlines
+ [
-- Code that will get highlighted before it is highlighted
".highlight-code {"
, "white-space: pre;"
, "font-family: monospace;"
, "}"
- ,
- -- Hlint styles
+ ]
+
+hlintCSS :: Text
+hlintCSS =
+ T.unlines
+ [
".suggestion-warning { "
, "font-weight: bold;"
, "color: rgb(200, 130, 0);"
diff --git a/src/IHaskell/Display.hs b/src/IHaskell/Display.hs
index b1dd0f0c..72592d72 100644
--- a/src/IHaskell/Display.hs
+++ b/src/IHaskell/Display.hs
@@ -25,6 +25,7 @@ module IHaskell.Display (
-- * Constructors for displays
plain,
html,
+ html',
bmp,
png,
jpg,
@@ -68,8 +69,9 @@ import System.IO.Unsafe (unsafePerformIO)
import qualified Data.Text.Encoding as E
-import IHaskell.Types
+import IHaskell.CSS (ihaskellCSS)
import IHaskell.Eval.Util (unfoldM)
+import IHaskell.Types
import StringUtils (rstrip)
type Base64 = Text
@@ -84,7 +86,13 @@ plain = DisplayData PlainText . T.pack . rstrip
-- | Generate an HTML display.
html :: String -> DisplayData
-html = DisplayData MimeHtml . T.pack
+html = html' Nothing
+
+-- | Generate an HTML display with optional styles.
+html' :: Maybe Text -> String -> DisplayData
+html' maybeStyles s = DisplayData MimeHtml $ case maybeStyles of
+ Just css -> mconcat ["", T.pack s]
+ Nothing -> T.pack s
-- | Generate an SVG display.
svg :: T.Text -> DisplayData
diff --git a/src/IHaskell/Eval/Evaluate.hs b/src/IHaskell/Eval/Evaluate.hs
index 0ae98931..103e615c 100644
--- a/src/IHaskell/Eval/Evaluate.hs
+++ b/src/IHaskell/Eval/Evaluate.hs
@@ -27,6 +27,7 @@ import qualified Data.Set as Set
import Data.Char as Char
import Data.Dynamic
import qualified Data.Binary as Binary
+import qualified Data.Text as Text
import System.Directory
import System.Posix.IO (fdToHandle)
import System.IO (hGetChar, hSetEncoding, utf8)
@@ -92,10 +93,12 @@ import qualified ErrUtils
import qualified GHC.Paths
import GHC hiding (Stmt, TypeSig)
+import IHaskell.CSS (ihaskellCSS)
import IHaskell.Types
import IHaskell.IPython
import IHaskell.Eval.Parser
import IHaskell.Display
+import IHaskell.Eval.Evaluate.HTML (htmlify)
import qualified IHaskell.Eval.Hoogle as Hoogle
import IHaskell.Eval.Util
import IHaskell.BrokenPackages
@@ -930,23 +933,17 @@ evalCommand _ (Directive GetInfo str) state = safely state $ do
-- Get all the info for all the names we're given.
strings <- unlines <$> getDescription str
- -- Make pager work without html by porting to newer architecture
- let htmlify str1 =
- html $
- concat
- [ "