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.jsto render the Playground widget examplesfolder 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\imgfolder from the frontend repository to thepublic/img - Copy the
dist/playground.min.jsto thepublic - Copy the
examples-highlight.cssandexamples-highlight.cssfrom thedist\examplesto thepublicfolder. - You can copy
examples\index.htmlas it is to thepublicand change theline to<script src='../playground.js' data-selector='.kotlin-code'></script>to use local server (change port if necessary).<script src='playground.min.js' data-selector='.kotlin-code' data-server='http://127.0.0.1:8080'></script> - 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: 980px; margin: 50px 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
./gradlew bootJarand run with
java -jar build/libs/kotlin-compiler-server-1.7.20-SNAPSHOT.jarCustomizations
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.ktfrom default 32 Mb -memoryLimit = 32, - Change timeout in the
src/main/kotlin/com/compiler/server/executor/JavaExecutor.ktfrom default 10 secondsconst val EXECUTION_TIMEOUT = 10000L. - Modify the JVM arguments in the same
JavaExecutor.kt, classCommandLineArgument
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.