Table of contents
Open Table of contents
Kotlin Playground
You might see Kotlin Playground on the https://play.kotlinlang.org/ page.
It is also widely used in the official documentation portal .
It is open-source, so we can run it in the local environment or using a custom server.
There might be a few reasons one needs to run it separately:
Use custom libraries (official Playground supports only standard libraries) to deploy Playground for internal projects
Use the server side in some projects for auto-complete, checking syntax if you don’t want to send the code fragments to 3rd party servers.
Modify the frontend part to support customized behavior: e.g., you can add image rendering for a playground for the image rendering library.
How to build the frontend part
Download or clone source code from the GitHub
Run yarn install
and yarn build:all
The dist
folder will contain the build results:
You can use dist/playground.min.js
to render the Playground widget
examples
folder has a sample HTML page for tests.
How to run the server part
Download or clone source code from the GitHub
Create a public
folder in the /src/main/resources
to serve the frontend resources:
Copy the src\img
folder from the frontend repository to the public/img
Copy the dist/playground.min.js
to the public
Copy the examples-highlight.css
and examples-highlight.css
from the dist\examples
to the public
folder.
You can copy examples\index.html
as it is to the public
and change the
< script src = '../playground.js' data-selector = '.kotlin-code' ></ script >
line to
< script src = 'playground.min.js' data-selector = '.kotlin-code' data-server = 'http://127.0.0.1:8080' ></ script >
to use local server (change port if necessary).
Or you can use a simple HTML file like:
<! doctype html >
< html >
< head >
< meta charset = "UTF-8" />
< title >Kotlin Playground examples</ title >
< link rel = "stylesheet" href = "examples.css" />
< link rel = "stylesheet" href = "examples-highlight.css" />
< style >
.markdown-body {
max-width : 980 px ;
margin : 50 px auto ;
}
</ style >
< script src = "playground.min.js" data-selector = ".kotlin-code" data-server = "http://127.0.0.1:8080" ></ script >
</ head >
< body class = "markdown-body" >
< h1 >Kotlin Playground demo</ h1 >
< pre >
< code class = "kotlin-code" data-crosslink = "disabled" auto-indent = "true" >
class Contact(val id: Int, var email: String)
fun main(args:Array < String > ) {
val contact = Contact(1, " mary@gmail.com " )
println(contact.id)
}
</ code >
</ pre >
</ body >
</ html >
You can refer to the whole list of options for the script
part and the code
element in the frontend project README.md
Run from IDE, main class is com.compiler.server.CompilerApplication
or build with
and run with
java -jar build/libs/kotlin-compiler-server-1.7.20-SNAPSHOT.jar
Customizations
Server part
Server runs code as a separate process and you can modify the JVM options:
Follow the guide from README.md to add custom dependencies to the Playground’s classpath
Change memory limit src/main/kotlin/com/compiler/server/compiler/components/KotlinCompiler.kt
from default 32 Mb - memoryLimit = 32,
Change timeout in the src/main/kotlin/com/compiler/server/executor/JavaExecutor.kt
from default 10 seconds const val EXECUTION_TIMEOUT = 10000L
.
Modify the JVM arguments in the same JavaExecutor.kt
, class CommandLineArgument
FrontEnd
You can modify the executeKotlinCode
function in src/webdemo-api.js
:
case TargetPlatform . JAVA :
if ( data . text ) output = processJVMOutput ( data . text , theme );
break ;
processJVMOutput
generates raw HTML code based on the output from the server side.
Or we can even create new TargetPlatform
(target platform is one of the html element attributes like <code data-target-platform="java">
), correspondent value should be addes to the server side ProjectType
enum.
E.g., we want to have custom render for the code output:
Server side :
enum class ProjectType ( @JsonValue val id: String ) {
JAVA ( "java" ),
JAVA_CUSTOM ( "java-custom" ),
JUNIT ( "junit" ),
CANVAS ( "canvas" ),
JS ( "js" ),
JS_IR ( "js-ir" );
fun isJsRelated (): Boolean = this == JS || this == JS_IR || this == CANVAS
}
ProjectType.JAVA -> kotlinProjectExecutor. run (project)
ProjectType.JAVA_CUSTOM -> kotlinProjectExecutor. run (project)
FrontEnd :
class TargetPlatform {
constructor ( id , printableName ) {
this . id = id ;
this . printableName = printableName ;
}
static getById ( id ) {
switch ( id ) {
case 'js' :
return TargetPlatform . JS ;
case 'js-ir' :
return TargetPlatform . JS_IR ;
case 'junit' :
return TargetPlatform . JUNIT ;
case 'java-custom' :
return TargetPlatform . JAVA_CUSTOM ;
case 'canvas' :
return TargetPlatform . CANVAS ;
default :
return TargetPlatform . JAVA ;
}
}
static isJavaRelated ( platform ) {
return (
platform === TargetPlatform . JAVA ||
platform === TargetPlatform . JAVA_CUSTOM ||
platform === TargetPlatform . JUNIT
);
}
static isJsRelated ( platform ) {
return (
platform === TargetPlatform . JS ||
platform === TargetPlatform . JS_IR ||
platform === TargetPlatform . CANVAS
);
}
}
TargetPlatform . JS = new TargetPlatform ( 'js' , 'JavaScript' );
TargetPlatform . JS_IR = new TargetPlatform ( 'js-ir' , 'JavaScript IR' );
TargetPlatform . JAVA = new TargetPlatform ( 'java' , 'JVM' );
TargetPlatform . JAVA_CUSTOM = new TargetPlatform ( 'java-custom' , 'JVM SVG' );
TargetPlatform . JUNIT = new TargetPlatform ( 'junit' , 'JUnit' );
TargetPlatform . CANVAS = new TargetPlatform ( 'canvas' , 'JavaScript(canvas)' );
export default TargetPlatform ;
export const API_URLS = {
server : RUNTIME_CONFIG . server || __WEBDEMO_URL__ ,
COMPILE ( platform , version ) {
let url ;
switch ( platform ) {
case TargetPlatform . JAVA :
case TargetPlatform . JAVA_CUSTOM :
url = ` ${ this . server } /api/ ${ version } /compiler/run` ;
break ;
// ... rest of the code
}
}
}
static executeKotlinCode ( code , compilerVersion , platform , args , theme , hiddenDependencies , onTestPassed , onTestFailed ) {
return executeCode ( API_URLS . COMPILE ( platform , compilerVersion ), code , compilerVersion , platform , args , hiddenDependencies ). then ( function ( data ) {
let output = "" ;
let errorsAndWarnings = flatten ( Object . values ( data . errors ));
let errors = errorsAndWarnings . filter ( error => error . severity === "ERROR" );
if ( errors . length > 0 ) {
output = processErrors ( errors , theme );
} else {
switch ( platform ) {
case TargetPlatform . JAVA :
if ( data . text ) output = processJVMOutput ( data . text , theme );
break ;
case TargetPlatform . JAVA_CUSTOM :
if ( data . text ) output = processJVMOutputCustom ( data . text , theme );
break ;
// rest of the code
}
})
}
and implement the processJVMOutputCustom
function similar to the processJVMOutput
.