{"id":15402039,"url":"https://github.com/mpollmeier/scala-repl-pp","last_synced_at":"2026-01-30T06:35:03.117Z","repository":{"id":64437983,"uuid":"554681775","full_name":"mpollmeier/scala-repl-pp","owner":"mpollmeier","description":"Scala REPL enhancements","archived":false,"fork":false,"pushed_at":"2025-07-14T15:14:13.000Z","size":1491,"stargazers_count":23,"open_issues_count":37,"forks_count":3,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-07-14T18:33:03.418Z","etag":null,"topics":["repl","scala","scripting"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mpollmeier.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-10-20T07:58:56.000Z","updated_at":"2025-07-14T15:14:16.000Z","dependencies_parsed_at":"2023-10-04T14:57:54.325Z","dependency_job_id":"6dfd1722-b89c-4341-b74c-7080e4f8478c","html_url":"https://github.com/mpollmeier/scala-repl-pp","commit_stats":null,"previous_names":[],"tags_count":189,"template":false,"template_full_name":null,"purl":"pkg:github/mpollmeier/scala-repl-pp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpollmeier%2Fscala-repl-pp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpollmeier%2Fscala-repl-pp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpollmeier%2Fscala-repl-pp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpollmeier%2Fscala-repl-pp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mpollmeier","download_url":"https://codeload.github.com/mpollmeier/scala-repl-pp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpollmeier%2Fscala-repl-pp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28906663,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T04:02:34.702Z","status":"ssl_error","status_checked_at":"2026-01-30T04:02:33.562Z","response_time":66,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["repl","scala","scripting"],"created_at":"2024-10-01T15:59:57.462Z","updated_at":"2026-01-30T06:35:03.102Z","avatar_url":"https://github.com/mpollmeier.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# srp \u003c scala-repl-pp \u003c Scala REPL PlusPlus\n\u003cimg src=\"demo.gif\" height=\"300\" /\u003e \u003cimg src=\"https://github.com/user-attachments/assets/04bbb50b-dd9a-4aa4-b3dd-f9e21f5d6ead\" height=\"300\" /\u003e\n\n`srp` enhances the stock Scala 3 REPL with pretty rendering, dependency handling, better scripting, runBefore code etc., makes it more customizable and let's you embed it into your project as a regular library dependency. \\\nWhen you read `srp` think \"syrup\" - full of goodness, glues things together :slightly_smiling_face:\n\nComparing `srp` and regular `scala` REPL side by side - `srp` uses pprint for pretty structured rendering including product labels. \n\u003cimg src=\"pretty-printing.png\" height=\"200\"/\u003e\n\n# Quick start\n\nEither download a binary...\n```bash\ncurl -fL https://github.com/mpollmeier/scala-repl-pp/releases/latest/download/srp.zip \u003e srp.zip\nunzip srp.zip\nsrp/bin/srp\n```\n\n... or add it as a library to your project, empowering it with a customizable REPL and scripting functionality. \u003cbr/\u003e\nThere's a [demo project](core/src/test/resources/demo-project) to get you started.\n```\nlibraryDependencies += \"com.michaelpollmeier\" % \"scala-repl-pp_3.7.0\" % \"0.5.5\"\n```\n\n# Table of contents\n\u003c!-- generated with:\nmarkdown-toc --maxdepth 2 README.md|tail -n +4 \n--\u003e\n- [Basic usage](#basic-usage)\n- [REPL, scripting and server mode features](#repl-scripting-and-server-mode-features)\n  * [`runBefore`: execute code at startup](#runbefore-execute-code-at-startup)\n  * [`predef`: add source files to the classpath](#predef-add-source-files-to-the-classpath)\n  * [`using file` directive: import additional files](#using-file-directive-import-additional-files)\n  * [`verbose` mode](#verbose-mode)\n  * [`#\u003e`, `#\u003e\u003e` and `#|` operators: redirect to file, pipe to external command](#%23-%23-and-%23-operators-redirect-to-file-pipe-to-external-command)\n  * [`dep`: add dependencies via maven coordinates](#dep-add-dependencies-via-maven-coordinates)\n  * [`repo`: add dependency resolvers](#repo-add-dependency-resolvers)\n  * [`classpathEntry`: additional classpath entries](#classpathentry-additional-classpath-entries)\n- [REPL-only features](#repl-only-features)\n  * [Rendering of output](#rendering-of-output)\n  * [Exiting the REPL](#exiting-the-repl)\n  * [customize prompt, greeting and exit code](#customize-prompt-greeting-and-exit-code)\n  * [Looking up the current terminal width](#looking-up-the-current-terminal-width)\n- [Scripting-only features](#scripting-only-features)\n  * [@main entrypoints](#main-entrypoints)\n  * [multiple @main entrypoints](#multiple-main-entrypoints)\n  * [named parameters](#named-parameters)\n  * [`using resolver` directive: add dependency resolvers](#using-resolver-directive-add-dependency-resolvers)\n  * [Attach a debugger for remote jvm debugging](#attach-a-debugger-for-remote-jvm-debugging)\n- [Server mode](#server-mode)\n  * [Server mode for your project](#server-mode-for-your-project)\n- [Showcase: integrate into a project](#showcase-integrate-into-a-project)\n- [FAQ](#faq)\n  * [Is this an extension of the stock REPL or a fork?](#is-this-an-extension-of-the-stock-repl-or-a-fork)\n  * [Why is `srp` published with the full scala version suffix (e.g. `_3.6.4` instead of just `_3`)?](#why-is-srp-published-with-the-full-scala-version-suffix-eg-_364-instead-of-just-_3)\n  * [Why do we ship a shaded copy of other libraries and not use dependencies?](#why-do-we-ship-a-shaded-copy-of-other-libraries-and-not-use-dependencies)\n  * [Where's the cache located on disk?](#wheres-the-cache-located-on-disk)\n  * [Why am I getting an AssertionError re `class module-info$` on first tab completion?](#why-am-i-getting-an-assertionerror-re-class-module-info-on-first-tab-completion)\n- [Comparison / alternatives](#comparison--alternatives)\n  * [Stock Scala REPL](#stock-scala-repl)\n  * [scala-cli](#scala-cli)\n  * [Ammonite](#ammonite)\n- [Contribution guidelines](#contribution-guidelines)\n  * [How can I build/stage a local version?](#how-can-i-buildstage-a-local-version)\n  * [How can I get a new binary (bootstrapped) release?](#how-can-i-get-a-new-binary-bootstrapped-release)\n  * [Adding support for a new Scala version](#adding-support-for-a-new-scala-version)\n  * [Updating the shaded libraries](#updating-the-shaded-libraries)\n- [Fineprint](#fineprint)\n\n\n\n\n# Basic usage\nStart the REPL...\n```\n./srp\n```\n\nor run a script:\n```bash\necho 'println(\"Hello!\")' \u003e test-simple.sc\n./srp --script test-simple.sc\n```\n\n### Cheat sheet: the most important parameters\n\n| parameter     | short         | description                           \n| ------------- | ------------- | --------------------------------------\n| `--help`      |               | Show help\n| `--predef`    | `-p`          | Import additional files\n| `--runBefore` |               | Import additional files\n| `--script`    |               | Execute given script\n| `--param`     |               | key/value pair for main function in script\n| `--verbose`   | `-v`          | Verbose mode\n| `--dep`       | `-d`          | Add dependencies via maven coordinates\n\n# REPL, scripting and server mode features\nThis section demonstrates features with the REPL, but these also work when running scripts as well as in server mode. \n\n## `runBefore`: execute code at startup\n```\n./srp --runBefore \"import Byte.MaxValue\"\n\nscala\u003e MaxValue\nval res0: Int = 127\n```\n\u003e [!TIP]\n\u003e Can by specified multiple times, the given statements will be executed in the given order, e.g. `--runBefore \"val foo = 42\" --runBefore \"println(foo)\"`.\n\nTo run code before every session, write it to `~/.scala-repl-pp.sc`\n```bash\necho 'import Short.MaxValue' \u003e ~/.scala-repl-pp.sc\n./srp\n\nscala\u003e MaxValue\nval res0: Int = 32767\n```\n\nIf the code you want to execute on startup is in a file, you can use your shell tooling:\n```bash\necho 'import Int.MaxValue' \u003e /tmp/runBeforeFile.sc\n./srp --runBefore \"$(cat /tmp/runBeforeFile.sc)\"\n\nscala\u003e MaxValue\nval res0: Int = 2147483647\n```\n\n## `predef`: add source files to the classpath\n```\necho 'def foo = 42' \u003e foo.sc\n./srp --predef foo.sc\nscala\u003e foo\nval res0: Int = 42\n```\n\u003e [!TIP]\n\u003e Can by specified multiple times, e.g. `--predef one.sc --predef two.sc`.\n\n\u003e [!NOTE]\n\u003e The given file(s) are only compiled, not executed. Use `--runBefore` if you want to execute code.\n\n\u003e [!NOTE]\n\u003e Why not use `runBefore` instead? For simple examples like the one above, you can do so. If it gets more complicated and you have multiple files referencing each others, `predef` allows you to treat it as one compilation unit, which isn't possible with `runBefore`. And as you add more code it's get's easier to manage in files rather than command line arguments. \n\n\u003e [!NOTE]\n\u003e Predef files may not contain toplevel statements like `println(\"foo\")`. These either belong into your main script (if you're executing one) and/or can be passed to the repl via `runBefore`.\n\n## `using file` directive: import additional files\n```\necho 'val bar = \"foo\"' \u003e myScript.sc\n./srp\n\n//\u003e using file myScript.sc\nprintln(bar) //foo\n```\n\nYou can specify the filename with relative or absolute paths:\n```java\n//\u003e using file scripts/myScript.sc\n//\u003e using file ../myScript.sc\n//\u003e using file /path/to/myScript.sc\n```\n\n## `verbose` mode\nIf verbose mode is enabled, you'll get additional information about classpaths and complete scripts etc. \nTo enable it, you can either pass `--verbose` or set the environment variable `SCALA_REPL_PP_VERBOSE=true`.\n\n## `#\u003e`, `#\u003e\u003e` and `#|` operators: redirect to file, pipe to external command\nInspired by unix pipe and redirection, you can redirect output into files with `#\u003e` (write output to file) and `#\u003e\u003e` (create or append to file), and use `#|` to pipe the output to an external command:\n```scala\n./srp\n\nscala\u003e \"hey there\" #\u003e  \"out.txt\"\nscala\u003e \"hey again\" #\u003e\u003e \"out.txt\"\nscala\u003e Seq(\"a\", \"b\", \"c\") #\u003e\u003e \"out.txt\"\n\n// pipe results to external command\nscala\u003e Seq(\"a\", \"b\", \"c\") #| \"cat\"\nval res0: String = \"\"\"a\nb\nc\"\"\"\n\n// pipe results to external command with arguments\nscala\u003e Seq(\"foo\", \"bar\", \"foobar\") #| (\"grep\", \"foo\")\nval res1: String = \"\"\"foo\nfoobar\"\"\"\n\n// pipe results to external command and let it inherit stdin/stdout\nscala\u003e Seq(\"a\", \"b\", \"c\") #|^ \"less\"\n\n// pipe results to external command with arguments and let it inherit stdin/stdout\nscala\u003e Seq(\"a\", \"b\", \"c\") #|^ (\"less\", \"-N\")\n```\n\nAll operators use the same pretty-printing that's used within the REPL, i.e. you get structured rendering including product labels etc. \n```scala\nscala\u003e case class PrettyPrintable(s: String, i: Int)\nscala\u003e PrettyPrintable(\"two\", 2) #\u003e \"out.txt\"\n// out.txt now contains `PrettyPrintable(s = \"two\", i = 2)` - in pretty colors\n```\n\nThe operators have a special handling for two common use cases that are applied at the root level of the object you hand them: list- or iterator-type objects are unwrapped and their elements are rendered in separate lines, and Strings are rendered without the surrounding `\"\"`. Examples:\n```scala\nscala\u003e \"a string\" #\u003e \"out.txt\"\n// rendered as `a string` without quotes\n\nscala\u003e Seq(\"one\", \"two\") #\u003e \"out.txt\"\n// rendered as two lines without quotes:\n// one\n// two\n\nscala\u003e Seq(\"one\", Seq(\"two\"), Seq(\"three\", 4), 5) #\u003e \"out.txt\"\n// top-level list-types are unwrapped\n// resulting top-level strings are rendered without quotes:\n// one\n// List(\"two\")\n// List(\"three\", 4)\n// 5\n```\n\nAll operators are prefixed with `#` in order to avoid naming clashes with more basic operators like `\u003e` for greater-than-comparisons. This naming convention is inspired by scala.sys.process.\n\n## `dep`: add dependencies via maven coordinates\n\u003e [!NOTE]\n\u003e the dependencies must be known on startup\n```\n./srp --dep com.michaelpollmeier:versionsort:1.0.7\nscala\u003e versionsort.VersionHelper.compare(\"1.0\", \"0.9\")\nval res0: Int = 1\n```\n\u003e [!TIP]\n\u003e Can by specified multiple times, e.g. `--dep a:b:0.1.0 --dep x:y:0.1.0`\n\nFor Scala dependencies use `::`:\n```\n./srp --dep com.michaelpollmeier::colordiff:0.36\n\ncolordiff.ColorDiff(List(\"a\", \"b\"), List(\"a\", \"bb\"))\n// color coded diff\n```\n\nIf you use a file that's read on startup (e.g. a script or a file passed via `--predef`), you can also use the `//\u003e using dep` directive:\n```bash\necho '//\u003e using dep com.michaelpollmeier:versionsort:1.0.7' \u003e predef.sc\n\n./srp --predef predef.sc\n\nscala\u003e versionsort.VersionHelper.compare(\"1.0\", \"0.9\")\nval res0: Int = 1\n```\n\n## `repo`: add dependency resolvers\n```bash\n./srp --repo \"https://repo.gradle.org/gradle/libs-releases\" --dep org.gradle:gradle-tooling-api:7.6.1\nscala\u003e org.gradle.tooling.GradleConnector.newConnector()\n```\n\u003e [!TIP]\n\u003e Can by specified multiple times.\n\nIf any of your resolvers require authentication, you can configure your username/passwords in a [`credentials.properties` file](https://get-coursier.io/docs/other-credentials#property-file), (`~/.config/coursier/credentials.properties` on Linux, `~/Library/Application Support/Coursier/credentials.properties` on OS X):\n```\nmycorp.realm=Artifactory Realm\nmycorp.host=shiftleft.jfrog.io\nmycorp.username=michael\nmycorp.password=secret\n\notherone.username=j\notherone.password=imj\notherone.host=nexus.other.com\n```\n\u003e [!NOTE]\n\u003e The prefix is arbitrary and is only used to specify several credentials in a single file.\n\n\n## `classpathEntry`: additional classpath entries\nIf you have some random class files, e.g. like so:\n```bash\nmkdir foo\ncd foo\necho 'class Foo { def foo = 42 } ' \u003e Foo.scala\nscalac Foo.scala\ncd ..\n```\n\nYou can add those as follows:\n```bash\n./srp --classpathEntry foo\n\nscala\u003e new Foo().foo\nval res0: Int = 42\n```\n\nFor scripts you can use the `//\u003e using classpath` directive as well. \n```bash\necho '//\u003e using classpath foo\nprintln(new Foo().foo)' \u003e myScript.sc\n\n./srp --script myScript.sc\n```\n\n# REPL-only features\n\n## Rendering of output\n\nUnlike the stock Scala REPL, `srp` does _not_ truncate the output by default. You can optionally specify the maxHeight parameter though:\n```\n./srp --maxHeight 5\nscala\u003e (1 to 100000).toSeq\nval res0: scala.collection.immutable.Range.Inclusive = Range(\n  1,\n  2,\n  3,\n...\n```\n\n## Exiting the REPL\nFamously one of the most popular question on stackoverflow is about how to exit `vim` - fortunately you can apply the answer as-is to exit `srp` :slightly_smiling_face:\n```\n// all of the following exit the REPL\n:exit\n:quit\n:q\n```\n\nWhen the REPL is waiting for input we capture `Ctrl-c` and don't exit. If there's currently a long-running execution that you really *might* want to cancel you can press `Ctrl-c` again immediately which will kill the entire repl:\n```\nscala\u003e Thread.sleep(50000)\n// press Ctrl-c\nCaptured interrupt signal `INT` - if you want to kill the REPL, press Ctrl-c again within three seconds\n\n// press Ctrl-c again will exit the repl\n$\n```\nContext: we'd prefer to cancel the long-running operation, but that's not so easy on the JVM.\n\n## customize prompt, greeting and exit code\n```\n./srp --prompt myprompt --greeting 'hey there!' --runAfter 'println(\"see ya!\")'\n\nhey there!\nmyprompt\u003e :exit\nsee ya!\n```\n\n## Looking up the current terminal width\nIn case you want to adjust your output rendering to the available terminal size, you can look it up:\n\n```\nscala\u003e replpp.util.terminalWidth\nval res0: util.Try[Int] = Success(value = 202)\n```\n\n# Scripting-only features\nThe following additional features work in scripting mode only. \n\u003e [!TIP]\n\u003e See [ScriptRunnerTest](core/src/test/scala/replpp/scripting/ScriptRunnerTest.scala) for a more complete and in-depth overview.\n\n## @main entrypoints\n```bash\necho '@main def main() = println(\"Hello, world!\")' \u003e test-main.sc\n\n./srp --script test-main.sc\n```\n\n## multiple @main entrypoints\n```bash\necho '\n@main def foo() = println(\"foo!\")\n@main def bar() = println(\"bar!\")\n' \u003e test-main-multiple.sc\n\n./srp --script test-main-multiple.sc --command foo\n```\n\n## named parameters\n```bash\necho '\n@main def main(first: String, last: String) = {\n  println(s\"Hello, $first $last!\")\n} ' \u003e test-main-withargs.sc\n\n./srp --script test-main-withargs.sc --param first=Michael --param last=Pollmeier\n```\nIf your parameter value contains whitespace, just wrap it quotes so that your shell doesn't split it up, e.g. `--param \"text=value with whitespace\"`\n\nOn windows the parameters need to be triple-quoted in any case:\n`srp.bat --script test-main-withargs.sc --param \"\"\"first=Michael\"\"\" --param \"\"\"last=Pollmeier\"\"\"`\n\n## `using resolver` directive: add dependency resolvers\nIf your script depends on external libraries, you'd need to specify the `--repo` parameter every time. Better: declare your dependency in your script or predef files with the `//\u003e using resolver`:\n\n```bash\necho '\n//\u003e using resolver https://repo.gradle.org/gradle/libs-releases\n//\u003e using dep org.gradle:gradle-tooling-api:7.6.1\nprintln(org.gradle.tooling.GradleConnector.newConnector())\n' \u003e script-with-resolver.sc\n\n./srp --script script-with-resolver.sc\n```\n\n\n## Attach a debugger for remote jvm debugging\nFor the REPL itself:\n```\nexport JAVA_OPTS='-Xdebug -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=y'\n./srp\nunset JAVA_OPTS\n```\nThen attach your favorite IDE / debugger on port 5005. \n\nIf you want to debug a script, it's slightly different. Scripts are executed in a separate subprocess - just specify the following parameter (and make sure `JAVA_OPTS` isn't also set).\n```\n./srp --script myScript.sc --remoteJvmDebug\n```\n\n# Server mode\n\u003e [!NOTE]\n\u003e `srp-server` isn't currently available as a bootstrapped binary, so you need to either [stage it locally](#how-can-i-buildstage-a-local-version) first using `sbt stage` or add it as a dependency to your project.\n\n```bash\n./srp-server\n\ncurl http://localhost:8080/query-sync -X POST -d '{\"query\": \"val foo = 42\"}'\n# {\"success\":true,\"stdout\":\"val foo: Int = 42\\n\",...}\n\ncurl http://localhost:8080/query-sync -X POST -d '{\"query\": \"val bar = foo + 1\"}'\n# {\"success\":true,\"stdout\":\"val bar: Int = 43\\n\",...}\n\ncurl http://localhost:8080/query-sync -X POST -d '{\"query\":\"println(\\\"OMG remote code execution!!1!\\\")\"}'\n# {\"success\":true,\"stdout\":\"\",...}%\n```\n\nFor a nice user experience enable colors and create small wrapper function to interact with the server:\n```bash\n./srp-server --colors\n\nfunction srp-remote() {\n  QUERY=\"{\\\"query\\\": \\\"$@\\\"}\"\n  curl --silent http://localhost:8080/query-sync -X POST -d $QUERY | jq --raw-output .stdout\n}\n\nsrp-remote 'val foo = 42'\n\u003e val foo: Int = 42\n```\n\u003cimg src=\"https://github.com/user-attachments/assets/f97a3701-cac5-4f56-9b3f-a00405a3fb1f\" width=\"500\" /\u003e\n\nThe same for windows and powershell:\n```\n./srp-server.bat\n\nInvoke-WebRequest -Method 'Post' -Uri http://localhost:8080/query-sync -ContentType \"application/json\" -Body '{\"query\": \"val foo = 42\"}'\n# Content           : {\"success\":true,\"stdout\":\"val foo: Int = 42\\r\\n\",\"uuid\":\"02f843ba-671d-4fb5-b345-91c1dcf5786d\"}\nInvoke-WebRequest -Method 'Post' -Uri http://localhost:8080/query-sync -ContentType \"application/json\" -Body '{\"query\": \"foo + 1\"}'\n# Content           : {\"success\":true,\"stdout\":\"val res0: Int = 43\\r\\n\",\"uuid\":\"dc49df42-a390-4177-98d0-ac87a277c7d5\"}\n```\n\nPredef code and runBefore work as well:\n```\necho val foo = 99 \u003e foo.sc\n./srp-server --predef foo.sc --runBefore 'import Short.MaxValue'\n\ncurl -XPOST http://localhost:8080/query-sync -d '{\"query\":\"val baz = foo + MaxValue\"}'\n# {\"success\":true,\"stdout\":\"val baz: Int = 32866\\n\",...}\n```\n\nAdding dependencies:\n```\necho '//\u003e using dep com.michaelpollmeier:versionsort:1.0.7' \u003e foo.sc\n./srp-server --predef foo.sc\n\ncurl http://localhost:8080/query-sync -X POST -d '{\"query\": \"versionsort.VersionHelper.compare(\\\"1.0\\\", \\\"0.9\\\")\"}'\n# {\"success\":true,\"stdout\":\"val res0: Int = 1\\n\",...}%\n```\n\n`srp-server` can be used in an asynchronous mode:\n```\n./srp-server\n\ncurl http://localhost:8080/query -X POST -d '{\"query\": \"val baz = 93\"}'\n# {\"success\":true,\"uuid\":\"e2640fcb-3193-4386-8e05-914b639c3184\"}%\n\ncurl http://localhost:8080/result/e2640fcb-3193-4386-8e05-914b639c3184\n{\"success\":true,\"uuid\":\"e2640fcb-3193-4386-8e05-914b639c3184\",\"stdout\":\"val baz: Int = 93\\n\"}%\n```\n\nThere's even a websocket channel that allows you to get notified when the query has finished. For more details and other use cases check out [ReplServerTests.scala](server/src/test/scala/replpp/server/ReplServerTests.scala)\n\nServer-specific configuration options as per `srp --help`:\n```\n--server-host \u003cvalue\u003e    Hostname on which to expose the REPL server\n--server-port \u003cvalue\u003e    Port on which to expose the REPL server\n--server-auth-username \u003cvalue\u003e Basic auth username for the REPL server\n--server-auth-password \u003cvalue\u003e Basic auth password for the REPL server\n```\n\n## Server mode for your project\n`build.sbt`:\n```scala\nlibraryDependencies += \"com.michaelpollmeier\" % \"scala-repl-pp-server_3.6.4\" % \"\u003cversion\u003e\"\n```\n\nThen in your project's sources, execute `replpp.server.ReplServer.startHttpServer` which takes a `replpp.server.Config` as input. For a full working example check out e.g. [joern's server mode](https://github.com/joernio/joern/blob/db22aec598f10ae1b4023ff712f991cb3d817e79/console/src/main/scala/io/joern/console/BridgeBase.scala#L426).\n\n# Showcase: integrate into a project\n\nexcerpt from [build.sbt](core/src/test/resources/demo-project/build.sbt):\n```scala\nlibraryDependencies += \n  \"com.michaelpollmeier\" % \"scala-repl-pp\" % srpVersion cross CrossVersion.full\n```\n\nexcerpt from [Main.scala](core/src/test/resources/demo-project/src/main/scala/stringcalc/Main.scala):\n```scala\nreplpp.Main.run(\n  replpp.Config(\n    scriptFile = config.scriptFile,\n    prompt = Some(\"stringcalc\"),\n    greeting = Some(\"Welcome to the magical world of string calculation! \\nType `help` for help\"),\n    verbose = config.verbose,\n    runBefore = Seq(\n      \"import stringcalc.*\",\n      \"import StringCalculator.*\",\n      \"\"\"def help: Unit = println(\"try this: `add(One, Two)`\")\"\"\"\n    )\n  )\n)\n```\n\nBuild it:\n```bash\ncd core/src/test/resources/demo-project\nsbt stage\n```\n\nREPL usage:\n```bash\n./stringcalc\n\nstringcalc\u003e add(One, Two)\nval res0: stringcalc.Number = Number(3)\nstringcalc\u003e :exit  // or press Ctrl-D\n```\n\nScript usage:\n```bash\n./stringcalc --script plus.sc\nexecuting plus.sc\nNumber(3)\n```\n\n\u003cimg src=\"https://github.com/user-attachments/assets/5b267ccb-07f8-4a0f-8073-39c72b23e98b\" width=\"300\" /\u003e\n\n\n# FAQ\n\n## Is this an extension of the stock REPL or a fork?\nTechnically it is a fork because we copied parts of the ReplDriver to make some adjustments. \u003cbr/\u003e\nHowever, semantically `srp` can be considered an extension of the stock repl. We don't want to create and maintain a competing REPL implementation, instead the idea is to provide a space for exploring new ideas and bringing them back into the dotty codebase. \n[When we forked](https://github.com/mpollmeier/scala-repl-pp/commit/eb2bf9a3bed681bffa945f657ada14781c6a7a14) the stock ReplDriver, we made sure to separate the commits into bitesized chunks so we can easily rebase. The changes are clearly marked, and whenever there's a new dotty version we're bringing in the relevant changes here (for instructions see below).\n\n## Why is `srp` published with the full scala version suffix (e.g. `_3.6.4` instead of just `_3`)?\nThe stock Scala REPL often has binary incompatible changes between minor version changes.  Different Scala patch versions typically work though, e.g. if your build uses Scala 3.6.3 you can use `scala-repl-pp_3.6.4`.\n\n## Why do we ship a shaded copy of other libraries and not use dependencies?\n`srp` includes some small libraries (e.g. most of the com-haoyili universe) that have been copied as-is, but then moved into the `replpp.shaded` namespace. We didn't include them as regular dependencies, because repl users may want to use a different version of them, which may be incompatible with the version the repl uses. Thankfully their license is very permissive - a big thanks to the original authors! The instructions of how to (re-) import then and which versions were used are available in [import-instructions.md](shaded-libs/import-instructions.md).\n\n## Where's the cache located on disk?\nThe cache? The caches you mean! :)\nThere's `~/.cache/scala-repl-pp` for the repl itself. Since we use coursier (via a subprocess) there's also `~/.cache/coursier`. \n\n## Why am I getting an AssertionError re `class module-info$` on first tab completion?\n```\nexception caught when loading module class module-info$: java.lang.AssertionError: assertion failed: attempt to parse java.lang.Object from classfile\n```\nThere's a [Scala 3 compiler bug](https://github.com/scala/scala3/issues/20421) that triggers and prints this exception if one of your dependencies ships a `module-info.class`. Until that's fixed you can use this hacky workaround in your sbt build:\n```\nlazy val removeModuleInfoFromJars = taskKey[Unit](\"remove module-info.class from dependency jars - a hacky workaround for a scala3 compiler bug https://github.com/scala/scala3/issues/20421\")\nremoveModuleInfoFromJars := {\n  import java.nio.file.{Files, FileSystems}\n  val logger = streams.value.log\n  val libDir = (Universal/stagingDirectory).value / \"lib\"\n\n  // remove all `/module-info.class` from all jars\n  Files.walk(libDir.toPath)\n    .filter(_.toString.endsWith(\".jar\"))\n    .forEach { jar =\u003e\n      val zipFs = FileSystems.newFileSystem(jar)\n      zipFs.getRootDirectories.forEach { zipRootDir =\u003e\n        Files.list(zipRootDir).filter(_.toString == \"/module-info.class\").forEach { moduleInfoClass =\u003e\n          logger.info(s\"workaround for scala completion bug: deleting $moduleInfoClass from $jar\")\n          Files.delete(moduleInfoClass)\n        }\n      }\n      zipFs.close()\n    }\n}\n```\n\nIf you use [sbt-native-packager](https://sbt-native-packager.readthedocs.io/en/latest/) to package your application, you can automatically invoke the task, e.g. like so:\n```\nremoveModuleInfoFromJars := removeModuleInfoFromJars.triggeredBy(Universal/stage).value\n```\n\n\n# Comparison / alternatives\n\n`srp` wouldn't exist if we could have just used scala-cli (which has now become the stock Scala REPL) or ammonite. \n\n## [scala-cli](https://scala-cli.virtuslab.org/) / stock Scala REPL\n`srp` allows you to:\n* use it as a library in your own build with *minimal* dependencies\n* use `#\u003e`, `#\u003e\u003e` and `#|` operators to redirect output to file and pipe to external command\n* run custom code on startup as well as on shutdown\n* import additional files, which may include `using` directives\n* customize the greeting and prompt\n* server mode\n* structured rendering including product labels and type information\n\u003cimg src=\"pretty-printing.png\" height=\"200\"/\u003e\n\n## [Ammonite](http://ammonite.io)\nAmmonite's Scala 3 support is far from complete - e.g. autocompletion for extension methods has [many shortcomings](https://github.com/com-lihaoyi/Ammonite/issues/1297). In comparison: `srp` uses the regular Scala3 ReplDriver rather than re-implementing it. \n\n`srp` allows you to use it as a library in your own build with *minimal* dependencies. Ammonite has some Scala2 dependencies intermixed, leading to downstream build problems like [this](https://github.com/com-lihaoyi/Ammonite/issues/1241). Therefor it's no longer easy to embed Ammonite into your own build (something we used to do when we used Scala 2.13). \n\nAmmonite allows to add dependencies dynamically even in the middle of the REPL session which is nice. In `srp` you need to know which dependencies you want on startup. \n\n\n# Contribution guidelines\n\n## How can I build/stage a local version?\n```bash\nsbt stage\n./srp\n```\n\n## How can I get a new binary (bootstrapped) release?\nWhile maven central jar releases are created for each commit on master (a new version tag is assigned automatically), the binary (bootstrapped) releases that end up in https://github.com/mpollmeier/scala-repl-pp/releases/latest are being triggered manually. Contributors can run the [bootstrap action](https://github.com/mpollmeier/scala-repl-pp/actions/workflows/bootstrap.yml).\n\n## Adding support for a new Scala version\nFirst, get relevant diff from dotty repo:\n```bash\ncd /path/to/dotty\ngit fetch\n\nOLD=3.7.0 # set to version that was used before you bumped it\nNEW=3.7.1 # set to version that you bumped it to\ntig $OLD..$NEW compiler/src/dotty/tools/repl\ngit diff $OLD..$NEW compiler/src/dotty/tools/repl\n```\nCheck if any of those changes need to be reapplied to this repo - some files have been copied and slightly adjusted, the majority of functionality is reused. \nIf there's any binary incompatible changes (which is typically the case between minor versions), you need to add new projects for `core` and `server` in [build.sbt](build.sbt), add new `core/src/main/scala-3.x.y` directories etc.\n\n## Updating the shaded libraries\nSee [import-instructions.md](shaded-libs/import-instructions.md).\n\n# Fineprint\n(*) To keep our codebase concise we do use libraries (mostly from the [com.lihaoyi](https://github.com/com-lihaoyi/) stack). We want to ensure that users can freely use their own dependencies without clashing with the `srp` classpath though, so we [copied them into our build](shaded-libs/src/main/scala/replpp/shaded) and [changed the namespace](shaded-libs/import-instructions) to `replpp.shaded`. Many thanks to the original authors for permissive licensing! \n  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpollmeier%2Fscala-repl-pp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmpollmeier%2Fscala-repl-pp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpollmeier%2Fscala-repl-pp/lists"}