Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Kotlin worksheets in Android project

I want to use Kotlin worksheets in my Android project in order to add code drafts like:

draft.ws.kts

package com.example.app

val a = 1 + 1
a

The worksheet itself is working:

val a: Int
2

But building my Android app fails with the following output:

> Task :appicals:compileDebugKotlin FAILED
e: org.jetbrains.kotlin.util.KotlinFrontEndException: Front-end Internal error: Failed to analyze declaration Draft_ws
File being compiled: (1,43) in /Users/me/secretproject/app/src/main/java/com/example/app/draft.ws.kts
The root cause org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException was thrown at: org.jetbrains.kotlin.resolve.lazy.BasicAbsentDescriptorHandler.diagnoseDescriptorNotFound(AbsentDescriptorHandler.kt:18)
    at org.jetbrains.kotlin.resolve.ExceptionWrappingKtVisitorVoid.visitDeclaration(ExceptionWrappingKtVisitorVoid.kt:43)
    at org.jetbrains.kotlin.psi.KtVisitorVoid.visitDeclaration(KtVisitorVoid.java:453)
    at org.jetbrains.kotlin.psi.KtVisitorVoid.visitDeclaration(KtVisitorVoid.java:21)
    at org.jetbrains.kotlin.psi.KtVisitor.visitScript(KtVisitor.java:78)
    at org.jetbrains.kotlin.psi.KtVisitorVoid.visitScript(KtVisitorVoid.java:73)
    at org.jetbrains.kotlin.psi.KtVisitorVoid.visitScript(KtVisitorVoid.java:519)
    at org.jetbrains.kotlin.psi.KtVisitorVoid.visitScript(KtVisitorVoid.java:21)
    at org.jetbrains.kotlin.psi.KtScript.accept(KtScript.java:69)
    at org.jetbrains.kotlin.psi.KtElementImplStub.accept(KtElementImplStub.java:59)
    at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer$analyzeDeclarations$1.registerDeclarations(LazyTopDownAnalyzer.kt:78)
    at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer$analyzeDeclarations$1.visitKtFile(LazyTopDownAnalyzer.kt:96)
    at org.jetbrains.kotlin.psi.KtVisitorVoid.visitKtFile(KtVisitorVoid.java:513)
    at org.jetbrains.kotlin.psi.KtVisitorVoid.visitKtFile(KtVisitorVoid.java:21)
    at org.jetbrains.kotlin.psi.KtFile.accept(KtFile.kt:242)
    at org.jetbrains.kotlin.psi.KtFile.accept(KtFile.kt:229)
    at org.jetbrains.kotlin.resolve.ExceptionWrappingKtVisitorVoid.visitElement(ExceptionWrappingKtVisitorVoid.kt:27)
    at org.jetbrains.kotlin.com.intellij.psi.PsiElementVisitor.visitFile(PsiElementVisitor.java:34)
    at org.jetbrains.kotlin.psi.KtVisitor.visitKtFile(KtVisitor.java:73)
    at org.jetbrains.kotlin.psi.KtVisitorVoid.visitKtFile(KtVisitorVoid.java:69)
    at org.jetbrains.kotlin.psi.KtVisitorVoid.visitKtFile(KtVisitorVoid.java:513)
    at org.jetbrains.kotlin.psi.KtVisitorVoid.visitKtFile(KtVisitorVoid.java:21)
    at org.jetbrains.kotlin.psi.KtFile.accept(KtFile.kt:242)
    at org.jetbrains.kotlin.psi.KtFile.accept(KtFile.kt:229)
    at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer.analyzeDeclarations(LazyTopDownAnalyzer.kt:201)
    at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer.analyzeDeclarations$default(LazyTopDownAnalyzer.kt:60)
    at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:112)
    at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:82)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:554)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:81)
    at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:107)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:545)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:176)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:163)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:51)
    at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:85)
    at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:43)
    at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:104)
    at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:349)
    at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:105)
    at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileIncrementally(IncrementalCompilerRunner.kt:237)
    at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.access$compileIncrementally(IncrementalCompilerRunner.kt:37)
    at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner$compile$2.invoke(IncrementalCompilerRunner.kt:79)
    at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:91)
    at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:606)
    at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:99)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1645)
    at sun.reflect.GeneratedMethodAccessor182.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException: Descriptor wasn't found for declaration SCRIPT
    at org.jetbrains.kotlin.resolve.lazy.BasicAbsentDescriptorHandler.diagnoseDescriptorNotFound(AbsentDescriptorHandler.kt:18)
    at org.jetbrains.kotlin.resolve.lazy.BasicAbsentDescriptorHandler.diagnoseDescriptorNotFound(AbsentDescriptorHandler.kt:17)
    at org.jetbrains.kotlin.resolve.lazy.LazyDeclarationResolver.findClassDescriptor(LazyDeclarationResolver.kt:88)
    at org.jetbrains.kotlin.resolve.lazy.LazyDeclarationResolver.getScriptDescriptor(LazyDeclarationResolver.kt:65)
    at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer$analyzeDeclarations$1.visitScript(LazyTopDownAnalyzer.kt:89)
    at org.jetbrains.kotlin.psi.KtVisitorVoid.visitScript(KtVisitorVoid.java:519)
    at org.jetbrains.kotlin.psi.KtVisitorVoid.visitScript(KtVisitorVoid.java:21)
    at org.jetbrains.kotlin.psi.KtScript.accept(KtScript.java:69)
    at org.jetbrains.kotlin.psi.KtElementImplStub.accept(KtElementImplStub.java:59)
    at org.jetbrains.kotlin.resolve.ExceptionWrappingKtVisitorVoid.visitDeclaration(ExceptionWrappingKtVisitorVoid.kt:32)
    ... 61 more

The dependency is implementation "org.jetbrains.kotlin:kotlin-script-runtime:1.3.70"

like image 711
mbo Avatar asked Nov 06 '22 09:11

mbo


1 Answers

Edit (2021-04-11): This is an ugly kludge which has no right to exist. Please read my shinier, newer, better answer.

Not sure if this counts as a great answer, since it doesn't just completely fix it, but the gist of it is... change the file extension. Just add an underscore at the end or something.

OMFSM I spent so long trying to find a proper way to do it. And then trying a million different kludges. And I didn't even have this problem before (didn't even know worksheets existed TBH), it just looked like a good idea.

There's a couple of ways to make that easier, but it still requires human intervention whenever you want to build (or you can just leave them off until you need them again).

Personally I just created a couple of batch files (although they're each only one command), which rename all the .kts files (and then rename them back) and created some handy shortcuts. I'm running Windows, and bash scripting is definitely not in my skill set, so I'm sure this can be done on *nix too.

To rename them all so they don't try and be compiled:

forfiles /S /M *.ws.kts /C "cmd /c ren @file @fname.kts_"

and to turn them back into valid worksheets:

forfiles /S /M *.ws.kts_ /C "cmd /c ren @file @fname.kts"

To make a batch file out of one of those:

  1. Open Notepad
  2. Copy one of those lines into it.
  3. Go to File > Save, navigate to the folder your project is saved in and give it a filename surrounded by double quotes (") and ending in .bat
    • For example "disable_worksheets.bat" and "enable_worksheets.bat" but make sure to include the double quotes.

Now you can just find that file in Windows Explorer and double click it to disable or enable them all at once.

If you want, you can also make a macro to do it each way in Android Studio, but AFAIK that can only change one file at a time (though you can set a keyboard shortcut, so it works if you don't have too many worksheets). To make the macro to disable a worksheet:

  1. Select your worksheet file in tree view on left
  2. In the menu bar, go to Edit > Macros and click "Start Macro Recording"
  3. Right click your worksheet in the tree view, and under the Refactor menu click "Rename file..."
  4. Press End on your keyboard
  5. Type an underscore _
  6. Press Enter
  7. In the menu bar, go to Edit > Macros and click "Stop Macro Recording"
  8. Give your macro a name and click OK

And for the one to re-enable it:

  1. Select your worksheet file in tree view on left
  2. In the menu bar, go to Edit > Macros and click "Start Macro Recording"
  3. Right click your worksheet in the tree view, and under the Refactor menu click "Rename..."
  4. Press End on your keyboard
  5. Press Backspace
  6. Press Enter
  7. In the menu bar, go to Edit > Macros and click "Stop Macro Recording"
  8. Give your macro a name and click OK

Now you can just select a file in the tree view, then in the menus go to Edit > Macros and click the one you need. But to make it more convenient, you can set keyboard shortcuts. To do that:

  1. In the menu bar, go to File and click "Settings..."
  2. In the menu on the left, click "Keymap"
  3. In the main pane of the editor, click the next to "Macros" to expand that section
  4. Right click the macro you want to set a shortcut for, and click "Add Keyboard Shortcut"
  5. Press the keys for the shortcut you want to use (for example Ctrl + Comma). It will warn you if you if a shortcut already uses those keys, so you may have to use a couple of modifiers (for example Ctrl + Shift + G)
    • A few I've found that are empty by default (at least on my install) and use only Ctrl as a modifier are Ctrl + Comma (,), Ctrl + Semicolon (;) and Ctrl + Backslash (\).
    • Most of the numpad keys are unused, but obviously they're not as convenient.
  6. Click OK to get back to the main settings window.
  7. If you want to set a shortcut for the other macro, just redo steps 4-6
  8. Click OK at the bottom of the settings window.

With those set all you have to do is click a filename in the tree view on the left and press your keyboard shortcut.

Hope all that helps someone! And sorry if this was a bit long, being terse isn't something in my skill set either.

like image 199
Slashee the Cow Avatar answered Nov 15 '22 12:11

Slashee the Cow