Skip to content
Permalink
Browse files

Rework API / helpers to display stuff

With an emphasis on allowing to maintain binary compatibility in the
future, and looking more alike the IPython display module.
  • Loading branch information...
alexarchambault committed Apr 9, 2019
1 parent e7fc81a commit 9000eaf0461c8f32933a2dc0aa44cf36a60621ab
Showing with 1,079 additions and 28 deletions.
  1. +164 −0 examples/displays.ipynb
  2. +31 −0 modules/scala/jupyter-api/src/main/scala/almond/display/Data.scala
  3. +76 −0 modules/scala/jupyter-api/src/main/scala/almond/display/Display.scala
  4. +60 −0 modules/scala/jupyter-api/src/main/scala/almond/display/FileLink.scala
  5. +32 −0 modules/scala/jupyter-api/src/main/scala/almond/display/Html.scala
  6. +68 −0 modules/scala/jupyter-api/src/main/scala/almond/display/IFrame.scala
  7. +157 −0 modules/scala/jupyter-api/src/main/scala/almond/display/Image.scala
  8. +32 −0 modules/scala/jupyter-api/src/main/scala/almond/display/Javascript.scala
  9. +46 −0 modules/scala/jupyter-api/src/main/scala/almond/display/Json.scala
  10. +32 −0 modules/scala/jupyter-api/src/main/scala/almond/display/Latex.scala
  11. +32 −0 modules/scala/jupyter-api/src/main/scala/almond/display/Markdown.scala
  12. +37 −0 modules/scala/jupyter-api/src/main/scala/almond/display/Math.scala
  13. +90 −0 modules/scala/jupyter-api/src/main/scala/almond/display/ProgressBar.scala
  14. +32 −0 modules/scala/jupyter-api/src/main/scala/almond/display/Svg.scala
  15. +32 −0 modules/scala/jupyter-api/src/main/scala/almond/display/Text.scala
  16. +83 −0 modules/scala/jupyter-api/src/main/scala/almond/display/TextDisplay.scala
  17. +26 −0 modules/scala/jupyter-api/src/main/scala/almond/display/UpdatableDisplay.scala
  18. +28 −17 modules/scala/scala-interpreter/src/main/scala/almond/ScalaInterpreter.scala
  19. +21 −11 modules/scala/scala-interpreter/src/test/scala/almond/ScalaKernelTests.scala
@@ -0,0 +1,164 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\u001b[32mimport \u001b[39m\u001b[36malmond.display._\u001b[39m"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import almond.display._"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<b>hello</b>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"Html(\"<b>hello</b>\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<label for='progress-2'>Hello 24 / 100</label><br><progress id='progress-2' style='width:60ex' max='100' value='24'></progress>"
],
"text/plain": [
"Hello 24 / 100\n",
"[####################### ]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"ProgressBar(24, 100).withLabel(\"Hello {progress} / {total}\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"\\begin{eqnarray}\n",
"\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} & = \\frac{4\\pi}{c}\\vec{\\mathbf{j}} \\\\\n",
"\\nabla \\cdot \\vec{\\mathbf{E}} & = 4 \\pi \\rho \\\\\n",
"\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t} & = \\vec{\\mathbf{0}} \\\\\n",
"\\nabla \\cdot \\vec{\\mathbf{B}} & = 0 \n",
"\\end{eqnarray}"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"Latex(\"\"\"\\begin{eqnarray}\n",
"\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} & = \\frac{4\\pi}{c}\\vec{\\mathbf{j}} \\\\\n",
"\\nabla \\cdot \\vec{\\mathbf{E}} & = 4 \\pi \\rho \\\\\n",
"\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t} & = \\vec{\\mathbf{0}} \\\\\n",
"\\nabla \\cdot \\vec{\\mathbf{B}} & = 0 \n",
"\\end{eqnarray}\"\"\")\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle a = b + c$"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"Math(\"a = b + c\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"# title\n",
"## subsec\n",
"foo\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"Markdown(\"\"\"\n",
"# title\n",
"## subsec\n",
"foo\n",
"\"\"\")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Scala (sources)",
"language": "scala",
"name": "scala"
},
"language_info": {
"codemirror_mode": "text/x-scala",
"file_extension": ".scala",
"mimetype": "text/x-scala",
"name": "scala",
"nbconvert_exporter": "script",
"version": "2.12.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
@@ -0,0 +1,31 @@
package almond.display

final class Data private(
data0: Map[String, String],
metadata0: Map[String, String],
val displayId: String
) extends UpdatableDisplay {

private def copy(
data: Map[String, String] = data0,
metadata: Map[String, String] = metadata0
): Data =
new Data(data, metadata, displayId)

def withData(data: Map[String, String]): Data =
copy(data = data)
def withMetadata(metadata: Map[String, String]): Data =
copy(metadata = metadata)

override def metadata(): Map[String, String] =
metadata0
def data(): Map[String, String] =
data0
}

object Data extends {
def apply(data: Map[String, String]): Data =
new Data(data, Map(), UpdatableDisplay.generateId())
def apply(data: (String, String)*): Data =
new Data(data.toMap, Map(), UpdatableDisplay.generateId())
}
@@ -0,0 +1,76 @@
package almond.display

import java.io.File
import java.net.URL
import java.nio.file.Path
import java.util.{Map => JMap}

import almond.interpreter.api.{DisplayData, OutputHandler}
import jupyter.{Displayer, Displayers}

import scala.collection.JavaConverters._

trait Display {
def data(): Map[String, String]
def metadata(): Map[String, String] = Map()
protected def displayData(): DisplayData =
DisplayData(data(), metadata = metadata())

def display()(implicit output: OutputHandler): Unit =
output.display(displayData())

// registering things with jvm-repr just in case
Display.registered
}

object Display {

private lazy val registered: Unit = {
Displayers.register(
classOf[Display],
new Displayer[Display] {
def display(d: Display): JMap[String, String] =
d.data().asJava
}
)
}


def markdown(content: String)(implicit output: OutputHandler): Unit =
Markdown(content).display()
def html(content: String)(implicit output: OutputHandler): Unit =
Html(content).display()
def latex(content: String)(implicit output: OutputHandler): Unit =
Latex(content).display()
def text(content: String)(implicit output: OutputHandler): Unit =
Text(content).display()

def js(content: String)(implicit output: OutputHandler): Unit =
Javascript(content).display()

def svg(content: String)(implicit output: OutputHandler): Unit =
Svg(content).display()


trait Builder[C, T] {

protected def build(contentOrUrl: Either[URL, C]): T

def apply(content: C): T =
build(Right(content))

def from(url: String): T =
build(Left(new URL(url)))
def from(url: URL): T =
build(Left(url))

def fromFile(file: File): T =
build(Left(file.toURI.toURL))
def fromFile(path: Path): T =
build(Left(path.toUri.toURL))
def fromFile(path: String): T =
build(Left(new File(path).toURI.toURL))
}


}
@@ -0,0 +1,60 @@
package almond.display

import java.net.URI

final class FileLink private(
val link: String,
val beforeHtml: String,
val afterHtml: String,
val urlPrefix: String,
val displayId: String
) extends UpdatableDisplay {

private def copy(
link: String = link,
beforeHtml: String = beforeHtml,
afterHtml: String = afterHtml,
urlPrefix: String = urlPrefix
): FileLink =
new FileLink(link, beforeHtml, afterHtml, urlPrefix, displayId)

def withLink(link: String): FileLink =
copy(link = link)
def withBeforeHtml(beforeHtml: String): FileLink =
copy(beforeHtml = beforeHtml)
def withAfterHtml(afterHtml: String): FileLink =
copy(afterHtml = afterHtml)
def withUrlPrefix(urlPrefix: String): FileLink =
copy(urlPrefix = urlPrefix)

private def html: String = {
val link0 = new URI(urlPrefix + link).toASCIIString
beforeHtml +
s"""<a href="$link0" target='_blank'>${FileLink.escapeHTML(link)}</a>""" +
afterHtml
}

def data(): Map[String, String] =
Map(Html.mimeType -> html)

}

object FileLink extends {
def apply(link: String): FileLink =
new FileLink(link, "", "<br>", "", UpdatableDisplay.generateId())

// https://stackoverflow.com/a/25228492/3714539
private def escapeHTML(s: String): String = {
val out = new StringBuilder(java.lang.Math.max(16, s.length))
for (i <- 0 until s.length) {
val c = s.charAt(i)
if (c > 127 || c == '"' || c == '<' || c == '>' || c == '&') {
out.append("&#")
out.append(c.toInt)
out.append(';')
} else
out.append(c)
}
out.toString
}
}
@@ -0,0 +1,32 @@
package almond.display

import java.net.URL

final class Html private(
val contentOrUrl: Either[URL, String],
val displayId: String
) extends TextDisplay {

private def copy(
contentOrUrl: Either[URL, String] = contentOrUrl
): Html =
new Html(contentOrUrl, displayId)

def withContent(code: String): Html =
copy(contentOrUrl = Right(code))
def withUrl(url: String): Html =
copy(contentOrUrl = Left(new URL(url)))
def withUrl(url: URL): Html =
copy(contentOrUrl = Left(url))

def data(): Map[String, String] =
Map(Html.mimeType -> finalContent)

}

object Html extends TextDisplay.Builder[Html] {
protected def build(contentOrUrl: Either[URL, String]): Html =
new Html(contentOrUrl, UpdatableDisplay.generateId())

def mimeType: String = "text/html"
}
Oops, something went wrong.

0 comments on commit 9000eaf

Please sign in to comment.
You can’t perform that action at this time.