Commit 8b58b36e authored by Andrew Gibiansky's avatar Andrew Gibiansky

Merge branch 'master' of github.com:gibiansky/IHaskell

parents b19792bc 0a181a17
......@@ -6,6 +6,9 @@
![IHaskell](https://raw.github.com/gibiansky/IHaskell/master/html/logo-64x64.png)
# IHaskell
> You can now try IHaskell directly in your browser at [try.jupyter.org](https://try.jupyter.org).
IHaskell is a kernel for the [Jupyter project](http://ipython.org), which allows you to use Haskell inside Jupyter frontends (including the console and notebook).
For a tour of some IHaskell features, check out the [demo Notebook](http://nbviewer.ipython.org/github/gibiansky/IHaskell/blob/master/notebooks/IHaskell.ipynb). More example notebooks are available on the [wiki](https://github.com/gibiansky/IHaskell/wiki).
......
......@@ -48,7 +48,7 @@ if [ $# -gt 0 ]; then
if [ $1 = "display" ] || [ $1 = "all" ]; then
# Install all the display libraries
cd ihaskell-display
for dir in `ls`
for dir in `ls | grep -v ihaskell-widgets`
do
INSTALLS="$INSTALLS ihaskell-display/$dir"
done
......@@ -71,6 +71,10 @@ INSTALL_DIRS=`echo $INSTALLS | tr ' ' '\n' | sed 's#^#./#' | tr ' ' '\n'`
echo CMD: cabal install --constraint "arithmoi -llvm" -j $INSTALL_DIRS --force-reinstalls --max-backjumps=-1 --reorder-goals
cabal install --constraint "arithmoi -llvm" -j $INSTALL_DIRS --force-reinstalls --max-backjumps=-1 --reorder-goals
if [ $1 = "display" ] || [ $1 = "all" ]; then
cabal install ihaskell-display/ihaskell-widgets
fi
if hash ihaskell 2>/dev/null; then
ihaskell install 2>/dev/null || echo "The command \"ihaskell install\" failed. Please check your 'ipython --version'. 3.0 or up is required but it is $(ipython --version)!"
else
......
......@@ -37,7 +37,7 @@ chartData renderable format = do
mkFile opts filename renderable
-- Convert to base64.
imgData <- fmap Char.pack $ readFile filename
imgData <- Char.readFile filename
return $
case format of
PNG -> png width height $ base64 imgData
......
......@@ -60,8 +60,8 @@ displayImageAsJpg renderable = do
-- Write the image
saveJpgImage 95 filename renderable
-- Convert to base64.
imgData <- readFile filename
return $ Display [jpg (imWidth renderable) (imHeight renderable) $ base64 (CBS.pack imgData)]
imgData <- CBS.readFile filename
return $ Display [jpg (imWidth renderable) (imHeight renderable) $ base64 imgData]
-- The type DynamicImage does not have a function to extract width and height
imWidth :: DynamicImage -> Int
......
......@@ -28,7 +28,7 @@ figureData figure format = do
writeFigure format fname (w, h) figure
-- Read back, and convert to base64.
imgData <- Char.pack <$> readFile fname
imgData <- Char.readFile fname
let value =
case format of
PNG -> png w h $ base64 imgData
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The Numeric Widgets\n",
"\n",
"#### `Int` Widgets\n",
"\n",
"+ IntText\n",
"+ BoundedIntText\n",
"+ IntProgress\n",
"+ IntSlider\n",
"+ IntRangeSlider\n",
"\n",
"#### `Float` Widgets\n",
"\n",
"+ FloatText\n",
"+ BoundedFloatText\n",
"+ FloatProgress\n",
"+ FloatSlider\n",
"+ FloatRangeSlider\n",
"\n",
"**NOTE**: Only the `Int` widgets are shown in this notebook. The `Float` widgets are the same as their `Int` counterparts, but hold `Float`s instead of `Int`s."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `IntText` and `BoundedIntText`"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"int <- mkIntText\n",
"int"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"bit <- mkBoundedIntText\n",
"bit"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Both the widgets are similar, but the second one possesses some additional properties."
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"setField bit SMaxInt 20\n",
"setField bit SMinInt 10\n",
"setField bit SChangeHandler (getField bit SIntValue >>= print)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, the first widget will accept arbitrary input whereas the second one wil accept input the the 10-20 range. For example, try entering large values and hitting return/enter in the second widget."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `IntSlider` and `IntRangeSlider`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Both these widgets are sliders (duh!). `IntSlider` represents a single value, whereas `IntRangeSlider` represents a pair (range) of values."
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"ins <- mkIntSlider\n",
"irs <- mkIntRangeSlider"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"ins\n",
"irs"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(25,75)"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"getField irs SIntPairValue"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `IntProgress`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This widget is meant to be used as a progress bar."
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"inp <- mkIntProgress\n",
"inp"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"setField inp SIntValue 42"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Haskell",
"language": "haskell",
"name": "haskell"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
This diff is collapsed.
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The `Selection` Widgets\n",
"\n",
"+ Dropdown\n",
"+ RadioButtons\n",
"+ ToggleButtons\n",
"+ Select\n",
"+ SelectMultiple"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"These widgets can be used to choose between multiple alternatives. The `SelectMultiple` widget allows multiple selections, whereas `Dropdown`, `RadioButtons`, `ToggleButtons`, and `Select` only allow one selection."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"{-# LANGUAGE OverloadedStrings #-}\n",
"import IHaskell.Display.Widgets"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"-- Allows single selection\n",
"tgbs <- mkToggleButtons\n",
"\n",
"-- Allows multiple selections\n",
"msel <- mkSelectMultiple"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"setField msel SDescription \"Functions to show (One or more)\"\n",
"setField msel SOptions (OptionLabels [\"sin\", \"cos\"])\n",
"\n",
"setField tgbs SDescription \"Plot style\"\n",
"setField tgbs SOptions (OptionLabels [\"line\", \"point\"])"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import Graphics.Rendering.Chart.Easy hiding (tan)\n",
"import Graphics.Rendering.Chart.Backend.Cairo\n",
"import qualified Data.ByteString as B\n",
"import Data.Text (pack, unpack)\n",
"import IHaskell.Display (base64)\n",
"import Control.Applicative ((<$>))\n",
"\n",
"import Control.Monad (when, forM)\n",
"import Data.Maybe (fromJust)\n",
"\n",
"dset :: [(String, [(Double, Double)])]\n",
"dset = [(\"sin\", zmap sin r), (\"cos\", zmap cos r)]\n",
" where zmap f xs = zip xs (map f xs)\n",
" r = [0, 0.1 .. 6.3]\n",
"\n",
"i <- mkImageWidget\n",
"setField i SWidth 500\n",
"setField i SHeight 500\n",
"\n",
"-- Redraw the plot based on values from the widgets\n",
"refresh = do\n",
" -- Read values from the widgets\n",
" funs <- map unpack <$> getField msel SSelectedValues\n",
" sty <- unpack <$> getField tgbs SSelectedValue\n",
" \n",
" let pts = zip funs (map (fromJust . flip lookup dset) funs)\n",
" opts = def { _fo_size = (500, 500) }\n",
" toFile opts \".chart\" $ do\n",
" layout_title .= \"Plotting: \" ++ unwords funs\n",
" if sty == \"line\"\n",
" then mapM_ (\\(s, ps) -> plot (line s [ps])) pts\n",
" else mapM_ (\\(s, ps) -> plot (points s ps)) pts\n",
"\n",
" img <- B.readFile \".chart\"\n",
" setField i SB64Value (base64 img)\n",
" \n",
"-- Add event handlers to make widgets work\n",
"setField msel SSelectionHandler refresh\n",
"setField tgbs SSelectionHandler refresh"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"data": {},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- Display the widgets\n",
"msel\n",
"tgbs\n",
"i"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `Dropdown`, `RadioButtons` and `Select` widgets behave just like the `ToggleButtons` widget. They have the same properties, and the same functionality."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Haskell",
"language": "haskell",
"name": "haskell"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
# IPython widget messaging specification
> Largely based on: https://github.com/ipython/ipython/wiki/IPEP-23:-Backbone.js-Widgets
> The messaging specification as detailed is riddled with assumptions IHaskell's widget
> implementation makes. It works for us, so it should work for everyone.
## Creating widgets
Let's say the user types in some code, and the only effect of that code is the creation of a widget.
The kernel will open a comm for the widget, and store a reference to that comm inside it. Then, to
notify the frontend about the creation of a widget, an initial state update is sent on the widget's
comm.
> The comm should be opened with a `target_name` of `"ipython.widget"`.
The initial state update message looks like this:
```json
{
"method": "update",
"state": { "<some/all widget properties>" }
}
```
Any *numeric* property initialized with the empty string is provided the default value by the
frontend. Some numbers need to be sent as actual numbers (when non-null), whereas some (especially
those used by sliders) need to be sent as strings.
The initial state update must *at least* have the following fields:
- `msg_throttle` (default 3): To prevent the kernel from flooding with messages, the messages from
the widget to the kernel are throttled. If `msg_throttle` messages were sent, and all are still
processing, the widget will not send anymore state messages.
- `_view_name` (depends on the widget): The frontend uses a generic model to represent
widgets. This field determines how a set of widget properties gets rendered into a
widget. Has the form `IPython.<widgetname>`, e.g `IPython.Button`.
- `_css` (default value = empty list): A list of 3-tuples, (selector, key, value).
- `visible` (default = True): Whether the widget is visible or not.
- Rest of the properties as required initially.
This state update is also used with fragments of the overall state to sync changes between the
frontend and the kernel.
## Displaying widgets
The creation of a widget does not display it. To display a widget, the kernel sends a display
message to the frontend on the widget's comm.
```json
{
"method": "display"
}
```
## Custom messages
* Widgets can also send a custom message, having the form:
```json
{
"method": "custom",
"content": { "<message content>" }
}
```
This message is used by widgets for ad-hoc syncronization, event handling and other stuff. An example
is mentioned in the next section.
## Handling changes to widget in the frontend
Changes to widgets in the frontend lead to messages being sent to the backend. These messages have
two possible formats:
1. Backbone.js initiated sync:
```json
{
"method": "backbone",
"sync_data": { "<changes to sync with the backend>" }
}
```
These messages are sent by the Backbone.js library when some change is made to a widget. For
example, whenever a change is made to the text inside a `TextWidget`, the complete contents are sent
to the kernel so that the kernel stays up-to-date about the widget's contents.
2. Custom message:
```json
{
"method": "custom",
"content": { "<custom message data>" }
}
```
This form is generally used to notify the kernel about events. For example, the `TextWidget` sends a
custom message when the text is submitted by hitting the 'Enter' key.
---
*NOTE*: It's important that the messages sent on the comm are in response to an execution message
from the front-end or another widget's comm message. This is required so the widget framework knows
what cell triggered the message and can display the widget in the correct location.
---
# IHaskell-Widgets
This package implements the [ipython widgets](https://github.com/ipython/ipywidgets) in
IHaskell. The frontend (javascript) is provided by the jupyter/ipython notebook environment, whereas
the backend is implemented in haskell.
To know more about the widget messaging protocol, see [MsgSpec.md](MsgSpec.md).
......@@ -44,7 +44,7 @@ build-type: Simple
-- Extra files to be distributed with the package, such as examples or a
-- README.
-- extra-source-files:
extra-source-files: README.md, MsgSpec.md
-- Constraint on the version of Cabal needed to build this package.
cabal-version: >=1.10
......@@ -55,22 +55,52 @@ library
-- Modules included in this library but not exported.
other-modules: IHaskell.Display.Widgets.Button
IHaskell.Display.Widgets.Box.Box
IHaskell.Display.Widgets.Box.FlexBox
IHaskell.Display.Widgets.Box.SelectionContainer.Accordion
IHaskell.Display.Widgets.Box.SelectionContainer.Tab
IHaskell.Display.Widgets.Bool.CheckBox
IHaskell.Display.Widgets.Bool.ToggleButton
IHaskell.Display.Widgets.Int.IntText
IHaskell.Display.Widgets.Int.BoundedInt.BoundedIntText
IHaskell.Display.Widgets.Int.BoundedInt.IntProgress
IHaskell.Display.Widgets.Int.BoundedInt.IntSlider
IHaskell.Display.Widgets.Int.BoundedIntRange.IntRangeSlider
IHaskell.Display.Widgets.Float.FloatText
IHaskell.Display.Widgets.Float.BoundedFloat.BoundedFloatText
IHaskell.Display.Widgets.Float.BoundedFloat.FloatProgress
IHaskell.Display.Widgets.Float.BoundedFloat.FloatSlider
IHaskell.Display.Widgets.Float.BoundedFloatRange.FloatRangeSlider
IHaskell.Display.Widgets.Image
IHaskell.Display.Widgets.Output
IHaskell.Display.Widgets.Selection.Dropdown
IHaskell.Display.Widgets.Selection.RadioButtons
IHaskell.Display.Widgets.Selection.Select
IHaskell.Display.Widgets.Selection.ToggleButtons
IHaskell.Display.Widgets.Selection.SelectMultiple
IHaskell.Display.Widgets.String.HTML
IHaskell.Display.Widgets.String.Latex
IHaskell.Display.Widgets.String.Text
IHaskell.Display.Widgets.String.TextArea
IHaskell.Display.Widgets.Types
IHaskell.Display.Widgets.Common
-- LANGUAGE extensions used by modules in this package.
-- other-extensions:
-- Other library packages from which modules are imported.
build-depends: aeson >= 0.8.1.0
build-depends: aeson >=0.7 && < 0.9
, base >=4.7 && <4.9
, ipython-kernel >= 0.6.1.0
, text >= 1.2.1.0
, unordered-containers >= 0.2.5.1
, containers >= 0.5
, ipython-kernel >= 0.6.1
, text >= 0.11
, unordered-containers -any
, nats -any
, vinyl >= 0.5
, vector -any
, singletons >= 0.9.0
, scientific -any
-- Waiting for the next release
, ihaskell -any
......@@ -81,3 +111,10 @@ library
-- Base language which the package is written in.
default-language: Haskell2010
-- Deal with small -fcontext-stack on ghc-7.8.
-- Default values:
-- ghc-7.6.* = 200
-- ghc-7.8.* = 20 -- Too small for vinyl & singletons
-- ghc-7.10.* = 100
if impl(ghc == 7.8.*)
ghc-options: -fcontext-stack=100
......@@ -2,11 +2,44 @@ module IHaskell.Display.Widgets (module X) where
import IHaskell.Display.Widgets.Button as X
import IHaskell.Display.Widgets.Box.Box as X
import IHaskell.Display.Widgets.Box.FlexBox as X
import IHaskell.Display.Widgets.Box.SelectionContainer.Accordion as X
import IHaskell.Display.Widgets.Box.SelectionContainer.Tab as X
import IHaskell.Display.Widgets.Bool.CheckBox as X
import IHaskell.Display.Widgets.Bool.ToggleButton as X
import IHaskell.Display.Widgets.Int.IntText as X
import IHaskell.Display.Widgets.Int.BoundedInt.BoundedIntText as X
import IHaskell.Display.Widgets.Int.BoundedInt.IntProgress as X
import IHaskell.Display.Widgets.Int.BoundedInt.IntSlider as X
import IHaskell.Display.Widgets.Int.BoundedIntRange.IntRangeSlider as X
import IHaskell.Display.Widgets.Float.FloatText as X
import IHaskell.Display.Widgets.Float.BoundedFloat.BoundedFloatText as X
import IHaskell.Display.Widgets.Float.BoundedFloat.FloatProgress as X
import IHaskell.Display.Widgets.Float.BoundedFloat.FloatSlider as X
import IHaskell.Display.Widgets.Float.BoundedFloatRange.FloatRangeSlider as X
import IHaskell.Display.Widgets.Image as X
import IHaskell.Display.Widgets.Output as X
import IHaskell.Display.Widgets.Selection.Dropdown as X
import IHaskell.Display.Widgets.Selection.RadioButtons as X
import IHaskell.Display.Widgets.Selection.Select as X
import IHaskell.Display.Widgets.Selection.ToggleButtons as X
import IHaskell.Display.Widgets.Selection.SelectMultiple as X
import IHaskell.Display.Widgets.String.HTML as X
import IHaskell.Display.Widgets.String.Latex as X
import IHaskell.Display.Widgets.String.Text as X
import IHaskell.Display.Widgets.String.TextArea as X
import IHaskell.Display.Widgets.Common as X (ButtonStyle(..), ImageFormat(..))
import IHaskell.Display.Widgets.Common as X
import IHaskell.Display.Widgets.Types as X (setField, getField, properties)
import IHaskell.Display.Widgets.Types as X (triggerDisplay, triggerChange, triggerClick,
triggerSelection, triggerSubmit,
ChildWidget(..))
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeSynonymInstances #-}
module IHaskell.Display.Widgets.Bool.CheckBox (
-- * The CheckBox Widget
CheckBox,
-- * Constructor
mkCheckBox) where
-- To keep `cabal repl` happy when running from the ihaskell repo
import Prelude
import Control.Monad (when, join, void)
import Data.Aeson
import Data.HashMap.Strict as HM
import Data.IORef (newIORef)
import Data.Text (Text)
import Data.Vinyl (Rec(..), (<+>))
import IHaskell.Display
import IHaskell.Eval.Widgets
import IHaskell.IPython.Message.UUID as U
import IHaskell.Display.Widgets.Types
import IHaskell.Display.Widgets.Common
-- | A 'CheckBox' represents a Checkbox widget from IPython.html.widgets.
type CheckBox = IPythonWidget CheckBoxType
-- | Create a new output widget
mkCheckBox :: IO CheckBox
mkCheckBox = do
-- Default properties, with a random uuid
uuid <- U.random
let widgetState = WidgetState $ defaultBoolWidget "CheckboxView"
stateIO <- newIORef widgetState
let widget = IPythonWidget uuid stateIO
initData = object
["model_name" .= str "WidgetModel", "widget_class" .= str "IPython.Checkbox"]
-- Open a comm for this widget, and store it in the kernel state
widgetSendOpen widget initData $ toJSON widgetState
-- Return the image widget
return widget
instance IHaskellDisplay CheckBox where
display b = do
widgetSendView b
return $ Display []
instance IHaskellWidget CheckBox where
getCommUUID = uuid
comm widget (Object dict1) _ = do
let key1 = "sync_data" :: Text
key2 = "value" :: Text
Just (Object dict2) = HM.lookup key1 dict1
Just (Bool value) = HM.lookup key2 dict2
setField' widget SBoolValue value
triggerChange widget
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeSynonymInstances #-}
module IHaskell.Display.Widgets.Bool.ToggleButton (
-- * The ToggleButton Widget
ToggleButton,
-- * Constructor
mkToggleButton) where
-- To keep `cabal repl` happy when running from the ihaskell repo
import Prelude
import Control.Monad (when, join, void)
import Data.Aeson
import Data.HashMap.Strict as HM
import Data.IORef (newIORef)
import Data.Text (Text)
import Data.Vinyl (Rec(..), (<+>))
import IHaskell.Display
import IHaskell.Eval.Widgets
import IHaskell.IPython.Message.UUID as U
import IHaskell.Display.Widgets.Types
import IHaskell.Display.Widgets.Common
-- | A 'ToggleButton' represents a ToggleButton widget from IPython.html.widgets.
type ToggleButton = IPythonWidget ToggleButtonType
-- | Create a new output widget
mkToggleButton :: IO ToggleButton
mkToggleButton = do
-- Default properties, with a random uuid
uuid <- U.random
let boolState = defaultBoolWidget "ToggleButtonView"
toggleState = (STooltip =:: "")
:& (SIcon =:: "")
:& (SButtonStyle =:: DefaultButton)
:& RNil
widgetState = WidgetState (boolState <+> toggleState)
stateIO <- newIORef widgetState
let widget = IPythonWidget uuid stateIO
initData = object
["model_name" .= str "WidgetModel", "widget_class" .= str "IPython.ToggleButton"]
-- Open a comm for this widget, and store it in the kernel state
widgetSendOpen widget initData $ toJSON widgetState
-- Return the image widget
return widget
instance IHaskellDisplay ToggleButton where
display b = do
widgetSendView b
return $ Display []
instance IHaskellWidget ToggleButton where
getCommUUID = uuid
comm widget (Object dict1) _ = do
let key1 = "sync_data" :: Text
key2 = "value" :: Text
Just (Object dict2) = HM.lookup key1 dict1
Just (Bool value) = HM.lookup key2 dict2
setField' widget SBoolValue value
triggerChange widget
......@@ -213,7 +213,7 @@ mkConfig var = KernelConfig
, displayResult = displayRes
, displayOutput = displayOut
, completion = langCompletion
, objectInfo = langInfo
, inspectInfo = langInfo
, run = parseAndRun
, debug = False
}
......
-- | Description : UUID generator and data structure
--
-- Generate, parse, and pretty print UUIDs for use with IPython.
module IHaskell.IPython.Message.UUID (UUID, random, randoms) where
module IHaskell.IPython.Message.UUID (UUID, random, randoms, uuidToString) where
import Control.Monad (mzero, replicateM)
import Control.Applicative ((<$>))
......@@ -16,7 +16,7 @@ data UUID =
-- present in the correct locations. For the purposes of new UUIDs, it does not matter,
-- but IPython expects UUIDs passed to kernels to be returned unchanged, so we cannot
-- actually parse them.
UUID String
UUID { uuidToString :: String }
deriving (Show, Read, Eq, Ord)
-- | Generate a list of random UUIDs.
......
......@@ -25,6 +25,7 @@ module IHaskell.IPython.Types (
HistoryAccessType(..),
HistoryReplyElement(..),
replyType,
showMessageType,
-- ** IPython display data message
DisplayData(..),
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment