Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

syntax highlighting patch #5

Closed
wants to merge 6 commits into from

2 participants

@adriaanm

Hi Tiark,

I added a stripped version of highlight.js (I couldn't figure out how to reuse the library as-is). The only difference is that I removed all the DOM manipulation because we know which nodes we want to replace, and I exported the core highlighting function. I highlight on blur and on session load. I also added a <code> tag inside the <pre> to make the CSS from highlight.js reusable.

I'm a total JavaScript/HTML noob, so please be wary of the patch ;-)

It works for me though :-)

adriaan

@TiarkRompf
Owner

cool, I'll take a look after tomorrow. you're highlighting only on blur, not as you type, right?

@adriaanm

yes, blur and session load

adriaanm added some commits
@adriaanm adriaanm closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 11, 2010
  1. @adriaanm
Commits on Oct 12, 2010
  1. @adriaanm

    improved highlighting so it doesnt break inserting new input fields: …

    adriaanm authored
    …removed code tag, using html(newHtml) instead of replaceWith(newNode) to set highlighted code
Commits on Apr 15, 2013
  1. @adriaanm
  2. @adriaanm

    cleanup

    adriaanm authored
Commits on Apr 17, 2013
  1. @adriaanm

    why define an extractor

    adriaanm authored
    when you can interpolate a string instead?
Commits on Jul 11, 2013
  1. @adriaanm

    Update README.md

    adriaanm authored
This page is out of date. Refresh to see the latest.
View
57 README.md
@@ -1,56 +1 @@
-Scala REPL HTML Interface
-=========================
-
-This project provides a Scala REPL with a GUI inspired by Mathematica worksheets. Commands can be edited and deleted, and new commands can be inserted anywhere. Whole worksheets can be re-evaluated with one click. Sessions can be saved and restored.
-
-The frontend is just an HTML page that communicates with a backend servlet via web sockets. The backend servlet does the actual command execution. The servlet is not multi-user save; the program is meant to be run on a single computer.
-
-**CAVEAT**: Right now, this is all highly experimental. And it has been thorougly tested only in Safari.
-
-How to Run it
--------------
-
-After downloading, use SBT to build
-
- sbt update
- sbt compile
-
-and then run the REPL servlet within an embedded Jetty server:
-
- sbt run
-
-Then open the html file that contains the frontend in your browser:
-
- src/main/webapp/index.html
-
-
-
-Accessing Application Classes
------------------------------
-
-The available classes are defined by two system properties, `replhtml.class.path` and `replhtml.extra.class.path`. By default, the former contains the Scala library and compiler jars while the latter can be freely used to load additional code.
-
-For example, the following command:
-
- sbt 'set replhtml.extra.class.path /Users/myself/projects/MyGreatApp/classes/' run
-
-will start the REPL with your application's classes loaded from the specified path, much like `scala -cp` would.
-
-With the backend running, point your browser to
-
- src/main/webapp/index.html
-
-and enjoy!
-
-
-Things to Try
--------------
-
-Use the - and + buttons to remove and insert commands. Hit tab and shift-tab to navigate up and down. Turn on completion (this will display available members but not actually complete your typing). Save and restore sessions.
-
-There is some limited support for interacting with the HTML environment. Text output that begins with `<js>` will be interpreted as JavaScript code. The following code adds a button to the HTML page that displays an alert box when clicked:
-
- def js(code: String) = println("<js>"+code)
- js("$('#container').append($('<button>Click me!</button>').click(function() { alert('hey!') }))")
-
-The `:power` mode is enabled by default. Use `repl` to access the interpreter object, or `servlet` to access the servlet.
+A minimal wrapper to access the Scala repl over websockets.
View
1  build.properties
@@ -0,0 +1 @@
+sbt.version=0.12.+
View
33 project/Build.scala
@@ -0,0 +1,33 @@
+import sbt._
+import Keys._
+
+object ReplHtmlBuild extends Build {
+ val mySettings = Defaults.defaultSettings ++ Seq(
+ organization := "ch.epfl.lamp",
+ name := "replhtml",
+ version := "1.1",
+ scalaVersion := "2.10.1",
+ libraryDependencies := Seq(
+ "org.scala-lang" % "scala-compiler" % "2.10.1",
+ "org.scala-lang" % "scala-reflect" % "2.10.1",
+ "org.scala-lang" % "scala-library" % "2.10.1",
+ "net.databinder" %% "unfiltered-filter" % "0.6.8",
+ "net.databinder" %% "unfiltered-netty-server" % "0.6.8",
+ "net.databinder" %% "unfiltered-netty-websockets" % "0.6.8")
+ )
+
+ val setupReplClassPath = TaskKey[Unit]("setup-repl-classpath", "Set up the repl server's classpath based on our dependencies.")
+
+ lazy val project = Project (
+ "replhtml",
+ file ("."),
+ settings = mySettings ++ Seq(
+ setupReplClassPath <<= (dependencyClasspath in Compile) map {cp =>
+ val cpStr = cp map { case Attributed(str) => str} mkString(System.getProperty("path.separator"))
+ println("Repl will use classpath "+ cpStr)
+ System.setProperty("replhtml.class.path", cpStr)
+ },
+ run in Compile <<= (run in Compile).dependsOn(setupReplClassPath)
+ )
+ )
+}
View
9 project/build.properties
@@ -1,9 +0,0 @@
-#Project properties
-#Sun Oct 03 23:23:22 CEST 2010
-project.organization=epfl.lamp
-project.name=replhtml
-sbt.version=0.7.4
-project.version=1.0
-replhtml.extra.class.path=arrr
-build.scala.versions=2.8.0
-project.initialize=false
View
28 project/build/Project.scala
@@ -1,28 +0,0 @@
-import sbt._
-
-class Project(info: ProjectInfo) extends DefaultWebProject(info)
-{
- val jetty7 = "org.eclipse.jetty" % "jetty-webapp" % "7.1.6.v20100715" % "compile"
- val jetty7webSocket = "org.eclipse.jetty" % "jetty-websocket" % "7.1.6.v20100715" % "compile"
- val servlet = "javax.servlet" % "servlet-api" % "2.5" % "compile"
-
- //override def unmanagedClasspath = super.unmanagedClasspath +++ ("lib2" / "scala-compiler.jar")
- val scalac = "org.scala-lang" % "scala-compiler" % "2.8.0" % "compile"
- val scala = "org.scala-lang" % "scala-library" % "2.8.0" % "compile"
-
- override def mainClass = Some("ch.epfl.lamp.replhtml.ReplMain")
-
- lazy val setupSysProps = task {
- System.setProperty("replhtml.class.path", (runClasspath +++ Path.fromFile(buildScalaInstance.compilerJar) +++
- Path.fromFile(buildScalaInstance.libraryJar)).absString)
- None
- } dependsOn(compile)
-
- override def runAction = task { args => super.runAction(args).dependsOn(setupSysProps) }
-
- // repositories
- val scalaToolsSnapshots = "Scala Tools Repository" at "http://nexus.scala-tools.org/content/repositories/snapshots/"
- val sonatypeNexusSnapshots = "Sonatype Nexus Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
- val sonatypeNexusReleases = "Sonatype Nexus Releases" at "https://oss.sonatype.org/content/repositories/releases"
- val fuseSourceSnapshots = "FuseSource Snapshot Repository" at "http://repo.fusesource.com/nexus/content/repositories/snapshots"
-}
View
69 src/main/scala/ReplMain.scala
@@ -1,30 +1,59 @@
package ch.epfl.lamp.replhtml
-//import javax.servlet.http._
-import org.eclipse.jetty.server.Server
-import org.eclipse.jetty.servlet.ServletContextHandler
-import org.eclipse.jetty.servlet.ServletHolder
-import org.eclipse.jetty.servlet.DefaultServlet
+import unfiltered.netty.websockets._
+import scala.util.matching.Regex
object ReplMain {
def main(args: Array[String]) {
- val server = new Server(8080)
+ val sockets = collection.mutable.ListBuffer.empty[WebSocket]
+ // TODO: WebSocketServer is deprecated in unfiltered 0.6.8
+ WebSocketServer("/socket/repl", 8080) {
+ case Open(s) => sockets += s
+ case Message(s, Text(str)) => println(s"message: $str")
+ val resp = interpret(str); println(s"Response: $resp")
+ sockets foreach (_.send(resp))
+ case Close(s) => sockets -= s
+ case Error(s, e) => println(s"error ${e.getMessage}")
+ } run ()
+ }
+
+ import scala.tools.nsc._
+ import scala.tools.nsc.interpreter._
- val context = new ServletContextHandler(ServletContextHandler.SESSIONS)
- context.setContextPath("/")
- server.setHandler(context)
+ val cmd = new CommandLine(Nil, println)
+ import cmd.settings
+ settings.classpath.value = System.getProperty("replhtml.class.path")
- context.addServlet(new ServletHolder(new ReplServlet()),"/socket/*")
- context.addServlet(new ServletHolder(new DefaultServlet()),"/*")
+ val interpreter = new IMain(settings)
+ val completion = new JLineCompletion(interpreter)
+ // interpreter.bind("servlet", "ch.epfl.lamp.replhtml.ReplServlet", ReplServlet.this) }
+ // interpreter.unleash()
+
+ def interpret(data: String): String = {
+ // TODO: use json
+ implicit class RContext(sc: StringContext) {
+ def rx = new Regex(sc.parts.mkString(""), sc.parts.tail.map(_ => "x"): _*)
+ }
+ object I { def unapply(x: String): Option[Int] = scala.util.Try { x.toInt } toOption }
+ data.split(":", 2) match {
+ case Array(rx"""complete@(\d*)${I(pos)}""", source) =>
+ "<completion>:" + pos + "\n" + {
+ lazy val tokens = source.substring(0, pos).split("""[\ \,\;\(\)\{\}]""") // could tokenize on client
+ if (pos <= source.length && tokens.nonEmpty)
+ completion.topLevelFor(Parsed.dotted(tokens.last, pos) withVerbosity 4).mkString("\n")
+ else ""
+ }
- server.start()
- println(">>> embedded jetty server started. press any key to stop.")
- while (System.in.available() == 0) {
- Thread.sleep(1500)
+ case Array("run", source) =>
+ util.stringFromStream { ostream =>
+ Console.withOut(ostream) {
+ interpreter.interpret(source) match {
+ case IR.Error => println("<done:error>")
+ case IR.Success => println("<done:success>")
+ case IR.Incomplete => println("<done:incomplete>")
+ }
+ }
+ }
}
- System.in.read()
- println(">>> stopping...")
- server.stop()
- server.join()
}
-}
+}
View
107 src/main/scala/ReplServlet.scala
@@ -1,107 +0,0 @@
-package ch.epfl.lamp.replhtml
-
-import scala.collection.mutable.Set
-import java.io.{ OutputStream, PrintStream }
-import javax.servlet.http._
-import org.eclipse.jetty.websocket._
-import org.eclipse.jetty.websocket.WebSocket.Outbound
-
-import scala.tools.nsc._
-import scala.tools.nsc.interpreter._
-
-class ReplServlet extends WebSocketServlet {
- val clients = Set.empty[ReplWebSocket]
-
- var classpath = System.getProperty("replhtml.class.path")
- assert(classpath ne null, "System property replhtml.class.path is not set. Repl needs a class path to operate.")
- classpath += System.getProperty("path.separator") + System.getProperty("replhtml.extra.class.path", "")
- println(classpath)
- println("EXTRA:"+System.getProperty("replhtml.extra.class.path"))
-
- val cmd = new InterpreterCommand(Nil, println)
- val settings = cmd.settings//new Settings
- settings.classpath.value = classpath
-// settings.usejavacp.value = true
-//settings.Ycompletion.value = true
- val interpreter = new Interpreter(settings) {
- override def reset() = { super.reset; unleash() }
- override def unleash() = { super.unleash; bind("servlet", "ch.epfl.lamp.replhtml.ReplServlet", ReplServlet.this) }
- }
- interpreter.unleash()
- val completion = new Completion(interpreter)
-
- override def doGet(req: HttpServletRequest, res: HttpServletResponse) =
- getServletContext.getNamedDispatcher("default").forward(req, res)
-
- override def doWebSocketConnect(req:HttpServletRequest, protocol:String ) =
- new ReplWebSocket
-
- class WebSocketPrintStream(cls: Set[ReplWebSocket]) extends PrintStream(new OutputStream { def write(b: Int) = {} }) {
-
- override def print(message: String) = {
- cls.foreach { c => c.outbound.sendMessage(0:Byte, message) }
- }
-/*
- override def println(message: String) = {
- clients.foreach { c => c.outbound.sendMessage(0:Byte, message+"\n\r") }
- }
- override def println() = {
- clients.foreach { c => c.outbound.sendMessage(0:Byte, "\n\r") }
- }
-*/
- }
-
-
- class ReplWebSocket extends WebSocket {
-
- var outbound:Outbound = _
-
- override def onConnect(outbound:Outbound) = {
- this.outbound = outbound
- clients += this
- }
-
- override def onMessage(frame:Byte, data:Array[Byte], offset:Int, length:Int) = {}
-
- override def onMessage(frame:Byte, data:String) = {
- val idx = data.indexOf(":")
- val key = if (idx > 0) data.substring(0,idx) else ""
- var source = if (idx >= 0) data.substring(idx+1) else data
- key match {
- case "complete" =>
-
- val out = new WebSocketPrintStream(Set(this))
-
- val idx = source.indexOf(":")
- val ipos = Integer.parseInt(source.substring(0,idx))
- source = source.substring(idx+1)
-
- if (ipos <= source.length) {
- val tokens = source.substring(0,ipos).split("""[\ \,\;\(\)\{\}]""") // could tokenize on client
- //println("try to complete: " + tokens.mkString(","))
- if (!tokens.isEmpty) {
- val cmpl = completion.topLevelFor(Parsed.dotted(tokens.last, ipos) withVerbosity 4) // (?)
- out.println("<completion>:"+ipos+"\n"+cmpl.mkString("\n"))
- } else {
- out.println("<completion>:"+ipos+"\n")
- }
- } else {
- out.println("<completion>:"+ipos+"\n")
- }
- //interpreter.requestFromLine(source)
-
- case _ =>
- Console.withOut(new WebSocketPrintStream(Set(this))) {
- interpreter.interpret(source) match {
- case InterpreterResults.Error => println("<done:error>")
- case InterpreterResults.Success => println("<done:success>")
- case InterpreterResults.Incomplete => println("<done:incomplete>")
- }
- }
- }
- }
-
- override def onDisconnect = clients -= this
-
- }
-}
View
584 src/main/webapp/index.html
@@ -3,6 +3,577 @@
<head>
<meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
+<!-- highlight.js stuff -->
+<script>
+// stripped version of highlight.js (http://softwaremaniacs.org/soft/highlight/) that exposes the core highlight() function
+// differences from upstream: removed DOM manipulating functions, call initialize() from highlight() and expose highlight() in hljs object
+// copy/pasted scala.js language definition at the end
+
+var hljs = new function() {
+ var LANGUAGES = {}
+ // selected_languages is used to support legacy mode of selecting languages
+ // available for highlighting by passing them as arguments into
+ // initHighlighting function. Currently the whole library is expected to
+ // contain only those language definitions that are actually get used.
+ var selected_languages = {};
+
+ /* Utility functions */
+
+ function escape(value) {
+ return value.replace(/&/gm, '&amp;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;');
+ }
+
+ function contains(array, item) {
+ if (!array)
+ return false;
+ for (var i = 0; i < array.length; i++)
+ if (array[i] == item)
+ return true;
+ return false;
+ }
+
+ function langRe(language, value, global) {
+ var mode = 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '');
+ return new RegExp(value, mode);
+ }
+
+ /* Core highlighting function */
+
+ function highlight(language_name, value) {
+ initialize()
+ function subMode(lexem, mode) {
+ for (var i = 0; i < mode.sub_modes.length; i++) {
+ if (mode.sub_modes[i].beginRe.test(lexem)) {
+ return mode.sub_modes[i];
+ }
+ }
+ return null;
+ }
+
+ function endOfMode(mode_index, lexem) {
+ if (modes[mode_index].end && modes[mode_index].endRe.test(lexem))
+ return 1;
+ if (modes[mode_index].endsWithParent) {
+ var level = endOfMode(mode_index - 1, lexem);
+ return level ? level + 1 : 0;
+ }
+ return 0;
+ }
+
+ function isIllegal(lexem, mode) {
+ return mode.illegalRe && mode.illegalRe.test(lexem);
+ }
+
+ function compileTerminators(mode, language) {
+ var terminators = [];
+
+ for (var i = 0; i < mode.sub_modes.length; i++) {
+ terminators.push(mode.sub_modes[i].begin);
+ }
+
+ var index = modes.length - 1;
+ do {
+ if (modes[index].end) {
+ terminators.push(modes[index].end);
+ }
+ index--;
+ } while (modes[index + 1].endsWithParent);
+
+ if (mode.illegal) {
+ terminators.push(mode.illegal);
+ }
+
+ return langRe(language, '(' + terminators.join('|') + ')', true);
+ }
+
+ function eatModeChunk(value, index) {
+ var mode = modes[modes.length - 1];
+ if (!mode.terminators) {
+ mode.terminators = compileTerminators(mode, language);
+ }
+ mode.terminators.lastIndex = index;
+ var match = mode.terminators.exec(value);
+ if (match)
+ return [value.substr(index, match.index - index), match[0], false];
+ else
+ return [value.substr(index), '', true];
+ }
+
+ function keywordMatch(mode, match) {
+ var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0]
+ for (var className in mode.keywordGroups) {
+ if (!mode.keywordGroups.hasOwnProperty(className))
+ continue;
+ var value = mode.keywordGroups[className].hasOwnProperty(match_str);
+ if (value)
+ return [className, value];
+ }
+ return false;
+ }
+
+ function processKeywords(buffer, mode) {
+ if (!mode.keywords || !mode.lexems)
+ return escape(buffer);
+ if (!mode.lexemsRe) {
+ var lexems_re = '(' + mode.lexems.join('|') + ')';
+ mode.lexemsRe = langRe(language, lexems_re, true);
+ }
+ var result = '';
+ var last_index = 0;
+ mode.lexemsRe.lastIndex = 0;
+ var match = mode.lexemsRe.exec(buffer);
+ while (match) {
+ result += escape(buffer.substr(last_index, match.index - last_index));
+ var keyword_match = keywordMatch(mode, match);
+ if (keyword_match) {
+ keyword_count += keyword_match[1];
+ result += '<span class="'+ keyword_match[0] +'">' + escape(match[0]) + '</span>';
+ } else {
+ result += escape(match[0]);
+ }
+ last_index = mode.lexemsRe.lastIndex;
+ match = mode.lexemsRe.exec(buffer);
+ }
+ result += escape(buffer.substr(last_index, buffer.length - last_index));
+ return result;
+ }
+
+ function processBuffer(buffer, mode) {
+ if (mode.subLanguage && selected_languages[mode.subLanguage]) {
+ var result = highlight(mode.subLanguage, buffer);
+ keyword_count += result.keyword_count;
+ relevance += result.relevance;
+ return result.value;
+ } else {
+ return processKeywords(buffer, mode);
+ }
+ }
+
+ function startNewMode(mode, lexem) {
+ var markup = mode.noMarkup?'':'<span class="' + mode.displayClassName + '">';
+ if (mode.returnBegin) {
+ result += markup;
+ mode.buffer = '';
+ } else if (mode.excludeBegin) {
+ result += escape(lexem) + markup;
+ mode.buffer = '';
+ } else {
+ result += markup;
+ mode.buffer = lexem;
+ }
+ modes[modes.length] = mode;
+ }
+
+ function processModeInfo(buffer, lexem, end) {
+ var current_mode = modes[modes.length - 1];
+ if (end) {
+ result += processBuffer(current_mode.buffer + buffer, current_mode);
+ return false;
+ }
+
+ var new_mode = subMode(lexem, current_mode);
+ if (new_mode) {
+ result += processBuffer(current_mode.buffer + buffer, current_mode);
+ startNewMode(new_mode, lexem);
+ relevance += new_mode.relevance;
+ return new_mode.returnBegin;
+ }
+
+ var end_level = endOfMode(modes.length - 1, lexem);
+ if (end_level) {
+ var markup = current_mode.noMarkup?'':'</span>';
+ if (current_mode.returnEnd) {
+ result += processBuffer(current_mode.buffer + buffer, current_mode) + markup;
+ } else if (current_mode.excludeEnd) {
+ result += processBuffer(current_mode.buffer + buffer, current_mode) + markup + escape(lexem);
+ } else {
+ result += processBuffer(current_mode.buffer + buffer + lexem, current_mode) + markup;
+ }
+ while (end_level > 1) {
+ markup = modes[modes.length - 2].noMarkup?'':'</span>';
+ result += markup;
+ end_level--;
+ modes.length--;
+ }
+ var last_ended_mode = modes[modes.length - 1];
+ modes.length--;
+ modes[modes.length - 1].buffer = '';
+ if (last_ended_mode.starts) {
+ for (var i = 0; i < language.modes.length; i++) {
+ if (language.modes[i].className == last_ended_mode.starts) {
+ startNewMode(language.modes[i], '');
+ break;
+ }
+ }
+ }
+ return current_mode.returnEnd;
+ }
+
+ if (isIllegal(lexem, current_mode))
+ throw 'Illegal';
+ }
+
+ var language = LANGUAGES[language_name];
+ var modes = [language.defaultMode];
+ var relevance = 0;
+ var keyword_count = 0;
+ var result = '';
+ try {
+ var index = 0;
+ language.defaultMode.buffer = '';
+ do {
+ var mode_info = eatModeChunk(value, index);
+ var return_lexem = processModeInfo(mode_info[0], mode_info[1], mode_info[2]);
+ index += mode_info[0].length;
+ if (!return_lexem) {
+ index += mode_info[1].length;
+ }
+ } while (!mode_info[2]);
+ if(modes.length > 1)
+ throw 'Illegal';
+ return {
+ relevance: relevance,
+ keyword_count: keyword_count,
+ value: result
+ }
+ } catch (e) {
+ if (e == 'Illegal') {
+ return {
+ relevance: 0,
+ keyword_count: 0,
+ value: escape(value)
+ }
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ /* Initialization */
+
+ function compileModes() {
+
+ function compileMode(mode, language) {
+ if (mode.compiled)
+ return;
+
+ if (mode.begin)
+ mode.beginRe = langRe(language, '^' + mode.begin);
+ if (mode.end)
+ mode.endRe = langRe(language, '^' + mode.end);
+ if (mode.illegal)
+ mode.illegalRe = langRe(language, '^(?:' + mode.illegal + ')');
+ if (mode.relevance == undefined)
+ mode.relevance = 1;
+ if (!mode.displayClassName)
+ mode.displayClassName = mode.className;
+ if (!mode.className)
+ mode.noMarkup = true;
+ for (var key in mode.keywords) {
+ if (!mode.keywords.hasOwnProperty(key))
+ continue;
+ if (mode.keywords[key] instanceof Object)
+ mode.keywordGroups = mode.keywords;
+ else
+ mode.keywordGroups = {'keyword': mode.keywords};
+ break;
+ }
+ mode.sub_modes = [];
+ if (mode.contains) {
+ for (var i = 0; i < mode.contains.length; i++) {
+ if (mode.contains[i] instanceof Object) { // inline mode
+ mode.sub_modes.push(mode.contains[i]);
+ } else { // named mode
+ for (var j = 0; j < language.modes.length; j++) {
+ if (language.modes[j].className == mode.contains[i]) {
+ mode.sub_modes.push(language.modes[j]);
+ }
+ }
+ }
+ }
+ }
+ // compiled flag is set before compiling submodes to avoid self-recursion
+ // (see lisp where quoted_list contains quoted_list)
+ mode.compiled = true;
+ for (var i = 0; i < mode.sub_modes.length; i++) {
+ compileMode(mode.sub_modes[i], language);
+ }
+ }
+
+ for (var i in LANGUAGES) {
+ if (!LANGUAGES.hasOwnProperty(i))
+ continue;
+ var modes = [LANGUAGES[i].defaultMode].concat(LANGUAGES[i].modes);
+ for (var j = 0; j < modes.length; j++) {
+ compileMode(modes[j], LANGUAGES[i]);
+ }
+ }
+ }
+
+ function initialize() {
+ if (initialize.called)
+ return;
+ initialize.called = true;
+ compileModes();
+ selected_languages = LANGUAGES;
+ }
+
+
+ /* Interface definition */
+
+ this.LANGUAGES = LANGUAGES;
+ this.highlight = highlight;
+
+ // Common regexps
+ this.IMMEDIATE_RE = '\\b|\\B'
+ this.IDENT_RE = '[a-zA-Z][a-zA-Z0-9_]*';
+ this.UNDERSCORE_IDENT_RE = '[a-zA-Z_][a-zA-Z0-9_]*';
+ this.NUMBER_RE = '\\b\\d+(\\.\\d+)?';
+ this.C_NUMBER_RE = '\\b(0x[A-Za-z0-9]+|\\d+(\\.\\d+)?)';
+ this.RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~';
+
+ // Common modes
+ this.APOS_STRING_MODE = {
+ className: 'string',
+ begin: '\'', end: '\'',
+ illegal: '\\n',
+ contains: ['escape'],
+ relevance: 0
+ };
+ this.QUOTE_STRING_MODE = {
+ className: 'string',
+ begin: '"', end: '"',
+ illegal: '\\n',
+ contains: ['escape'],
+ relevance: 0
+ };
+ this.BACKSLASH_ESCAPE = {
+ className: 'escape',
+ begin: '\\\\.', end: this.IMMEDIATE_RE, noMarkup: true,
+ relevance: 0
+ };
+ this.C_LINE_COMMENT_MODE = {
+ className: 'comment',
+ begin: '//', end: '$',
+ relevance: 0
+ };
+ this.C_BLOCK_COMMENT_MODE = {
+ className: 'comment',
+ begin: '/\\*', end: '\\*/'
+ };
+ this.HASH_COMMENT_MODE = {
+ className: 'comment',
+ begin: '#', end: '$'
+ };
+ this.NUMBER_MODE = {
+ className: 'number',
+ begin: this.NUMBER_RE, end: this.IMMEDIATE_RE,
+ relevance: 0
+ };
+ this.C_NUMBER_MODE = {
+ className: 'number',
+ begin: this.C_NUMBER_RE, end: this.IMMEDIATE_RE,
+ relevance: 0
+ };
+
+ // Utility functions
+ this.inherit = function(parent, obj) {
+ var result = {}
+ for (var key in parent)
+ result[key] = parent[key];
+ if (obj)
+ for (var key in obj)
+ result[key] = obj[key];
+ return result;
+ }
+}();
+
+/*
+Language: Scala
+Author: Jan Berkel <jan.berkel@gmail.com>
+
+languages/scala.js from the highlight.js distribution
+*/
+
+hljs.LANGUAGES.scala = {
+ defaultMode: {
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ contains: ['javadoc', 'comment', 'string', 'class', 'number', 'annotation'],
+ keywords: { 'type': 1, 'yield': 1, 'lazy': 1, 'implicit': 1, 'override': 1, 'def': 1, 'with': 1, 'val':1, 'var': 1, 'false': 1, 'true': 1, 'sealed': 1, 'abstract': 1, 'private': 1, 'trait': 1, 'object': 1, 'null': 1, 'if': 1, 'for': 1, 'while': 1, 'throw': 1, 'finally': 1, 'protected': 1, 'extends': 1, 'import': 1, 'final': 1, 'return': 1, 'else': 1, 'break': 1, 'new': 1, 'catch': 1, 'super': 1, 'class': 1, 'case': 1,'package': 1, 'default': 1, 'try': 1, 'this': 1, 'match': 1, 'continue': 1, 'throws': 1}
+ },
+ modes: [
+ {
+ className: 'class',
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ begin: '((case )?class |object |trait )', end: '({|$)',
+ illegal: ':',
+ keywords: {'case' : 1, 'class': 1, 'trait': 1, 'object': 1},
+ contains: [
+ {
+ begin: '(extends|with)', end: hljs.IMMEDIATE_RE,
+ lexems: [hljs.IDENT_RE],
+ keywords: {'extends': 1, 'with': 1},
+ relevance: 10
+ },
+ {
+ className: 'title',
+ begin: hljs.UNDERSCORE_IDENT_RE, end: hljs.IMMEDIATE_RE
+ },
+ {
+ className: 'params',
+ begin: '\\(', end: '\\)',
+ contains: ['string', 'annotation']
+ }
+ ]
+ },
+ hljs.C_NUMBER_MODE,
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.BACKSLASH_ESCAPE,
+ hljs.C_LINE_COMMENT_MODE,
+ {
+ className: 'javadoc',
+ begin: '/\\*\\*', end: '\\*/',
+ contains: [{
+ className: 'javadoctag',
+ begin: '@[A-Za-z]+', end: hljs.IMMEDIATE_RE
+ }],
+ relevance: 10
+ },
+ hljs.C_BLOCK_COMMENT_MODE,
+ {
+ className: 'annotation',
+ begin: '@[A-Za-z]+', end: hljs.IMMEDIATE_RE
+ },
+ {
+ className: 'string',
+ begin: 'u?r?"""', end: '"""',
+ relevance: 10
+ }
+ ]
+};
+</script>
+<style type="text/css">
+/*
+
+Intellij Idea-like styling (c) Vasily Polovnyov <vast@whiteants.net>
+
+styles/idea.css from the highlight.js distribution (except padding was removed from `pre code`)
+*/
+
+pre {
+ display: block;
+ color: #000;
+ background: #fff;
+}
+
+pre .subst,
+pre .title {
+ font-weight: normal;
+ color: #000;
+}
+
+pre .comment,
+pre .template_comment,
+pre .javadoc,
+pre .diff .header {
+ color: #808080;
+ font-style: italic;
+}
+
+pre .annotation,
+pre .decorator,
+pre .preprocessor,
+pre .doctype,
+pre .pi,
+pre .chunk,
+pre .shebang,
+pre .apache .cbracket {
+ color: #808000;
+}
+
+pre .tag,
+pre .pi {
+ background: #efefef;
+}
+
+pre .tag .title,
+pre .id,
+pre .attr_selector,
+pre .pseudo,
+pre .literal,
+pre .keyword,
+pre .hexcolor,
+pre .css .function,
+pre .ini .title,
+pre .css .class,
+pre .list .title,
+pre .tex .command {
+ font-weight: bold;
+ color: #000080;
+}
+
+pre .attribute,
+pre .rules .keyword,
+pre .number,
+pre .date,
+pre .regexp,
+pre .tex .special {
+ font-weight: bold;
+ color: #0000ff;
+}
+
+pre .number,
+pre .regexp {
+ font-weight: normal;
+}
+
+pre .string,
+pre .value,
+pre .filter .argument,
+pre .css .function .params,
+pre .apache .tag {
+ color: #008000;
+ font-weight: bold;
+}
+
+pre .symbol,
+pre .ruby .symbol .string,
+pre .ruby .symbol .keyword,
+pre .ruby .symbol .keymethods,
+pre .char,
+pre .tex .formula {
+ color: #000;
+ background: #d0eded;
+ font-style: italic;
+}
+
+pre .phpdoc,
+pre .yardoctag,
+pre .javadoctag {
+ text-decoration: underline;
+}
+
+pre .variable,
+pre .envvar,
+pre .apache .sqbracket,
+pre .nginx .built_in {
+ color: #660e7a;
+}
+
+pre .addition {
+ background: #baeeba;
+}
+
+pre .deletion {
+ background: #ffc8bd;
+}
+
+pre .diff .change {
+ background: #bccff9;
+}
+</style>
+
<style type="text/css">
body {
font-family: sans-serif;
@@ -300,7 +871,12 @@
}
// ------------ box creation / deletion
-
+ function highlight(input) {
+ var result = hljs.highlight('scala', input.text()).value
+ if (result) {
+ input.html(result)
+ }
+ }
function newBox(after) {
var box = $('<div class="box">'+
' <div class="runIn"><span class="prompt">scala&gt</span><span class="buttons"><span class="remove">-</span>&nbsp;<span class="add">+</span></span></div><pre class="input">'+settings.inputDefault+'</pre>'+
@@ -321,7 +897,7 @@
}
} else if (event.keyCode == 0) { // ctrl+space (at least on Safari) -> explicit completion
if (event.ctrlKey) {
- var mode = "complete:"+window.getSelection().getRangeAt(0).endOffset
+ var mode = "complete@"+window.getSelection().getRangeAt(0).endOffset
send($(this), mode)
return false
}
@@ -334,7 +910,7 @@
completionTimer = null
var sel = window.getSelection()
if (sel.rangeCount) {
- var mode = "complete:"+sel.getRangeAt(0).endOffset
+ var mode = "complete@"+sel.getRangeAt(0).endOffset+"]"
send(box, mode)
} else $("#globalCompletions").text("")
},50)
@@ -345,6 +921,7 @@
$('.completions',box).text("").hide()
$('#globalCompletions').text("")
$('.buttons',box).removeClass('shown')
+ highlight($(this))
})
$('.input',box).focus(function(event) {
$('.buttons',box).addClass('shown')
@@ -390,6 +967,7 @@
var box = newBox()
var rec = array[i]
$('.input',box).text(rec.input);
+ highlight($('.input',box));
$('.output',box).text(rec.output);
message("loaded " + key)
}
Something went wrong with that request. Please try again.