├── .git-blame-ignore-revs ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── publish-artifacts.yml │ └── run-tests.yml ├── .gitignore ├── .mill-version ├── .scalafmt.conf ├── LICENSE ├── amm-template.sh ├── amm ├── compiler │ ├── interface │ │ └── src │ │ │ └── main │ │ │ └── scala │ │ │ └── ammonite │ │ │ └── compiler │ │ │ └── iface │ │ │ ├── CodeWrapper.scala │ │ │ ├── Compiler.scala │ │ │ ├── CompilerBuilder.scala │ │ │ ├── CompilerLifecycleManager.scala │ │ │ ├── Parser.scala │ │ │ └── Preprocessor.scala │ └── src │ │ ├── main │ │ ├── scala-2.12.0_12 │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── CompilerCompatibility.scala │ │ ├── scala-2.12.0_8 │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── ExtraCompilerCompatibility.scala │ │ ├── scala-2.12.10-2.13.1+ │ │ │ └── scala │ │ │ │ └── tools │ │ │ │ └── nsc │ │ │ │ ├── AmmClassPath.scala │ │ │ │ └── WhiteListClasspath.scala │ │ ├── scala-2.12.13+ │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ ├── CompilerCompatibility.scala │ │ │ │ └── MakeReporter.scala │ │ ├── scala-2.12.9+ │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── ExtraCompilerCompatibility.scala │ │ ├── scala-2.13.1-2.13.11 │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── MakeReporter.scala │ │ ├── scala-2.13.12+ │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── MakeReporter.scala │ │ ├── scala-2.13 │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── CompilerCompatibility.scala │ │ ├── scala-2 │ │ │ ├── ammonite │ │ │ │ └── compiler │ │ │ │ │ ├── AmmonitePlugin.scala │ │ │ │ │ ├── Compiler.scala │ │ │ │ │ ├── CompilerBuilder.scala │ │ │ │ │ ├── CompilerExtensions.scala │ │ │ │ │ ├── CompilerLifecycleManager.scala │ │ │ │ │ ├── DefaultPreprocessor.scala │ │ │ │ │ ├── Highlighter.scala │ │ │ │ │ ├── Parsers.scala │ │ │ │ │ ├── Pressy.scala │ │ │ │ │ ├── internal │ │ │ │ │ └── CustomURLZipArchive.scala │ │ │ │ │ └── tools │ │ │ │ │ ├── HighlightJava.scala │ │ │ │ │ ├── SourceRuntime.scala │ │ │ │ │ ├── desugar.scala │ │ │ │ │ └── source.scala │ │ │ └── scala │ │ │ │ └── tools │ │ │ │ └── nsc │ │ │ │ └── CustomZipAndJarFileLookupFactory.scala │ │ ├── scala-3.0.0-3.3.1 │ │ │ ├── ammonite │ │ │ │ └── compiler │ │ │ │ │ ├── AmmonitePhase.scala │ │ │ │ │ ├── Compiler.scala │ │ │ │ │ ├── DirectoryClassPath.scala │ │ │ │ │ ├── Preprocessor.scala │ │ │ │ │ └── SyntaxHighlighting.scala │ │ │ └── dotty │ │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── AmmCompletion.scala │ │ ├── scala-3.0.0-3.6.2 │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── DottyParser.scala │ │ ├── scala-3.3.2+ │ │ │ ├── ammonite │ │ │ │ └── compiler │ │ │ │ │ ├── AmmonitePhase.scala │ │ │ │ │ ├── Compiler.scala │ │ │ │ │ ├── DirectoryClassPath.scala │ │ │ │ │ ├── Preprocessor.scala │ │ │ │ │ └── SyntaxHighlighting.scala │ │ │ └── dotty │ │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── AmmCompletion.scala │ │ ├── scala-3.4.2+ │ │ │ ├── ammonite │ │ │ │ └── compiler │ │ │ │ │ ├── AmmonitePhase.scala │ │ │ │ │ ├── Compiler.scala │ │ │ │ │ ├── DirectoryClassPath.scala │ │ │ │ │ ├── Preprocessor.scala │ │ │ │ │ └── SyntaxHighlighting.scala │ │ │ └── dotty │ │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── AmmCompletion.scala │ │ ├── scala-3.5.0+ │ │ │ ├── ammonite │ │ │ │ └── compiler │ │ │ │ │ ├── AmmonitePhase.scala │ │ │ │ │ ├── Compiler.scala │ │ │ │ │ ├── DirectoryClassPath.scala │ │ │ │ │ ├── Preprocessor.scala │ │ │ │ │ └── SyntaxHighlighting.scala │ │ │ └── dotty │ │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── AmmCompletion.scala │ │ ├── scala-3.6.3+ │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── DottyParser.scala │ │ ├── scala-3 │ │ │ ├── ammonite │ │ │ │ └── compiler │ │ │ │ │ ├── AsmPositionUpdater.scala │ │ │ │ │ ├── CompatibilityParser.scala │ │ │ │ │ ├── CompilerBuilder.scala │ │ │ │ │ ├── CompilerExtensions.scala │ │ │ │ │ ├── CompilerLifecycleManager.scala │ │ │ │ │ ├── Extensions.scala │ │ │ │ │ ├── Parsers.scala │ │ │ │ │ ├── internal │ │ │ │ │ └── CompilerHelper.scala │ │ │ │ │ └── tools │ │ │ │ │ ├── desugar.scala │ │ │ │ │ └── source.scala │ │ │ └── dotty │ │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ ├── AmmCompletionExtras.scala │ │ │ │ └── WhiteListClassPath.scala │ │ ├── scala-not-2.12.10-2.13.1+ │ │ │ └── scala │ │ │ │ └── tools │ │ │ │ └── nsc │ │ │ │ ├── AmmClassPath.scala │ │ │ │ └── WhiteListClasspath.scala │ │ ├── scala-not-2.12.13+-2.13.1+ │ │ │ └── ammonite │ │ │ │ └── compiler │ │ │ │ └── MakeReporter.scala │ │ └── scala │ │ │ └── ammonite │ │ │ └── compiler │ │ │ ├── CodeClassWrapper.scala │ │ │ ├── CompilerUtil.scala │ │ │ └── DefaultCodeWrapper.scala │ │ └── test │ │ ├── scala-2 │ │ └── ammonite │ │ │ └── compiler │ │ │ └── test │ │ │ └── CompilerTestExtensions.scala │ │ └── scala-3 │ │ └── ammonite │ │ └── compiler │ │ └── test │ │ └── CompilerTestExtensions.scala ├── helper │ └── src │ │ └── main │ │ └── scala-3 │ │ └── ammonite │ │ └── helper │ │ └── Helper.scala ├── interp │ ├── api │ │ └── src │ │ │ └── main │ │ │ └── scala │ │ │ └── ammonite │ │ │ ├── Stubs.scala │ │ │ └── interp │ │ │ └── api │ │ │ ├── APIHolder.scala │ │ │ ├── AmmoniteExit.scala │ │ │ ├── InterpAPI.scala │ │ │ └── IvyConstructor.scala │ └── src │ │ └── main │ │ └── scala │ │ └── ammonite │ │ └── interp │ │ ├── DependencyLoader.scala │ │ ├── Interpreter.scala │ │ ├── IvyThing.scala │ │ ├── PredefInitialization.scala │ │ ├── Watchable.scala │ │ └── script │ │ ├── AmmoniteBuildServer.scala │ │ ├── Diagnostic.scala │ │ ├── DummyBuildServerImplems.scala │ │ ├── Script.scala │ │ ├── ScriptCache.scala │ │ ├── ScriptCompileResult.scala │ │ ├── ScriptCompiler.scala │ │ ├── ScriptProcessor.scala │ │ ├── SemanticdbProcessor.scala │ │ └── SingleScriptCompiler.scala ├── repl │ ├── api │ │ └── src │ │ │ └── main │ │ │ ├── scala-2.12 │ │ │ └── ammonite │ │ │ │ └── repl │ │ │ │ └── api │ │ │ │ └── History.scala │ │ │ ├── scala-2.13-or-3 │ │ │ └── ammonite │ │ │ │ └── repl │ │ │ │ └── api │ │ │ │ └── History.scala │ │ │ ├── scala-2 │ │ │ └── ammonite │ │ │ │ └── repl │ │ │ │ ├── FullReplAPIScalaVersionSpecific.scala │ │ │ │ └── api │ │ │ │ └── ReplAPIScalaVersionSpecific.scala │ │ │ ├── scala-3 │ │ │ └── ammonite │ │ │ │ └── repl │ │ │ │ ├── FullReplAPIScalaVersionSpecific.scala │ │ │ │ └── api │ │ │ │ └── ReplAPIScalaVersionSpecific.scala │ │ │ └── scala │ │ │ └── ammonite │ │ │ ├── repl │ │ │ ├── FullReplAPI.scala │ │ │ ├── api │ │ │ │ ├── FrontEnd.scala │ │ │ │ ├── FrontEndAPI.scala │ │ │ │ ├── ReplAPI.scala │ │ │ │ └── SessionChanged.scala │ │ │ └── tools │ │ │ │ └── Util.scala │ │ │ └── runtime │ │ │ └── tools │ │ │ ├── Tools.scala │ │ │ └── package.scala │ └── src │ │ ├── main │ │ ├── scala-2 │ │ │ └── ammonite │ │ │ │ └── main │ │ │ │ └── DefaultsScalaVersionSpecific.scala │ │ ├── scala-3 │ │ │ └── ammonite │ │ │ │ └── main │ │ │ │ └── DefaultsScalaVersionSpecific.scala │ │ └── scala │ │ │ └── ammonite │ │ │ ├── main │ │ │ └── Defaults.scala │ │ │ └── repl │ │ │ ├── AmmoniteFrontEnd.scala │ │ │ ├── ApiImpls.scala │ │ │ ├── FrontEndUtils.scala │ │ │ ├── FrontEnds.scala │ │ │ ├── PPrints.scala │ │ │ ├── Repl.scala │ │ │ ├── Signaller.scala │ │ │ └── package.scala │ │ └── test │ │ ├── scala-2.12 │ │ └── ammonite │ │ │ └── unit │ │ │ └── SourceTests212.scala │ │ └── scala │ │ └── ammonite │ │ ├── DualTestRepl.scala │ │ ├── SerializationUtil.scala │ │ ├── TestRepl.scala │ │ ├── TestReplBridge.scala │ │ ├── TestUtils.scala │ │ ├── interp │ │ ├── AutocompleteTests.scala │ │ └── PrintTests.scala │ │ ├── session │ │ ├── AdvancedTests.scala │ │ ├── BuiltinTests.scala │ │ ├── EulerTests.scala │ │ ├── EvaluatorTests.scala │ │ ├── FailureTests.scala │ │ ├── ImportHookTests.scala │ │ ├── ImportTests.scala │ │ ├── ProjectTests.scala │ │ └── SerializationTests.scala │ │ ├── testcode │ │ └── PaulpImports.scala │ │ └── unit │ │ ├── ClipboardTests.scala │ │ ├── HighlightTests.scala │ │ ├── ParserTests.scala │ │ └── SourceTests.scala ├── runtime │ └── src │ │ └── main │ │ └── scala │ │ └── ammonite │ │ └── runtime │ │ ├── ClassLoaders.scala │ │ ├── Evaluator.scala │ │ ├── ImportHook.scala │ │ ├── Storage.scala │ │ └── package.scala ├── src │ ├── main │ │ └── scala │ │ │ └── ammonite │ │ │ ├── AmmoniteMain.scala │ │ │ ├── Main.scala │ │ │ ├── MainRunner.scala │ │ │ └── main │ │ │ ├── Config.scala │ │ │ ├── ProxyFromEnv.scala │ │ │ ├── Scripts.scala │ │ │ ├── TrapExitSecurityManager.scala │ │ │ └── package.scala │ └── test │ │ ├── resources │ │ ├── bsp │ │ │ ├── comment │ │ │ │ └── script.sc │ │ │ ├── dash-1 │ │ │ │ └── main-1.sc │ │ │ ├── error │ │ │ │ ├── error-and-invalid-import-file.sc │ │ │ │ ├── foo.sc │ │ │ │ └── invalid-import-file.sc │ │ │ ├── import-file │ │ │ │ ├── lib.sc │ │ │ │ └── script.sc │ │ │ ├── multi │ │ │ │ ├── lib1.sc │ │ │ │ ├── lib2.sc │ │ │ │ ├── lib3.sc │ │ │ │ └── script.sc │ │ │ ├── semdb │ │ │ │ ├── other.sc │ │ │ │ └── script.sc │ │ │ └── simple │ │ │ │ └── script.sc │ │ ├── importHooks │ │ │ ├── Basic.sc │ │ │ ├── BasicTwo.sc │ │ │ ├── Deep.sc │ │ │ ├── DeepImport.sc │ │ │ ├── FileImport.sc │ │ │ ├── IndirectFileImport.sc │ │ │ ├── IvyImport.sc │ │ │ └── UrlImport.sc │ │ ├── lineNumbers │ │ │ ├── CompilationErrorLineNumberTest.sc │ │ │ ├── ErrorLineNumberTest.sc │ │ │ ├── MultipleCompilationUnitErrorMsgTest1.sc │ │ │ ├── MultipleCompilationUnitErrorMsgTest2.sc │ │ │ ├── RuntimeCompilationErrorLineNumberTest.sc │ │ │ ├── compilationErrorInClass.sc │ │ │ ├── compilationErrorInFourthBlock.sc │ │ │ ├── compilationErrorInSecondBlock.sc │ │ │ ├── compilationErrorWithCommentsAtTop.sc │ │ │ └── sourceCodeMetadata.sc │ │ ├── loadable │ │ │ └── hello │ │ │ │ └── Hello.java │ │ ├── mains │ │ │ ├── ArgList.sc │ │ │ ├── Args.sc │ │ │ ├── Args2.sc │ │ │ ├── CompilerCrash.sc │ │ │ ├── Hello.sc │ │ │ ├── Main.sc │ │ │ ├── MultiMain.sc │ │ │ ├── MultiMainDoc.sc │ │ │ └── Varargs.sc │ │ ├── scriptCompilerSettings │ │ │ ├── configureCompiler.sc │ │ │ ├── preConfigureCompiler.sc │ │ │ ├── yRangepos.sc │ │ │ └── yRangeposError.sc │ │ ├── scriptLevelCaching │ │ │ ├── QuickSort.sc │ │ │ ├── fileToBeImported.sc │ │ │ ├── ivyCacheTest.sc │ │ │ ├── ivyCachedResourceTest.sc │ │ │ ├── runTimeExceptions.sc │ │ │ ├── scriptOne.sc │ │ │ ├── scriptToBeLoaded.sc │ │ │ ├── scriptTwo.sc │ │ │ ├── testFileImport.sc │ │ │ └── testLoadModule.sc │ │ ├── scripts │ │ │ ├── Annotation.sc │ │ │ ├── BlockSepSyntax.sc │ │ │ ├── CompilationError.sc │ │ │ ├── Encapsulation.sc │ │ │ ├── LimitImports.sc │ │ │ ├── LoadIvy.sc │ │ │ ├── MultiBlockError.sc │ │ │ ├── MultilineSheBang.sc │ │ │ ├── NestedScripts.sc │ │ │ ├── OneBlock.sc │ │ │ ├── PreserveImports.sc │ │ │ ├── Resolvers.sc │ │ │ ├── ResolversFail.sc │ │ │ ├── ResolversStatic.sc │ │ │ ├── ScriptDontUnwrap.sc │ │ │ ├── SheBang.sc │ │ │ ├── SyntaxError.sc │ │ │ ├── TagBase.sc │ │ │ ├── TagPrevCommand.sc │ │ │ ├── ThreeBlocks.sc │ │ │ ├── TwoBlocks.sc │ │ │ ├── cachedCompilerInit.sc │ │ │ ├── caching │ │ │ │ ├── scalatagsPredef.sc │ │ │ │ └── scalatagsScript.sc │ │ │ ├── loadIvyAdvanced.sc │ │ │ └── predefWithLoad │ │ │ │ ├── Loaded.sc │ │ │ │ ├── PredefLoadExec.sc │ │ │ │ ├── PredefLoadModule.sc │ │ │ │ └── PredefMagicImport.sc │ │ └── testdata │ │ │ ├── Resume.docx │ │ │ └── images │ │ │ ├── GettingStarted.png │ │ │ ├── Highlighting.png │ │ │ └── SystemShell.png │ │ └── scala │ │ └── ammonite │ │ ├── interp │ │ ├── CachingTests.scala │ │ ├── CompilerSettingsTests.scala │ │ ├── YRangeposTests.scala │ │ └── script │ │ │ ├── AmmoniteBuildServerTests.scala │ │ │ └── TestBuildClient.scala │ │ ├── main │ │ ├── InProcessMainMethodRunner.scala │ │ ├── InProcessMainMethodRunnerRawArgs.scala │ │ ├── LineNumberTests.scala │ │ └── MainTests.scala │ │ ├── readme.md │ │ └── session │ │ └── ScriptTests.scala └── util │ └── src │ └── main │ ├── java │ └── io │ │ └── github │ │ └── retronym │ │ └── java9rtexport │ │ ├── Copy.java │ │ └── Export.java │ └── scala │ └── ammonite │ └── util │ ├── Classpath.scala │ ├── Frame.scala │ ├── Imports.scala │ ├── Model.scala │ ├── Position.scala │ ├── PositionOffsetConversion.scala │ ├── ReplClassLoader.scala │ ├── Res.scala │ ├── Util.scala │ └── WhiteListClassLoader.scala ├── build.mill ├── build.sbt ├── ci ├── deploy_master_docs.sh ├── package.mill └── upload.mill ├── integration └── src │ └── test │ ├── resources │ ├── ammonite │ │ └── integration │ │ │ ├── basic │ │ │ ├── Complex.sc │ │ │ ├── Failure.sc │ │ │ ├── Hello.sc │ │ │ ├── HttpApi.sc │ │ │ ├── MultiMain.sc │ │ │ ├── PlayFramework.sc │ │ │ ├── Print.sc │ │ │ ├── QuickSort.sc │ │ │ ├── Resources.sc │ │ │ ├── SourceDownload.sc │ │ │ ├── Spark.sc │ │ │ ├── Spark2.json │ │ │ ├── Spark2.sc │ │ │ ├── Varargs.sc │ │ │ ├── http-api-data.json │ │ │ ├── ivyResolveItv1.sc │ │ │ ├── ivyResolveItv2.sc │ │ │ ├── ivyResolveSnapshot1.sc │ │ │ ├── ivyResolveSnapshot2.sc │ │ │ ├── scalaTags.sc │ │ │ └── wrongIvyCordinates.sc │ │ │ ├── errorTruncation │ │ │ ├── compileError.sc │ │ │ ├── compileErrorMultiExpr.sc │ │ │ ├── parseError.sc │ │ │ └── runtimeError.sc │ │ │ └── lineNumbers │ │ │ └── compilationErrorInSecondBlock.sc │ └── some-dummy-library │ │ ├── build.sbt │ │ └── project │ │ └── build.properties │ ├── scala-2.13 │ └── ammonite │ │ └── integration │ │ └── ProjectTests213.scala │ └── scala │ └── ammonite │ └── integration │ ├── AmmoniteBridge.scala │ ├── BasicTests.scala │ ├── ErrorTruncationTests.scala │ ├── LineNumberTests.scala │ ├── ProjectTests.scala │ ├── TestMain.scala │ └── TestUtils.scala ├── internals-docs ├── layering.md ├── packages.md └── predef.md ├── mill ├── project ├── build.properties └── plugins.sbt ├── readme.md ├── readme ├── ANSI.scala ├── Cookbook.scalatex ├── Footer.scalatex ├── Index.scalatex ├── Repl.scalatex ├── Sample.scala ├── Scripts.scalatex └── resources │ ├── Browse.gif │ ├── ColoredTraces.png │ ├── Debugging.png │ ├── DebuggingViaSshd.png │ ├── Desugar.png │ ├── Editing.gif │ ├── GettingStarted.png │ ├── Highlighting.png │ ├── HistorySearch.gif │ ├── IvyComplete.gif │ ├── ScriptFolderLayout.png │ ├── ScriptRepl.gif │ ├── Source.gif │ ├── Swing1.png │ ├── Swing2.png │ ├── Swing3.png │ ├── SystemShell.png │ ├── UndoRedo.gif │ ├── Watch.gif │ ├── favicon-old.png │ ├── favicon.png │ ├── smaller-favicon.png │ └── square-favicon.png ├── sshd └── src │ ├── main │ └── scala │ │ └── ammonite │ │ └── sshd │ │ ├── ShellSession.scala │ │ ├── SshServer.scala │ │ ├── SshServerConfig.scala │ │ ├── SshdRepl.scala │ │ └── util │ │ └── Environment.scala │ └── test │ └── scala │ └── ammonite │ └── sshd │ ├── Main.scala │ ├── ScalaCheckSupport.scala │ ├── SshServerTests.scala │ ├── SshTestingUtils.scala │ └── SshdReplTest.scala └── terminal └── src ├── main └── scala │ └── ammonite │ └── terminal │ ├── ConsoleDim.scala │ ├── Filter.scala │ ├── FilterTools.scala │ ├── LineReader.scala │ ├── Protocol.scala │ ├── SpecialKeys.scala │ ├── Terminal.scala │ ├── Utils.scala │ └── filters │ ├── BasicFilters.scala │ ├── GUILikeFilters.scala │ ├── HistoryFilter.scala │ ├── ReadlineFilters.scala │ └── UndoFilter.scala └── test ├── resource └── toobig.txt └── scala └── ammonite └── terminal ├── Checker.scala ├── EditTests.scala ├── HeightTests.scala ├── HistoryTests.scala ├── NavigationTests.scala └── TestMain.scala /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # Reformatted scala code 2 | 78d98a149f2a4d7ad81f398edc72475a4fe8c5bf 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: lihaoyi 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # documentation for all configuration options: 2 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: "github-actions" 7 | directory: "/" 8 | schedule: 9 | interval: "weekly" 10 | -------------------------------------------------------------------------------- /.github/workflows/publish-artifacts.yml: -------------------------------------------------------------------------------- 1 | name: Publish Artifacts 2 | 3 | on: 4 | push: 5 | tags: 6 | - '**' 7 | workflow_dispatch: 8 | 9 | jobs: 10 | publish-maven: 11 | 12 | runs-on: ubuntu-latest 13 | env: 14 | MILL_SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} 15 | MILL_SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} 16 | MILL_PGP_SECRET_BASE64: ${{ secrets.SONATYPE_PGP_PRIVATE_KEY }} 17 | MILL_PGP_PASSPHRASE: ${{ secrets.SONATYPE_PGP_PRIVATE_KEY_PASSWORD }} 18 | LANG: "en_US.UTF-8" 19 | LC_MESSAGES: "en_US.UTF-8" 20 | LC_ALL: "en_US.UTF-8" 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | - uses: actions/setup-java@v3 25 | with: 26 | distribution: 'temurin' 27 | java-version: 11 28 | - name: Publish to Maven Central 29 | run: ./mill -i mill.scalalib.PublishModule/ 30 | 31 | publish-docs: 32 | runs-on: ubuntu-latest 33 | env: 34 | DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} 35 | steps: 36 | - uses: actions/checkout@v4 37 | with: 38 | fetch-depth: 0 39 | - uses: actions/setup-java@v4 40 | with: 41 | java-version: '11' 42 | distribution: temurin 43 | 44 | - name: Setup sbt launcher 45 | uses: sbt/setup-sbt@v1 46 | 47 | - name: publish docs 48 | shell: 'script -q -e -c "bash {0}"' 49 | run: echo "Hello World" && ./mill -i publishDocs 50 | env: 51 | TERM: xterm-256color 52 | 53 | publish-executable: 54 | runs-on: ubuntu-latest 55 | env: 56 | AMMONITE_BOT_AUTH_TOKEN: ${{ secrets.AMMONITE_BOT_AUTH_TOKEN }} 57 | steps: 58 | - uses: actions/checkout@v4 59 | with: 60 | fetch-depth: 0 61 | - uses: actions/setup-java@v4 62 | with: 63 | java-version: '11' 64 | distribution: temurin 65 | - run: ./mill -i publishExecutable 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | *.iml 3 | .idea 4 | .settings 5 | .classpath 6 | .project 7 | .cache 8 | .sbtserver 9 | project/.sbtserver 10 | tags 11 | nohup.out 12 | out 13 | .bloop 14 | .vscode 15 | .metals 16 | .bsp 17 | -------------------------------------------------------------------------------- /.mill-version: -------------------------------------------------------------------------------- 1 | 0.12.0 2 | -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 1 | # Newer versions won't work with Java 8! 2 | version = "3.7.15" 3 | 4 | align.openParenCallSite = false 5 | align.preset = none 6 | align.stripMargin = true 7 | 8 | assumeStandardLibraryStripMargin = true 9 | 10 | continuationIndent.callSite = 2 11 | continuationIndent.defnSite = 4 12 | 13 | docstrings.oneline = keep 14 | docstrings.style = Asterisk 15 | docstrings.wrap = no 16 | 17 | maxColumn = 100 18 | 19 | newlines.source = keep 20 | 21 | project.git = true 22 | 23 | runner.dialect = scala213 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015 Li Haoyi (haoyi.sg@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /amm-template.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # This is a wrapper script, that automatically download ammonite from GitHub release pages 4 | # You can give the required ammonite version with AMM_VERSION env variable 5 | # If no version is given, it falls back to the value of DEFAULT_AMM_VERSION 6 | DEFAULT_AMM_VERSION= 7 | DEFAULT_SCALA_VERSION= 8 | set -e 9 | 10 | if [ -z "$AMM_VERSION" ] ; then 11 | AMM_VERSION=$DEFAULT_AMM_VERSION 12 | fi 13 | if [ -z "$SCALA_VERSION" ] ; then 14 | SCALA_VERSION=$DEFAULT_SCALA_VERSION 15 | fi 16 | 17 | if [ "x${XDG_CACHE_HOME}" != "x" ] ; then 18 | AMM_DOWNLOAD_PATH="${XDG_CACHE_HOME}/ammonite/download" 19 | else 20 | AMM_DOWNLOAD_PATH="${HOME}/.cache/ammonite/download" 21 | fi 22 | AMM_EXEC_PATH="${AMM_DOWNLOAD_PATH}/${AMM_VERSION}_$SCALA_VERSION" 23 | 24 | if [ ! -x "$AMM_EXEC_PATH" ] ; then 25 | mkdir -p $AMM_DOWNLOAD_PATH 26 | DOWNLOAD_FILE=$AMM_EXEC_PATH-tmp-download 27 | AMM_VERSION_TAG=$(echo $AMM_VERSION | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/') 28 | AMM_DOWNLOAD_URL="https://github.com/lihaoyi/ammonite/releases/download/${AMM_VERSION_TAG}/$SCALA_VERSION-$AMM_VERSION" 29 | curl --fail -L -o "$DOWNLOAD_FILE" "$AMM_DOWNLOAD_URL" 30 | chmod +x "$DOWNLOAD_FILE" 31 | mv "$DOWNLOAD_FILE" "$AMM_EXEC_PATH" 32 | unset DOWNLOAD_FILE 33 | unset AMM_DOWNLOAD_URL 34 | fi 35 | 36 | unset AMM_DOWNLOAD_PATH 37 | unset AMM_VERSION 38 | 39 | exec $AMM_EXEC_PATH "$@" 40 | -------------------------------------------------------------------------------- /amm/compiler/interface/src/main/scala/ammonite/compiler/iface/CodeWrapper.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler.iface 2 | 3 | import ammonite.util.{Imports, Name} 4 | import ammonite.util.Util.CodeSource 5 | 6 | abstract class CodeWrapper { 7 | def wrapperPath: Seq[Name] = Nil 8 | def apply( 9 | code: String, 10 | source: CodeSource, 11 | imports: Imports, 12 | printCode: String, 13 | indexedWrapper: Name, 14 | extraCode: String 15 | ): (String, String, Int) 16 | 17 | def wrapCode( 18 | codeSource: CodeSource, 19 | indexedWrapperName: Name, 20 | code: String, 21 | printCode: String, 22 | imports: Imports, 23 | extraCode: String, 24 | markScript: Boolean 25 | ) = { 26 | 27 | // we need to normalize topWrapper and bottomWrapper in order to ensure 28 | // the snippets always use the platform-specific newLine 29 | val extraCode0 = 30 | if (markScript) extraCode + "/**/" 31 | else extraCode 32 | val (topWrapper, bottomWrapper, userCodeNestingLevel) = 33 | apply(code, codeSource, imports, printCode, indexedWrapperName, extraCode0) 34 | val (topWrapper0, bottomWrapper0) = 35 | if (markScript) (topWrapper + "/**/ /**/" + bottomWrapper) 36 | else (topWrapper, bottomWrapper) 37 | val importsLen = topWrapper0.length 38 | 39 | (topWrapper0 + code + bottomWrapper0, importsLen, userCodeNestingLevel) 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /amm/compiler/interface/src/main/scala/ammonite/compiler/iface/Compiler.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler.iface 2 | 3 | import ammonite.util.{Imports, Printer} 4 | 5 | abstract class Compiler { 6 | 7 | def compile( 8 | src: Array[Byte], 9 | printer: Printer, 10 | importsLen: Int, 11 | userCodeNestingLevel: Int, 12 | fileName: String 13 | ): Option[Compiler.Output] 14 | 15 | def preprocessor(fileName: String, markGeneratedSections: Boolean = false): Preprocessor 16 | 17 | } 18 | 19 | object Compiler { 20 | 21 | case class Output( 22 | classFiles: Vector[(String, Array[Byte])], 23 | imports: Imports, 24 | usedEarlierDefinitions: Option[Seq[String]] 25 | ) 26 | 27 | } 28 | -------------------------------------------------------------------------------- /amm/compiler/interface/src/main/scala/ammonite/compiler/iface/CompilerBuilder.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler.iface 2 | 3 | import java.net.URL 4 | import java.nio.file.Path 5 | 6 | import ammonite.util.Frame 7 | 8 | abstract class CompilerBuilder { 9 | 10 | def newManager( 11 | rtCacheDir: Option[Path], 12 | headFrame: => Frame, 13 | dependencyCompleter: => Option[String => (Int, Seq[String])], 14 | whiteList: Set[Seq[String]], 15 | initialClassLoader: ClassLoader, 16 | settings: Seq[String] 17 | ): CompilerLifecycleManager 18 | 19 | def create( 20 | initialClassPath: Seq[URL], 21 | classPath: Seq[URL], 22 | dynamicClassPath: Seq[(String, Array[Byte])], 23 | evalClassLoader: ClassLoader, 24 | pluginClassLoader: ClassLoader, 25 | reporter: Option[CompilerBuilder.Message => Unit], 26 | settings: Seq[String], 27 | classPathWhiteList: Set[Seq[String]], 28 | lineNumberModifier: Boolean 29 | ): Compiler 30 | 31 | def scalaVersion: String 32 | } 33 | 34 | object CompilerBuilder { 35 | 36 | case class Message( 37 | severity: String, 38 | start: Int, 39 | end: Int, 40 | message: String 41 | ) 42 | 43 | } 44 | -------------------------------------------------------------------------------- /amm/compiler/interface/src/main/scala/ammonite/compiler/iface/CompilerLifecycleManager.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler.iface 2 | 3 | import java.nio.file.Path 4 | 5 | import ammonite.util.{Frame, Printer} 6 | import ammonite.util.Util.ClassFiles 7 | 8 | abstract class CompilerLifecycleManager { 9 | def compiler: Compiler 10 | def compilationCount: Int 11 | 12 | def preprocess(fileName: String): Preprocessor 13 | 14 | def scalaVersion: String 15 | 16 | def outputDir: Option[Path] 17 | 18 | def init(force: Boolean = false): Unit 19 | 20 | def complete( 21 | offset: Int, 22 | previousImports: String, 23 | snippet: String 24 | ): (Int, Seq[String], Seq[String]) 25 | 26 | def compileClass( 27 | processed: Preprocessor.Output, 28 | printer: Printer, 29 | fileName: String 30 | ): Option[Compiler.Output] 31 | 32 | def addToClasspath(classFiles: ClassFiles): Unit 33 | 34 | def shutdownPressy(): Unit 35 | } 36 | -------------------------------------------------------------------------------- /amm/compiler/interface/src/main/scala/ammonite/compiler/iface/Parser.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler.iface 2 | 3 | import ammonite.util.ImportTree 4 | import ammonite.util.Util.CodeSource 5 | 6 | abstract class Parser { 7 | 8 | def split( 9 | code: String, 10 | ignoreIncomplete: Boolean = true, 11 | fileName: String = "(console)" 12 | ): Option[Either[String, Seq[String]]] 13 | 14 | final def parseImportHooks( 15 | source: CodeSource, 16 | stmts: Seq[String] 17 | ): (Seq[String], Seq[ImportTree]) = 18 | parseImportHooksWithIndices(source, stmts.map((0, _))) 19 | def parseImportHooksWithIndices( 20 | source: CodeSource, 21 | stmts: Seq[(Int, String)] 22 | ): (Seq[String], Seq[ImportTree]) 23 | 24 | /** 25 | * Splits up a script file into its constituent blocks, each of which 26 | * is a tuple of (leading-whitespace, statements). Leading whitespace 27 | * is returned separately so we can later manipulate the statements e.g. 28 | * by adding `val res2 = ` without the whitespace getting in the way 29 | */ 30 | def splitScript( 31 | rawCode: String, 32 | fileName: String 33 | ): Either[String, IndexedSeq[(String, Seq[String])]] 34 | 35 | def scriptBlocksWithStartIndices( 36 | rawCode: String, 37 | fileName: String 38 | ): Either[Parser.ScriptSplittingError, Seq[Parser.ScriptBlock]] 39 | 40 | def defaultHighlight( 41 | buffer: Vector[Char], 42 | comment: fansi.Attrs, 43 | `type`: fansi.Attrs, 44 | literal: fansi.Attrs, 45 | keyword: fansi.Attrs, 46 | reset: fansi.Attrs, 47 | notImplemented: fansi.Attrs 48 | ): Vector[Char] 49 | 50 | def isObjDef(code: String): Boolean 51 | } 52 | 53 | object Parser { 54 | 55 | case class ParsedImportHooks( 56 | hookStatements: Seq[String], 57 | importTrees: Seq[ImportTree] 58 | ) 59 | 60 | case class ScriptBlock( 61 | startIndex: Int, 62 | ncomment: String, 63 | codeWithStartIndices: Seq[(Int, String)] 64 | ) 65 | 66 | object ScriptBlock { 67 | def apply( 68 | ncomment: String, 69 | codeWithStartIndices: Seq[(Int, String)] 70 | ): ScriptBlock = 71 | ScriptBlock(0, ncomment, codeWithStartIndices) 72 | } 73 | 74 | class ScriptSplittingError( 75 | message: String, 76 | val index: Int = -1, 77 | val expected: String = "" 78 | ) extends Exception(message) 79 | } 80 | -------------------------------------------------------------------------------- /amm/compiler/interface/src/main/scala/ammonite/compiler/iface/Preprocessor.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler.iface 2 | 3 | import ammonite.util.{Imports, Name, Res} 4 | import ammonite.util.Util.CodeSource 5 | 6 | /** 7 | * Responsible for all scala-source-code-munging that happens within the 8 | * Ammonite REPL. 9 | * 10 | * Performs several tasks: 11 | * 12 | * - Takes top-level Scala expressions and assigns them to `res{1, 2, 3, ...}` 13 | * values so they can be accessed later in the REPL 14 | * 15 | * - Wraps the code snippet with an wrapper `object` since Scala doesn't allow 16 | * top-level expressions 17 | * 18 | * - Mangles imports from our [[ammonite.util.ImportData]] data structure into a source 19 | * String 20 | * 21 | * - Combines all of these into a complete compilation unit ready to feed into 22 | * the Scala compiler 23 | */ 24 | abstract class Preprocessor { 25 | 26 | def transform( 27 | stmts: Seq[String], 28 | resultIndex: String, 29 | leadingSpaces: String, 30 | codeSource: CodeSource, 31 | indexedWrapperName: Name, 32 | imports: Imports, 33 | printerTemplate: String => String, 34 | extraCode: String, 35 | skipEmpty: Boolean, 36 | markScript: Boolean, 37 | codeWrapper: CodeWrapper 38 | ): Res[Preprocessor.Output] 39 | 40 | } 41 | 42 | object Preprocessor { 43 | 44 | case class Output( 45 | code: String, 46 | prefixCharLength: Int, 47 | userCodeNestingLevel: Int 48 | ) 49 | 50 | } 51 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-2.12.0_12/ammonite/compiler/CompilerCompatibility.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import ammonite.util.Classpath 4 | 5 | import scala.reflect.internal.util.Position 6 | import scala.reflect.io.FileZipArchive 7 | import scala.tools.nsc 8 | import scala.tools.nsc.{Global, Settings} 9 | import scala.tools.nsc.classpath.{AggregateClassPath, ZipAndJarClassPathFactory} 10 | import scala.tools.nsc.interactive.{InteractiveAnalyzer, Global => InteractiveGlobal} 11 | import scala.tools.nsc.plugins.Plugin 12 | import scala.tools.nsc.reporters.AbstractReporter 13 | import scala.tools.nsc.typechecker.Analyzer 14 | 15 | object CompilerCompatibility extends ExtraCompilerCompatibility { 16 | def analyzer(g: Global, cl: ClassLoader): Analyzer { val global: g.type } = { 17 | new { val global: g.type = g } with Analyzer { 18 | override def findMacroClassLoader() = cl 19 | } 20 | } 21 | 22 | def interactiveAnalyzer( 23 | g: InteractiveGlobal, 24 | cl: ClassLoader 25 | ): InteractiveAnalyzer { val global: g.type } = { 26 | new { val global: g.type = g } with InteractiveAnalyzer { 27 | override def findMacroClassLoader() = cl 28 | } 29 | } 30 | def importInfo(g: Global)(t: g.Import) = 31 | new g.analyzer.ImportInfo(t, 0) 32 | 33 | def initGlobal( 34 | settings: Settings, 35 | reporter: AbstractReporter, 36 | jcp: AggregateClassPath, 37 | evalClassloader: ClassLoader, 38 | createPlugins: Global => List[Plugin] 39 | ): Global = { 40 | 41 | new nsc.Global(settings, reporter) { g => 42 | override lazy val plugins = createPlugins(g) 43 | 44 | // Actually jcp, avoiding a path-dependent type issue in 2.10 here 45 | override def classPath = jcp 46 | 47 | override lazy val platform: ThisPlatform = new GlobalPlatform { 48 | override val global = g 49 | override val settings = g.settings 50 | override val classPath = jcp 51 | } 52 | 53 | override lazy val analyzer = CompilerCompatibility.analyzer(g, evalClassloader) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-2.12.0_8/ammonite/compiler/ExtraCompilerCompatibility.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import scala.reflect.io.FileZipArchive 4 | import scala.tools.nsc.Settings 5 | import scala.tools.nsc.classpath.ZipAndJarClassPathFactory 6 | 7 | abstract class ExtraCompilerCompatibility { 8 | 9 | def createZipJarFactory(arc: FileZipArchive, settings: Settings) = { 10 | ZipAndJarClassPathFactory.create(arc, settings) 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-2.12.10-2.13.1+/scala/tools/nsc/AmmClassPath.scala: -------------------------------------------------------------------------------- 1 | package scala.tools.nsc 2 | 3 | import java.io.File 4 | import java.net.URL 5 | 6 | import ammonite.compiler.internal.CustomURLZipArchive 7 | 8 | import scala.reflect.io.AbstractFile 9 | import scala.tools.nsc.classpath.FileUtils.AbstractFileOps 10 | import scala.tools.nsc.classpath.{ClassPathEntries, _} 11 | import scala.tools.nsc.util.{ClassPath, ClassRepresentation} 12 | 13 | trait AmmClassPath extends ClassPath { 14 | def zipUrl: URL 15 | def ammPackages(inPackage: String): Seq[PackageEntry] 16 | def packages(inPackage: scala.tools.nsc.classpath.PackageName): Seq[PackageEntry] = { 17 | ammPackages(inPackage.dottedString) 18 | } 19 | 20 | def ammList(inPackage: String): ClassPathEntries 21 | def list(inPackage: scala.tools.nsc.classpath.PackageName): ClassPathEntries = { 22 | ammList(inPackage.dottedString) 23 | } 24 | 25 | def ammClasses(inPackage: String): Seq[ClassFileEntry] 26 | def classes(inPackage: scala.tools.nsc.classpath.PackageName): Seq[ClassFileEntry] = { 27 | ammClasses(inPackage.dottedString) 28 | } 29 | 30 | def ammHasPackage(pkg: String): Boolean 31 | def hasPackage(pkg: scala.tools.nsc.classpath.PackageName) = ammHasPackage(pkg.dottedString) 32 | } 33 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-2.12.10-2.13.1+/scala/tools/nsc/WhiteListClasspath.scala: -------------------------------------------------------------------------------- 1 | package scala.tools.nsc 2 | 3 | import ammonite.util.Util 4 | 5 | import scala.tools.nsc.classpath.ClassPathEntries 6 | import scala.tools.nsc.util.ClassPath 7 | 8 | class WhiteListClasspath(aggregates: Seq[ClassPath], whitelist: Set[Seq[String]]) 9 | extends scala.tools.nsc.classpath.AggregateClassPath(aggregates) { 10 | override def findClassFile(name: String) = { 11 | val tokens = name.split('.') 12 | if (Util.lookupWhiteList(whitelist, tokens.init ++ Seq(tokens.last + ".class"))) { 13 | super.findClassFile(name) 14 | } else None 15 | } 16 | override def list(inPackage: scala.tools.nsc.classpath.PackageName) = { 17 | val superList = super.list(inPackage) 18 | ClassPathEntries( 19 | superList.packages.filter { p => Util.lookupWhiteList(whitelist, p.name.split('.')) }, 20 | superList.classesAndSources.filter { t => 21 | Util.lookupWhiteList(whitelist, inPackage.dottedString.split('.') ++ Seq(t.name + ".class")) 22 | } 23 | ) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-2.12.13+/ammonite/compiler/CompilerCompatibility.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import ammonite.util.Classpath 4 | 5 | import scala.reflect.internal.util.Position 6 | import scala.reflect.io.FileZipArchive 7 | import scala.tools.nsc 8 | import scala.tools.nsc.classpath.{AggregateClassPath, ZipAndJarClassPathFactory} 9 | import scala.tools.nsc.{Global, Settings} 10 | import scala.tools.nsc.interactive.{InteractiveAnalyzer, Global => InteractiveGlobal} 11 | import scala.tools.nsc.plugins.Plugin 12 | import scala.tools.nsc.reporters.Reporter 13 | import scala.tools.nsc.typechecker.Analyzer 14 | 15 | object CompilerCompatibility { 16 | 17 | def analyzer(g: Global, cl: ClassLoader): Analyzer { val global: g.type } = { 18 | new { val global: g.type = g } with Analyzer { 19 | override def findMacroClassLoader() = cl 20 | } 21 | } 22 | 23 | def interactiveAnalyzer( 24 | g: InteractiveGlobal, 25 | cl: ClassLoader 26 | ): InteractiveAnalyzer { val global: g.type } = { 27 | new { val global: g.type = g } with InteractiveAnalyzer 28 | } 29 | 30 | def importInfo(g: Global)(t: g.Import) = 31 | new g.analyzer.ImportInfo(t, 0) 32 | 33 | def initGlobal( 34 | settings: Settings, 35 | reporter: Reporter, 36 | jcp: AggregateClassPath, 37 | evalClassloader: ClassLoader, 38 | createPlugins: Global => List[Plugin] 39 | ): Global = { 40 | 41 | new nsc.Global(settings, reporter) { g => 42 | override lazy val plugins = createPlugins(g) 43 | 44 | override def classPath = jcp 45 | 46 | override lazy val platform: ThisPlatform = new GlobalPlatform { 47 | override val global = g 48 | override val settings = g.settings 49 | override val classPath = jcp 50 | } 51 | 52 | override lazy val analyzer = CompilerCompatibility.analyzer(g, evalClassloader) 53 | } 54 | } 55 | 56 | def createZipJarFactory(arc: FileZipArchive, settings: Settings) = { 57 | ZipAndJarClassPathFactory.create(arc, settings, new scala.tools.nsc.CloseableRegistry()) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-2.12.13+/ammonite/compiler/MakeReporter.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import ammonite.util.Classpath 4 | 5 | import scala.reflect.internal.util.Position 6 | import scala.reflect.io.FileZipArchive 7 | import scala.tools.nsc 8 | import scala.tools.nsc.classpath.{AggregateClassPath, ZipAndJarClassPathFactory} 9 | import scala.tools.nsc.{Global, Settings} 10 | import scala.tools.nsc.interactive.{InteractiveAnalyzer, Global => InteractiveGlobal} 11 | import scala.tools.nsc.plugins.Plugin 12 | import scala.tools.nsc.reporters.FilteringReporter 13 | import scala.tools.nsc.typechecker.Analyzer 14 | 15 | object MakeReporter { 16 | 17 | type Reporter = scala.tools.nsc.reporters.Reporter 18 | 19 | def makeReporter( 20 | errorLogger: (Position, String) => Unit, 21 | warningLogger: (Position, String) => Unit, 22 | infoLogger: (Position, String) => Unit, 23 | outerSettings: Settings 24 | ): Reporter = 25 | new FilteringReporter { 26 | 27 | def doReport( 28 | pos: scala.reflect.internal.util.Position, 29 | msg: String, 30 | severity: Severity 31 | ): Unit = 32 | display(pos, msg, severity) 33 | 34 | def display(pos: Position, msg: String, severity: Severity) = 35 | severity match { 36 | case ERROR => 37 | Classpath.traceClasspathProblem(s"ERROR: $msg") 38 | errorLogger(pos, msg) 39 | case WARNING => 40 | warningLogger(pos, msg) 41 | case INFO => 42 | infoLogger(pos, msg) 43 | } 44 | 45 | def settings = outerSettings 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-2.12.9+/ammonite/compiler/ExtraCompilerCompatibility.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import scala.reflect.io.FileZipArchive 4 | import scala.tools.nsc.Settings 5 | import scala.tools.nsc.classpath.ZipAndJarClassPathFactory 6 | 7 | abstract class ExtraCompilerCompatibility { 8 | 9 | def createZipJarFactory(arc: FileZipArchive, settings: Settings) = { 10 | ZipAndJarClassPathFactory.create(arc, settings, new scala.tools.nsc.CloseableRegistry()) 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-2.13.1-2.13.11/ammonite/compiler/MakeReporter.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import ammonite.util.Classpath 4 | 5 | import scala.reflect.internal.util.Position 6 | import scala.reflect.io.FileZipArchive 7 | import scala.tools.nsc 8 | import scala.tools.nsc.classpath.{AggregateClassPath, ZipAndJarClassPathFactory} 9 | import scala.tools.nsc.{Global, Settings} 10 | import scala.tools.nsc.interactive.{InteractiveAnalyzer, Global => InteractiveGlobal} 11 | import scala.tools.nsc.plugins.Plugin 12 | import scala.tools.nsc.reporters.FilteringReporter 13 | import scala.tools.nsc.typechecker.Analyzer 14 | 15 | object MakeReporter { 16 | 17 | type Reporter = scala.tools.nsc.reporters.Reporter 18 | 19 | def makeReporter( 20 | errorLogger: (Position, String) => Unit, 21 | warningLogger: (Position, String) => Unit, 22 | infoLogger: (Position, String) => Unit, 23 | outerSettings: Settings 24 | ): Reporter = 25 | new FilteringReporter { 26 | 27 | def doReport( 28 | pos: scala.reflect.internal.util.Position, 29 | msg: String, 30 | severity: Severity 31 | ): Unit = 32 | display(pos, msg, severity) 33 | 34 | def display(pos: Position, msg: String, severity: Severity) = 35 | severity match { 36 | case ERROR => 37 | Classpath.traceClasspathProblem(s"ERROR: $msg") 38 | errorLogger(pos, msg) 39 | case WARNING => 40 | warningLogger(pos, msg) 41 | case INFO => 42 | infoLogger(pos, msg) 43 | } 44 | 45 | def settings = outerSettings 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-2.13.12+/ammonite/compiler/MakeReporter.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import ammonite.util.Classpath 4 | 5 | import scala.reflect.internal.util.{CodeAction, Position} 6 | import scala.reflect.io.FileZipArchive 7 | import scala.tools.nsc 8 | import scala.tools.nsc.classpath.{AggregateClassPath, ZipAndJarClassPathFactory} 9 | import scala.tools.nsc.{Global, Settings} 10 | import scala.tools.nsc.interactive.{InteractiveAnalyzer, Global => InteractiveGlobal} 11 | import scala.tools.nsc.plugins.Plugin 12 | import scala.tools.nsc.reporters.FilteringReporter 13 | import scala.tools.nsc.typechecker.Analyzer 14 | 15 | object MakeReporter { 16 | 17 | type Reporter = scala.tools.nsc.reporters.Reporter 18 | 19 | def makeReporter( 20 | errorLogger: (Position, String) => Unit, 21 | warningLogger: (Position, String) => Unit, 22 | infoLogger: (Position, String) => Unit, 23 | outerSettings: Settings 24 | ): Reporter = 25 | new FilteringReporter { 26 | 27 | override def doReport( 28 | pos: scala.reflect.internal.util.Position, 29 | msg: String, 30 | severity: Severity, 31 | actions: List[CodeAction] 32 | ): Unit = 33 | display(pos, msg, severity) 34 | 35 | def display(pos: Position, msg: String, severity: Severity) = 36 | severity match { 37 | case ERROR => 38 | Classpath.traceClasspathProblem(s"ERROR: $msg") 39 | errorLogger(pos, msg) 40 | case WARNING => 41 | warningLogger(pos, msg) 42 | case INFO => 43 | infoLogger(pos, msg) 44 | } 45 | 46 | def settings = outerSettings 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-2.13/ammonite/compiler/CompilerCompatibility.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import ammonite.util.Classpath 4 | 5 | import scala.reflect.internal.util.Position 6 | import scala.reflect.io.FileZipArchive 7 | import scala.tools.nsc 8 | import scala.tools.nsc.classpath.{AggregateClassPath, ZipAndJarClassPathFactory} 9 | import scala.tools.nsc.{Global, Settings} 10 | import scala.tools.nsc.interactive.{InteractiveAnalyzer, Global => InteractiveGlobal} 11 | import scala.tools.nsc.plugins.Plugin 12 | import scala.tools.nsc.reporters.Reporter 13 | import scala.tools.nsc.typechecker.Analyzer 14 | import scala.tools.nsc.typechecker.MacroAnnotationNamers 15 | 16 | object CompilerCompatibility { 17 | 18 | def analyzer(g: Global, cl: ClassLoader): Analyzer { val global: g.type } = { 19 | 20 | // Adding MacroAnnotationNamers like scalac does, see 21 | // https://github.com/scala/scala/blob/434a3d78/src/compiler/scala/tools/nsc/Global.scala#L481 22 | val macroAnnotations = g.settings.YmacroAnnotations.value 23 | 24 | if (macroAnnotations) 25 | new { val global: g.type = g } with Analyzer with MacroAnnotationNamers { 26 | override def defaultMacroClassloader = global.findMacroClassLoader 27 | } 28 | else 29 | new { val global: g.type = g } with Analyzer { 30 | override def defaultMacroClassloader = global.findMacroClassLoader 31 | } 32 | } 33 | 34 | def interactiveAnalyzer( 35 | g: InteractiveGlobal, 36 | cl: ClassLoader 37 | ): InteractiveAnalyzer { val global: g.type } = { 38 | new { val global: g.type = g } with InteractiveAnalyzer {} 39 | } 40 | 41 | def importInfo(g: Global)(t: g.Import) = 42 | new g.analyzer.ImportInfo(t, 0, false) 43 | 44 | def initGlobal( 45 | settings: Settings, 46 | reporter: Reporter, 47 | jcp: AggregateClassPath, 48 | evalClassloader: ClassLoader, 49 | createPlugins: Global => List[Plugin] 50 | ): Global = { 51 | 52 | new nsc.Global(settings, reporter) { g => 53 | override lazy val plugins = createPlugins(g) 54 | 55 | // Actually jcp, avoiding a path-dependent type issue in 2.10 here 56 | override def classPath = jcp 57 | override def findMacroClassLoader() = evalClassloader 58 | override lazy val platform: ThisPlatform = new GlobalPlatform { 59 | override val global = g 60 | override val settings = g.settings 61 | override val classPath = jcp 62 | } 63 | 64 | override lazy val analyzer = CompilerCompatibility.analyzer(g, evalClassloader) 65 | } 66 | } 67 | 68 | def createZipJarFactory(arc: FileZipArchive, settings: Settings) = { 69 | ZipAndJarClassPathFactory.create(arc, settings, new scala.tools.nsc.CloseableRegistry()) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-2/ammonite/compiler/CompilerExtensions.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import ammonite.interp.api.InterpAPI 4 | import ammonite.repl.api.ReplAPI 5 | 6 | import java.nio.file.Path 7 | 8 | object CompilerExtensions { 9 | 10 | implicit class CompilerInterpAPIExtensions(private val api: InterpAPI) extends AnyVal { 11 | 12 | private def compilerManager = api._compilerManager.asInstanceOf[CompilerLifecycleManager] 13 | 14 | /** 15 | * Configures the current compiler, or if the compiler hasn't been initialized 16 | * yet, registers the configuration callback and applies it to the compiler 17 | * when it ends up being initialized later 18 | */ 19 | def configureCompiler(c: scala.tools.nsc.Global => Unit): Unit = 20 | compilerManager.configureCompiler(c) 21 | 22 | /** 23 | * Pre-configures the next compiler. Useful for tuning options that are 24 | * used during parsing such as -Yrangepos 25 | */ 26 | def preConfigureCompiler(c: scala.tools.nsc.Settings => Unit): Unit = 27 | compilerManager.preConfigureCompiler(c) 28 | 29 | /** 30 | * Directory where the byte code resulting from compiling the user code is written. 31 | * This is non-empty only if the `--output-directory` or `--tmp-output-directory` options 32 | * are passed to Ammonite upon launch. 33 | */ 34 | def outputDir: Option[Path] = 35 | compilerManager.outputDir 36 | } 37 | 38 | implicit class CompilerReplAPIExtensions(private val api: ReplAPI) extends AnyVal { 39 | 40 | private def compilerManager = api._compilerManager.asInstanceOf[CompilerLifecycleManager] 41 | 42 | /** 43 | * Access the compiler to do crazy things if you really want to! 44 | */ 45 | def compiler: scala.tools.nsc.Global = 46 | compilerManager.compiler.compiler 47 | 48 | /** 49 | * Access the presentation compiler to do even crazier things if you really want to! 50 | */ 51 | def interactiveCompiler: scala.tools.nsc.interactive.Global = 52 | compilerManager.pressy.compiler 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-2/ammonite/compiler/tools/desugar.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler.tools 2 | 3 | import sourcecode.Compat._ 4 | import scala.language.experimental.macros 5 | 6 | class Desugared(s: String) { 7 | override def toString() = s 8 | } 9 | object desugar { 10 | def transformer(c: Context)(expr: c.Expr[Any]): c.Expr[Desugared] = { 11 | import c.universe._ 12 | c.Expr[Desugared]( 13 | q"ammonite.compiler.tools.SourceRuntime.desugarImpl(${c.universe.showCode(expr.tree)})" 14 | ) 15 | } 16 | 17 | def apply(expr: Any): Desugared = macro transformer 18 | } 19 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3.0.0-3.3.1/ammonite/compiler/DirectoryClassPath.scala: -------------------------------------------------------------------------------- 1 | package dotty.ammonite.compiler 2 | 3 | import java.io.{File => JFile} 4 | import dotty.tools.dotc.classpath 5 | import dotty.tools.io.{AbstractFile, PlainFile, ClassPath, ClassRepresentation, EfficientClassPath} 6 | import classpath.FileUtils._ 7 | 8 | case class DirectoryClassPath(dir: JFile) 9 | extends classpath.JFileDirectoryLookup[classpath.ClassFileEntryImpl] 10 | with classpath.NoSourcePaths { 11 | override def findClass(className: String): Option[ClassRepresentation] = 12 | findClassFile(className) map classpath.ClassFileEntryImpl 13 | 14 | def findClassFile(className: String): Option[AbstractFile] = { 15 | val relativePath = classpath.FileUtils.dirPath(className) 16 | val classFile = new JFile(dir, relativePath + ".class") 17 | if (classFile.exists) { 18 | val wrappedClassFile = new dotty.tools.io.File(classFile.toPath) 19 | val abstractClassFile = new PlainFile(wrappedClassFile) 20 | Some(abstractClassFile) 21 | } else None 22 | } 23 | 24 | protected def createFileEntry(file: AbstractFile): classpath.ClassFileEntryImpl = 25 | classpath.ClassFileEntryImpl(file) 26 | protected def isMatchingFile(f: JFile): Boolean = 27 | f.isClass 28 | 29 | private[dotty] def classes(inPackage: classpath.PackageName): Seq[classpath.ClassFileEntry] = 30 | files(inPackage) 31 | } 32 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3.0.0-3.6.2/ammonite/compiler/DottyParser.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import dotty.tools.dotc 4 | import dotc.ast.untpd 5 | import dotc.core.Contexts.Context 6 | import dotc.core.Flags 7 | import dotc.core.StdNames.nme 8 | import dotc.parsing.Parsers.{Location, Parser} 9 | import dotc.parsing.Tokens 10 | import dotc.reporting.IllegalStartOfStatement 11 | import dotc.util.SourceFile 12 | 13 | import scala.collection.mutable 14 | 15 | class DottyParser(source: SourceFile)(using Context) extends Parser(source) with CompatibilityParser { 16 | 17 | // From 18 | // https://github.com/lampepfl/dotty/blob/3.0.0-M3/ 19 | // compiler/src/dotty/tools/dotc/parsing/Parsers.scala/#L67-L71 20 | extension (buf: mutable.ListBuffer[untpd.Tree]) 21 | def +++=(x: untpd.Tree) = x match { 22 | case x: untpd.Thicket => buf ++= x.trees 23 | case x => buf += x 24 | } 25 | 26 | private val oursLocalModifierTokens = Tokens.localModifierTokens + Tokens.PRIVATE 27 | 28 | override def localDef( 29 | start: Int, 30 | implicitMods: untpd.Modifiers = untpd.EmptyModifiers 31 | ): untpd.Tree = { 32 | var mods = defAnnotsMods(oursLocalModifierTokens) 33 | for (imod <- implicitMods.mods) mods = addMod(mods, imod) 34 | if (mods.is(Flags.Final)) 35 | // A final modifier means the local definition is "class-like". 36 | // FIXME: Deal with modifiers separately 37 | tmplDef(start, mods) 38 | else 39 | defOrDcl(start, mods) 40 | } 41 | 42 | // Adapted from 43 | // https://github.com/lampepfl/dotty/blob/3.2.0/ 44 | // compiler/src/dotty/tools/dotc/parsing/Parsers.scala#L4075-L4094 45 | // Unlike it, we accept private modifiers for top-level definitions. 46 | override def blockStatSeq(): List[untpd.Tree] = checkNoEscapingPlaceholders { 47 | val stats = new mutable.ListBuffer[untpd.Tree] 48 | while 49 | var empty = false 50 | if (in.token == Tokens.IMPORT) 51 | stats ++= compatibilityImportClause() 52 | else if (isExprIntro) 53 | stats += expr(Location.InBlock) 54 | else if in.token == Tokens.IMPLICIT && !in.inModifierPosition() then 55 | stats += closure( 56 | in.offset, 57 | Location.InBlock, 58 | modifiers(scala.collection.immutable.BitSet(Tokens.IMPLICIT)) 59 | ) 60 | else if isIdent(nme.extension) && followingIsExtension() then 61 | stats += extension() 62 | else if isDefIntro(oursLocalModifierTokens, excludedSoftModifiers = Set(nme.`opaque`)) then 63 | stats +++= localDef(in.offset) 64 | else 65 | empty = true 66 | statSepOrEnd(stats, noPrevStat = empty, altEnd = Tokens.CASE) 67 | do () 68 | stats.toList 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3.3.2+/ammonite/compiler/DirectoryClassPath.scala: -------------------------------------------------------------------------------- 1 | package dotty.ammonite.compiler 2 | 3 | import java.io.{File => JFile} 4 | import dotty.tools.dotc.classpath 5 | import dotty.tools.io.{AbstractFile, PlainFile, ClassPath, ClassRepresentation, EfficientClassPath} 6 | import classpath.FileUtils._ 7 | 8 | case class DirectoryClassPath(dir: JFile) 9 | extends classpath.JFileDirectoryLookup[classpath.ClassFileEntryImpl] 10 | with classpath.NoSourcePaths { 11 | override def findClass(className: String): Option[ClassRepresentation] = 12 | findClassFile(className) map classpath.ClassFileEntryImpl 13 | 14 | def findClassFile(className: String): Option[AbstractFile] = { 15 | val relativePath = classpath.FileUtils.dirPath(className) 16 | val classFile = new JFile(dir, relativePath + ".class") 17 | if (classFile.exists) { 18 | val wrappedClassFile = new dotty.tools.io.File(classFile.toPath) 19 | val abstractClassFile = new PlainFile(wrappedClassFile) 20 | Some(abstractClassFile) 21 | } else None 22 | } 23 | 24 | protected def createFileEntry(file: AbstractFile): classpath.ClassFileEntryImpl = 25 | classpath.ClassFileEntryImpl(file) 26 | protected def isMatchingFile(f: JFile): Boolean = 27 | f.isClass 28 | 29 | private[dotty] def classes(inPackage: classpath.PackageName): Seq[classpath.ClassFileEntry] = 30 | files(inPackage) 31 | } 32 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3.4.2+/ammonite/compiler/DirectoryClassPath.scala: -------------------------------------------------------------------------------- 1 | package dotty.ammonite.compiler 2 | 3 | import java.io.{File => JFile} 4 | import dotty.tools.dotc.classpath 5 | import dotty.tools.io.{AbstractFile, PlainFile, ClassPath, ClassRepresentation, EfficientClassPath} 6 | import classpath.FileUtils._ 7 | 8 | case class DirectoryClassPath(dir: JFile) 9 | extends classpath.JFileDirectoryLookup[classpath.BinaryFileEntry] 10 | with classpath.NoSourcePaths { 11 | override def findClass(className: String): Option[ClassRepresentation] = 12 | findClassFile(className) map classpath.BinaryFileEntry.apply 13 | 14 | def findClassFile(className: String): Option[AbstractFile] = { 15 | val relativePath = classpath.FileUtils.dirPath(className) 16 | val classFile = new JFile(dir, relativePath + ".class") 17 | if (classFile.exists) { 18 | val wrappedClassFile = new dotty.tools.io.File(classFile.toPath) 19 | val abstractClassFile = new PlainFile(wrappedClassFile) 20 | Some(abstractClassFile) 21 | } else None 22 | } 23 | 24 | protected def createFileEntry(file: AbstractFile): classpath.BinaryFileEntry = 25 | classpath.BinaryFileEntry(file) 26 | protected def isMatchingFile(f: JFile): Boolean = 27 | f.isClass 28 | 29 | private[dotty] def classes(inPackage: classpath.PackageName): Seq[classpath.BinaryFileEntry] = 30 | files(inPackage) 31 | } 32 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3.5.0+/ammonite/compiler/DirectoryClassPath.scala: -------------------------------------------------------------------------------- 1 | package dotty.ammonite.compiler 2 | 3 | import java.io.{File => JFile} 4 | import dotty.tools.dotc.classpath 5 | import dotty.tools.io.{AbstractFile, PlainFile, ClassPath, ClassRepresentation, EfficientClassPath} 6 | import classpath.FileUtils._ 7 | 8 | case class DirectoryClassPath(dir: JFile) 9 | extends classpath.JFileDirectoryLookup[classpath.BinaryFileEntry] 10 | with classpath.NoSourcePaths { 11 | 12 | def findClassFile(className: String): Option[AbstractFile] = { 13 | val relativePath = classpath.FileUtils.dirPath(className) 14 | val classFile = new JFile(dir, relativePath + ".class") 15 | if (classFile.exists) { 16 | val wrappedClassFile = new dotty.tools.io.File(classFile.toPath) 17 | val abstractClassFile = new PlainFile(wrappedClassFile) 18 | Some(abstractClassFile) 19 | } else None 20 | } 21 | 22 | protected def createFileEntry(file: AbstractFile): classpath.BinaryFileEntry = 23 | classpath.BinaryFileEntry(file) 24 | protected def isMatchingFile(f: JFile): Boolean = 25 | f.isClass 26 | 27 | private[dotty] def classes(inPackage: classpath.PackageName): Seq[classpath.BinaryFileEntry] = 28 | files(inPackage) 29 | } 30 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3.6.3+/ammonite/compiler/DottyParser.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import dotty.tools.dotc 4 | import dotc.ast.untpd 5 | import dotc.core.Contexts.Context 6 | import dotc.core.Flags 7 | import dotc.core.StdNames.nme 8 | import dotc.parsing.Parsers.{Location, Parser} 9 | import dotc.parsing.Tokens 10 | import dotc.reporting.IllegalStartOfStatement 11 | import dotc.util.SourceFile 12 | 13 | import scala.collection.mutable 14 | 15 | class DottyParser(source: SourceFile)(using Context) extends Parser(source) with CompatibilityParser { 16 | 17 | // From 18 | // https://github.com/lampepfl/dotty/blob/3.0.0-M3/ 19 | // compiler/src/dotty/tools/dotc/parsing/Parsers.scala/#L67-L71 20 | extension (buf: mutable.ListBuffer[untpd.Tree]) 21 | def +++=(x: untpd.Tree) = x match { 22 | case x: untpd.Thicket => buf ++= x.trees 23 | case x => buf += x 24 | } 25 | 26 | private val oursLocalModifierTokens = Tokens.localModifierTokens + Tokens.PRIVATE 27 | 28 | override def localDef( 29 | start: Int, 30 | implicitMods: untpd.Modifiers = untpd.EmptyModifiers 31 | ): untpd.Tree = { 32 | var mods = defAnnotsMods(oursLocalModifierTokens) 33 | for (imod <- implicitMods.mods) mods = addMod(mods, imod) 34 | if (mods.is(Flags.Final)) 35 | // A final modifier means the local definition is "class-like". 36 | // FIXME: Deal with modifiers separately 37 | tmplDef(start, mods) 38 | else 39 | defOrDcl(start, mods) 40 | } 41 | 42 | // Adapted from 43 | // https://github.com/lampepfl/dotty/blob/3.2.0/ 44 | // compiler/src/dotty/tools/dotc/parsing/Parsers.scala#L4075-L4094 45 | // Unlike it, we accept private modifiers for top-level definitions. 46 | override def blockStatSeq(outermost: Boolean = false): List[untpd.Tree] = checkNoEscapingPlaceholders { 47 | val stats = new mutable.ListBuffer[untpd.Tree] 48 | while 49 | var empty = false 50 | if (in.token == Tokens.IMPORT) 51 | stats ++= compatibilityImportClause() 52 | else if (isExprIntro) 53 | stats += expr(Location.InBlock) 54 | else if in.token == Tokens.IMPLICIT && !in.inModifierPosition() then 55 | stats += closure( 56 | in.offset, 57 | Location.InBlock, 58 | modifiers(scala.collection.immutable.BitSet(Tokens.IMPLICIT)) 59 | ) 60 | else if isIdent(nme.extension) && followingIsExtension() then 61 | stats += extension() 62 | else if isDefIntro(oursLocalModifierTokens, excludedSoftModifiers = Set(nme.`opaque`)) then 63 | stats +++= localDef(in.offset) 64 | else 65 | empty = true 66 | statSepOrEnd(stats, noPrevStat = empty, altEnd = Tokens.CASE) 67 | do () 68 | stats.toList 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3/ammonite/compiler/AsmPositionUpdater.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | // originally based on https://github.com/VirtusLab/scala-cli/blob/67db91cfbaa74de806fd1d5ed00096affa0125c0/modules/build/src/main/scala/scala/build/postprocessing/AsmPositionUpdater.scala 4 | 5 | import org.objectweb.asm 6 | import java.io.InputStream 7 | 8 | object AsmPositionUpdater { 9 | 10 | private class LineNumberTableMethodVisitor( 11 | lineShift: Int, 12 | delegate: asm.MethodVisitor 13 | ) extends asm.MethodVisitor(asm.Opcodes.ASM9, delegate) { 14 | override def visitLineNumber(line: Int, start: asm.Label): Unit = 15 | super.visitLineNumber(line + lineShift, start) 16 | } 17 | 18 | private class LineNumberTableClassVisitor( 19 | mappings: Map[String, (String, Int)], 20 | cw: asm.ClassWriter 21 | ) extends asm.ClassVisitor(asm.Opcodes.ASM9, cw) { 22 | private var lineShiftOpt = Option.empty[Int] 23 | def mappedStuff = lineShiftOpt.nonEmpty 24 | override def visitSource(source: String, debug: String): Unit = 25 | mappings.get(source) match { 26 | case None => 27 | super.visitSource(source, debug) 28 | case Some((newSource, lineShift)) => 29 | lineShiftOpt = Some(lineShift) 30 | super.visitSource(newSource, debug) 31 | } 32 | override def visitMethod( 33 | access: Int, 34 | name: String, 35 | descriptor: String, 36 | signature: String, 37 | exceptions: Array[String] 38 | ): asm.MethodVisitor = { 39 | val main = super.visitMethod(access, name, descriptor, signature, exceptions) 40 | lineShiftOpt match { 41 | case None => main 42 | case Some(lineShift) => new LineNumberTableMethodVisitor(lineShift, main) 43 | } 44 | } 45 | } 46 | 47 | def postProcess( 48 | mappings: Map[String, (String, Int)], 49 | clsInputStream: InputStream 50 | ): Option[Array[Byte]] = { 51 | val reader = new asm.ClassReader(clsInputStream) 52 | val writer = new asm.ClassWriter(reader, 0) 53 | val checker = new LineNumberTableClassVisitor(mappings, writer) 54 | reader.accept(checker, 0) 55 | if (checker.mappedStuff) Some(writer.toByteArray) 56 | else None 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3/ammonite/compiler/CompatibilityParser.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import dotty.tools.dotc.parsing.Parsers.Parser 4 | import dotty.tools.dotc.parsing.Tokens 5 | 6 | trait CompatibilityParser { self: Parser => 7 | 8 | def compatibilityImportClause() = 9 | importClause() 10 | 11 | } 12 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3/ammonite/compiler/CompilerBuilder.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import java.net.URL 4 | import java.nio.file.Path 5 | 6 | import ammonite.compiler.iface.{ 7 | Compiler => ICompiler, 8 | CompilerBuilder => ICompilerBuilder, 9 | CompilerLifecycleManager => ICompilerLifecycleManager, 10 | _ 11 | } 12 | import ammonite.util.Frame 13 | import dotty.tools.io.AbstractFile 14 | 15 | case class CompilerBuilder( 16 | outputDir: Option[Path] = None 17 | ) extends ICompilerBuilder: 18 | 19 | def create( 20 | initialClassPath: Seq[URL], 21 | classPath: Seq[URL], 22 | dynamicClassPath: Seq[(String, Array[Byte])], 23 | evalClassLoader: ClassLoader, 24 | pluginClassLoader: ClassLoader, 25 | reporter: Option[ICompilerBuilder.Message => Unit], 26 | settings: Seq[String], 27 | classPathWhiteList: Set[Seq[String]], 28 | lineNumberModifier: Boolean 29 | ): ICompiler = { 30 | val tempDir = AbstractFile.getDirectory(outputDir.getOrElse(os.temp.dir().toNIO)) 31 | Compiler.addToClasspath(dynamicClassPath, tempDir, outputDir) 32 | new Compiler( 33 | tempDir, 34 | initialClassPath, 35 | classPath, 36 | evalClassLoader, 37 | classPathWhiteList, 38 | settings = settings, 39 | reporter = reporter 40 | ) 41 | } 42 | 43 | def scalaVersion = CompilerBuilder.scalaVersion 44 | 45 | def newManager( 46 | rtCacheDir: Option[Path], 47 | headFrame: => Frame, 48 | dependencyCompleter: => Option[String => (Int, Seq[String])], 49 | whiteList: Set[Seq[String]], 50 | initialClassLoader: ClassLoader, 51 | settings: Seq[String] 52 | ): ICompilerLifecycleManager = 53 | new CompilerLifecycleManager( 54 | rtCacheDir, 55 | headFrame, 56 | dependencyCompleter, 57 | whiteList, 58 | initialClassLoader, 59 | outputDir, 60 | settings 61 | ) 62 | 63 | object CompilerBuilder: 64 | def scalaVersion = dotty.tools.dotc.config.Properties.versionNumberString 65 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3/ammonite/compiler/CompilerExtensions.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import ammonite.interp.api.InterpAPI 4 | import ammonite.repl.api.ReplAPI 5 | 6 | import java.nio.file.Path 7 | 8 | object CompilerExtensions { 9 | 10 | implicit class CompilerInterpAPIExtensions(private val api: InterpAPI) extends AnyVal { 11 | 12 | private def compilerManager = api._compilerManager.asInstanceOf[CompilerLifecycleManager] 13 | 14 | /** 15 | * Configures the current compiler, or if the compiler hasn't been initialized 16 | * yet, registers the configuration callback and applies it to the compiler 17 | * when it ends up being initialized later 18 | */ 19 | def configureCompiler(c: dotty.tools.dotc.Compiler => Unit): Unit = 20 | compilerManager.configureCompiler(c) 21 | 22 | /** 23 | * Pre-configures the next compiler context. Useful for tuning options that are 24 | * used during parsing. 25 | */ 26 | def preConfigureCompiler(c: dotty.tools.dotc.core.Contexts.FreshContext => Unit): Unit = 27 | compilerManager.preConfigureCompiler(c) 28 | 29 | /** 30 | * Directory where the byte code resulting from compiling the user code is written. 31 | * This is non-empty only if the `--output-directory` or `--tmp-output-directory` options 32 | * are passed to Ammonite upon launch. 33 | */ 34 | def outputDir: Option[Path] = 35 | compilerManager.outputDir 36 | } 37 | 38 | implicit class CompilerReplAPIExtensions(private val api: ReplAPI) extends AnyVal { 39 | 40 | private def compilerManager = api._compilerManager.asInstanceOf[CompilerLifecycleManager] 41 | 42 | def initialContext: dotty.tools.dotc.core.Contexts.Context = 43 | compilerManager.compiler.initialCtx 44 | 45 | /** 46 | * Access the compiler to do crazy things if you really want to! 47 | */ 48 | def compiler: dotty.tools.dotc.Compiler = 49 | compilerManager.compiler.compiler 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3/ammonite/compiler/Extensions.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import ammonite.interp.api.InterpAPI 4 | 5 | object Extensions { 6 | 7 | implicit class CompilerInterAPIExtensions(private val self: InterpAPI) extends AnyVal 8 | 9 | } 10 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3/ammonite/compiler/internal/CompilerHelper.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler.internal 2 | 3 | import dotty.tools.dotc.core.Contexts._ 4 | import dotty.tools.dotc.parsing.Parser 5 | import dotty.tools.dotc.reporting.{Diagnostic, MessageRendering} 6 | import dotty.tools.dotc.typer.TyperPhase 7 | 8 | object CompilerHelper { 9 | def frontEndPhases = List( 10 | List(new Parser), 11 | List(new TyperPhase) 12 | ) 13 | def messageAndPos(messageRenderer: MessageRendering, diagnostic: Diagnostic)(implicit 14 | ctx: Context 15 | ) = 16 | messageRenderer.messageAndPos(diagnostic) 17 | } 18 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3/ammonite/compiler/tools/desugar.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler.tools 2 | 3 | object desugar 4 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3/ammonite/compiler/tools/source.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler.tools 2 | 3 | import ammonite.util.Util.Location 4 | 5 | object source { 6 | 7 | def load(f: => Any): Location = ??? 8 | 9 | } 10 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3/dotty/ammonite/compiler/AmmCompletionExtras.scala: -------------------------------------------------------------------------------- 1 | package dotty.ammonite.compiler 2 | 3 | import dotty.tools.dotc.interactive.Completion 4 | 5 | trait AmmCompletionExtras { 6 | 7 | def maybeBackticked(input: String, hasBackTick: Boolean): Completion = 8 | Completion.backtickCompletions(Completion(input, "", Nil), hasBackTick) 9 | def backtick(completion: Completion): Completion = 10 | Completion.backtickCompletions(completion, completion.label.startsWith("`")) 11 | 12 | } 13 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-3/dotty/ammonite/compiler/WhiteListClassPath.scala: -------------------------------------------------------------------------------- 1 | package dotty.ammonite.compiler 2 | 3 | import ammonite.util.Util 4 | 5 | import dotty.tools.dotc.classpath.{ClassPathEntries, PackageName} 6 | import dotty.tools.io.ClassPath 7 | 8 | class WhiteListClasspath(aggregates: Seq[ClassPath], whitelist: Set[Seq[String]]) 9 | extends dotty.tools.dotc.classpath.AggregateClassPath(aggregates) { 10 | override def findClassFile(name: String) = { 11 | val tokens = name.split('.') 12 | if (Util.lookupWhiteList(whitelist, tokens.init ++ Seq(tokens.last + ".class"))) { 13 | super.findClassFile(name) 14 | } else None 15 | } 16 | 17 | override def list(inPackage: PackageName) = { 18 | val superList = super.list(inPackage) 19 | ClassPathEntries( 20 | superList.packages.filter { p => Util.lookupWhiteList(whitelist, p.name.split('.')) }, 21 | superList.classesAndSources.filter { t => 22 | Util.lookupWhiteList(whitelist, inPackage.dottedString.split('.') ++ Seq(t.name + ".class")) 23 | } 24 | ) 25 | } 26 | 27 | override def toString: String = 28 | s"WhiteListClasspath($aggregates, ${whitelist.size} white-listed elements)" 29 | } 30 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-not-2.12.10-2.13.1+/scala/tools/nsc/AmmClassPath.scala: -------------------------------------------------------------------------------- 1 | package scala.tools.nsc 2 | 3 | import java.io.File 4 | import java.net.URL 5 | 6 | import ammonite.compiler.internal.CustomURLZipArchive 7 | 8 | import scala.reflect.io.AbstractFile 9 | import scala.tools.nsc.classpath.FileUtils.AbstractFileOps 10 | import scala.tools.nsc.classpath.{ClassPathEntries, _} 11 | import scala.tools.nsc.util.{ClassPath, ClassRepresentation} 12 | 13 | trait AmmClassPath extends ClassPath { 14 | def zipUrl: URL 15 | def ammPackages(inPackage: String): Seq[PackageEntry] 16 | def packages(inPackage: String): Seq[PackageEntry] = { 17 | ammPackages(inPackage) 18 | } 19 | 20 | def ammList(inPackage: String): ClassPathEntries 21 | def list(inPackage: String): ClassPathEntries = { 22 | ammList(inPackage) 23 | } 24 | 25 | def ammClasses(inPackage: String): Seq[ClassFileEntry] 26 | def classes(inPackage: String): Seq[ClassFileEntry] = { 27 | ammClasses(inPackage) 28 | } 29 | 30 | def ammHasPackage(pkg: String): Boolean 31 | def hasPackage(pkg: String) = ammHasPackage(pkg) 32 | } 33 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-not-2.12.10-2.13.1+/scala/tools/nsc/WhiteListClasspath.scala: -------------------------------------------------------------------------------- 1 | package scala.tools.nsc 2 | 3 | import ammonite.util.Util 4 | 5 | import scala.tools.nsc.classpath.ClassPathEntries 6 | import scala.tools.nsc.util.ClassPath 7 | 8 | class WhiteListClasspath(aggregates: Seq[ClassPath], whitelist: Set[Seq[String]]) 9 | extends scala.tools.nsc.classpath.AggregateClassPath(aggregates) { 10 | override def findClassFile(name: String) = { 11 | val tokens = name.split('.') 12 | if (Util.lookupWhiteList(whitelist, tokens.init ++ Seq(tokens.last + ".class"))) { 13 | super.findClassFile(name) 14 | } else None 15 | } 16 | override def list(inPackage: String) = { 17 | val superList = super.list(inPackage) 18 | ClassPathEntries( 19 | superList.packages.filter { p => Util.lookupWhiteList(whitelist, p.name.split('.')) }, 20 | superList.classesAndSources.filter { t => 21 | Util.lookupWhiteList(whitelist, inPackage.split('.') ++ Seq(t.name + ".class")) 22 | } 23 | ) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala-not-2.12.13+-2.13.1+/ammonite/compiler/MakeReporter.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import ammonite.util.Classpath 4 | 5 | import scala.reflect.internal.util.Position 6 | import scala.reflect.io.FileZipArchive 7 | import scala.tools.nsc 8 | import scala.tools.nsc.{Global, Settings} 9 | import scala.tools.nsc.classpath.{AggregateClassPath, ZipAndJarClassPathFactory} 10 | import scala.tools.nsc.interactive.{InteractiveAnalyzer, Global => InteractiveGlobal} 11 | import scala.tools.nsc.plugins.Plugin 12 | import scala.tools.nsc.reporters.AbstractReporter 13 | import scala.tools.nsc.typechecker.Analyzer 14 | 15 | object MakeReporter { 16 | 17 | type Reporter = AbstractReporter 18 | 19 | def makeReporter( 20 | errorLogger: (Position, String) => Unit, 21 | warningLogger: (Position, String) => Unit, 22 | infoLogger: (Position, String) => Unit, 23 | outerSettings: Settings 24 | ): Reporter = 25 | new AbstractReporter { 26 | def displayPrompt(): Unit = ??? 27 | 28 | def display(pos: Position, msg: String, severity: Severity) = { 29 | severity match { 30 | case ERROR => 31 | Classpath.traceClasspathProblem(s"ERROR: $msg") 32 | errorLogger(pos, msg) 33 | case WARNING => 34 | warningLogger(pos, msg) 35 | case INFO => 36 | infoLogger(pos, msg) 37 | } 38 | } 39 | 40 | val settings = outerSettings 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala/ammonite/compiler/CompilerUtil.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | object CompilerUtil { 4 | 5 | val ignoredSyms = Set( 6 | "package class-use", 7 | "object package-info", 8 | "class package-info" 9 | ) 10 | val ignoredNames = Set( 11 | // Probably synthetic 12 | "", 13 | "", 14 | "$main", 15 | // Don't care about this 16 | "toString", 17 | "equals", 18 | "wait", 19 | "notify", 20 | "notifyAll", 21 | "synchronized", 22 | "hashCode", 23 | "getClass", 24 | "eq", 25 | "ne", 26 | "##", 27 | "==", 28 | "!=", 29 | "isInstanceOf", 30 | "asInstanceOf", 31 | // Behaves weird in 2.10.x, better to just ignore. 32 | "_" 33 | ) 34 | 35 | } 36 | -------------------------------------------------------------------------------- /amm/compiler/src/main/scala/ammonite/compiler/DefaultCodeWrapper.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler 2 | 3 | import ammonite.compiler.iface.CodeWrapper 4 | import ammonite.util._ 5 | import ammonite.util.Util.{CodeSource, normalizeNewlines} 6 | 7 | object DefaultCodeWrapper extends CodeWrapper { 8 | private val userCodeNestingLevel = 1 9 | def apply( 10 | code: String, 11 | source: CodeSource, 12 | imports: Imports, 13 | printCode: String, 14 | indexedWrapperName: Name, 15 | extraCode: String 16 | ) = { 17 | import source.pkgName 18 | val top = normalizeNewlines(s""" 19 | package ${pkgName.head.encoded} 20 | package ${Util.encodeScalaSourcePath(pkgName.tail)} 21 | $imports 22 | 23 | object ${indexedWrapperName.backticked}{\n""") 24 | val bottom = normalizeNewlines(s"""\ndef $$main() = { $printCode } 25 | override def toString = "${indexedWrapperName.encoded}" 26 | $extraCode 27 | } 28 | """) 29 | 30 | (top, bottom, userCodeNestingLevel) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /amm/compiler/src/test/scala-2/ammonite/compiler/test/CompilerTestExtensions.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler.test 2 | 3 | object CompilerTestExtensions 4 | -------------------------------------------------------------------------------- /amm/compiler/src/test/scala-3/ammonite/compiler/test/CompilerTestExtensions.scala: -------------------------------------------------------------------------------- 1 | package ammonite.compiler.test 2 | 3 | import dotty.tools.dotc.{Compiler => DottyCompiler} 4 | 5 | object CompilerTestExtensions { 6 | implicit class DottyCompilerExtensions(private val self: DottyCompiler) extends AnyVal { 7 | // scala.tools.nsc.Global in Scala 2 has that. 8 | // We only add it here so that code calling that compiles, and 9 | // make sure this method is not called at the end when the 10 | // Scala 3 amm-compiler module is used. 11 | def useOffsetPositions: Boolean = ??? 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /amm/helper/src/main/scala-3/ammonite/helper/Helper.scala: -------------------------------------------------------------------------------- 1 | package ammonite.helper 2 | 3 | abstract class Helper 4 | -------------------------------------------------------------------------------- /amm/interp/api/src/main/scala/ammonite/Stubs.scala: -------------------------------------------------------------------------------- 1 | package ammonite 2 | 3 | // Dummy packages just to populate the existence of these top-level synthetic 4 | // packages in the Scala compiler. 5 | 6 | /** 7 | * Package that gets filled with any script files that the user imports 8 | */ 9 | package $file { 10 | object $ 11 | } 12 | 13 | /** 14 | * Package that gets filled with any script files that the user imports 15 | */ 16 | package $exec { 17 | object $ 18 | } 19 | 20 | /** 21 | * Package that gets filled with ivy artifacts the user loads 22 | */ 23 | package $ivy { 24 | object $ 25 | } 26 | 27 | /** 28 | * Package that gets filled with any web scripts people load from http URLs 29 | */ 30 | package $url { 31 | object $ 32 | } 33 | 34 | /** 35 | * Package to import from when you don't want to import anything 36 | */ 37 | package $stub { 38 | object $ 39 | } 40 | 41 | /** 42 | * Package to import from when you don't want to import anything 43 | */ 44 | package $cp { 45 | object $ 46 | } 47 | 48 | /** 49 | * Package to import from when you don't want to import anything 50 | */ 51 | package $plugin { 52 | object $ 53 | } 54 | 55 | package $repo { 56 | object $ 57 | } 58 | -------------------------------------------------------------------------------- /amm/interp/api/src/main/scala/ammonite/interp/api/APIHolder.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp.api 2 | 3 | class APIHolder[T >: Null <: AnyRef] { 4 | var value0: T = null 5 | implicit final lazy val value: T = value0 6 | } 7 | -------------------------------------------------------------------------------- /amm/interp/api/src/main/scala/ammonite/interp/api/AmmoniteExit.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp.api 2 | 3 | import scala.util.control.ControlThrowable 4 | 5 | /** 6 | * Thrown to exit the REPL cleanly 7 | */ 8 | case class AmmoniteExit(value: Any) extends ControlThrowable 9 | -------------------------------------------------------------------------------- /amm/interp/api/src/main/scala/ammonite/interp/api/InterpAPI.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp.api 2 | 3 | import ammonite.util.{Colors, Ref} 4 | import coursierapi.{Dependency, Fetch, Repository} 5 | 6 | import scala.collection.mutable 7 | 8 | object InterpBridge extends APIHolder[InterpAPI] 9 | 10 | trait InterpAPI { 11 | 12 | /** 13 | * When running a script in `--watch` mode, re-run the main script if this 14 | * file changes. By default, this happens for all script files, but you can 15 | * call this to watch arbitrary files your script may depend on 16 | */ 17 | def watch(p: os.Path): Unit 18 | 19 | /** 20 | * A generalization of [[watch]], allows watching arbitrary values and not 21 | * just the contents of file paths. 22 | */ 23 | def watchValue[T](v: => T): T 24 | 25 | /** 26 | * The colors that will be used to render the Ammonite REPL in the terminal, 27 | * or for rendering miscellaneous info messages when running scripts. 28 | */ 29 | val colors: Ref[Colors] 30 | 31 | /** 32 | * Tools related to loading external scripts and code into the REPL 33 | */ 34 | def load: InterpLoad 35 | 36 | /** 37 | * resolvers to use when loading jars 38 | */ 39 | def repositories: Ref[List[Repository]] 40 | 41 | /** 42 | * Functions that will be chained and called on the coursier 43 | * Fetch object right before they are run 44 | */ 45 | val resolutionHooks: mutable.Buffer[Fetch => Fetch] 46 | 47 | /** 48 | * Exit the Ammonite REPL. You can also use Ctrl-D to exit 49 | */ 50 | def exit = throw AmmoniteExit(()) 51 | 52 | /** 53 | * Exit the Ammonite REPL. You can also use Ctrl-D to exit 54 | */ 55 | def exit(value: Any) = throw AmmoniteExit(value) 56 | 57 | /** 58 | * Functions that will be chained and called on the 59 | * exitValue before the repl exits 60 | */ 61 | val beforeExitHooks: mutable.Buffer[Any => Any] 62 | 63 | implicit def scalaVersion: ScalaVersion 64 | 65 | def _compilerManager: ammonite.compiler.iface.CompilerLifecycleManager 66 | } 67 | 68 | trait LoadJar { 69 | 70 | /** 71 | * Load a `.jar` file or directory into your JVM classpath 72 | */ 73 | def cp(jar: os.Path): Unit 74 | 75 | /** 76 | * Load a `.jar` from a URL into your JVM classpath 77 | */ 78 | def cp(jar: java.net.URL): Unit 79 | 80 | /** 81 | * Load one or more `.jar` files or directories into your JVM classpath 82 | */ 83 | def cp(jars: Seq[os.Path]): Unit 84 | 85 | /** 86 | * Load a library from its maven/ivy coordinates 87 | */ 88 | def ivy(coordinates: Dependency*): Unit 89 | } 90 | 91 | trait InterpLoad extends LoadJar { 92 | 93 | def module(path: os.Path): Unit 94 | 95 | def plugin: LoadJar 96 | 97 | } 98 | -------------------------------------------------------------------------------- /amm/interp/api/src/main/scala/ammonite/interp/api/IvyConstructor.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp.api 2 | 3 | import coursierapi.{Dependency, Module} 4 | 5 | case class ScalaVersion(value: String) 6 | 7 | object IvyConstructor extends IvyConstructor { 8 | 9 | def scalaBinaryVersion(sv: String) = { 10 | val retain = if (sv.startsWith("2")) 2 else 1 11 | sv.split('.').take(retain).mkString(".") 12 | } 13 | 14 | } 15 | trait IvyConstructor { 16 | implicit class GroupIdExt(groupId: String) { 17 | def %(artifactId: String) = Module.of(groupId, artifactId) 18 | def %%(artifactId: String)(implicit sv: ScalaVersion) = Module.of( 19 | groupId, 20 | artifactId + "_" + IvyConstructor.scalaBinaryVersion(sv.value) 21 | ) 22 | } 23 | implicit class ArtifactIdExt(t: Module) { 24 | def %(version: String) = Dependency.of(t, version) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /amm/interp/src/main/scala/ammonite/interp/DependencyLoader.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp 2 | 3 | import java.io.File 4 | 5 | import ammonite.runtime.Storage 6 | import ammonite.util.Printer 7 | import coursierapi.{Dependency, Fetch, Repository} 8 | 9 | final class DependencyLoader( 10 | printer: Printer, 11 | storage: Storage, 12 | alreadyLoadedDependencies: Seq[Dependency], 13 | verboseOutput: Boolean 14 | ) { 15 | 16 | private val alwaysExclude = alreadyLoadedDependencies 17 | .map(dep => (dep.getModule.getOrganization, dep.getModule.getName)) 18 | .toSet 19 | 20 | def load( 21 | coordinates: Seq[Dependency], 22 | repositories: => Seq[Repository], 23 | resolutionHooks: Seq[Fetch => Fetch] 24 | ): Either[String, Seq[File]] = { 25 | val repositories0 = repositories 26 | val cacheKey = ( 27 | repositories0.hashCode.toString, 28 | coordinates 29 | // FIXME Add resolutionHooks somehow? 30 | ) 31 | 32 | storage.ivyCache().get(cacheKey) match { 33 | case Some(res) => Right(res.map(new java.io.File(_))) 34 | case None => 35 | ammonite.runtime.tools.IvyThing.resolveArtifact( 36 | repositories0, 37 | coordinates 38 | .filter(dep => !alwaysExclude((dep.getModule.getOrganization, dep.getModule.getName))) 39 | .map { dep => 40 | alwaysExclude.iterator.foldLeft(Dependency.of(dep))((dep, excl) => 41 | dep.addExclusion(excl._1, excl._2) 42 | ) 43 | }, 44 | verbose = verboseOutput, 45 | output = printer.errStream, 46 | hooks = resolutionHooks 47 | ) match { 48 | case Right((canBeCached, loaded)) => 49 | if (canBeCached) 50 | storage.ivyCache() = storage.ivyCache().updated( 51 | cacheKey, 52 | loaded.map(_.getAbsolutePath) 53 | ) 54 | Right(loaded) 55 | case Left(l) => 56 | Left(l) 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /amm/interp/src/main/scala/ammonite/interp/IvyThing.scala: -------------------------------------------------------------------------------- 1 | package ammonite.runtime.tools 2 | 3 | import java.io.PrintStream 4 | 5 | import coursierapi.{Cache, Dependency, Fetch, Logger, Repository} 6 | 7 | import scala.collection.JavaConverters._ 8 | import scala.util.Try 9 | 10 | object IvyThing { 11 | def completer( 12 | repositories: Seq[Repository], 13 | verbose: Boolean 14 | ): String => (Int, Seq[String]) = { 15 | val cache = Cache.create() 16 | .withLogger(if (verbose) Logger.progressBars() else Logger.nop) 17 | val sv = scala.util.Properties.versionNumberString 18 | val sbv = sv.split('.').take(2).mkString(".") 19 | 20 | s => 21 | val res = coursierapi.Complete.create() 22 | .withCache(cache) 23 | .withScalaVersion(sv) 24 | .withScalaBinaryVersion(sbv) 25 | .withInput(s) 26 | .complete() 27 | (res.getFrom, res.getCompletions.asScala.toVector) 28 | } 29 | def resolveArtifact( 30 | repositories: Seq[Repository], 31 | dependencies: Seq[Dependency], 32 | verbose: Boolean, 33 | output: PrintStream, 34 | hooks: Seq[Fetch => Fetch] 35 | ) = synchronized { 36 | val fetch = Fetch.create() 37 | .addDependencies(dependencies: _*) 38 | .withRepositories(repositories: _*) 39 | .withCache( 40 | Cache.create() 41 | .withLogger(if (verbose) Logger.progressBars(output) else Logger.nop) 42 | ) 43 | .withMainArtifacts() 44 | .addClassifiers("sources") 45 | 46 | val finalFetch = Function.chain(hooks)(fetch) 47 | Try(finalFetch.fetchResult()).toEither match { 48 | case Left(err) => Left("Failed to resolve ivy dependencies:" + err.getMessage) 49 | case Right(res) => 50 | // should really be fetch != finalFetch, but coursierapi.Fetch is mutable for now 51 | val customParams = hooks.nonEmpty 52 | def noChangingArtifact = res.getArtifacts.asScala.forall(!_.getKey.isChanging) 53 | def noVersionInterval = dependencies.map(_.getVersion).forall { v => 54 | !v.startsWith("latest.") && 55 | !v.exists(Set('[', ']', '(', ')')) && 56 | !v.endsWith("+") 57 | } 58 | val files = res.getFiles.asScala.toList 59 | Right((!customParams && noChangingArtifact && noVersionInterval, files)) 60 | } 61 | } 62 | 63 | val defaultRepositories = Repository.defaults().asScala.toList 64 | 65 | } 66 | -------------------------------------------------------------------------------- /amm/interp/src/main/scala/ammonite/interp/PredefInitialization.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp 2 | 3 | import ammonite.interp.api.InterpAPI 4 | import ammonite.runtime.{SpecialClassLoader, Storage} 5 | import ammonite.util.ScriptOutput.Metadata 6 | import ammonite.util.{ImportData, Imports, Name, PredefInfo, Res} 7 | import ammonite.util.Util.CodeSource 8 | 9 | /** 10 | * The logic around executing an [[Interpreter]]'s predef during 11 | * initialization 12 | */ 13 | object PredefInitialization { 14 | def initBridge[T >: Null <: AnyRef](classloader: SpecialClassLoader, name: String, t: T) = { 15 | classloader.findClassPublic(name + "$") 16 | classloader.findClassPublic(name) 17 | .getDeclaredMethods 18 | .find(_.getName == "value0_$eq") 19 | .get 20 | .invoke(null, t) 21 | } 22 | def initBridges(bridges: Seq[(String, String)]): Imports = { 23 | 24 | val allImports = 25 | for ((name, shortName) <- bridges) 26 | yield Imports( 27 | Seq(ImportData( 28 | Name("value"), 29 | Name(shortName), 30 | // FIXME Not sure special chars / backticked things in name are fine here 31 | Name("_root_") +: name.stripPrefix("_root_.").split('.').map(Name(_)).toSeq, 32 | ImportData.Term 33 | )) 34 | ) 35 | 36 | allImports.foldLeft(Imports())(_ ++ _) 37 | } 38 | def initBridges( 39 | bridges: Seq[(String, String, AnyRef)], 40 | evalClassloader: SpecialClassLoader 41 | ): Imports = { 42 | 43 | for ((name, shortName, bridge) <- bridges) 44 | initBridge(evalClassloader, name, bridge) 45 | 46 | initBridges(bridges.map { case (name, shortName, _) => (name, shortName) }) 47 | } 48 | def apply( 49 | interpApi: InterpAPI, 50 | storage: Storage, 51 | basePredefs: Seq[PredefInfo], 52 | customPredefs: Seq[PredefInfo], 53 | processModule: (String, CodeSource, Boolean) => Res[Metadata], 54 | addImports: Imports => Unit, 55 | watch: os.Path => Unit 56 | ): Res[_] = { 57 | 58 | val predefs = { 59 | basePredefs ++ 60 | storage.loadPredef.map { 61 | case (code, path) => 62 | PredefInfo(Name(path.last.stripSuffix(".sc")), code, false, Some(path)) 63 | } ++ 64 | customPredefs 65 | } 66 | 67 | Res.fold((), predefs) { (_, predefInfo) => 68 | predefInfo.path.foreach(watch) 69 | if (predefInfo.code.isEmpty) Res.Success(()) 70 | else { 71 | processModule( 72 | predefInfo.code, 73 | CodeSource( 74 | predefInfo.name, 75 | Seq(), 76 | Seq(Name("ammonite"), Name("predef")), 77 | predefInfo.path 78 | ), 79 | predefInfo.hardcoded 80 | ) match { 81 | case Res.Skip => Res.Success(()) 82 | case Res.Success(processed) => 83 | addImports(processed.blockInfo.last.hookInfo.imports) 84 | addImports(processed.blockInfo.last.finalImports) 85 | Res.Success(()) 86 | 87 | case x => x.map(_ => ()) 88 | } 89 | 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /amm/interp/src/main/scala/ammonite/interp/Watchable.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp 2 | 3 | trait Watchable { 4 | def poll(): Long 5 | } 6 | object Watchable { 7 | def mtimeIfExists(p: os.Path) = if (os.exists(p)) os.mtime(p) else 0L 8 | 9 | /** 10 | * Recursively mtimes things, with the sole purpose of providing a number 11 | * that will change if that file changes or that folder's contents changes 12 | * 13 | * Ensure we include the file paths within a folder as part of the folder 14 | * signature, as file moves often do not update the mtime but we want to 15 | * trigger a "something changed" event anyway 16 | */ 17 | def pathSignature(p: os.Path) = 18 | if (!os.exists(p)) 0L 19 | else 20 | try { 21 | if (os.isDir(p)) os.walk(p).map(x => x.hashCode + mtimeIfExists(x)).sum 22 | else os.mtime(p) 23 | } catch { 24 | case e: java.nio.file.NoSuchFileException => 25 | 0L 26 | } 27 | case class Path(p: os.Path) extends Watchable { 28 | def poll() = pathSignature(p) 29 | } 30 | case class Value(f: () => Long) extends Watchable { 31 | def poll() = f() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /amm/interp/src/main/scala/ammonite/interp/script/Diagnostic.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp.script 2 | 3 | import ammonite.util.Position 4 | 5 | final case class Diagnostic( 6 | severity: String, 7 | start: Position, 8 | end: Position, 9 | message: String 10 | ) 11 | -------------------------------------------------------------------------------- /amm/interp/src/main/scala/ammonite/interp/script/DummyBuildServerImplems.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp.script 2 | 3 | import java.util.concurrent.CompletableFuture 4 | import ch.epfl.scala.bsp4j._ 5 | import scala.collection.JavaConverters._ 6 | 7 | private[script] trait DummyBuildServerImplems extends BuildServer with ScalaBuildServer { 8 | override def buildTargetDependencyModules(dmp: DependencyModulesParams) 9 | : CompletableFuture[DependencyModulesResult] = 10 | CompletableFuture.completedFuture(new DependencyModulesResult(List.empty.asJava)) 11 | 12 | override def buildTargetOutputPaths(opp: OutputPathsParams) 13 | : CompletableFuture[OutputPathsResult] = 14 | CompletableFuture.completedFuture(new OutputPathsResult(List.empty.asJava)) 15 | 16 | override def buildTargetResources(params: ResourcesParams): CompletableFuture[ResourcesResult] = { 17 | val items = params.getTargets.asScala.toList.map { target => 18 | new ResourcesItem(target, List.empty[String].asJava) 19 | } 20 | val result = new ResourcesResult(items.asJava) 21 | CompletableFuture.completedFuture(result) 22 | } 23 | 24 | override def buildTargetRun(params: RunParams): CompletableFuture[RunResult] = { 25 | val result = new RunResult(StatusCode.ERROR) 26 | result.setOriginId(params.getOriginId) 27 | CompletableFuture.completedFuture(result) 28 | } 29 | 30 | override def buildTargetTest(params: TestParams): CompletableFuture[TestResult] = { 31 | val result = new TestResult(StatusCode.ERROR) 32 | result.setOriginId(params.getOriginId) 33 | CompletableFuture.completedFuture(result) 34 | } 35 | 36 | override def buildTargetScalaMainClasses( 37 | params: ScalaMainClassesParams 38 | ): CompletableFuture[ScalaMainClassesResult] = { 39 | val items = params.getTargets.asScala.map { target => 40 | new ScalaMainClassesItem(target, List.empty[ScalaMainClass].asJava) 41 | } 42 | val result = new ScalaMainClassesResult(items.asJava) 43 | CompletableFuture.completedFuture(result) 44 | } 45 | 46 | override def buildTargetScalaTestClasses( 47 | params: ScalaTestClassesParams 48 | ): CompletableFuture[ScalaTestClassesResult] = { 49 | val items = params.getTargets.asScala.map { target => 50 | new ScalaTestClassesItem(target, List.empty[String].asJava) 51 | } 52 | val result = new ScalaTestClassesResult(items.asJava) 53 | CompletableFuture.completedFuture(result) 54 | } 55 | 56 | override def debugSessionStart(dsp: DebugSessionParams): CompletableFuture[DebugSessionAddress] = 57 | CompletableFuture.completedFuture(new DebugSessionAddress("")) 58 | 59 | override def onBuildExit(): Unit = () 60 | override def onBuildInitialized(): Unit = () 61 | 62 | override def workspaceReload(): CompletableFuture[Object] = 63 | CompletableFuture.completedFuture(new {}) 64 | } 65 | -------------------------------------------------------------------------------- /amm/interp/src/main/scala/ammonite/interp/script/ScriptCompileResult.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp.script 2 | 3 | import ammonite.compiler.iface.Compiler.Output 4 | 5 | final case class ScriptCompileResult( 6 | diagnostics: Seq[Diagnostic], 7 | errorOrOutput: Either[String, Seq[Output]] 8 | ) 9 | -------------------------------------------------------------------------------- /amm/repl/api/src/main/scala-2.12/ammonite/repl/api/History.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl.api 2 | 3 | import scala.collection.generic.CanBuildFrom 4 | import scala.collection.{IndexedSeqLike, mutable} 5 | 6 | class History(s: Vector[String]) 7 | extends IndexedSeq[String] 8 | with IndexedSeqLike[String, History] { 9 | def length: Int = s.length 10 | def apply(idx: Int): String = s.apply(idx) 11 | override def newBuilder = History.builder 12 | } 13 | 14 | object History { 15 | def builder = new mutable.Builder[String, History] { 16 | val buffer = mutable.Buffer.empty[String] 17 | def +=(elem: String): this.type = { buffer += elem; this } 18 | 19 | def result(): History = new History(buffer.toVector) 20 | 21 | def clear(): Unit = buffer.clear() 22 | } 23 | implicit def cbf = new CanBuildFrom[History, String, History] { 24 | def apply(from: History) = builder 25 | def apply() = builder 26 | } 27 | implicit def toHistory(s: Seq[String]): History = new History(s.toVector) 28 | } 29 | -------------------------------------------------------------------------------- /amm/repl/api/src/main/scala-2.13-or-3/ammonite/repl/api/History.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl.api 2 | 3 | import scala.collection.generic.IsSeq 4 | import scala.collection.{Iterable, SeqOps, mutable} 5 | 6 | class History(s: Vector[String]) 7 | extends IndexedSeq[String] { 8 | def length: Int = s.length 9 | def apply(idx: Int): String = s.apply(idx) 10 | 11 | override protected def newSpecificBuilder: mutable.Builder[String, History] = 12 | History.builder 13 | } 14 | 15 | object History { 16 | def builder = new mutable.Builder[String, History] { 17 | val buffer = mutable.Buffer.empty[String] 18 | def addOne(elem: String): this.type = { buffer += elem; this } 19 | 20 | def result(): History = new History(buffer.toVector) 21 | 22 | def clear(): Unit = buffer.clear() 23 | } 24 | implicit def toHistory(s: Seq[String]): History = new History(s.toVector) 25 | } 26 | -------------------------------------------------------------------------------- /amm/repl/api/src/main/scala-2/ammonite/repl/FullReplAPIScalaVersionSpecific.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl 2 | 3 | import scala.reflect.runtime.universe._ 4 | 5 | trait FullReplAPIScalaVersionSpecific { 6 | 7 | def typeOf[T: WeakTypeTag] = scala.reflect.runtime.universe.weakTypeOf[T] 8 | def typeOf[T: WeakTypeTag](t: => T) = scala.reflect.runtime.universe.weakTypeOf[T] 9 | 10 | } 11 | -------------------------------------------------------------------------------- /amm/repl/api/src/main/scala-2/ammonite/repl/api/ReplAPIScalaVersionSpecific.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl.api 2 | 3 | import scala.reflect.runtime.universe._ 4 | 5 | trait ReplAPIScalaVersionSpecific { 6 | 7 | /** 8 | * Get the `Type` object of [[T]]. Useful for finding 9 | * what its methods are and what you can do with it 10 | */ 11 | def typeOf[T: WeakTypeTag]: Type 12 | 13 | /** 14 | * Get the `Type` object representing the type of `t`. Useful 15 | * for finding what its methods are and what you can do with it 16 | */ 17 | def typeOf[T: WeakTypeTag](t: => T): Type 18 | 19 | } 20 | -------------------------------------------------------------------------------- /amm/repl/api/src/main/scala-3/ammonite/repl/FullReplAPIScalaVersionSpecific.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl 2 | 3 | trait FullReplAPIScalaVersionSpecific 4 | -------------------------------------------------------------------------------- /amm/repl/api/src/main/scala-3/ammonite/repl/api/ReplAPIScalaVersionSpecific.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl.api 2 | 3 | trait ReplAPIScalaVersionSpecific 4 | -------------------------------------------------------------------------------- /amm/repl/api/src/main/scala/ammonite/repl/api/FrontEnd.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl.api 2 | 3 | import java.io.{InputStream, OutputStream} 4 | 5 | import ammonite.util.{Colors, Res} 6 | 7 | /** JLine interface */ 8 | trait FrontEnd { 9 | def width: Int 10 | def height: Int 11 | def action( 12 | input: InputStream, 13 | reader: java.io.Reader, 14 | output: OutputStream, 15 | prompt: String, 16 | colors: Colors, 17 | compilerComplete: (Int, String) => (Int, Seq[String], Seq[String]), 18 | history: IndexedSeq[String], 19 | addHistory: String => Unit 20 | ): Res[(String, Seq[String])] 21 | } 22 | -------------------------------------------------------------------------------- /amm/repl/api/src/main/scala/ammonite/repl/api/FrontEndAPI.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl.api 2 | 3 | import ammonite.interp.api.APIHolder 4 | 5 | trait FrontEndAPI { 6 | def apply(name: String): FrontEnd 7 | } 8 | 9 | object FrontEndBridge extends APIHolder[FrontEndAPI] 10 | -------------------------------------------------------------------------------- /amm/repl/api/src/main/scala/ammonite/repl/api/SessionChanged.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl.api 2 | 3 | trait SessionChanged { 4 | def removedImports: Set[scala.Symbol] 5 | def addedImports: Set[scala.Symbol] 6 | def removedJars: Set[java.net.URL] 7 | def addedJars: Set[java.net.URL] 8 | } 9 | -------------------------------------------------------------------------------- /amm/repl/api/src/main/scala/ammonite/repl/tools/Util.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl.tools 2 | 3 | object Util { 4 | 5 | /** 6 | * Additional [[mainargs.TokensReader]] instance to teach it how to read Ammonite paths 7 | */ 8 | implicit object PathRead extends mainargs.TokensReader.Simple[os.Path] { 9 | def shortName = "path" 10 | def read(strs: Seq[String]) = Right(os.Path(strs.last, os.pwd)) 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /amm/repl/api/src/main/scala/ammonite/runtime/tools/package.scala: -------------------------------------------------------------------------------- 1 | package ammonite 2 | 3 | /** 4 | * Things that are available inside the Ammonite REPL, are really convenient 5 | * to have available. 6 | */ 7 | package object tools 8 | -------------------------------------------------------------------------------- /amm/repl/src/main/scala-2/ammonite/main/DefaultsScalaVersionSpecific.scala: -------------------------------------------------------------------------------- 1 | package ammonite.main 2 | 3 | import ammonite.util.{ImportData, Imports} 4 | 5 | private[main] trait DefaultsScalaVersionSpecific { 6 | val replImports = Imports( 7 | ImportData("""ammonite.repl.ReplBridge.value.{ 8 | codeColorsImplicit, 9 | tprintColorsImplicit, 10 | show, 11 | typeOf 12 | }""") 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /amm/repl/src/main/scala-3/ammonite/main/DefaultsScalaVersionSpecific.scala: -------------------------------------------------------------------------------- 1 | package ammonite.main 2 | 3 | import ammonite.util.{ImportData, Imports} 4 | 5 | private[main] trait DefaultsScalaVersionSpecific { 6 | val replImports = Imports( 7 | ImportData("""ammonite.repl.ReplBridge.value.{ 8 | codeColorsImplicit, 9 | tprintColorsImplicit, 10 | show 11 | }""") 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /amm/repl/src/main/scala/ammonite/main/Defaults.scala: -------------------------------------------------------------------------------- 1 | package ammonite.main 2 | 3 | import java.io.InputStream 4 | 5 | import ammonite.util.Util 6 | import coursierapi.Dependency 7 | 8 | import scala.io.Codec 9 | 10 | /** 11 | * Constants used in the default configuration for the Ammonite REPL 12 | */ 13 | object Defaults extends DefaultsScalaVersionSpecific { 14 | 15 | val welcomeBanner = { 16 | def ammoniteVersion = ammonite.Constants.version 17 | def javaVersion = System.getProperty("java.version") 18 | Util.normalizeNewlines( 19 | s"Welcome to the Ammonite Repl $ammoniteVersion (Scala %SCALA_VERSION% Java $javaVersion)" 20 | ) 21 | } 22 | 23 | def ammoniteHome = os.Path(System.getProperty("user.home")) / ".ammonite" 24 | 25 | def alreadyLoadedDependencies( 26 | resourceName: String = "amm-dependencies.txt" 27 | ): Seq[Dependency] = { 28 | 29 | var is: InputStream = null 30 | 31 | try { 32 | is = Thread.currentThread().getContextClassLoader.getResourceAsStream(resourceName) 33 | if (is == null) 34 | throw new Exception(s"Resource $resourceName not found") 35 | scala.io.Source.fromInputStream(is)(Codec.UTF8) 36 | .mkString 37 | .split('\n') 38 | .filter(_.nonEmpty) 39 | .map(l => 40 | l.split(':') match { 41 | case Array(org, name, ver) => 42 | Dependency.of(org, name, ver) 43 | case other => 44 | throw new Exception(s"Cannot parse line '$other' from resource $resourceName") 45 | } 46 | ) 47 | } finally { 48 | if (is != null) 49 | is.close() 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /amm/repl/src/main/scala/ammonite/repl/FrontEndUtils.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl 2 | import scala.annotation.tailrec 3 | 4 | import ammonite.util.Util.newLine 5 | 6 | /** 7 | * Created by haoyi on 8/29/15. 8 | */ 9 | object FrontEndUtils { 10 | def width = 11 | if (scala.util.Properties.isWin) ammonite.repl.FrontEnds.width 12 | else ammonite.terminal.ConsoleDim.width() 13 | def height = 14 | if (scala.util.Properties.isWin) ammonite.repl.FrontEnds.height 15 | else ammonite.terminal.ConsoleDim.height() 16 | def tabulate(snippetsRaw: Seq[fansi.Str], width: Int): Iterator[String] = { 17 | val gap = 2 18 | val snippets = if (snippetsRaw.isEmpty) Seq(fansi.Str("")) else snippetsRaw 19 | val maxLength = snippets.maxBy(_.length).length + gap 20 | val columns = math.max(1, width / maxLength) 21 | 22 | val grouped = 23 | snippets.toList 24 | .grouped(math.ceil(snippets.length * 1.0 / columns).toInt) 25 | .toList 26 | 27 | ammonite.util.Util.transpose(grouped).iterator.flatMap { 28 | case first :+ last => 29 | first.map(x => x ++ " " * (width / columns - x.length)) :+ last :+ fansi.Str(newLine) 30 | }.map(_.render) 31 | } 32 | 33 | @tailrec def findPrefix(strings: Seq[String], i: Int = 0): String = { 34 | if (strings.count(_.length > i) == 0) strings(0).take(i) 35 | else if (strings.collect { case x if x.length > i => x(i) }.distinct.length > 1) 36 | strings(0).take(i) 37 | else findPrefix(strings, i + 1) 38 | } 39 | 40 | def printCompletions(completions: Seq[String], details: Seq[String]): List[String] = { 41 | 42 | val prelude = 43 | if (details.length != 0 || completions.length != 0) List(newLine) 44 | else Nil 45 | 46 | val detailsText = 47 | if (details.length == 0) Nil 48 | else FrontEndUtils.tabulate(details.map(fansi.Str(_)), FrontEndUtils.width) 49 | 50 | val completionText = 51 | if (completions.length == 0) Nil 52 | else FrontEndUtils.tabulate(completions.map(fansi.Str(_)), FrontEndUtils.width) 53 | 54 | prelude ++ detailsText ++ completionText 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /amm/repl/src/main/scala/ammonite/repl/PPrints.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl 2 | 3 | import ammonite.repl.api.History 4 | import ammonite.runtime.tools.GrepResult 5 | import ammonite.util.Util 6 | import pprint.Renderer 7 | 8 | object PPrints { 9 | def replPPrintHandlers(width: => Int): PartialFunction[Any, pprint.Tree] = { 10 | // case x: os.Path => PPrints.pathRepr(x) 11 | // case x: os.RelPath => PPrints.relPathRepr(x) 12 | case t: History => pprint.Tree.Lazy(ctx => Iterator(t.mkString(Util.newLine))) 13 | case t: GrepResult => pprint.Tree.Lazy(ctx => Iterator(GrepResult.grepResultRepr(t, ctx))) 14 | case t: scala.xml.Elem => pprint.Tree.Lazy(_ => Iterator(t.toString)) 15 | } 16 | 17 | def reprSection(s: String, cfg: pprint.Tree.Ctx): fansi.Str = { 18 | val validIdentifier = "([a-zA-Z_][a-zA-Z_0-9]+)".r 19 | 20 | if (validIdentifier.findFirstIn(s) == Some(s)) { 21 | cfg.literalColor('\'' + s) 22 | } else { 23 | cfg.literalColor(pprint.Util.literalize(s)) 24 | } 25 | } 26 | 27 | def relPathRepr(p: os.RelPath) = pprint.Tree.Lazy(ctx => 28 | Iterator( 29 | (Seq.fill(p.ups)("up") ++ p.segments.map(reprSection(_, ctx))).mkString("/") 30 | ) 31 | ) 32 | 33 | def pathRepr(p: os.Path) = pprint.Tree.Lazy(ctx => 34 | Iterator("root") ++ p.segments.map("/" + reprSection(_, ctx)) 35 | ) 36 | 37 | } 38 | -------------------------------------------------------------------------------- /amm/repl/src/main/scala/ammonite/repl/Signaller.scala: -------------------------------------------------------------------------------- 1 | package ammonite.repl 2 | 3 | import sun.misc.{Signal, SignalHandler} 4 | 5 | object Signaller { 6 | val handlers = scala.collection.mutable.Map[Signal, List[SignalHandler]]() 7 | } 8 | 9 | /** 10 | * Lets you turn on signal handling within a certain block, 11 | * attaching a callback to the handler and then turning it 12 | * properly off again when the block exits. Does sketchy 13 | * `unsafe` stuff because that's the only way you can make 14 | * it properly reset when you're finished. 15 | */ 16 | case class Signaller(sigStr: String)(f: => Unit) extends Scoped { 17 | import Signaller._ 18 | 19 | def apply[T](t: => T): T = { 20 | val handler = new SignalHandler() { 21 | def handle(sig: Signal) = f 22 | } 23 | 24 | val sig = new Signal(sigStr) 25 | 26 | handlers(sig) = sun.misc.Signal.handle(sig, handler) :: handlers.getOrElse(sig, List()) 27 | 28 | try t 29 | finally { 30 | val head :: tail = handlers(sig) 31 | handlers(sig) = tail 32 | val handlerToRegister = tail.headOption.getOrElse(sun.misc.SignalHandler.SIG_DFL) 33 | sun.misc.Signal.handle(sig, handlerToRegister) 34 | } 35 | } 36 | } 37 | 38 | /** 39 | * Converts something with a scoped `apply` method into 40 | * something which can be similarly used in a for-comprehension 41 | */ 42 | trait Scoped { 43 | def apply[T](t: => T): T 44 | def foreach[T](t: Unit => T): T = apply(t(())) 45 | def flatMap[T](t: Unit => T): T = apply(t(())) 46 | def map[T](t: Unit => T): T = apply(t(())) 47 | } 48 | -------------------------------------------------------------------------------- /amm/repl/src/main/scala/ammonite/repl/package.scala: -------------------------------------------------------------------------------- 1 | package ammonite 2 | 3 | /** 4 | * Everything to do with the interaction of the Ammonite REPL with the user 5 | * and the terminal. Interfacing with ammonite-terminal (or with JLine) 6 | */ 7 | package object repl 8 | -------------------------------------------------------------------------------- /amm/repl/src/test/scala/ammonite/DualTestRepl.scala: -------------------------------------------------------------------------------- 1 | package ammonite 2 | 3 | import ammonite.compiler.CodeClassWrapper 4 | import ammonite.util.{Evaluated, Res} 5 | 6 | /** 7 | * Wraps several [[TestRepl]], and runs its tests against all of them. 8 | */ 9 | class DualTestRepl { dual => 10 | 11 | def predef: (String, Option[os.Path]) = ("", None) 12 | def wrapperNamePrefix = Option.empty[String] 13 | 14 | def warnings = true 15 | 16 | def compilerBuilder = ammonite.compiler.CompilerBuilder() 17 | val repls = Seq( 18 | new TestRepl(compilerBuilder) { 19 | override def predef = dual.predef 20 | override def wrapperNamePrefix = dual.wrapperNamePrefix 21 | override def warnings = dual.warnings 22 | }, 23 | new TestRepl(compilerBuilder) { 24 | override def predef = dual.predef 25 | override def codeWrapper = CodeClassWrapper 26 | override def wrapperNamePrefix = dual.wrapperNamePrefix 27 | override def warnings = dual.warnings 28 | } 29 | ) 30 | 31 | def scalaVersion = compilerBuilder.scalaVersion 32 | lazy val scalaBinaryVersion = 33 | if (scalaVersion.startsWith("2.")) scalaVersion.split('.').take(2).mkString(".") 34 | else scalaVersion.takeWhile(_ != '.') 35 | def scala2 = scalaVersion.startsWith("2.") 36 | def scala2_12 = scalaVersion.startsWith("2.12.") 37 | def scala3_5_1OrHigher = 38 | (scalaVersion.startsWith("3.5.") && scalaVersion.split("\\.")(2).toInt >= 1) || 39 | scalaVersion.split("\\.")(1).toInt >= 6 40 | 41 | def interps = repls.map(_.interp) 42 | 43 | def session(sess: String): Unit = 44 | repls.foreach(_.session(sess)) 45 | def session(objWrapperSess: String, classWrapperSess: String): Unit = 46 | repls.foreach { repl => 47 | val sess = if (repl.codeWrapper == CodeClassWrapper) classWrapperSess else objWrapperSess 48 | repl.session(sess) 49 | } 50 | def result(input: String, expected: Res[Evaluated]): Unit = 51 | repls.foreach(_.result(input, expected)) 52 | def fail(input: String, failureCheck: String => Boolean = _ => true): Unit = 53 | repls.foreach(_.fail(input, failureCheck)) 54 | 55 | def notFound(name: String): String = 56 | repls.headOption.fold("")(_.notFound(name)) 57 | } 58 | -------------------------------------------------------------------------------- /amm/repl/src/test/scala/ammonite/SerializationUtil.scala: -------------------------------------------------------------------------------- 1 | package ammonite 2 | 3 | object SerializationUtil { 4 | 5 | import java.io._ 6 | 7 | def serialize(m: AnyRef): Array[Byte] = { 8 | val baos = new ByteArrayOutputStream() 9 | val oos = new ObjectOutputStream(baos) 10 | try { 11 | oos.writeObject(m) 12 | baos.toByteArray 13 | } finally oos.close() 14 | } 15 | 16 | def deserialize(b: Array[Byte], loader: ClassLoader): AnyRef = { 17 | val bais = new ByteArrayInputStream(b) 18 | val ois = new ClassLoaderObjectInputStream(loader, bais) 19 | try ois.readObject() 20 | finally ois.close() 21 | } 22 | 23 | // from akka.util 24 | 25 | /** 26 | * ClassLoaderObjectInputStream tries to utilize the provided ClassLoader 27 | * to load Classes and falls back to ObjectInputStreams resolver. 28 | * 29 | * @param classLoader - the ClassLoader which is to be used primarily 30 | * @param is - the InputStream that is wrapped 31 | */ 32 | class ClassLoaderObjectInputStream( 33 | classLoader: ClassLoader, 34 | is: InputStream 35 | ) extends ObjectInputStream(is) { 36 | override protected def resolveClass(objectStreamClass: ObjectStreamClass): Class[_] = 37 | try Class.forName(objectStreamClass.getName, false, classLoader) 38 | catch { 39 | case cnfe: ClassNotFoundException ⇒ super.resolveClass(objectStreamClass) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /amm/repl/src/test/scala/ammonite/TestReplBridge.scala: -------------------------------------------------------------------------------- 1 | package ammonite 2 | 3 | import ammonite.interp.api.APIHolder 4 | 5 | trait TestReplApi { 6 | def message: String 7 | } 8 | 9 | object TestReplBridge extends APIHolder[TestReplApi] 10 | 11 | case class Nope(n: Int) 12 | -------------------------------------------------------------------------------- /amm/repl/src/test/scala/ammonite/interp/PrintTests.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp 2 | 3 | import ammonite.DualTestRepl 4 | import ammonite.util.Util.newLine 5 | import utest._ 6 | 7 | object PrintTests extends TestSuite { 8 | val tests = Tests { 9 | println("PrintTests") 10 | val check = new DualTestRepl() 11 | 12 | test("simple") { 13 | for (repl <- check.repls) { 14 | val t @ (ev, out, res, warn, err, inf) = repl.run("val n = 2", 0) 15 | val expectedRes = "n: Int = 2" 16 | 17 | assert({ identity(t); ev.isSuccess }) 18 | assert({ identity(t); out.isEmpty }) 19 | assert({ identity(t); res == expectedRes }) 20 | } 21 | } 22 | 23 | test("out") { 24 | for (repl <- check.repls) { 25 | val t @ (ev, out, res, warn, err, inf) = repl.run("show(List(1, 2, 3))", 0) 26 | val expectedOut = "List(1, 2, 3)" + newLine 27 | 28 | assert({ identity(t); ev.isSuccess }) 29 | assert({ identity(t); out == expectedOut }) 30 | assert({ identity(t); res.isEmpty }) 31 | } 32 | } 33 | 34 | test("both") { 35 | for (repl <- check.repls) { 36 | val t @ (ev, out, res, warn, err, inf) = repl.run("show(List(1, 2, 3)); val n = 3", 0) 37 | val expectedOut = "List(1, 2, 3)" + newLine 38 | val expectedRes = "n: Int = 3" 39 | 40 | assert({ identity(t); ev.isSuccess }) 41 | assert({ identity(t); out == expectedOut }) 42 | assert({ identity(t); res == expectedRes }) 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /amm/repl/src/test/scala/ammonite/testcode/PaulpImports.scala: -------------------------------------------------------------------------------- 1 | package ammonite.testcode 2 | 3 | package paulp1 { 4 | class Paulp { 5 | override def toString = "paulp1.Paulp1" 6 | } 7 | } 8 | 9 | package paulp2 { 10 | object Paulp { 11 | override def toString = "paulp2.Paulp2" 12 | } 13 | } 14 | 15 | package paulp3 { 16 | object Paulp { 17 | override def toString = "paulp3.Paulp-object" 18 | } 19 | class Paulp { 20 | override def toString = "paulp3.Paulp-class" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /amm/repl/src/test/scala/ammonite/unit/ClipboardTests.scala: -------------------------------------------------------------------------------- 1 | package ammonite.unit 2 | 3 | import ammonite.repl.api.Clipboard 4 | import ammonite.repl.ClipboardImpl 5 | 6 | import java.awt.Toolkit 7 | import java.awt.datatransfer.DataFlavor 8 | 9 | import utest._ 10 | 11 | import scala.util.Try 12 | 13 | object ClipboardTests extends TestSuite { 14 | 15 | val clipboard: Clipboard = ClipboardImpl 16 | 17 | /** 18 | * This test suite requires an environment with access to a window 19 | * service (either under, Windows, MacOs, X11, ...) CI environment 20 | * doesn't satisfy that condition and that is detected in the following 21 | * check in order to skip [[Clipboard]] test when running on CI. 22 | */ 23 | val canTest = Try( 24 | Toolkit.getDefaultToolkit.getSystemClipboard.isDataFlavorAvailable( 25 | DataFlavor.stringFlavor 26 | ) 27 | ).getOrElse(false) 28 | 29 | override def tests = Tests { 30 | println("ClipboardTests") 31 | test("clipboard") { 32 | val newClipboardContents = "hello Ammonite" 33 | test("copyandpaste") { 34 | if (canTest) { 35 | clipboard.write(newClipboardContents) 36 | assert(clipboard.read == newClipboardContents) 37 | } else { 38 | println( 39 | "The environment doesn't allow testing clipboard - skipping" 40 | ) 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /amm/runtime/src/main/scala/ammonite/runtime/package.scala: -------------------------------------------------------------------------------- 1 | package ammonite 2 | 3 | /** 4 | * What actually lets us compile and execute code in the Ammonite REPL; deals 5 | * with the Scala compiler, preprocessing the strings, JVM classloaders, etc. 6 | */ 7 | package object runtime 8 | -------------------------------------------------------------------------------- /amm/src/main/scala/ammonite/main/ProxyFromEnv.scala: -------------------------------------------------------------------------------- 1 | package ammonite.main 2 | 3 | /** 4 | * Give Ammonite the ability to read (linux) system proxy environment variables 5 | * and convert them into java proxy properties. Which allows Ammonite to work 6 | * through proxy automatically, instead of setting `System.properties` manually. 7 | * 8 | * See issue 460. 9 | * 10 | * Parameter pattern: 11 | * https://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html 12 | * 13 | * Created by cuz on 17-5-21. 14 | */ 15 | private[ammonite] object ProxyFromEnv { 16 | private lazy val KeyPattern = """([\w\d]+)_proxy""".r 17 | private lazy val UrlPattern = """([\w\d]+://)?(.+@)?([\w\d\.\-]+):(\d+)/?""".r 18 | 19 | /** 20 | * Get current proxy environment variables. 21 | */ 22 | private def getEnvs = 23 | sys.env.map { case (k, v) => (k.toLowerCase, v.toLowerCase) } 24 | .filterKeys(_.endsWith("proxy")) 25 | .toMap 26 | 27 | /** 28 | * Convert single proxy environment variable to corresponding system proxy properties. 29 | */ 30 | private def envToProps(env: (String, String)): Map[String, String] = env match { 31 | case ("no_proxy", noProxySeq) => 32 | val converted = noProxySeq.split(""",""").mkString("|") 33 | // https uses the same as http's. Ftp need not to be set here. 34 | Map("http.nonProxyHosts" -> converted) 35 | 36 | case (KeyPattern(proto), UrlPattern(_, cred, host, port)) => 37 | val propHost = s"$proto.proxyHost" -> host 38 | val propPort = s"$proto.proxyPort" -> port 39 | val propCred = if (cred.isDefined) { 40 | val credPair = cred.dropRight(1).split(":") 41 | val propUser = s"$proto.proxyUser" -> credPair.head 42 | val propPassword = credPair.drop(1).map(s"$proto.proxyPassword" -> _) 43 | Seq(propUser) ++ propPassword 44 | } else Nil 45 | (Seq(propHost, propPort) ++ propCred).toMap 46 | case bad => Map.empty 47 | } 48 | 49 | /** 50 | * Set system proxy properties from environment variables. 51 | * Existing properties will not be overwritten. 52 | */ 53 | def setPropProxyFromEnv(envs: Map[String, String] = this.getEnvs): Unit = { 54 | val sysProps = sys.props 55 | val proxyProps = envs.flatMap { env => 56 | val props = envToProps(env) 57 | props 58 | }.filter(p => !sysProps.exists(sp => sp._1 == p._1)) 59 | sysProps ++= proxyProps 60 | } 61 | 62 | /** 63 | * helper implicit conversion: add isDefined method to String. 64 | */ 65 | implicit private class StringIsDefined(s: String) { 66 | def isDefined: Boolean = s != null && s.length > 0 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /amm/src/main/scala/ammonite/main/TrapExitSecurityManager.scala: -------------------------------------------------------------------------------- 1 | package ammonite.main 2 | import java.security.Permission 3 | 4 | /** 5 | * This security manager is assigned as default one when we run user scripts with the --watch option 6 | * This allows to trap sys.exit by throwing a special TrapExitException 7 | */ 8 | object TrapExitSecurityManager extends SecurityManager { 9 | 10 | override def checkExit(status: Int): Unit = throw new TrapExitException(status) 11 | 12 | override def checkPermission(perm: Permission): Unit = {} 13 | 14 | private class TrapExitException(status: Int) extends RuntimeException { 15 | override def toString: String = s"script exited with status $status" 16 | override def getStackTrace: Array[StackTraceElement] = Array.empty 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /amm/src/main/scala/ammonite/main/package.scala: -------------------------------------------------------------------------------- 1 | package ammonite 2 | 3 | /** 4 | * Code related to invoking Ammonite from the outside world: default 5 | * configuration, running scripts, printing error messages, etc. 6 | */ 7 | package object main 8 | -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/comment/script.sc: -------------------------------------------------------------------------------- 1 | // foo -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/dash-1/main-1.sc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/amm/src/test/resources/bsp/dash-1/main-1.sc -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/error/error-and-invalid-import-file.sc: -------------------------------------------------------------------------------- 1 | import $file.nope.nope.nope 2 | 3 | zz 4 | -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/error/foo.sc: -------------------------------------------------------------------------------- 1 | aa 2 | val n = 2 3 | 4 | zz 5 | 6 | val p = n + 1 -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/error/invalid-import-file.sc: -------------------------------------------------------------------------------- 1 | import scala.collection.mutable._ 2 | import $file.nope.nope.nope 3 | 4 | val n = 2 5 | -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/import-file/lib.sc: -------------------------------------------------------------------------------- 1 | 2 | val value = 2 3 | -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/import-file/script.sc: -------------------------------------------------------------------------------- 1 | 2 | import $file.lib, lib.value 3 | 4 | println(value + 1) 5 | -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/multi/lib1.sc: -------------------------------------------------------------------------------- 1 | trait HasFoo { 2 | def foo: String = "foo" 3 | } -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/multi/lib2.sc: -------------------------------------------------------------------------------- 1 | import $ivy.`io.circe::circe-core:0.12.3 compat` 2 | import $ivy.`io.circe::circe-generic:0.12.3 compat` 3 | import $ivy.`io.circe::circe-parser:0.12.3 compat` 4 | 5 | import $file.lib1, lib1.HasFoo 6 | 7 | trait HasReallyFoo extends HasFoo 8 | -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/multi/lib3.sc: -------------------------------------------------------------------------------- 1 | // See https://github.com/Baccata/gradle-simple/blob/master/src/main/java/Hello.java 2 | import $repo.`https://jitpack.io` 3 | import $ivy.`com.github.jupyter:jvm-repr:0.4.0` 4 | 5 | import jupyter.Displayers 6 | -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/multi/script.sc: -------------------------------------------------------------------------------- 1 | import $file.lib2, lib2.HasReallyFoo 2 | import $file.lib3 3 | import io.circe._, io.circe.generic.auto._, io.circe.parser._, io.circe.syntax._ 4 | 5 | sealed trait Foo extends HasReallyFoo 6 | case class Bar(xs: Vector[String]) extends Foo 7 | case class Qux(i: Int, d: Option[Double]) extends Foo 8 | 9 | val foo: Foo = Qux(13, Some(14.0)) 10 | 11 | val json = foo.asJson.noSpaces 12 | 13 | val decodedFoo = decode[Foo](json) 14 | 15 | val helloFromJupyter = jupyter.Displayers.registration 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/semdb/other.sc: -------------------------------------------------------------------------------- 1 | val list = List(1, 2) 2 | -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/semdb/script.sc: -------------------------------------------------------------------------------- 1 | 2 | import $ivy.`com.softwaremill.sttp.client::core:2.0.6 compat` 3 | import sttp.client.quick._ 4 | quickRequest.get(uri"http://httpbin.org/ip").send() 5 | -------------------------------------------------------------------------------- /amm/src/test/resources/bsp/simple/script.sc: -------------------------------------------------------------------------------- 1 | 2 | import $ivy.`com.softwaremill.sttp.client::core:2.0.6 compat` 3 | import sttp.client.quick._ 4 | quickRequest.get(uri"http://httpbin.org/ip").send() 5 | -------------------------------------------------------------------------------- /amm/src/test/resources/importHooks/Basic.sc: -------------------------------------------------------------------------------- 1 | // Basic.sc 2 | val basicValue = 31337 3 | 4 | -------------------------------------------------------------------------------- /amm/src/test/resources/importHooks/BasicTwo.sc: -------------------------------------------------------------------------------- 1 | val basicValueTwo = 1337 2 | 3 | -------------------------------------------------------------------------------- /amm/src/test/resources/importHooks/Deep.sc: -------------------------------------------------------------------------------- 1 | object DeepObject{ 2 | object DeepInner { 3 | val deepValue = "deeeep" 4 | } 5 | } 6 | 7 | 8 | -------------------------------------------------------------------------------- /amm/src/test/resources/importHooks/DeepImport.sc: -------------------------------------------------------------------------------- 1 | import $file.Deep, Deep.DeepObject.DeepInner.deepValue 2 | 3 | val deepValueImported = deepValue -------------------------------------------------------------------------------- /amm/src/test/resources/importHooks/FileImport.sc: -------------------------------------------------------------------------------- 1 | // FileImport.sc 2 | import $file.Basic 3 | 4 | val fileImportVal = Basic.basicValue + 1 -------------------------------------------------------------------------------- /amm/src/test/resources/importHooks/IndirectFileImport.sc: -------------------------------------------------------------------------------- 1 | // IndirectFileImport.sc 2 | import $file.FileImport 3 | 4 | val indirectFileImportVal = FileImport.fileImportVal + 1 -------------------------------------------------------------------------------- /amm/src/test/resources/importHooks/IvyImport.sc: -------------------------------------------------------------------------------- 1 | import $ivy.`com.lihaoyi::scalatags:0.7.0 compat`, scalatags.Text.all._ 2 | 3 | val rendered = div("Moo").render -------------------------------------------------------------------------------- /amm/src/test/resources/importHooks/UrlImport.sc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/amm/src/test/resources/importHooks/UrlImport.sc -------------------------------------------------------------------------------- /amm/src/test/resources/lineNumbers/CompilationErrorLineNumberTest.sc: -------------------------------------------------------------------------------- 1 | // Test Code 2 | 3 | object test{ 4 | 5 | 6 | 7 | val x = noSuchObject.badFunction 8 | 9 | } 10 | 11 | 12 | -------------------------------------------------------------------------------- /amm/src/test/resources/lineNumbers/ErrorLineNumberTest.sc: -------------------------------------------------------------------------------- 1 | object Qs{ 2 | def main(a: Int) = { 3 | println("OK") 4 | var unsorted: List[Int] = List(5,4,2,3,1) 5 | printlnqs(unsorted)) 6 | } 7 | 8 | def qs(unsorted: List[Int]): List[Int] = { 9 | if(unsorted.length <= 1) unsorted 10 | else{ 11 | val pivot = unsorted.head 12 | return qs(unsorted.filter(_ < pivot)) ::: List(pivot) ::: qs(unsorted.filter(_ > pivot)) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /amm/src/test/resources/lineNumbers/MultipleCompilationUnitErrorMsgTest1.sc: -------------------------------------------------------------------------------- 1 | 1 + 1 2 | @ 3 | object Thing{ 4 | foo} 5 | } -------------------------------------------------------------------------------- /amm/src/test/resources/lineNumbers/MultipleCompilationUnitErrorMsgTest2.sc: -------------------------------------------------------------------------------- 1 | object Thing{ 2 | foo} 3 | } 4 | @ 5 | 1 + 1 -------------------------------------------------------------------------------- /amm/src/test/resources/lineNumbers/RuntimeCompilationErrorLineNumberTest.sc: -------------------------------------------------------------------------------- 1 | 2 | //Code to check runtime error ilne numbers 3 | 4 | object foo{ 5 | 6 | def f(i: Int): Double = 5/i 7 | 8 | } 9 | 10 | @ 11 | 12 | println(foo.f(0)) 13 | -------------------------------------------------------------------------------- /amm/src/test/resources/lineNumbers/compilationErrorInClass.sc: -------------------------------------------------------------------------------- 1 | 2 | //adsfasdfasd 3 | println("Hello") 4 | 5 | //Comment before an empty line 6 | 7 | @ 8 | 9 | class numPair(a: Int, b: Int){ 10 | 11 | val num1 = a 12 | val num2 = b 13 | } 14 | 15 | def functionSwap(nums: numPair) = { 16 | 17 | val temp = nums.a ^ nums.b 18 | nums.a = nums.a ^ nums.b 19 | nums.b = nums.a ^ nums.b 20 | nums.a = nums.a ^ nums.b 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /amm/src/test/resources/lineNumbers/compilationErrorInFourthBlock.sc: -------------------------------------------------------------------------------- 1 | 2 | 3 | //Comment after empty lines 4 | @ 5 | //Another Comment 6 | 7 | def quicksort(unsorted : List[Int]) : List[Int] = { 8 | if(unsorted.length <= 1) unsorted 9 | else{ 10 | val pivot = unsorted.head 11 | quicksort(unsorted.filter(_ < pivot)):::List(pivot):::quicksort(unsorted.filter(_ > pivot)) 12 | } 13 | } 14 | 15 | @ 16 | 17 | println("OK") 18 | 19 | //One more comment 20 | //This one is long one! 21 | //check empty lines 22 | 23 | val x = 1 24 | println(x) 25 | //print the value of x 26 | @ 27 | 28 | //lots of comments!! 29 | 30 | prinntl("Ammonite") 31 | -------------------------------------------------------------------------------- /amm/src/test/resources/lineNumbers/compilationErrorInSecondBlock.sc: -------------------------------------------------------------------------------- 1 | 2 | //Another Comment 3 | 4 | def quicksort(unsorted : List[Int]) : List[Int] = { 5 | if(unsorted.length <= 1) unsorted 6 | else{ 7 | val pivot = unsorted.head 8 | quicksort(unsorted.filter(_ < pivot)):::List(pivot):::quicksort(unsorted.filter(_ > pivot)) 9 | } 10 | } 11 | 12 | @ 13 | 14 | printnl("OK") 15 | 16 | //One more comment 17 | //This one is long one! 18 | //check empty lines 19 | 20 | val x = 1 21 | println(x) 22 | //print the value of x 23 | @ 24 | 25 | //lots of comments!! 26 | 27 | prinntl("Ammonite") 28 | -------------------------------------------------------------------------------- /amm/src/test/resources/lineNumbers/compilationErrorWithCommentsAtTop.sc: -------------------------------------------------------------------------------- 1 | 2 | 3 | //Comment after empty lines 4 | @ 5 | //Another Comment 6 | 7 | def quicksort(unsorted : List[Int]) : List[Int] = { 8 | if(unsorted.length <= 1) unsorted 9 | else{ 10 | val pivot = unsorted.head 11 | quicort(unsorted.filter(_ < pivot)):::List(pivot):::quicksort(unsorted.filter(_ > pivot)) 12 | } 13 | } 14 | 15 | @ 16 | 17 | println("OK") 18 | 19 | //One more comment 20 | //This one is long one! 21 | //check empty lines 22 | 23 | val x = 1 24 | println(x) 25 | //print the value of x 26 | @ 27 | 28 | //lots of comments!! 29 | 30 | prinntl("Ammonite") 31 | -------------------------------------------------------------------------------- /amm/src/test/resources/lineNumbers/sourceCodeMetadata.sc: -------------------------------------------------------------------------------- 1 | Console.err.println(sourcecode.FileName()) 2 | Console.err.println(sourcecode.File()) 3 | //Console.err.println(sourcecode.Line()) doesn't work in scala 3 -------------------------------------------------------------------------------- /amm/src/test/resources/loadable/hello/Hello.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | public class Hello{ 3 | public static String hello(){ 4 | return "Hello!"; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /amm/src/test/resources/mains/ArgList.sc: -------------------------------------------------------------------------------- 1 | @main 2 | def main(args: String*): Unit = { 3 | args.foreach(arg => println(s"Argument: $arg")) 4 | } -------------------------------------------------------------------------------- /amm/src/test/resources/mains/Args.sc: -------------------------------------------------------------------------------- 1 | // Args.sc 2 | val x = 1 3 | 4 | @main 5 | def main(i: Int, s: String, path: os.Path = os.pwd) = { 6 | s"Hello! ${s * i} ${path.last}." 7 | } -------------------------------------------------------------------------------- /amm/src/test/resources/mains/Args2.sc: -------------------------------------------------------------------------------- 1 | // Args.sc 2 | val x = 1 3 | 4 | @main 5 | def main(i: Int, s: String, path: os.Path = os.pwd): Unit = { 6 | println(s"Hello! ${s * i} ${path.last}.") 7 | } -------------------------------------------------------------------------------- /amm/src/test/resources/mains/CompilerCrash.sc: -------------------------------------------------------------------------------- 1 | trait Bar { super[Object].hashCode } -------------------------------------------------------------------------------- /amm/src/test/resources/mains/Hello.sc: -------------------------------------------------------------------------------- 1 | println("Hello World") -------------------------------------------------------------------------------- /amm/src/test/resources/mains/Main.sc: -------------------------------------------------------------------------------- 1 | val x = 1 2 | 3 | @main 4 | def main() = { 5 | println("Hello! " + x) 6 | } -------------------------------------------------------------------------------- /amm/src/test/resources/mains/MultiMain.sc: -------------------------------------------------------------------------------- 1 | // MultiMain.sc 2 | 3 | val x = 1 4 | 5 | @main 6 | def mainA() = { 7 | println("Hello! " + x) 8 | } 9 | 10 | @main 11 | def functionB(i: Int, s: String, path: os.Path = os.pwd) = { 12 | println(s"Hello! ${s * i} ${path.relativeTo(os.pwd)}.") 13 | } -------------------------------------------------------------------------------- /amm/src/test/resources/mains/MultiMainDoc.sc: -------------------------------------------------------------------------------- 1 | // MultiMainDoc.sc 2 | 3 | val x = 1 4 | 5 | @main 6 | def mainA() = { 7 | println("Hello! " + x) 8 | } 9 | 10 | @arg(doc = "This explains what the function does") 11 | @main 12 | def functionB(@arg(doc = 13 | "how many times to repeat the string to make " + 14 | "it very very long, more than it originally was") 15 | i: Int , 16 | @arg(doc = "the string to repeat") 17 | s: String , 18 | path: os.Path = os.pwd) = { 19 | println(s"Hello! ${s * i} ${path.relativeTo(os.pwd)}.") 20 | } -------------------------------------------------------------------------------- /amm/src/test/resources/mains/Varargs.sc: -------------------------------------------------------------------------------- 1 | // Varargs.sc 2 | @main 3 | def main(i: Int, s: String, things: mainargs.Leftover[String]): Unit = { 4 | println(i) 5 | println(s) 6 | println(things.value.toList) 7 | } -------------------------------------------------------------------------------- /amm/src/test/resources/scriptCompilerSettings/configureCompiler.sc: -------------------------------------------------------------------------------- 1 | val scalacOptions = List( 2 | "-Yrangepos:true" 3 | ) 4 | interp.configureCompiler(_.settings.processArguments(scalacOptions, true)) 5 | 6 | // Forcing the re-initialisation of the compiler. 7 | // compiler.useOffsetPosition should remain true because it's initialised 8 | // eagerly 9 | @ 10 | 11 | -------------------------------------------------------------------------------- /amm/src/test/resources/scriptCompilerSettings/preConfigureCompiler.sc: -------------------------------------------------------------------------------- 1 | val scalacOptions = List( 2 | "-Yrangepos:true" 3 | ) 4 | interp.preConfigureCompiler(_.processArguments(scalacOptions, true)) 5 | 6 | // Forcing the re-initialisation of the compiler. 7 | // compiler.useOffsetPosition should now be false because the configuration of 8 | // the settings will have occurred before the new compiler become instantiated 9 | @ 10 | 11 | -------------------------------------------------------------------------------- /amm/src/test/resources/scriptCompilerSettings/yRangepos.sc: -------------------------------------------------------------------------------- 1 | val scalacOptions = List( 2 | "-Yrangepos:true" 3 | ) 4 | interp.preConfigureCompiler(_.processArguments(scalacOptions, true)) 5 | 6 | @ 7 | 8 | case class ABC(a : Int, b : String) 9 | println(ABC(1, "2")) 10 | 11 | -------------------------------------------------------------------------------- /amm/src/test/resources/scriptCompilerSettings/yRangeposError.sc: -------------------------------------------------------------------------------- 1 | val scalacOptions = List( 2 | "-Yrangepos:true" 3 | ) 4 | interp.preConfigureCompiler(_.processArguments(scalacOptions, true)) 5 | 6 | @ 7 | 8 | case class ABC(a : Int, b : String) 9 | val a = ABC(1, 1) // compiler error, the test checks the line at which it throws 10 | 11 | -------------------------------------------------------------------------------- /amm/src/test/resources/scriptLevelCaching/QuickSort.sc: -------------------------------------------------------------------------------- 1 | def fib(n : Int): Int = { 2 | if (n == 0) 0 3 | else if (n == 1) 1 4 | else fib(n-1) + fib(n-2) 5 | } 6 | 7 | def quicksort(unsorted : List[Int]): List[Int] = { 8 | if(unsorted.length <= 1) unsorted 9 | else{ 10 | val pivot = unsorted.head 11 | quicksort(unsorted.filter(_ < pivot)):::List(pivot):::quicksort(unsorted.filter(_ > pivot)) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /amm/src/test/resources/scriptLevelCaching/fileToBeImported.sc: -------------------------------------------------------------------------------- 1 | def listScalaFiles = os.list(os.pwd).filter(_.last.endsWith(".sc")) -------------------------------------------------------------------------------- /amm/src/test/resources/scriptLevelCaching/ivyCacheTest.sc: -------------------------------------------------------------------------------- 1 | import $ivy.`com.lihaoyi::scalatags:0.7.0 compat`, scalatags.Text.all._ 2 | 3 | val rendered = div("Moo").render 4 | 5 | -------------------------------------------------------------------------------- /amm/src/test/resources/scriptLevelCaching/ivyCachedResourceTest.sc: -------------------------------------------------------------------------------- 1 | import $ivy.`io.kamon::kamon-core:2.1.0 compat` 2 | os.read(os.resource/"reference.conf") 3 | -------------------------------------------------------------------------------- /amm/src/test/resources/scriptLevelCaching/runTimeExceptions.sc: -------------------------------------------------------------------------------- 1 | println(5/os.read(os.pwd/"amm"/"target"/"test"/"resources"/"scriptLevelCaching"/"num.value").trim.toInt) 2 | os.remove.all(os.pwd/"amm"/"target"/"test"/"resources"/"scriptLevelCaching"/"num.value") 3 | os.write(os.pwd/"amm"/"target"/"test"/"resources"/"scriptLevelCaching"/"num.value", "0") 4 | -------------------------------------------------------------------------------- /amm/src/test/resources/scriptLevelCaching/scriptOne.sc: -------------------------------------------------------------------------------- 1 | // Test Code 2 | object test{ 3 | 4 | val x = interp 5 | } 6 | println(test.x) 7 | 8 | @ 9 | 10 | def f = "Hello" 11 | println(System.lineSeparator*2 + "It has executed") 12 | 13 | -------------------------------------------------------------------------------- /amm/src/test/resources/scriptLevelCaching/scriptToBeLoaded.sc: -------------------------------------------------------------------------------- 1 | 2 | println(interp) 3 | println("First Block") 4 | 5 | @ 6 | 7 | println(interp) 8 | println("Second Block") 9 | 10 | @ 11 | 12 | println(interp) 13 | println("Third Block") 14 | 15 | @ 16 | 17 | println(interp) 18 | println("Fourth Block") 19 | 20 | val x = interp 21 | -------------------------------------------------------------------------------- /amm/src/test/resources/scriptLevelCaching/scriptTwo.sc: -------------------------------------------------------------------------------- 1 | 2 | println("Test Script") 3 | println(interp) 4 | 5 | -------------------------------------------------------------------------------- /amm/src/test/resources/scriptLevelCaching/testFileImport.sc: -------------------------------------------------------------------------------- 1 | import $file.fileToBeImported 2 | 3 | @ 4 | 5 | println("Hope It works!!") 6 | 7 | @ 8 | println(fileToBeImported.listScalaFiles) 9 | println("Yup!! It worked :) ") 10 | -------------------------------------------------------------------------------- /amm/src/test/resources/scriptLevelCaching/testLoadModule.sc: -------------------------------------------------------------------------------- 1 | // Test case to check whether it can load modules from cache and use the imports successfully 2 | 3 | println("Script starts!!") 4 | val scriptDir = os.pwd/"amm"/"src"/"test"/"resources"/"scriptLevelCaching" 5 | interp.load.module(scriptDir/"scriptToBeLoaded.sc") 6 | 7 | @ 8 | 9 | println(x) 10 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/Annotation.sc: -------------------------------------------------------------------------------- 1 | import annotation.tailrec 2 | val list= List(1,2,3,4) 3 | @tailrec def product(acc: Int, l: List[Int]): Int = { 4 | if(l.isEmpty) acc 5 | else product(acc*l.head,l.tail) 6 | } 7 | val res = product(1,list) 8 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/BlockSepSyntax.sc: -------------------------------------------------------------------------------- 1 | "block1" 2 | @ 3 | "block2" 4 | @ 5 | "block3" 6 | @ "block4" 7 | @ "block5" 8 | val res = 24 9 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/CompilationError.sc: -------------------------------------------------------------------------------- 1 | nonexistentSymbol 2 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/Encapsulation.sc: -------------------------------------------------------------------------------- 1 | asd 2 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/LimitImports.sc: -------------------------------------------------------------------------------- 1 | val res = 1 2 | @ 3 | val asd = 1 4 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/LoadIvy.sc: -------------------------------------------------------------------------------- 1 | interp.load.ivy("com.lihaoyi" %% "scalatags" % "0.12.0") 2 | @ 3 | import scalatags.Text.all._ 4 | val res = a("omg", href:="www.google.com").render 5 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/MultiBlockError.sc: -------------------------------------------------------------------------------- 1 | val res1 = 1 2 | @ 3 | thisWillFail 4 | @ 5 | val res2 = 1 6 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/MultilineSheBang.sc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec /usr/bin/amm "$0" "$@" 3 | !# 4 | 5 | val res = 42 6 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/NestedScripts.sc: -------------------------------------------------------------------------------- 1 | println("script start") 2 | interp.load.module(os.pwd/"amm"/"src"/"test"/"resources"/"scripts"/"LimitImports.sc") 3 | @ 4 | println("module should be loaded") 5 | @ 6 | val asd2 = asd 7 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/OneBlock.sc: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/PreserveImports.sc: -------------------------------------------------------------------------------- 1 | import scala.util.{Either, Left} 2 | @ 3 | val res = Left("asd") 4 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/Resolvers.sc: -------------------------------------------------------------------------------- 1 | interp.repositories() ++= Seq(coursierapi.IvyRepository.of( 2 | "https://ambiata-oss.s3-ap-southeast-2.amazonaws.com/[defaultPattern]" 3 | )) 4 | 5 | @ 6 | 7 | import $ivy.`com.ambiata::mundane:1.2.1-20141230225616-50fc792` 8 | import com.ambiata.mundane._ 9 | 10 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/ResolversFail.sc: -------------------------------------------------------------------------------- 1 | interp.repositories() ++= Seq(coursierapi.IvyRepository.of( 2 | "https://ambiata-oss.s3-ap-southeast-2.amazonaws.com/[defaultPattern]" 3 | )) 4 | 5 | import $ivy.`com.ambiata::mundane:1.2.1-20141230225616-50fc792` 6 | import com.ambiata.mundane._ 7 | 8 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/ResolversStatic.sc: -------------------------------------------------------------------------------- 1 | import $repo.`https://jitpack.io` 2 | import $ivy.`com.github.jupyter:jvm-repr:0.4.0` 3 | import jupyter._ 4 | 5 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/ScriptDontUnwrap.sc: -------------------------------------------------------------------------------- 1 | {{ 2 | val wrappedValue = 1 3 | val y = 2 4 | }} 5 | def foo = "foo def" -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/SheBang.sc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/amm 2 | val res = 42 3 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/SyntaxError.sc: -------------------------------------------------------------------------------- 1 | #syntaxError 2 | val res = 1 3 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/TagBase.sc: -------------------------------------------------------------------------------- 1 | def tagBase = "asd" 2 | @ 3 | tagBase 4 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/TagPrevCommand.sc: -------------------------------------------------------------------------------- 1 | def tagBase = "a" 2 | @ 3 | tagBase 4 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/ThreeBlocks.sc: -------------------------------------------------------------------------------- 1 | 1 2 | @ 3 | 2 4 | @ 5 | 3 6 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/TwoBlocks.sc: -------------------------------------------------------------------------------- 1 | 1 2 | @ 3 | 2 4 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/cachedCompilerInit.sc: -------------------------------------------------------------------------------- 1 | // Show compiler warnings 2 | interp.configureCompiler(c => println(c)) 3 | -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/caching/scalatagsPredef.sc: -------------------------------------------------------------------------------- 1 | import $ivy.`com.lihaoyi::scalatags:0.7.0`, scalatags.Text.all._ -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/caching/scalatagsScript.sc: -------------------------------------------------------------------------------- 1 | println(div("<('.'<)").render) -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/loadIvyAdvanced.sc: -------------------------------------------------------------------------------- 1 | import coursierapi.Dependency 2 | 3 | interp.load.ivy( 4 | // Using SBT-style syntax 5 | "xom" % "xom" % "1.1", 6 | // Directly using coursier API. Can pass in exclusions, 7 | // attributes, configurations, classifiers, etc. 8 | Dependency.of("net.sf.json-lib", "json-lib", "2.4") 9 | .withClassifier("jdk15") 10 | ) 11 | 12 | @ 13 | 14 | // Code using the dependencies 15 | val serializer = new net.sf.json.xml.XMLSerializer -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/predefWithLoad/Loaded.sc: -------------------------------------------------------------------------------- 1 | val loadedDefinedValue = 1337 -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/predefWithLoad/PredefLoadExec.sc: -------------------------------------------------------------------------------- 1 | repl.load.exec( 2 | os.pwd/"amm"/"src"/"test"/"resources"/"scripts"/"predefWithLoad"/"Loaded.sc" 3 | ) 4 | 5 | @ 6 | 7 | val predefDefinedValue = loadedDefinedValue -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/predefWithLoad/PredefLoadModule.sc: -------------------------------------------------------------------------------- 1 | interp.load.module( 2 | os.pwd/"amm"/"src"/"test"/"resources"/"scripts"/"predefWithLoad"/"Loaded.sc" 3 | ) 4 | 5 | @ 6 | val predefDefinedValue = loadedDefinedValue -------------------------------------------------------------------------------- /amm/src/test/resources/scripts/predefWithLoad/PredefMagicImport.sc: -------------------------------------------------------------------------------- 1 | import $file.Loaded 2 | 3 | val predefDefinedValue = Loaded.loadedDefinedValue -------------------------------------------------------------------------------- /amm/src/test/resources/testdata/Resume.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/amm/src/test/resources/testdata/Resume.docx -------------------------------------------------------------------------------- /amm/src/test/resources/testdata/images/GettingStarted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/amm/src/test/resources/testdata/images/GettingStarted.png -------------------------------------------------------------------------------- /amm/src/test/resources/testdata/images/Highlighting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/amm/src/test/resources/testdata/images/Highlighting.png -------------------------------------------------------------------------------- /amm/src/test/resources/testdata/images/SystemShell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/amm/src/test/resources/testdata/images/SystemShell.png -------------------------------------------------------------------------------- /amm/src/test/scala/ammonite/interp/CompilerSettingsTests.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp 2 | 3 | import ammonite.TestUtils._ 4 | 5 | import ammonite.compiler.test.CompilerTestExtensions._ 6 | import ammonite.runtime.Storage 7 | import ammonite.main.Scripts 8 | import utest._ 9 | 10 | object CompilerSettingsTests extends TestSuite { 11 | val tests = Tests { 12 | println("CompilerSettingsTests") 13 | 14 | val scriptPath = os.pwd / "amm" / "src" / "test" / "resources" / "scriptCompilerSettings" 15 | 16 | test("configureYrangepos") { 17 | 18 | // In this test, the script sets -Yrangepos to true using "configureCompiler", 19 | // which is called AFTER the compiler instantiates. As useOffsetPositions 20 | // is set eagerly during the compiler instantiation as !Yrangepos, its 21 | // value remains "true". 22 | if (scala2_12) { 23 | val storage = Storage.InMemory() 24 | val interp = createTestInterp(storage) 25 | Scripts.runScript(os.pwd, scriptPath / "configureCompiler.sc", interp) 26 | 27 | assert( 28 | interp 29 | .compilerManager 30 | .asInstanceOf[ammonite.compiler.CompilerLifecycleManager] 31 | .compiler 32 | .compiler 33 | .useOffsetPositions 34 | ) 35 | } else "Disabled" 36 | } 37 | 38 | test("preConfigureYrangepos") { 39 | // In this test, the script sets -Yrangepos using "preConfigureCompiler", 40 | // which is called BEFORE the compiler instantiates, resulting in 41 | // useOffsetPositions initializing as false, as expected 42 | if (scala2) { 43 | val storage = Storage.InMemory() 44 | val interp = createTestInterp( 45 | storage, 46 | predefImports = Interpreter.predefImports 47 | ) 48 | Scripts.runScript(os.pwd, scriptPath / "preConfigureCompiler.sc", interp) 49 | 50 | assert( 51 | !interp 52 | .compilerManager 53 | .asInstanceOf[ammonite.compiler.CompilerLifecycleManager] 54 | .compiler 55 | .compiler 56 | .useOffsetPositions 57 | ) 58 | } else "Disabled in Scala 3" 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /amm/src/test/scala/ammonite/interp/YRangeposTests.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp 2 | 3 | import ammonite.TestUtils._ 4 | 5 | import ammonite.runtime.Storage 6 | import ammonite.main._ 7 | import utest._ 8 | 9 | object YRangeposTests extends TestSuite { 10 | val tests = Tests { 11 | println("YRangeposTests") 12 | 13 | def checkErrorMessage(file: os.Path, expected: String): Unit = { 14 | val e = new InProcessMainMethodRunner(file, Nil, Nil) 15 | 16 | assert(e.err.contains(expected)) 17 | } 18 | 19 | val scriptFolderPath = 20 | os.pwd / "amm" / "src" / "test" / "resources" / "scriptCompilerSettings" 21 | 22 | def simpleTest() = { 23 | // This tests shows that enabling Yrangepos does not mess with ammonite's 24 | // behaviour. The compiler not crashing is the test itself. 25 | val storage = Storage.InMemory() 26 | val interp = createTestInterp( 27 | storage, 28 | predefImports = Interpreter.predefImports 29 | ) 30 | val res = Scripts.runScript(os.pwd, scriptFolderPath / "yRangepos.sc", interp) 31 | assert(res.isSuccess) 32 | } 33 | test("Yrangepos") { 34 | if (scala2) simpleTest() 35 | else "Disabled in Scala 3" 36 | } 37 | 38 | def errorTest() = { 39 | // This tests shows that enabling Yrangepos does not mess with ammonite's 40 | // behaviour, by checking that the line at which the error is found matches 41 | // the expected one in the file 42 | val expectedErrorMessage = "yRangeposError.sc:9: type mismatch;" 43 | checkErrorMessage( 44 | InProcessMainMethodRunner.base / "scriptCompilerSettings" / "yRangeposError.sc", 45 | expectedErrorMessage 46 | ) 47 | } 48 | test("YrangeposError") { 49 | if (scala2) errorTest() 50 | else "Disabled in Scala 3" 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /amm/src/test/scala/ammonite/interp/script/TestBuildClient.scala: -------------------------------------------------------------------------------- 1 | package ammonite.interp.script 2 | 3 | import java.util.concurrent.{ConcurrentHashMap, ConcurrentLinkedQueue} 4 | 5 | import ch.epfl.scala.bsp4j.{Diagnostic => BDiagnostic, _} 6 | 7 | import scala.collection.JavaConverters._ 8 | 9 | class TestBuildClient extends BuildClient { 10 | 11 | import TestBuildClient._ 12 | 13 | private val diagnostics0 = 14 | new ConcurrentHashMap[ 15 | (BuildTargetIdentifier, TextDocumentIdentifier), 16 | Seq[BDiagnostic] 17 | ] 18 | 19 | private val taskEvents0 = new ConcurrentLinkedQueue[TaskEvent] 20 | private val didChangeNotifications0 = new ConcurrentLinkedQueue[BuildTargetEvent] 21 | 22 | def diagnostics( 23 | targetId: BuildTargetIdentifier, 24 | document: TextDocumentIdentifier 25 | ): Option[Seq[BDiagnostic]] = 26 | Option(diagnostics0.get((targetId, document))) 27 | 28 | def taskEvents(): Seq[TaskEvent] = 29 | taskEvents0.iterator().asScala.toVector 30 | def didChangeNotifications(): Seq[BuildTargetEvent] = 31 | didChangeNotifications0.iterator().asScala.toVector 32 | def clearDidChangeNotifications(): Unit = 33 | didChangeNotifications0.clear() 34 | 35 | def onBuildPublishDiagnostics(params: PublishDiagnosticsParams): Unit = 36 | diagnostics0.put( 37 | (params.getBuildTarget, params.getTextDocument), 38 | params.getDiagnostics.asScala.toVector 39 | ) 40 | 41 | def onBuildTaskStart(params: TaskStartParams): Unit = 42 | taskEvents0.add(TaskEvent.Start(params)) 43 | def onBuildTaskProgress(params: TaskProgressParams): Unit = 44 | taskEvents0.add(TaskEvent.Progress(params)) 45 | def onBuildTaskFinish(params: TaskFinishParams): Unit = 46 | taskEvents0.add(TaskEvent.Finish(params)) 47 | 48 | def onBuildTargetDidChange(params: DidChangeBuildTarget): Unit = 49 | didChangeNotifications0.addAll(params.getChanges) 50 | 51 | def onBuildLogMessage(params: LogMessageParams): Unit = () 52 | def onBuildShowMessage(params: ShowMessageParams): Unit = () 53 | } 54 | 55 | object TestBuildClient { 56 | 57 | sealed abstract class TaskEvent extends Product with Serializable 58 | object TaskEvent { 59 | final case class Start(params: TaskStartParams) extends TaskEvent 60 | final case class Progress(params: TaskProgressParams) extends TaskEvent 61 | final case class Finish(params: TaskFinishParams) extends TaskEvent 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /amm/src/test/scala/ammonite/main/InProcessMainMethodRunner.scala: -------------------------------------------------------------------------------- 1 | package ammonite.main 2 | 3 | import java.io.{ByteArrayInputStream, ByteArrayOutputStream} 4 | 5 | object InProcessMainMethodRunner { 6 | val base = os.pwd / "amm" / "src" / "test" / "resources" 7 | } 8 | 9 | /** 10 | * An in-memory mock subprocess; exposes the same API as a subprocess call: 11 | * stdin, stdout, stderr, and command-line arguments as a Array[String]. But 12 | * runs the computation in memory, which is often a lot faster. 13 | * 14 | * Attempts to capture stdout and stderr from the current thread via 15 | * the `Console.with*` methods. This doesn't always work, e.g. it doesn't 16 | * capture Java `System.*.println` methods, and overall this doesn't guarantee 17 | * JVM-level isolation between tests. But it works well enough for 18 | * our unit tests. 19 | */ 20 | class InProcessMainMethodRunner(p: os.Path, preArgs: List[String], args: Seq[String]) { 21 | 22 | val in = new ByteArrayInputStream(Array.empty[Byte]) 23 | val err0 = new ByteArrayOutputStream() 24 | val out0 = new ByteArrayOutputStream() 25 | val path = p 26 | 27 | val success = Console.withIn(in) { 28 | Console.withErr(err0) { 29 | Console.withOut(out0) { 30 | ammonite.AmmoniteMain.main0( 31 | List("--home", os.temp.dir().toString) ++ 32 | preArgs ++ 33 | Seq(path.toString) ++ 34 | args.toList, 35 | in, 36 | out0, 37 | err0 38 | ) 39 | } 40 | } 41 | } 42 | 43 | val out = new String(out0.toByteArray) 44 | val err = new String(err0.toByteArray) 45 | override def toString = { 46 | s"Executor($out, $err)" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /amm/src/test/scala/ammonite/main/InProcessMainMethodRunnerRawArgs.scala: -------------------------------------------------------------------------------- 1 | package ammonite.main 2 | 3 | import java.io.{ByteArrayInputStream, ByteArrayOutputStream} 4 | 5 | /** 6 | * Same purpose as [[InProcessMainMethodRunner]] but it accepts the arguments 7 | * as they are. This is somewhat analogous to [[ammonite.Main.main0]] but it 8 | * attempts to capture the output and error streams like 9 | * [[InProcessMainMethodRunner]] without having to append any prefix arguments 10 | * such as the current path. 11 | * 12 | * @see [[InProcessMainMethodRunner]]. 13 | */ 14 | class InProcessMainMethodRunnerRawArgs(args: Seq[String]) { 15 | 16 | val in = new ByteArrayInputStream(Array.empty[Byte]) 17 | val err0 = new ByteArrayOutputStream() 18 | val out0 = new ByteArrayOutputStream() 19 | 20 | val success = Console.withIn(in) { 21 | Console.withErr(err0) { 22 | Console.withOut(out0) { 23 | ammonite.AmmoniteMain.main0(args.toList, in, out0, err0) 24 | } 25 | } 26 | } 27 | 28 | val out = new String(out0.toByteArray) 29 | val err = new String(err0.toByteArray) 30 | 31 | override def toString = 32 | s"Executor($out, $err)" 33 | } 34 | -------------------------------------------------------------------------------- /amm/src/test/scala/ammonite/readme.md: -------------------------------------------------------------------------------- 1 | The tests in this folder are roughly broken down into: 2 | 3 | - `unit` tests: small, self-contained functions or utilities 4 | 5 | - `interp` tests: instantiating an `Interpreter` object, then poking at its 6 | internals and running its functionality 7 | 8 | - `session` tests: simulating a REPL session, running multiple commands one 9 | after another and checking that the output matches what you'd expect 10 | 11 | - `main` tests: tests running Ammonite's `main0` method, which is basically 12 | equivalent to spawning a new Ammonite process, except the logic is run 13 | in-process with mock `stdin`/`stdout`/`stderr` streams. 14 | 15 | These are listed in increasing levels of "integration"-ness; anything more 16 | integrated than this would be in the separate integration/ test subproject, 17 | which literally spins up a separate Ammonite process from the jar file and 18 | makes sure everything works end-to-end -------------------------------------------------------------------------------- /amm/util/src/main/scala/ammonite/util/Frame.scala: -------------------------------------------------------------------------------- 1 | package ammonite.util 2 | 3 | import java.net.URL 4 | 5 | trait Frame { 6 | def classloader: ReplClassLoader 7 | def pluginClassloader: ReplClassLoader 8 | 9 | def classpath: Seq[URL] 10 | def version: Int 11 | 12 | /** Adds a [[Frame.Hook]] to be called every time JARs are added to the class path */ 13 | def addHook(hook: Frame.Hook): Unit 14 | } 15 | 16 | object Frame { 17 | 18 | /** A hook that can be called every time JARs are added to the class path */ 19 | trait Hook { 20 | 21 | /** Called when new JARs are added to the class path */ 22 | def addClasspath(additional: Seq[java.net.URL]): Unit 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /amm/util/src/main/scala/ammonite/util/Position.scala: -------------------------------------------------------------------------------- 1 | package ammonite.util 2 | 3 | final case class Position(line: Int, char: Int) 4 | -------------------------------------------------------------------------------- /amm/util/src/main/scala/ammonite/util/ReplClassLoader.scala: -------------------------------------------------------------------------------- 1 | package ammonite.util 2 | 3 | import java.net.{URL, URLClassLoader} 4 | 5 | abstract class ReplClassLoader(urls: Array[URL], parent: ClassLoader) 6 | extends URLClassLoader(urls, parent) { 7 | def inMemoryClasses: Map[String, Array[Byte]] 8 | } 9 | -------------------------------------------------------------------------------- /amm/util/src/main/scala/ammonite/util/WhiteListClassLoader.scala: -------------------------------------------------------------------------------- 1 | package ammonite.util 2 | 3 | import java.net.URLClassLoader 4 | 5 | class WhiteListClassLoader(whitelist: Set[Seq[String]], parent: ClassLoader) 6 | extends URLClassLoader(Array(), parent) { 7 | override def loadClass(name: String, resolve: Boolean) = { 8 | val tokens = name.split('.') 9 | if (Util.lookupWhiteList(whitelist, tokens.init ++ Seq(tokens.last + ".class"))) { 10 | super.loadClass(name, resolve) 11 | } else { 12 | throw new ClassNotFoundException(name) 13 | } 14 | 15 | } 16 | override def getResource(name: String) = { 17 | if (Util.lookupWhiteList(whitelist, name.split('/'))) super.getResource(name) 18 | else null 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | import scalatex.ScalatexReadme 2 | 3 | lazy val readme = ScalatexReadme( 4 | projectId = "readme", 5 | wd = file(""), 6 | url = "https://github.com/com-lihaoyi/Ammonite/tree/main", 7 | source = "Index" 8 | ).settings( 9 | scalaVersion := "2.12.18", 10 | libraryDependencies += "com.lihaoyi" %% "fansi" % "0.2.14", 11 | libraryDependencies += "com.lihaoyi" %% "os-lib" % "0.7.8", 12 | Test / envVars := Map( 13 | "AMMONITE_ASSEMBLY" -> sys.env("AMMONITE_ASSEMBLY"), 14 | "AMMONITE_SHELL" -> sys.env("AMMONITE_SHELL") 15 | ), 16 | fork := true, 17 | Compile / run / baseDirectory := (Compile / run / baseDirectory).value / "..", 18 | (Compile / unmanagedSources) += file(sys.env("CONSTANTS_FILE")) 19 | ) 20 | -------------------------------------------------------------------------------- /ci/deploy_master_docs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euxv 3 | 4 | # Mangle ssh-key stuff to work with the deploy_key written by python 5 | eval "$(ssh-agent -s)" 6 | chmod 600 deploy_key 7 | ssh-add deploy_key 8 | rm deploy_key 9 | 10 | # Set up git so we can actually do things with it 11 | git config --global user.email "haoyi.sg+travis@gmail.com" 12 | git config --global user.name "Ammonite Travis Bot" 13 | git fetch origin gh-pages:gh-pages 14 | 15 | # Do all the git-foo to push the readme to the relevant gh-pages folder 16 | git checkout -f gh-pages 17 | cp -r readme/target/scalatex/* . 18 | git add -A 19 | git commit -am $(git rev-parse HEAD) 20 | git push git@github.com:$GITHUB_REPOSITORY.git gh-pages:gh-pages 21 | -------------------------------------------------------------------------------- /ci/package.mill: -------------------------------------------------------------------------------- 1 | package build.ci 2 | -------------------------------------------------------------------------------- /ci/upload.mill: -------------------------------------------------------------------------------- 1 | package build.ci 2 | 3 | def apply( 4 | uploadedFile: os.Path, 5 | tagName: String, 6 | uploadName: String, 7 | authKey: String, 8 | ghOrg: String, 9 | ghRepo: String 10 | ): String = { 11 | println("upload.apply") 12 | println(uploadedFile) 13 | println(tagName) 14 | println(uploadName) 15 | println(authKey) 16 | println(ghOrg) 17 | println(ghRepo) 18 | val body = requests.get( 19 | s"https://api.github.com/repos/${ghOrg}/${ghRepo}/releases/tags/" + tagName, 20 | headers = Seq("Authorization" -> s"token $authKey") 21 | ) 22 | 23 | val parsed = ujson.read(body.text) 24 | 25 | println(body) 26 | 27 | val snapshotReleaseId = parsed("id").num.toInt 28 | 29 | val uploadUrl = 30 | s"https://uploads.github.com/repos/${ghOrg}/${ghRepo}/releases/" + 31 | s"$snapshotReleaseId/assets?name=$uploadName" 32 | 33 | val res = requests.post( 34 | uploadUrl, 35 | headers = Seq( 36 | "Content-Type" -> "application/octet-stream", 37 | "Authorization" -> s"token $authKey" 38 | ), 39 | connectTimeout = 5000, 40 | readTimeout = 60000, 41 | data = os.read.bytes(uploadedFile) 42 | ).text 43 | 44 | println(res) 45 | 46 | val longUrl = ujson.read(res)("browser_download_url").str 47 | 48 | longUrl 49 | } 50 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/Complex.sc: -------------------------------------------------------------------------------- 1 | import $ivy.`org.spire-math::spire:0.13.0` 2 | 3 | import spire.implicits._ 4 | import spire.math._ 5 | 6 | println("Spire Interval " + Interval(0, 10)) -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/Failure.sc: -------------------------------------------------------------------------------- 1 | println(x) -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/Hello.sc: -------------------------------------------------------------------------------- 1 | println("Hello World") -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/HttpApi.sc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env amm 2 | // HttpApi.sc 3 | 4 | import $ivy.{ 5 | `com.lihaoyi::requests:0.2.0 compat`, 6 | `com.lihaoyi::ujson:0.7.5 compat` 7 | } 8 | 9 | lazy val jsonPlaceHolderBase = 10 | Option(System.getenv("JSONPLACEHOLDER")).getOrElse { 11 | "http://jsonplaceholder.typicode.com" 12 | } 13 | 14 | @main 15 | def addPost(title: String, body: String) = { 16 | ujson.read( 17 | requests.post( 18 | s"$jsonPlaceHolderBase/posts", 19 | data = Seq( 20 | "title" -> title, 21 | "body" -> body, 22 | "userId" -> "1" 23 | ) 24 | ).text() 25 | ).obj.get("id").map(_.num.toInt).getOrElse(0) 26 | 27 | 28 | } 29 | 30 | @main 31 | def comments(postId: Int) = { 32 | val json = ujson.read( 33 | requests 34 | .get(s"$jsonPlaceHolderBase/comments?postId=$postId") 35 | .text() 36 | ) 37 | val names = for{ 38 | item <- json.arr 39 | name <- item.obj.get("name") 40 | } yield name.str 41 | names.mkString(",") 42 | } 43 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/MultiMain.sc: -------------------------------------------------------------------------------- 1 | // MultiMain.sc 2 | 3 | val x = 1 4 | 5 | @main 6 | def mainA() = { 7 | println("Hello! " + x) 8 | } 9 | 10 | @main 11 | def functionB(i: Int, s: String, path: os.Path = os.pwd) = { 12 | println(s"Hello! ${s * i} ${path.relativeTo(os.pwd)}.") 13 | } -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/PlayFramework.sc: -------------------------------------------------------------------------------- 1 | /** 2 | * Single-file play framework application! 3 | */ 4 | import $ivy.{ 5 | `com.typesafe.play::play:2.5.0`, 6 | `com.typesafe.play::play-netty-server:2.5.0`, 7 | `com.lihaoyi::requests:0.2.0` 8 | } 9 | 10 | import play.core.server._, play.api.routing.sird._, play.api.mvc._ 11 | val server = NettyServer.fromRouter(new ServerConfig( 12 | rootDir = new java.io.File("."), 13 | port = Some(19000), sslPort = None, 14 | address = "0.0.0.0", mode = play.api.Mode.Dev, 15 | properties = System.getProperties, 16 | configuration = play.api.Configuration( 17 | "play.server.netty" -> Map( 18 | "maxInitialLineLength" -> 4096, 19 | "maxHeaderSize" -> 8192, 20 | "maxChunkSize" -> 8192, 21 | "log.wire" -> false, 22 | "eventLoopThreads" -> 0, 23 | "transport" -> "jdk", 24 | "option.child" -> Map() 25 | ) 26 | ) 27 | )) { 28 | case GET(p"/hello/$to") => Action { Results.Ok(s"Hello $to") } 29 | } 30 | try { 31 | println(requests.get("http://localhost:19000/hello/bar").text()) 32 | } finally{ 33 | server.stop() 34 | } 35 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/Print.sc: -------------------------------------------------------------------------------- 1 | println(os.list(os.pwd/"out")) -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/QuickSort.sc: -------------------------------------------------------------------------------- 1 | def fib(n : Int) : Int = { 2 | if (n == 0) 0 3 | else if (n == 1) 1 4 | else fib(n-1) + fib(n-2) 5 | } 6 | 7 | def quicksort(unsorted : List[Int]) : List[Int] = { 8 | if(unsorted.length <= 1) unsorted 9 | else{ 10 | val pivot = unsorted.head 11 | quicksort(unsorted.filter(_ < pivot)):::List(pivot):::quicksort(unsorted.filter(_ > pivot)) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/Resources.sc: -------------------------------------------------------------------------------- 1 | interp.load.ivy("org.apache.jackrabbit" % "oak-core" % "1.3.16") 2 | @ 3 | val path = os.resource/"org"/"apache"/"jackrabbit"/"oak"/"plugins"/"blob"/"blobstore.properties" 4 | println(os.read(path).length) // Should work -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/SourceDownload.sc: -------------------------------------------------------------------------------- 1 | import $ivy.`com.lihaoyi::scalatags:0.7.0 compat` 2 | 3 | val loc = source.load(scalatags.Text) 4 | val snip = Predef.augmentString(loc.fileContent) 5 | .lines 6 | .slice(loc.lineNum-15, loc.lineNum+15) 7 | .mkString("\n") 8 | 9 | assert(snip.contains("object Text")) 10 | assert(snip.contains("extends generic.Bundle")) -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/Spark.sc: -------------------------------------------------------------------------------- 1 | 2 | import $ivy.{ 3 | `org.apache.hadoop:hadoop-common:2.5.1`, 4 | `org.apache.hadoop:hadoop-auth:2.5.1`, 5 | `commons-configuration:commons-configuration:1.9`, 6 | `commons-collections:commons-collections:3.2.1`, 7 | `commons-lang:commons-lang:2.6`, 8 | `org.apache.spark::spark-core:2.1.1`, 9 | `org.apache.spark::spark-repl:2.1.1`, 10 | `org.apache.spark::spark-network-common:2.1.1`, 11 | `org.apache.spark::spark-network-shuffle:2.1.1`, 12 | `org.eclipse.jetty.aggregate:jetty-all-server:8.1.14.v20131031` 13 | } 14 | 15 | import java.net.InetAddress 16 | import org.eclipse.jetty.server.Server 17 | import org.eclipse.jetty.server.bio.SocketConnector 18 | import org.eclipse.jetty.server.handler.{DefaultHandler, HandlerList, ResourceHandler} 19 | import org.eclipse.jetty.util.thread.QueuedThreadPool 20 | import org.eclipse.jetty.util.resource.Resource 21 | import org.apache.spark.{SparkConf, SparkContext} 22 | 23 | 24 | val server = { 25 | val server = new Server() 26 | 27 | val connector = new SocketConnector 28 | connector.setMaxIdleTime(60 * 1000) 29 | connector.setSoLingerTime(-1) 30 | connector.setPort(0) 31 | server.addConnector(connector) 32 | 33 | val threadPool = new QueuedThreadPool 34 | threadPool.setDaemon(true) 35 | server.setThreadPool(threadPool) 36 | 37 | val resHandler = new ResourceHandler 38 | resHandler.setBaseResource(Resource.newClassPathResource("/")) 39 | 40 | val handlerList = new HandlerList 41 | handlerList.setHandlers(Array(resHandler, new DefaultHandler)) 42 | 43 | server.setHandler(handlerList) 44 | 45 | server.start() 46 | 47 | server 48 | } 49 | 50 | val port = server.getConnectors()(0).getLocalPort 51 | 52 | println("Starting spark test") 53 | 54 | val conf = new SparkConf() 55 | .setAppName("test") 56 | .setMaster("local[*]") 57 | .set( 58 | "spark.repl.class.uri", 59 | s"http://${InetAddress.getLocalHost().getHostName()}:$port" 60 | ) 61 | // To allow retries for this test. 62 | .set("spark.driver.allowMultipleContexts", "true") 63 | val sc = new SparkContext(conf) 64 | val result = sc.parallelize(1 to 5).map(_ * 10).collect 65 | 66 | server.stop() 67 | println(s"Spark result: ${result.toList}") 68 | assert(result.toList == List(10, 20, 30, 40, 50)) -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/Spark2.json: -------------------------------------------------------------------------------- 1 | {"hello": 1}, 2 | {"hello": 2}, 3 | 4 | {"hello": 3} 5 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/Spark2.sc: -------------------------------------------------------------------------------- 1 | import $ivy.{ 2 | `org.apache.spark::spark-core:2.1.0`, 3 | `org.apache.spark::spark-sql:2.1.0` 4 | } 5 | import org.apache.spark.sql.SparkSession 6 | 7 | val spark = SparkSession.builder.master("local[*]").appName("bxm").getOrCreate 8 | 9 | val df = spark.read.json( 10 | "integration/src/test/resources/ammonite/integration/basic/Spark2.json" 11 | ) 12 | 13 | df.foreachPartition { records => 14 | records.foreach { 15 | record => println("fake db write") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/Varargs.sc: -------------------------------------------------------------------------------- 1 | // Varargs.sc 2 | @main 3 | def main(i: Int, s: String, things: String*): Unit = { 4 | println(i) 5 | println(s) 6 | println(things) 7 | } -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/http-api-data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "body": "eum laborum quidem omnis facere harum ducimus dolores quaerat\ncorporis quidem aliquid\nquod aut aut at dolorum aspernatur reiciendis\nexercitationem quasi consectetur asperiores vero blanditiis dolor", 4 | "email": "Jenifer_Lowe@reuben.ca", 5 | "id": 196, 6 | "name": "totam vel saepe aut qui velit quis", 7 | "postId": 40 8 | }, 9 | { 10 | "body": "fugit ut laborum provident\nquos provident voluptatibus quam non\nsed accusantium explicabo dolore quia distinctio voluptatibus et\nconsequatur eos qui iure minus eaque praesentium", 11 | "email": "Cecelia_Nitzsche@marty.com", 12 | "id": 197, 13 | "name": "non perspiciatis omnis facere rem", 14 | "postId": 40 15 | }, 16 | { 17 | "body": "est veritatis mollitia atque quas et sint et dolor\net ut beatae aut\nmagni corporis dolores voluptatibus optio molestiae enim minus est\nreiciendis facere voluptate rem officia doloribus ut", 18 | "email": "Christop_Friesen@jordan.me", 19 | "id": 198, 20 | "name": "quod vel enim sit quia ipsa quo dolores", 21 | "postId": 40 22 | }, 23 | { 24 | "body": "veniam eos ab voluptatem in fugiat ipsam quis\nofficiis non qui\nquia ut id voluptates et a molestiae commodi quam\ndolorem enim soluta impedit autem nulla", 25 | "email": "Cooper_Boehm@damian.biz", 26 | "id": 199, 27 | "name": "pariatur aspernatur nam atque quis", 28 | "postId": 40 29 | }, 30 | { 31 | "body": "facere maxime alias aspernatur ab quibusdam necessitatibus\nratione similique error enim\nsed minus et\net provident minima voluptatibus", 32 | "email": "Amir@kaitlyn.org", 33 | "id": 200, 34 | "name": "aperiam et omnis totam", 35 | "postId": 40 36 | } 37 | ] -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/ivyResolveItv1.sc: -------------------------------------------------------------------------------- 1 | import $ivy.`com.lihaoyi::some-dummy-library:0.2+` 2 | 3 | import io.circe._ 4 | val json = Json.obj("a" -> Json.True) 5 | 6 | println(dummy.Dummy.thing) 7 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/ivyResolveItv2.sc: -------------------------------------------------------------------------------- 1 | import $ivy.`com.lihaoyi::some-dummy-library:0.2+` 2 | 3 | import argonaut._ 4 | val json = Json.obj("a" -> Json.jTrue, "c" -> Json.jString("b")) 5 | 6 | println(dummy.Dummy.thing) 7 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/ivyResolveSnapshot1.sc: -------------------------------------------------------------------------------- 1 | import $ivy.`com.lihaoyi::some-dummy-library:0.1-SNAPSHOT` 2 | 3 | import io.circe._ 4 | val json = Json.obj("a" -> Json.True) 5 | 6 | println(dummy.Dummy.thing) 7 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/ivyResolveSnapshot2.sc: -------------------------------------------------------------------------------- 1 | import $ivy.`com.lihaoyi::some-dummy-library:0.1-SNAPSHOT` 2 | 3 | import argonaut._ 4 | val json = Json.obj("a" -> Json.jTrue, "c" -> Json.jString("b")) 5 | 6 | println(dummy.Dummy.thing) 7 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/scalaTags.sc: -------------------------------------------------------------------------------- 1 | interp.load.ivy("com.lihaoyi" %% "scalatags" % "0.7.0") 2 | @ 3 | import scalatags.Text.all._ 4 | val res = a("omg", href:="www.google.com").render 5 | 6 | println(res) 7 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/basic/wrongIvyCordinates.sc: -------------------------------------------------------------------------------- 1 | import $ivy.`com.lihaoyi::somethingWhichDoesNotExist:0.4.5` 2 | 3 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/errorTruncation/compileError.sc: -------------------------------------------------------------------------------- 1 | doesntexist 2 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/errorTruncation/compileErrorMultiExpr.sc: -------------------------------------------------------------------------------- 1 | // Make sure the line numbers work properly in cases where we have statement 2 | // breaks, both implicitly due to newlines, explicitly due to semi-colons, or 3 | // both! 4 | 123;456 5 | 6 | ;implicitly{ 7 | math.max(1 + 2 + 3, 4) 8 | } 9 | 10 | identity("Hello"); 11 | doesntexist 12 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/errorTruncation/parseError.sc: -------------------------------------------------------------------------------- 1 | } 2 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/errorTruncation/runtimeError.sc: -------------------------------------------------------------------------------- 1 | 1/0 2 | -------------------------------------------------------------------------------- /integration/src/test/resources/ammonite/integration/lineNumbers/compilationErrorInSecondBlock.sc: -------------------------------------------------------------------------------- 1 | 2 | //Another Comment 3 | 4 | def quicksort(unsorted : List[Int]) : List[Int] = { 5 | if(unsorted.length <= 1) unsorted 6 | else{ 7 | val pivot = unsorted.head 8 | quicksort(unsorted.filter(_ < pivot)):::List(pivot):::quicksort(unsorted.filter(_ > pivot)) 9 | } 10 | } 11 | 12 | @ 13 | 14 | printnl("OK") 15 | 16 | //One more comment 17 | //This one is long one! 18 | //check empty lines 19 | 20 | val x = 1 21 | println(x) 22 | //print the value of x 23 | @ 24 | 25 | //lots of comments!! 26 | 27 | prinntl("Ammonite") 28 | -------------------------------------------------------------------------------- /integration/src/test/resources/some-dummy-library/build.sbt: -------------------------------------------------------------------------------- 1 | val scalaV = sys.env("SCALA_VERSION") 2 | val circeVersion = if(scalaV.startsWith("3.")) "0.14.6" else "0.12.0-M3" 3 | 4 | lazy val root = (project in file(".")). 5 | settings( 6 | name := "some-dummy-library", 7 | organization := "com.lihaoyi", 8 | version := sys.env("VERSION"), 9 | scalaVersion := sys.env("SCALA_VERSION"), 10 | libraryDependencies += { 11 | if (sys.env("FIRST_RUN").toBoolean) 12 | "io.circe" %% "circe-core" % circeVersion 13 | else 14 | "io.argonaut" %% "argonaut" % "6.2.6" 15 | } 16 | ) 17 | -------------------------------------------------------------------------------- /integration/src/test/resources/some-dummy-library/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.9.6 2 | -------------------------------------------------------------------------------- /integration/src/test/scala-2.13/ammonite/integration/ProjectTests213.scala: -------------------------------------------------------------------------------- 1 | package ammonite.integration 2 | 3 | import ammonite.integration.TestUtils._ 4 | import utest._ 5 | 6 | object ProjectTests213 extends TestSuite { 7 | 8 | val tests = Tests { 9 | println("Running ProjectTest213") 10 | 11 | test("httpApi") { 12 | def addPostTest() = jsonplaceholder.withServer { url => 13 | val res = execWithEnv( 14 | Seq("JSONPLACEHOLDER" -> url), 15 | os.rel / 'basic / "HttpApi.sc", 16 | "addPost", 17 | "title", 18 | "some text" 19 | ) 20 | assert(res.out.trim.contains("101")) 21 | } 22 | def commentsTest() = jsonplaceholder.withServer { url => 23 | val res = execWithEnv( 24 | Seq("JSONPLACEHOLDER" -> url), 25 | os.rel / 'basic / "HttpApi.sc", 26 | "comments", 27 | "40" 28 | ) 29 | assert(res.out.trim.contains("totam vel saepe aut")) 30 | assert(res.out.trim.contains("aperiam et omnis totam")) 31 | } 32 | test("addPost") { 33 | if (isScala2) addPostTest() 34 | else "Disabled in Scala 3" 35 | } 36 | test("comments") { 37 | if (isScala2) commentsTest() 38 | else "Disabled in Scala 3" 39 | } 40 | } 41 | } 42 | } 43 | 44 | object jsonplaceholder extends cask.MainRoutes { 45 | 46 | private val comments = Map( 47 | 40 -> ujson.read( 48 | os.read(replStandaloneResources / 'basic / "http-api-data.json") 49 | ) 50 | ) 51 | 52 | @cask.postForm("/posts") 53 | def posts(title: String, body: String, userId: String) = { 54 | System.err.println(s"got request $title, $body, $userId") 55 | cask.Response(ujson.Obj("id" -> 101).render()) 56 | } 57 | 58 | @cask.get("/comments") 59 | def commentsHandler(postId: String) = { 60 | val postId0 = scala.util.Try(postId.toInt).getOrElse(0) 61 | val resp = comments.getOrElse(postId0, ujson.Obj()) 62 | cask.Response(resp) 63 | } 64 | 65 | initialize() 66 | 67 | def withServer[T](f: String => T): T = { 68 | import scala.collection.JavaConverters._ 69 | var server: io.undertow.Undertow = null 70 | try { 71 | server = io.undertow.Undertow.builder 72 | .addHttpListener(0, "localhost") 73 | .setHandler(defaultHandler) 74 | .build() 75 | server.start() 76 | val addr = server 77 | .getListenerInfo 78 | .asScala 79 | .head 80 | .getAddress 81 | .asInstanceOf[java.net.InetSocketAddress] 82 | val url = s"http://${addr.getHostString}:${addr.getPort}" 83 | f(url) 84 | } finally { 85 | if (server != null) 86 | server.stop() 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /integration/src/test/scala/ammonite/integration/AmmoniteBridge.scala: -------------------------------------------------------------------------------- 1 | package ammonite.integration 2 | object AmmoniteBridge { 3 | def main(args: Array[String]): Unit = { 4 | ammonite.AmmoniteMain.main(args) 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /integration/src/test/scala/ammonite/integration/LineNumberTests.scala: -------------------------------------------------------------------------------- 1 | package ammonite.integration 2 | import ammonite.util.Util 3 | import utest._ 4 | import TestUtils._ 5 | 6 | /** 7 | * Mostly already tested in the `ammonite.main` unit tests; one test case is 8 | * left here just to verify end-to-end correctness 9 | */ 10 | object LineNumberTests extends TestSuite { 11 | val tests = this { 12 | 13 | def checkErrorMessage(file: os.RelPath, expected: String): Unit = { 14 | val e = intercept[os.SubprocessException] { 15 | exec(file) 16 | }.result.err.text() 17 | assert(TestUtils.containsLines(e, expected)) 18 | } 19 | 20 | test("compilationErrorInSecondBlock") { 21 | val path = os.rel / "lineNumbers" / "compilationErrorInSecondBlock.sc" 22 | val sp = " " 23 | checkErrorMessage( 24 | file = path, 25 | expected = Util.normalizeNewlines( 26 | if (isScala2) 27 | """compilationErrorInSecondBlock.sc:14: not found: value printnl 28 | |val res_0 = printnl("OK") 29 | | ^""".stripMargin 30 | else if (scalaVersion < "3.3.4") 31 | s"""-- [E006] Not Found Error: ${replStandaloneResources / path}:1:12$sp 32 | |1 |val res_0 = printnl("OK") 33 | | | ^^^^^^^ 34 | | | Not found: printnl 35 | |Compilation Failed""".stripMargin 36 | else 37 | s"""-- [E006] Not Found Error: ${replStandaloneResources / path}:1:12$sp 38 | |1 |val res_0 = printnl("OK") 39 | | | ^^^^^^^ 40 | | | Not found: printnl - did you mean print? or perhaps printf or println? 41 | | | 42 | | | longer explanation available when compiling with `-explain` 43 | |Compilation Failed""".stripMargin 44 | ) 45 | ) 46 | } 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /integration/src/test/scala/ammonite/integration/ProjectTests.scala: -------------------------------------------------------------------------------- 1 | package ammonite.integration 2 | 3 | import ammonite.integration.TestUtils._ 4 | import ammonite.util.Util 5 | import utest._ 6 | 7 | /** 8 | * Run a small number of scripts using the Ammonite standalone executable, 9 | * to make sure that this works. Otherwise it tends to break since the 10 | * standalone executable has a pretty different classloading environment 11 | * from the "run in SBT on raw class files" that the rest of the tests use. 12 | * 13 | * These are also the only tests that cover all the argument-parsing 14 | * and configuration logic inside, which the unit tests don't cover since 15 | * they call the REPL programmatically 16 | */ 17 | object ProjectTests extends TestSuite { 18 | 19 | val tests = Tests { 20 | println("Running ProjectTest") 21 | 22 | test("playframework") { 23 | if (!Util.windowsPlatform) { 24 | if (scalaVersion.startsWith("2.11.") && javaVersion.startsWith("1.8.")) { 25 | val evaled = exec(os.rel / "basic" / "PlayFramework.sc") 26 | assert(evaled.out.text().contains("Hello bar")) 27 | } 28 | } 29 | } 30 | // Disabled due to travis instability 31 | // test("spark"){ 32 | // // Note that this script screws up if you try to run it within SBT! It has to 33 | // // be run as an integration test, or via `sbt amm/test:assembly && amm/target/amm` 34 | // if (!Util.windowsPlatform) { 35 | // if (scalaVersion.startsWith("2.11.") && javaVersion.startsWith("1.8.")){ 36 | // val evaled = exec('basic/"Spark.sc") 37 | // assert(evaled.out.string.contains("List(10, 20, 30, 40, 50)")) 38 | // } 39 | // } 40 | // } 41 | 42 | test("spark2") { 43 | // Note that this script screws up if you try to run it within SBT! It has to 44 | // be run as an integration test, or via `sbt amm/test:assembly && amm/target/amm` 45 | if (!Util.windowsPlatform) { 46 | if (scalaVersion.startsWith("2.11.") && javaVersion.startsWith("1.8.")) { 47 | val evaled = exec(os.rel / "basic" / "Spark2.sc") 48 | assert(evaled.out.text().contains("fake db write")) 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /integration/src/test/scala/ammonite/integration/TestMain.scala: -------------------------------------------------------------------------------- 1 | package ammonite.integration 2 | object TestMain { 3 | def main(args: Array[String]): Unit = { 4 | val hello = "Hello" 5 | // Break into debug REPL with 6 | ammonite.Main( 7 | predefCode = "println(\"Starting Debugging!\")" 8 | ).run( 9 | "hello" -> hello, 10 | "fooValue" -> foo() 11 | ) 12 | } 13 | def foo() = 1 14 | } 15 | -------------------------------------------------------------------------------- /integration/src/test/scala/ammonite/integration/TestUtils.scala: -------------------------------------------------------------------------------- 1 | package ammonite.integration 2 | 3 | import ammonite.util.Util 4 | 5 | /** 6 | * Created by haoyi on 6/4/16. 7 | */ 8 | object TestUtils { 9 | val scalaVersion = ammonite.compiler.CompilerBuilder.scalaVersion 10 | val isScala2 = scalaVersion.startsWith("2.") 11 | val javaVersion = scala.util.Properties.javaVersion 12 | val ammVersion = ammonite.Constants.version 13 | val ammAssembly = System.getenv("AMMONITE_ASSEMBLY") 14 | val executable = 15 | if (Util.windowsPlatform) 16 | Seq(ammAssembly) 17 | else 18 | Seq("bash", ammAssembly) 19 | val intTestResources = os.pwd / "integration" / "src" / "test" / "resources" 20 | val replStandaloneResources = intTestResources / "ammonite" / "integration" 21 | val shellAmmoniteResources = 22 | os.pwd / "shell" / "src" / "main" / "resources" / "ammonite" / "shell" 23 | 24 | // we use an empty predef file here to isolate the tests from external forces. 25 | def execBase( 26 | name: os.RelPath, 27 | extraAmmArgs: Seq[String], 28 | home: os.Path, 29 | args: Seq[String], 30 | thin: Boolean, 31 | extraEnv: Iterable[(String, String)] 32 | ) = { 33 | os.proc( 34 | executable, 35 | extraAmmArgs, 36 | if (thin) Seq("--thin") else Nil, 37 | "--home", 38 | home, 39 | replStandaloneResources / name, 40 | args 41 | ).call( 42 | env = Map("JAVA_OPTS" -> null) ++ extraEnv, 43 | stderr = os.Pipe 44 | ) 45 | } 46 | def exec(name: os.RelPath, args: String*) = 47 | execBase(name, Nil, os.temp.dir(), args, thin = true, Nil) 48 | def execWithEnv(env: Iterable[(String, String)], name: os.RelPath, args: String*) = 49 | execBase(name, Nil, os.temp.dir(), args, thin = true, env) 50 | def execNonThin(name: os.RelPath, args: String*) = 51 | execBase(name, Nil, os.temp.dir(), args, thin = false, Nil) 52 | def execWithHome(home: os.Path, name: os.RelPath, args: String*) = 53 | execBase(name, Nil, home, args, thin = true, Nil) 54 | def execSilent(name: os.RelPath, args: String*) = 55 | execBase(name, Seq("-s"), os.temp.dir(), args, thin = true, Nil) 56 | 57 | /** 58 | * Counts number of non-overlapping occurrences of `subs` in `s` 59 | */ 60 | def substrCount(s: String, subs: String, count: Int = 0, ptr: Int = 0): Int = { 61 | s.indexOf(subs, ptr) match { 62 | case -1 => count 63 | case x => substrCount(s, subs, count + 1, x + subs.length) 64 | } 65 | } 66 | 67 | def containsLines(output: String, expected: String): Boolean = 68 | containsLines(output.linesIterator.toList, expected.linesIterator.toList) 69 | 70 | @annotation.tailrec 71 | def containsLines(output: List[String], expected: List[String]): Boolean = 72 | expected match { 73 | case Nil => true 74 | case h :: t => 75 | output match { 76 | case Nil => false 77 | case h0 :: t0 => 78 | val remaining = if (h0.contains(h)) t else expected 79 | containsLines(t0, remaining) 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /internals-docs/packages.md: -------------------------------------------------------------------------------- 1 | Packages 2 | ======== 3 | 4 | Like most JVM programs, Ammonite is split into separate packages. Unlike 5 | most of them, it also contains some synthetic packages that house user code 6 | compiled and run within the Ammonite REPL. 7 | 8 | The main static packages containing Ammonite code are: 9 | 10 | - `ammonite.terminal`: a standalone replacement for JLine, with more features 11 | such as syntax-highlighting, GUI-style keybindings and good multiline editing 12 | 13 | - `ammonite`: the main Ammonite REPL 14 | 15 | - `ammonite.sshd`: spin up an Ammonite server in any existing process you can 16 | connect to via SSH 17 | 18 | Each of these has its own unit tests, along with the integration suite in 19 | 20 | - `ammonite.integration`: tests that package up the Ammonite jar, spawn 21 | Ammonite subprocess via the command-line interface and ensure the whole 22 | thing works end-to-end. This has no published artifact 23 | 24 | Lastly, there are the packages which aren't visible in the source code but 25 | contain code that is generated at runtime by Ammonite 26 | 27 | - `$sess`: contains the wrapper-objects that contains any code 28 | a user enters into the REPL. Any values, functions, classes, etc. you write 29 | into the REPL are wraNpped in a wrapper object and placed in this package 30 | 31 | - `$file`: contains the code that results from loading Ammonite 32 | script files into the REPL, or running them using Ammonite from the 33 | command-line. Any scripts are placed in `$file.foo.bar.baz` 34 | for a script in folder `foo/bar/baz/` relative to the current working 35 | directory; scripts outside the current working directory have the 36 | corresponding number of `..` packages e.g. `$file.`..`.foo.bar` 37 | to represent a script in the folder `../foo/bar/` relative to the working 38 | directory. -------------------------------------------------------------------------------- /internals-docs/predef.md: -------------------------------------------------------------------------------- 1 | Predef 2 | ====== 3 | 4 | Ammonite has the concept of a "Predef": Code you can run before entering the 5 | REPL, and provides all sorts of useful things: 6 | 7 | - Import the implicits necessary for the REPL to run at all (pretty-printing 8 | code and types) 9 | 10 | - Loading "common" modules that you want available: `ammonite-shell` to make the 11 | REPL behave like a systems shell, 12 | 13 | - Initialize common definitions *the end-user* of Ammonite desires every time 14 | the REPL is opened 15 | 16 | The Predef itself is made of several parts: 17 | 18 | - `hardcodedPredef`: imports the minimal implicits for the REPL to run. 19 | This is mostly just the implicits necessary for pretty-printing values and 20 | types. 21 | 22 | - `defaultPredefString`: brings in the default set of imports that 23 | Ammonite starts with. This brings in Ammonite Ops' various `|` `|?` `|>` 24 | pipes, `ammonite.tools` like `grep` `time` and `browse`, implicits to 25 | add SBT-style syntax for loading stuff from `load.ivy`, and importing 26 | everything from the `repl` object. This is loaded by default, but can 27 | be disabled by a `--no-default-predef` flag, or `defaultPredef = false` to 28 | `Main` 29 | 30 | - The assignment of any arguments to the `debug` entrypoint to local `val`s 31 | 32 | - Any `commandLinePredef` string you pass in via `predef = "..."` or `--predef "..."` 33 | 34 | - Any predef file, which defaults `~/.ammonite/predef.sc` for the REPL and 35 | `~/.ammonite/predefScript.sc` for scripts, but can be set manually via 36 | `--predef ...`. This split allows you to e.g. put REPL-specific setup 37 | code inside `predef.sc`, without it messing up scripts. Both the REPL and 38 | scripts also run `~/.ammonite/predefShared.sc` for setup code you want to 39 | apply to both 40 | 41 | Unlike script files, anything that is run in the predef is automatically made 42 | available to every executed script without needing to `load.module` or import 43 | it manually. This includes any files being loaded in the predef itself. 44 | 45 | -------------------------------------------------------------------------------- /mill: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # This is a wrapper script, that automatically download mill from GitHub release pages 4 | # You can give the required mill version with MILL_VERSION env variable 5 | # If no version is given, it falls back to the value of DEFAULT_MILL_VERSION 6 | 7 | set -e 8 | 9 | if [ -z "${DEFAULT_MILL_VERSION}" ] ; then 10 | DEFAULT_MILL_VERSION=0.11.12 11 | fi 12 | 13 | if [ -z "$MILL_VERSION" ] ; then 14 | if [ -f ".mill-version" ] ; then 15 | MILL_VERSION="$(head -n 1 .mill-version 2> /dev/null)" 16 | elif [ -f ".config/mill-version" ] ; then 17 | MILL_VERSION="$(head -n 1 .config/mill-version 2> /dev/null)" 18 | elif [ -f "mill" ] && [ "$0" != "mill" ] ; then 19 | MILL_VERSION=$(grep -F "DEFAULT_MILL_VERSION=" "mill" | head -n 1 | cut -d= -f2) 20 | else 21 | MILL_VERSION=$DEFAULT_MILL_VERSION 22 | fi 23 | fi 24 | 25 | if [ "x${XDG_CACHE_HOME}" != "x" ] ; then 26 | MILL_DOWNLOAD_PATH="${XDG_CACHE_HOME}/mill/download" 27 | else 28 | MILL_DOWNLOAD_PATH="${HOME}/.cache/mill/download" 29 | fi 30 | MILL_EXEC_PATH="${MILL_DOWNLOAD_PATH}/${MILL_VERSION}" 31 | 32 | version_remainder="$MILL_VERSION" 33 | MILL_MAJOR_VERSION="${version_remainder%%.*}"; version_remainder="${version_remainder#*.}" 34 | MILL_MINOR_VERSION="${version_remainder%%.*}"; version_remainder="${version_remainder#*.}" 35 | 36 | if [ ! -s "$MILL_EXEC_PATH" ] ; then 37 | mkdir -p "$MILL_DOWNLOAD_PATH" 38 | if [ "$MILL_MAJOR_VERSION" -gt 0 ] || [ "$MILL_MINOR_VERSION" -ge 5 ] ; then 39 | ASSEMBLY="-assembly" 40 | fi 41 | DOWNLOAD_FILE=$MILL_EXEC_PATH-tmp-download 42 | MILL_VERSION_TAG=$(echo $MILL_VERSION | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/') 43 | MILL_DOWNLOAD_URL="https://repo1.maven.org/maven2/com/lihaoyi/mill-dist/$MILL_VERSION/mill-dist-$MILL_VERSION.jar" 44 | curl --fail -L -o "$DOWNLOAD_FILE" "$MILL_DOWNLOAD_URL" 45 | chmod +x "$DOWNLOAD_FILE" 46 | mv "$DOWNLOAD_FILE" "$MILL_EXEC_PATH" 47 | unset DOWNLOAD_FILE 48 | unset MILL_DOWNLOAD_URL 49 | fi 50 | 51 | if [ -z "$MILL_MAIN_CLI" ] ; then 52 | MILL_MAIN_CLI="${0}" 53 | fi 54 | 55 | MILL_FIRST_ARG="" 56 | 57 | # first arg is a long flag for "--interactive" or starts with "-i" 58 | if [ "$1" = "--bsp" ] || [ "${1#"-i"}" != "$1" ] || [ "$1" = "--interactive" ] || [ "$1" = "--no-server" ] || [ "$1" = "--repl" ] || [ "$1" = "--help" ] ; then 59 | # Need to preserve the first position of those listed options 60 | MILL_FIRST_ARG=$1 61 | shift 62 | fi 63 | 64 | unset MILL_DOWNLOAD_PATH 65 | unset MILL_VERSION 66 | 67 | exec $MILL_EXEC_PATH $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@" 68 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.7 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.lihaoyi" % "scalatex-sbt-plugin" % "0.3.11") 2 | -------------------------------------------------------------------------------- /readme/ANSI.scala: -------------------------------------------------------------------------------- 1 | package readme 2 | 3 | import scala.collection.mutable 4 | import scalatags.Text.all._ 5 | 6 | object ANSI { 7 | 8 | // http://flatuicolors.com/ 9 | val red = "#c0392b" 10 | val green = "#27ae60" 11 | val yellow = "#f39c12" 12 | val blue = "#2980b9" 13 | val magenta = "#8e44ad" 14 | val cyan = "#16a085" 15 | val black = "#000" 16 | val white = "#fff" 17 | 18 | val foregrounds = Map[fansi.Attr, String]( 19 | fansi.Color.Black -> black, 20 | fansi.Color.Red -> red, 21 | fansi.Color.Green-> green, 22 | fansi.Color.Yellow-> yellow, 23 | fansi.Color.Blue -> blue, 24 | fansi.Color.Magenta-> magenta, 25 | fansi.Color.Cyan -> cyan, 26 | fansi.Color.White -> white 27 | ) 28 | val backgrounds = Map[fansi.Attr, String]( 29 | fansi.Back.Black -> black, 30 | fansi.Back.Red -> red, 31 | fansi.Back.Green-> green, 32 | fansi.Back.Yellow-> yellow, 33 | fansi.Back.Blue -> blue, 34 | fansi.Back.Magenta-> magenta, 35 | fansi.Back.Cyan -> cyan, 36 | fansi.Back.White -> white 37 | ) 38 | def ansiToHtml(ansiInput: String): Frag = { 39 | val wrapped = mutable.Buffer.empty[scalatags.Text.Frag] 40 | val parsed = fansi.Str(ansiInput, errorMode = fansi.ErrorMode.Strip) 41 | val chars = parsed.getChars 42 | val colors = parsed.getColors 43 | 44 | var i = 0 45 | var previousColor = 0L 46 | val snippetBuffer = new mutable.StringBuilder() 47 | 48 | def createSnippet() = { 49 | val foreground = fansi.Color.lookupAttr(previousColor & fansi.Color.mask) 50 | val background = fansi.Back.lookupAttr(previousColor & fansi.Back.mask) 51 | val snippet = snippetBuffer.toString 52 | snippetBuffer.clear() 53 | wrapped.append(span( 54 | foregrounds.get(foreground).map(color := _), 55 | backgrounds.get(background).map(backgroundColor := _), 56 | snippet 57 | )) 58 | } 59 | 60 | while(i < parsed.length){ 61 | if (colors(i) != previousColor && snippetBuffer.nonEmpty) createSnippet() 62 | previousColor = colors(i) 63 | snippetBuffer += chars(i) 64 | i += 1 65 | } 66 | createSnippet() 67 | wrapped.toVector 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /readme/resources/Browse.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/Browse.gif -------------------------------------------------------------------------------- /readme/resources/ColoredTraces.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/ColoredTraces.png -------------------------------------------------------------------------------- /readme/resources/Debugging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/Debugging.png -------------------------------------------------------------------------------- /readme/resources/DebuggingViaSshd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/DebuggingViaSshd.png -------------------------------------------------------------------------------- /readme/resources/Desugar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/Desugar.png -------------------------------------------------------------------------------- /readme/resources/Editing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/Editing.gif -------------------------------------------------------------------------------- /readme/resources/GettingStarted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/GettingStarted.png -------------------------------------------------------------------------------- /readme/resources/Highlighting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/Highlighting.png -------------------------------------------------------------------------------- /readme/resources/HistorySearch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/HistorySearch.gif -------------------------------------------------------------------------------- /readme/resources/IvyComplete.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/IvyComplete.gif -------------------------------------------------------------------------------- /readme/resources/ScriptFolderLayout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/ScriptFolderLayout.png -------------------------------------------------------------------------------- /readme/resources/ScriptRepl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/ScriptRepl.gif -------------------------------------------------------------------------------- /readme/resources/Source.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/Source.gif -------------------------------------------------------------------------------- /readme/resources/Swing1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/Swing1.png -------------------------------------------------------------------------------- /readme/resources/Swing2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/Swing2.png -------------------------------------------------------------------------------- /readme/resources/Swing3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/Swing3.png -------------------------------------------------------------------------------- /readme/resources/SystemShell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/SystemShell.png -------------------------------------------------------------------------------- /readme/resources/UndoRedo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/UndoRedo.gif -------------------------------------------------------------------------------- /readme/resources/Watch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/Watch.gif -------------------------------------------------------------------------------- /readme/resources/favicon-old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/favicon-old.png -------------------------------------------------------------------------------- /readme/resources/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/favicon.png -------------------------------------------------------------------------------- /readme/resources/smaller-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/smaller-favicon.png -------------------------------------------------------------------------------- /readme/resources/square-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/com-lihaoyi/Ammonite/2fdc440b23c9bc7eb782c496c05ec1d3c10ee3d6/readme/resources/square-favicon.png -------------------------------------------------------------------------------- /sshd/src/main/scala/ammonite/sshd/ShellSession.scala: -------------------------------------------------------------------------------- 1 | package ammonite.sshd 2 | 3 | import java.io.{InputStream, OutputStream} 4 | 5 | import org.apache.sshd.server._ 6 | import org.apache.sshd.server.session.ServerSession 7 | 8 | /** 9 | * Implementation of ssh server's remote shell session, 10 | * which will be serving remote user. 11 | * @param remoteShell actual shell implementation, 12 | * which will serve remote user's shell session. 13 | */ 14 | private[sshd] class ShellSession(remoteShell: ShellSession.Server) 15 | extends Command { 16 | var in: InputStream = _ 17 | var out: OutputStream = _ 18 | var exit: ExitCallback = _ 19 | lazy val thread = createShellServingThread() 20 | 21 | override def setInputStream(in: InputStream) = { 22 | this.in = in 23 | } 24 | override def setOutputStream(out: OutputStream) = { 25 | this.out = new SshOutputStream(out) 26 | } 27 | /* ammonite doesn't uses err stream so we don't need this */ 28 | override def setErrorStream(err: OutputStream) = {} 29 | 30 | /** 31 | * called by ssh server to instrument this session 32 | * with a callback that it finished serving a user 33 | */ 34 | override def setExitCallback(exit: ExitCallback) = { 35 | this.exit = exit 36 | } 37 | 38 | /** 39 | * called when ssh server is ready to start this session. 40 | * Starts the actual shell-serving task. 41 | */ 42 | override def start(env: Environment) = { 43 | thread.start() 44 | } 45 | 46 | /** 47 | * called when ssh server wants to destroy shell session. 48 | * Whatever shell session serving a user was doing at this moment 49 | * we are free to stop it. 50 | */ 51 | override def destroy() = { 52 | thread.interrupt() 53 | } 54 | 55 | private def createShellServingThread(): Thread = new Thread { 56 | override def run(): Unit = { 57 | remoteShell(in, out) 58 | exit.onExit(0, "repl finished") 59 | } 60 | } 61 | 62 | // proxy which fixes output to the remote side to be ssh compatible. 63 | private class SshOutputStream(out: OutputStream) extends OutputStream { 64 | override def close() = { out.close() } 65 | override def flush() = { out.flush() } 66 | 67 | override def write(byte: Int): Unit = { 68 | // ssh client's only accepts new lines with \r so we make \n to be \r\n. 69 | // Unneeded \r will not be seen anyway 70 | if (byte.toChar == '\n') out.write('\r') 71 | out.write(byte) 72 | } 73 | 74 | override def write(bytes: Array[Byte]): Unit = for { 75 | i ← bytes.indices 76 | } write(bytes(i)) 77 | 78 | override def write(bytes: Array[Byte], offset: Int, length: Int): Unit = { 79 | write(bytes.slice(offset, offset + length)) 80 | } 81 | } 82 | 83 | } 84 | 85 | object ShellSession { 86 | type Server = ((InputStream, OutputStream) => Unit) 87 | } 88 | -------------------------------------------------------------------------------- /sshd/src/main/scala/ammonite/sshd/SshServerConfig.scala: -------------------------------------------------------------------------------- 1 | package ammonite.sshd 2 | 3 | import ammonite.main.Defaults 4 | import org.apache.sshd.server.auth.password.PasswordAuthenticator 5 | import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator 6 | 7 | /** 8 | * Ssh server parameters 9 | * @param port a port to be used by ssh server. Set it as `0` to let server choose some random port. 10 | * @param ammoniteHome path that ammonite repl sessions will be using as their home directory 11 | * @param hostKeyFile path to the place where to store server's identity key 12 | */ 13 | case class SshServerConfig( 14 | address: String, 15 | port: Int, 16 | ammoniteHome: os.Path = Defaults.ammoniteHome, 17 | hostKeyFile: Option[os.Path] = None, 18 | passwordAuthenticator: Option[PasswordAuthenticator] = None, 19 | publicKeyAuthenticator: Option[PublickeyAuthenticator] = None 20 | ) { 21 | require( 22 | passwordAuthenticator.orElse(publicKeyAuthenticator).isDefined, 23 | "you must provide at least one authenticator" 24 | ) 25 | override def toString = 26 | s"(port = $port," + 27 | s"home = '$ammoniteHome', hostKeyFile = $hostKeyFile," + 28 | s"passwordAuthenticator = $passwordAuthenticator," + 29 | s"publicKeyAuthenticator = $publicKeyAuthenticator)" 30 | } 31 | -------------------------------------------------------------------------------- /sshd/src/main/scala/ammonite/sshd/util/Environment.scala: -------------------------------------------------------------------------------- 1 | package ammonite.sshd.util 2 | 3 | import java.io.{InputStream, OutputStream, PrintStream} 4 | 5 | /** 6 | * Container for staging environment important for Ammonite repl to run correctly. 7 | * @param thread a thread where execution takes place. Important for restoring contextClassLoader 8 | * @param contextClassLoader thread's context class loader. Ammonite repl uses that to load classes 9 | * @param systemIn 10 | * @param systemOut 11 | * @param systemErr 12 | */ 13 | case class Environment( 14 | thread: Thread, 15 | contextClassLoader: ClassLoader, 16 | systemIn: InputStream, 17 | systemOut: PrintStream, 18 | systemErr: PrintStream 19 | ) 20 | 21 | object Environment { 22 | def apply(classLoader: ClassLoader, in: InputStream, out: PrintStream): Environment = 23 | apply(Thread.currentThread(), classLoader, in, out, out) 24 | 25 | def apply(classLoader: ClassLoader, in: InputStream, out: OutputStream): Environment = 26 | apply(classLoader, in, new PrintStream(out)) 27 | 28 | /** 29 | * Runs your code with supplied environment installed. 30 | * After execution of supplied code block will restore original environment 31 | */ 32 | def withEnvironment(env: Environment)(code: ⇒ Any): Any = { 33 | val oldClassLoader = env.thread.getContextClassLoader 34 | try { 35 | env.thread.setContextClassLoader(env.contextClassLoader) 36 | Console.withIn(env.systemIn) { 37 | Console.withOut(env.systemOut) { 38 | Console.withErr(env.systemErr) { 39 | code 40 | } 41 | } 42 | } 43 | } finally { 44 | env.thread.setContextClassLoader(oldClassLoader) 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /sshd/src/test/scala/ammonite/sshd/Main.scala: -------------------------------------------------------------------------------- 1 | package ammonite.sshd 2 | 3 | import java.security.PublicKey 4 | import org.apache.sshd.common.config.keys.{KeyUtils, PublicKeyEntryResolver} 5 | import org.apache.sshd.server.auth.password.PasswordAuthenticator 6 | import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator 7 | import org.apache.sshd.server.config.keys.AuthorizedKeysAuthenticator 8 | import org.apache.sshd.server.session.ServerSession 9 | import scala.annotation.tailrec 10 | import scala.collection.JavaConverters._ 11 | 12 | object Main { 13 | def main(args: Array[String]): Unit = { 14 | val config = SshServerConfig( 15 | "localhost", 16 | 2222, 17 | passwordAuthenticator = None, 18 | publicKeyAuthenticator = Some(publicKeyChecker) 19 | ) 20 | val ammoniteServer = new SshdRepl(config) 21 | 22 | ammoniteServer.start() 23 | println(s"Ammonite server started. $helpMessage." + 24 | s"To connect use ssh [${currentUserName}@] -p${config.port}") 25 | exitAwaitLoop() 26 | ammoniteServer.stop() 27 | 28 | println("Ammonite server finished") 29 | } 30 | 31 | object publicKeyChecker extends PublickeyAuthenticator { 32 | def authenticate(username: String, key: PublicKey, session: ServerSession): Boolean = { 33 | val keys = AuthorizedKeysAuthenticator.readDefaultAuthorizedKeys() 34 | username == currentUserName && 35 | keys.asScala 36 | .exists { entry => 37 | KeyUtils.compareKeys(entry.resolvePublicKey(PublicKeyEntryResolver.IGNORING), key) 38 | } 39 | } 40 | } 41 | 42 | object passwordChecker extends PasswordAuthenticator { 43 | def authenticate(username: String, password: String, session: ServerSession): Boolean = { 44 | username == currentUserName && password == getPassword 45 | } 46 | } 47 | 48 | def currentUserName = System.getProperty("user.name") 49 | 50 | private def getPassword = "password" 51 | 52 | private val helpMessage = "Print 'q' to quit." 53 | 54 | @tailrec private def exitAwaitLoop(): Unit = System.console().readLine() match { 55 | case "q" => println("exiting...") 56 | case cmd => 57 | println(s"'$cmd' is illegal command! $helpMessage") 58 | exitAwaitLoop() 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /sshd/src/test/scala/ammonite/sshd/ScalaCheckSupport.scala: -------------------------------------------------------------------------------- 1 | package ammonite.sshd 2 | 3 | import org.scalacheck.Test.{PropException, Result, TestCallback} 4 | import org.scalacheck.{Prop, Test} 5 | 6 | trait ScalaCheckSupport { 7 | def check(prop: Prop): Unit = check(Test.Parameters.default.minSuccessfulTests)(prop) 8 | 9 | def check(minSuccessfulTests: Int)(prop: Prop): Unit = { 10 | val resultHolder = new ResultHolder 11 | prop.check { 12 | _.withTestCallback(resultHolder).withMinSuccessfulTests(minSuccessfulTests) 13 | } 14 | val result = resultHolder.result 15 | result.status match { 16 | case PropException(_, e, _) ⇒ throw e 17 | case _ ⇒ assert(result.passed) 18 | } 19 | } 20 | 21 | implicit def utestCheckToProp: Unit ⇒ Prop = { (_) ⇒ Prop.apply(true) } 22 | 23 | class ResultHolder extends TestCallback { 24 | var result: Result = _ 25 | 26 | override def onTestResult(name: String, result: Result): Unit = { 27 | this.result = result 28 | } 29 | 30 | override def toString = s"ResultHolder($result)" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /sshd/src/test/scala/ammonite/sshd/SshdReplTest.scala: -------------------------------------------------------------------------------- 1 | package ammonite.sshd 2 | 3 | import utest._ 4 | 5 | import scala.concurrent.{Await, Promise} 6 | import scala.language.postfixOps 7 | import scala.concurrent.duration._ 8 | import SshTestingUtils._ 9 | 10 | object SshdReplTest extends TestSuite { 11 | val remotePromise = Promise[Boolean]() 12 | 13 | override val tests = Tests { 14 | // Diabled on charge of flakiness 15 | 16 | // test("canExecuteRemoteCommand") - retry(3){ // Flaky, not sure why 17 | // withTmpDirectory { tmpDir => 18 | // val repl = new SshdRepl( 19 | // SshServerConfig("localhost", 0, testUsername, testPassword, tmpDir), 20 | // predef = "val predefinedValue = \"Hello\"" 21 | // ) 22 | // repl.start() 23 | // val client = sshClient((testUsername, testPassword), "localhost", repl.port) 24 | // client.connect() 25 | // assert(client.isConnected) 26 | // 27 | // val shell = new Shell(client) 28 | // shell.connect() 29 | // assert(shell.isConnected) 30 | // 31 | // shell.input.println("2 + 2") 32 | // shell.input.println("import ammonite.sshd.SshdReplTest") 33 | // shell.input.println("predefinedValue") 34 | // shell.input.println("SshdReplTest.remotePromise.success(true)") 35 | // shell.input.println("exit") 36 | // 37 | // assert(Await.result(remotePromise.future, 60 seconds)) 38 | // shell.awaitToBecomeDisconnected(60 seconds) 39 | // 40 | // val outputLines = shell.output.readAll.lines.toList 41 | // val Seq(firstBannerLine, secondBannerLine) = outputLines.take(2) 42 | // val Seq(mathTestPrompt, mathOutput) = outputLines.slice(2, 4) 43 | // val Seq(importAppPackage, importResult) = outputLines.slice(4, 6) 44 | // val Seq(checkPredef, checkPredefResult) = outputLines.slice(6, 8) 45 | // 46 | // assert( 47 | // firstBannerLine.startsWith("Welcome to the Ammonite Repl"), 48 | // secondBannerLine.contains("Scala"), 49 | // secondBannerLine.contains("Java") 50 | // ) 51 | // assert( 52 | // mathTestPrompt.contains("2"), 53 | // mathTestPrompt.contains("+"), 54 | // mathOutput.contains("4") 55 | // ) 56 | // assert( 57 | // importAppPackage.contains("import"), 58 | // importAppPackage.contains("ammonite.sshd.SshdReplTest"), 59 | // !importResult.toLowerCase.contains("error") 60 | // ) 61 | // assert( 62 | // checkPredef.contains("predefinedValue"), 63 | // checkPredefResult.contains("Hello") 64 | // ) 65 | // } 66 | // } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /terminal/src/main/scala/ammonite/terminal/ConsoleDim.scala: -------------------------------------------------------------------------------- 1 | package ammonite.terminal 2 | 3 | import sun.misc.{Signal, SignalHandler} 4 | 5 | final class ConsoleDim { 6 | 7 | @volatile private var dimsOpt: Option[(Int, Int)] = None 8 | private var initialized = false 9 | private val lock = new Object 10 | 11 | private def setup(): Unit = { 12 | 13 | // From https://stackoverflow.com/q/31594364/3714539 14 | 15 | val terminalSizeChangedHandler: SignalHandler = 16 | new SignalHandler { 17 | override def handle(sig: Signal): Unit = 18 | lock.synchronized { 19 | dimsOpt = None 20 | } 21 | } 22 | 23 | Signal.handle(new Signal("WINCH"), terminalSizeChangedHandler) 24 | 25 | initialized = true 26 | } 27 | 28 | private def dims(): (Int, Int) = 29 | dimsOpt.getOrElse { 30 | lock.synchronized { 31 | dimsOpt.getOrElse { 32 | if (!initialized) 33 | setup() 34 | val dims = (TTY.consoleDim("cols"), TTY.consoleDim("lines")) 35 | dimsOpt = Some(dims) 36 | dims 37 | } 38 | } 39 | } 40 | 41 | def width(): Int = 42 | dims()._1 43 | def height(): Int = 44 | dims()._2 45 | 46 | } 47 | 48 | object ConsoleDim { 49 | 50 | lazy val get: ConsoleDim = 51 | new ConsoleDim 52 | 53 | def width(): Int = 54 | get.width() 55 | def height(): Int = 56 | get.height() 57 | 58 | } 59 | -------------------------------------------------------------------------------- /terminal/src/main/scala/ammonite/terminal/FilterTools.scala: -------------------------------------------------------------------------------- 1 | package ammonite.terminal 2 | 3 | /** 4 | * A collection of helpers that to simpify the common case of building filters 5 | */ 6 | object FilterTools { 7 | 8 | /** 9 | * Shorthand for pattern matching on [[TermState]] 10 | */ 11 | val TS = TermState 12 | 13 | def findChunks(b: Vector[Char], c: Int) = { 14 | val chunks = LineReader.splitBuffer(b) 15 | // The index of the first character in each chunk 16 | val chunkStarts = chunks.inits.map(x => x.length + x.sum).toStream.reverse 17 | // Index of the current chunk that contains the cursor 18 | val chunkIndex = chunkStarts.indexWhere(_ > c) match { 19 | case -1 => chunks.length - 1 20 | case x => x - 1 21 | } 22 | (chunks, chunkStarts, chunkIndex) 23 | } 24 | 25 | def firstRow(cursor: Int, buffer: Vector[Char], width: Int) = { 26 | cursor < width && (buffer.indexOf('\n') >= cursor || buffer.indexOf('\n') == -1) 27 | } 28 | def firstRowInfo(ti: TermInfo) = firstRow(ti.ts.cursor, ti.ts.buffer, ti.width) 29 | def lastRow(cursor: Int, buffer: Vector[Char], width: Int) = { 30 | (buffer.length - cursor) < width && 31 | (buffer.lastIndexOf('\n') < cursor || buffer.lastIndexOf('\n') == -1) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /terminal/src/main/scala/ammonite/terminal/Protocol.scala: -------------------------------------------------------------------------------- 1 | package ammonite.terminal 2 | 3 | case class TermInfo(ts: TermState, width: Int) 4 | 5 | sealed trait TermAction 6 | case class Printing(ts: TermState, stdout: String) extends TermAction 7 | case class TermState(inputs: LazyList[Int], buffer: Vector[Char], cursor: Int, msg: fansi.Str = "") 8 | extends TermAction 9 | object TermState { 10 | def unapply(ti: TermInfo): Option[(LazyList[Int], Vector[Char], Int, fansi.Str)] = { 11 | TermState.unapply(ti.ts) 12 | } 13 | def unapply(ti: TermAction): Option[(LazyList[Int], Vector[Char], Int, fansi.Str)] = ti match { 14 | case ts: TermState => Some((ts.inputs, ts.buffer, ts.cursor, ts.msg)) 15 | case _ => None 16 | } 17 | 18 | } 19 | case class ClearScreen(ts: TermState) extends TermAction 20 | case object Exit extends TermAction 21 | case class Result(s: String) extends TermAction 22 | -------------------------------------------------------------------------------- /terminal/src/main/scala/ammonite/terminal/Terminal.scala: -------------------------------------------------------------------------------- 1 | package ammonite.terminal 2 | 3 | /** 4 | * The core logic around a terminal; it defines the base `filters` API 5 | * through which anything (including basic cursor-navigation and typing) 6 | * interacts with the terminal. 7 | * 8 | * Maintains basic invariants, such as "cursor should always be within 9 | * the buffer", and "ansi terminal should reflect most up to date TermState" 10 | */ 11 | object Terminal { 12 | 13 | type Action = (Vector[Char], Int) => (Vector[Char], Int) 14 | type MsgAction = (Vector[Char], Int) => (Vector[Char], Int, String) 15 | 16 | /** 17 | * Blockingly reads a line from the given input stream and returns it. 18 | * 19 | * @param prompt The prompt to display when requesting input 20 | * @param reader The input-stream where characters come in, e.g. System.in 21 | * @param writer The output-stream where print-outs go, e.g. System.out 22 | * @param filters A set of actions that can be taken depending on the input, 23 | * to manipulate the internal state of the terminal. 24 | * @param displayTransform code to manipulate the display of the buffer and 25 | * cursor, without actually changing the logical 26 | * values inside them. 27 | */ 28 | def readLine( 29 | prompt: Prompt, 30 | reader: java.io.Reader, 31 | writer: java.io.Writer, 32 | filters: Filter, 33 | displayTransform: (Vector[Char], Int) => (fansi.Str, Int) = LineReader.noTransform 34 | ): Option[String] = { 35 | TTY.withSttyOverride(TTY.readLineStty()) { 36 | new LineReader(ConsoleDim.width(), prompt, reader, writer, filters, displayTransform) 37 | .readChar(TermState(LazyList.continually(reader.read()), Vector.empty, 0, ""), 0) 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /terminal/src/test/resource/toobig.txt: -------------------------------------------------------------------------------- 1 | class Ansi(output: Writer){ 2 | def control(n: Int, c: Char) = output.write(s"\033[" + n + c) 3 | 4 | /** 5 | * Moves to the desired row and column, using individual 6 | * cursor movements. `0` is in the top/left counting up 7 | * towards the bottom/right, and `-1` is in the bottom/right 8 | * counting down towards the top/left 9 | */ 10 | def moveTo(row: Int, col: Int) = { 11 | if (row >= 0) { 12 | up(9999) 13 | down(row) 14 | }else{ 15 | down(9999) 16 | up(-1-row) 17 | } 18 | if (col >= 0) { 19 | left(9999) 20 | right(col) 21 | }else{ 22 | right(9999) 23 | left(-1-col) 24 | } 25 | } 26 | /** 27 | * Move up `n` squares 28 | */ 29 | def up(n: Int) = if (n == 0) "" else control(n, 'A') 30 | /** 31 | * Move down `n` squares 32 | */ 33 | def down(n: Int) = if (n == 0) "" else control(n, 'B') 34 | /** 35 | * Move right `n` squares 36 | */ 37 | def right(n: Int) = if (n == 0) "" else control(n, 'C') 38 | /** 39 | 40 | 41 | /** 42 | * Clear the screen 43 | * 44 | * n=0: clear from cursor to end of screen 45 | * n=1: clear from cursor to start of screen 46 | * n=2: clear entire screen 47 | */ 48 | def clearScreen(n: Int) = control(n, 'J') 49 | 50 | } -------------------------------------------------------------------------------- /terminal/src/test/scala/ammonite/terminal/Checker.scala: -------------------------------------------------------------------------------- 1 | package ammonite.terminal 2 | 3 | import ammonite.terminal.filters.{GUILikeFilters, BasicFilters, ReadlineFilters} 4 | import utest._ 5 | object Checker { 6 | def normalize(s: String) = { 7 | // Only do line/margin mangling for multi-line strings 8 | if (s.indexOf('\n') == -1) s 9 | else { 10 | val lines = Predef.augmentString(s).lines.toVector 11 | val min = lines.map(_.indexWhere(_ != ' ')) 12 | .filter(_ != -1) 13 | .min 14 | lines.drop(1).dropRight(1).map(_.drop(min)).mkString("\n").replace("\\\n", "") 15 | 16 | } 17 | } 18 | 19 | def apply(width: Int, grid: String) = 20 | new Checker(width, normalize(grid)) 21 | } 22 | 23 | /** 24 | * A shell emulator that you can use to test out sequences of various 25 | * [[Terminal.Action]]s against an in-memory (Vector[Char], Int) and 26 | * verify that they do the right thing. 27 | */ 28 | class Checker(width: Int, grid: String) { 29 | override def toString = s"Checker($stringGrid)" 30 | var currentGrid = grid.replace("_", "").toVector 31 | var currentCursor = grid.indexOf('_') 32 | var currentMsg = "" 33 | Predef.assert( 34 | currentCursor != -1, 35 | "Cannot find `_` in grid passed to Checker, it needs to " + 36 | "exist to tell the checker where the cursor starts off at" 37 | ) 38 | def runMsg(actions: Terminal.MsgAction*) = { 39 | val (endGrid, endCursor, endMsg) = actions.foldLeft((currentGrid, currentCursor, "")) { 40 | case ((g, c, m0), f) => 41 | val (g1, c1, msg) = f(g, c) 42 | (g1, math.min(g1.length, math.max(0, c1)), msg) 43 | } 44 | currentGrid = endGrid 45 | currentCursor = endCursor 46 | currentMsg = endMsg 47 | this 48 | } 49 | def run(actions: Terminal.Action*) = { 50 | runMsg(actions.map { f => (b: Vector[Char], c: Int) => 51 | val (b1, c1) = f(b, c) 52 | (b1, c1, "") 53 | }: _*) 54 | } 55 | def stringGrid = { 56 | val prefix = currentGrid.take(currentCursor) 57 | val suffix = currentGrid.drop(currentCursor) 58 | val middle = "_" 59 | 60 | (prefix ++ middle ++ suffix).mkString 61 | } 62 | def check(end0: String) = { 63 | val expectedStringGrid = Checker.normalize(end0) 64 | val actualGrid = stringGrid 65 | assert(actualGrid == expectedStringGrid) 66 | this 67 | } 68 | def checkMsg(expectedMsg: String) = { 69 | assert(currentMsg == expectedMsg) 70 | this 71 | } 72 | def apply(end0: String, actions: Terminal.Action*) = { 73 | run(actions: _*) 74 | check(end0) 75 | } 76 | val edit = new ReadlineFilters.CutPasteFilter() 77 | val down: Terminal.Action = BasicFilters.moveDown(_, _, width) 78 | val up: Terminal.Action = BasicFilters.moveUp(_, _, width) 79 | val home: Terminal.Action = BasicFilters.moveStart(_, _, width) 80 | val end: Terminal.Action = BasicFilters.moveEnd(_, _, width) 81 | val wordLeft: Terminal.Action = GUILikeFilters.wordLeft 82 | val wordRight: Terminal.Action = GUILikeFilters.wordRight 83 | } 84 | -------------------------------------------------------------------------------- /terminal/src/test/scala/ammonite/terminal/HeightTests.scala: -------------------------------------------------------------------------------- 1 | package ammonite.terminal 2 | 3 | import utest._ 4 | 5 | import scala.collection.{immutable => imm} 6 | 7 | object HeightTests extends TestSuite { 8 | val tests = Tests { 9 | 10 | test("a") { 11 | val height = LineReader.calculateHeight0( 12 | LineReader.splitBuffer("abcde".toVector), 13 | width = 2 14 | ) 15 | assert(height == Seq(3)) 16 | // ab 17 | // cd 18 | // e 19 | } 20 | test("b") { 21 | val height = LineReader.calculateHeight0( 22 | LineReader.splitBuffer("abcd".toVector), 23 | width = 2 24 | ) 25 | assert(height == Seq(3)) 26 | // ab 27 | // cd 28 | // | 29 | } 30 | test("c") { 31 | val height = LineReader.calculateHeight0( 32 | LineReader.splitBuffer("abcd".toVector), 33 | width = 2 34 | ) 35 | assert(height == Seq(3)) 36 | // |b 37 | // cd 38 | // _ 39 | } 40 | 41 | test("d") { 42 | val height = LineReader.calculateHeight0( 43 | LineReader.splitBuffer("ab\ncd".toVector), 44 | width = 2 45 | ) 46 | assert(height == Seq(2, 2)) 47 | // |b 48 | // _ 49 | // cd 50 | // _ 51 | } 52 | 53 | test("e") { 54 | val height = LineReader.calculateHeight0( 55 | LineReader.splitBuffer("ab\ncd".toVector), 56 | width = 2 57 | ) 58 | assert(height == Seq(2, 2)) 59 | // ab 60 | // _ 61 | // cd 62 | // | 63 | } 64 | test("f") { 65 | val height = LineReader.calculateHeight0( 66 | LineReader.splitBuffer("ab\ncd".toVector), 67 | width = 2 68 | ) 69 | assert(height == Seq(2, 2)) 70 | // ab 71 | // | 72 | // cd 73 | // _ 74 | } 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /terminal/src/test/scala/ammonite/terminal/TestMain.scala: -------------------------------------------------------------------------------- 1 | package ammonite.terminal 2 | 3 | import java.io.OutputStreamWriter 4 | 5 | import ammonite.terminal.filters._ 6 | import GUILikeFilters.SelectionFilter 7 | import ammonite.terminal.LazyList.~: 8 | 9 | import scala.annotation.tailrec 10 | 11 | // Test Unicode: 漢語;𩶘da 12 | /** 13 | * A "full" test terminal including all readline-style functionality 14 | * included as filters, but without any Scala/Ammonite specific logic 15 | * at all. Provides a minimal environment for manual testing 16 | */ 17 | object TestMain { 18 | 19 | def main(args: Array[String]): Unit = { 20 | System.setProperty("ammonite-sbt-build", "true") 21 | var history = List.empty[String] 22 | val selection = GUILikeFilters.SelectionFilter(indent = 4) 23 | def multilineFilter: Filter = Filter.partial { 24 | case TermState(13 ~: rest, b, c, _) if b.count(_ == '(') != b.count(_ == ')') => 25 | BasicFilters.injectNewLine(b, c, rest) 26 | } 27 | val reader = new java.io.InputStreamReader(System.in) 28 | val cutPaste = ReadlineFilters.CutPasteFilter() 29 | rec() 30 | @tailrec def rec(): Unit = { 31 | val historyFilter = new HistoryFilter(() => history.toVector, fansi.Color.Blue) 32 | Terminal.readLine( 33 | Console.MAGENTA + (0 until 10).mkString + "\n@@@ " + Console.RESET, 34 | reader, 35 | new OutputStreamWriter(System.out), 36 | Filter.merge( 37 | UndoFilter(), 38 | cutPaste, 39 | historyFilter, 40 | multilineFilter, 41 | selection, 42 | BasicFilters.tabFilter(4), 43 | GUILikeFilters.altFilter, 44 | GUILikeFilters.fnFilter, 45 | ReadlineFilters.navFilter, 46 | // Example multiline support by intercepting Enter key 47 | BasicFilters.all 48 | ), 49 | // Example displayTransform: underline all non-spaces 50 | displayTransform = (buffer, cursor) => { 51 | // underline all non-blank lines 52 | 53 | def hl(b: Vector[Char]): Vector[Char] = b.flatMap { 54 | case ' ' => " " 55 | case '\n' => "\n" 56 | case c => Console.UNDERLINED + c + Console.RESET 57 | } 58 | // and highlight the selection 59 | val ansiBuffer = fansi.Str(SeqCharSequence(hl(buffer))) 60 | val (newBuffer, cursorOffset) = SelectionFilter.mangleBuffer( 61 | selection, 62 | ansiBuffer, 63 | cursor, 64 | fansi.Reversed.On 65 | ) 66 | val newNewBuffer = HistoryFilter.mangleBuffer( 67 | historyFilter, 68 | newBuffer, 69 | cursor, 70 | fansi.Color.Green 71 | ) 72 | 73 | (newNewBuffer, cursorOffset) 74 | } 75 | ) match { 76 | case None => println("Bye!") 77 | case Some(s) => 78 | history = s :: history 79 | println(s) 80 | rec() 81 | } 82 | } 83 | } 84 | } 85 | --------------------------------------------------------------------------------