AST and Language Service Plugin - vscode-extensions

I would like to create a vscode extension which can help with unit testing and "live" debugging.
Lets say you have the following code:
/*1*/ export class Test {
/*2*/ public add(a: any, b: any): any {
/*3*/ return a + b;
/*4*/ }
/*5*/ }
Live debugging:
New option in the context menu to test the add function (e.g. something similar to current Peek Definition) where you can provide the function input and check the output in a new smaller editor.
Unit test generation:
After you wrote an input and checked the output you can simply generate a new unit test from it.
Now I'm only at the beginning of this project but it seems like getting type information is much more complicated than I expected.
First I would like to get some simple type information (based on cursor position) e.g.:
Line 1 is a class
Line 2-4 is a function
Line 5 is a class
After hours of Google search I think what I have to do is to implement my own TypeScript Language Service Plugin and use it somehow in my extension.
My questions:
Is there any extension similar to my idea which I could use?
Is there an easier way to get the type information I need?
Am I on a right track at all?
Do you have some material about how to use this language service plugin from extension?
P.S. I know that it won't be easy (e.g. several states with different visibility), but good practice for a home project.

Related

How to replace all `public void` "Test"-methods with just "void" (with SSR and IntelliJ)

I've recently joined a codebase that no one seemed to ever run SonarLint against, and now every test class I open in IntelliJ is highlighted like a Christmas tree - all test methods are public, even though JUnit5 is used.
Tired of removing those public modifiers manually, I decided to implement an SSR template to do that for me. However, I can't seem to make it work with method parameter annotations! (which seem to be rather usual thing with JMockit)
The best I can have thus far is this:
Open Edit->Find->Replace structurally
Paste this into Search field:
#$MethodAnnotation$
public void $MethodName$(#mockit.Injectable $ParameterType$ $Parameter$) {
$statement$;
}
Choose file type: Java - Class Member
Add filter for MethodAnnotation variable: Text=org.junit.jupiter.api.Test
Add Min=0 for statement and Parameter variables
Paste this into Replace field:
#$MethodAnnotation$
void $MethodName$(#Injectable $ParameterType$ $Parameter$) {
$statement$;
}
(mind the indentation, otherwise it will be problematic!)
Select Complete match value for Search target
Find
As you can see, the annotation is hard-coded, which of course limits the applicability of this snippet seriously.
Is this a problem with IntelliJ or rather my bad knowledge of SSR? What would be a proposed solution?

Is there a Kotlin "eval"

I have a bunch of strings like these in my already existing and quit big template file:
Hello $World I say hello to $User, too
I was thinking I could somehow let kotlin parse/search&replace this file as a kotlin string, and I'd just have to set the variables World and User to get an evaluated string... How is this possible?
This is not a kotlin source file, but a file that's beeing read by my kotlin program.
Why I want to do this? I used bash's envsubst before, and had to move away from this, since things were getting too complicated. But now I have no easy way to replace strings in a file anymore...
Thanks
What you want is called a template engine.
You don't really need an eval (which would allow running a full Kotlin application from a String) in this case.
For example, FreeMarker templates use a syntax that's similar to Kotlin template Strings, so a template may look like this:
<h1>Welcome ${user}!</h1>
Then, from Kotlin, you can evaluate the template with a Map holding the template bindings (variables the template can use) like this:
val user = "joe"
val bindings = mapOf("user" to user)
val cfg = new Configuration(Configuration.VERSION_2_3_29)
cfg.directoryForTemplateLoading = File("/where/you/store/templates")
val template = cfg.getTemplate("test.ftlh")
// write the resolved template to stdout
val out = OutputStreamWriter(System.out)
template.process(bindings, out)
See a Java example here: https://freemarker.apache.org/docs/pgui_quickstart_all.html
There are many other template engines, and the KTor site lists a few:
https://ktor.io/docs/working-with-views.html
If you're using KTor, BTW, it makes it much easier to use template engines... your framework may even have similar.
Warning: Please see my other answer first: you probably don't want to run a full Kotlin script just to parse some text file with variables... use a template engine for that.
It's possible to execute Kotlin scripts, i.e. eval Kotlin code, but it requires that you basically ship the Kotlin compiler with your application.
This GitHub project, KtsRunner, for example, does that, so you can do this:
val scriptContent = "5 + 10"
val fromScript: Int = KtsObjectLoader().load<Int>(scriptContent))
println(fromScript)
// >> 15
It requires some hacking though, is very slow and it uses a bunch of Kotlin "internal" APIs to work.
See the full list of libraries this project uses here:
https://github.com/s1monw1/KtsRunner/blob/master/lib/build.gradle.kts#L21
A "proper" KEEP proposal (discussion here) exists to add first-class support for this in Kotlin, but it's not finalized yet.
Currently, it looks something like this:
fun evalFile(scriptFile: File): ResultWithDiagnostics<EvaluationResult> {
val compilationConfiguration = createJvmCompilationConfigurationFromTemplate<MainKtsScript>()
val evaluationConfiguration = createJvmEvaluationConfigurationFromTemplate<MainKtsScript>()
return BasicJvmScriptingHost().eval(scriptFile.toScriptSource(), compilationConfiguration, evaluationConfiguration)
}
But it'll probably change before being released.

how do I write Intellij plugin to display python class methods return value from static analysis (for very simple expressions)?

I would like to write Intellij plugin that can display values returned by class def() in python. I would like those values to be evaluated as much as possible and done by static analysis. I need this to work only for very simple expressions in one particular use case.
We have class definitions in our python code base that consist of a lot of very simple def()s.
All the defs are just one return statement returning very simple expression.
All of the code follows the same pattern and uses very few python operator.
the code is long and really hard to follow.
After few jumps "to definition" within this class I can't remember where I am anymore.
I am hoping that some intellij plugin can lessen the pain.
So for example. this is short and very simplified code fragment. hopefully it will be enough to demonstrate the problem.
class SomeClass(object):
def __init__(self, param):
self.param = param
def a(self):
return self.param + 1
def b(self):
return self.a + otherfunc()
def c(self):
return self.b + 3
I would like the plugin to display the following:
class SomeClass(object):
def __init__(self, param):
self.param = param
def a(self): # = param + 1
return self.param + 1
def b(self): # = param + 1 + otherfunc()
return self.a + otherfunc()
def c(self): # = param + 1 + otherfunc() + 3
return self.b + 3
This is just an illustration, real code makes more sense. but the expressions themselves are that simple.
Comments represent plugin output. I would like those values to be always visible as code hints, tooltips or whatever. and be updated as I type.
I don't want to evaluate the defs, because some of the values are not available before runtime. I want to get the expression itself from AST.
Obviously this is impossible to do in the general case. But I have a very specific use case in our code base
where very small python subset is used. And all the code follows the same pattern.
I already have a script that does this in python with ast module. I wonder if there is a way to do the same on the fly in Intellij.
Is there some way to achieve this? or something similar?
Is there a plugin that does something like that?
I doubt that there is. at least not exactly. So I want to try to implement it myself. (the use case is common and very annoying).
I skimmed through some of Intellij Platform Plugin SDK documentation. it's still not clear to me where to begin.
So what would be the easiest way to implement it from scratch or using another plugin as an example?
Is there an opensource plugin that does something similar that I can look at to figure out how to implement this myself?
My best guess is that I would need to implement:
create a call back that will be called every time def() is changed. (by implementing various extensions, no? which one?)
find this def in the file.
walk expression with PSI to extract the expression
create some GUI element to represent the def expression. (what are my options? is there some predefined elements that I can use?
ideally I would assign value to some existing GUI element)
assign value to the GUI element
but I don't know how to begin implementing any of the above. (I can probably figure out PSI part)
I searched for existing plugins, but couldn't find anything even remotely close. I skimmed the documentation, I did the tutorial, but I couldn't figure out which of the many extensions I need to use.
I considered using the debugger for that, but I don't see how debugger can help me here.
Any help (plugins, tutorials, extensions, plugins as an example, or details for implementation) would be greatly appreciated. thanks.
What you want to find is some extension point that will change the text user sees. I suggest you to look at the annotator class but maybe this is not the best extension point for you and you will need to find more suitable one (this is the most difficult part of creating plugins for JetBrain's IDEs). Full list of all available extension points you can find here.
After you find right extension point you need to implement it and change plugin.xml to let IDE know that some changes were made.
Some useful links:
Example plugins from developers
Official documentation
Quick course from JetBrain's developer (in Russian)

Can I introspect the name of the main.main package?

This is a fairly niche problem, but I'm currently trying to write a conventions-based settings storage library with golang. It would be a great API boon if I could programmatically determine the running package name that wants to store something (eg "github.net/author/projectname/pkg") calling my library function.
With Python a similar thing could be achieved with the inspect module, or even with __main__.__file__ and a look at the file system.
You can get similar information if you use the following functions:
runtime.Caller
runtime.FuncForPC
The code may look like this:
pc, file, line, ok := runtime.Caller(1)
if !ok { /*failed*/ }
println(pc, file, line, ok)
f := runtime.FuncForPC(pc)
if f == nil { /*failed*/ }
println(f.Name())
If I put the above code (with the 1st line changed into runtime.Caller(0)) into a (randomly chosen) Go library which I have installed in GOROOT, it prints:
134626026 /tmp/go-build223663414/github.com/mattn/go-gtk/gtk/_obj/gtk.cgo1.go -4585 true
github.com/mattn/go-gtk/gtk.Init
Or it prints:
134515752 /home/user/go/src/github.com/mattn/go-gtk/example/event/event.go 12 true
main.main
The filename on the 1st line, and the 2nd line, seem to contain the information you are looking for.
There are two problems:
It may give incorrect result if functions are automatically inlined by the compiler
For any function F defined in package main, the function name is just main.F. For example, if runtime.Caller(0) is called from main(), the function name is main.main even if the main() function is defined in a Go file found in GOROOT/src/github.com/mattn/go-gtk/.... In this case, the output from runtime.Caller is more useful than the output from runtime.FuncForPC.

Static testing for Scala

There are some nice libraries for testing in Scala (Specs, ScalaTest, ScalaCheck). However, with Scala's powerful type system, important parts of an API being developed in Scala are expressed statically, usually in the form of some undesirable or disallowed behavior being prevented by the compiler.
So, what is the best way to test whether something is prevented by the compiler when designing an library or other API? It is unsatisfying to comment out code that is supposed to be uncompilable and then uncomment it to verify.
A contrived example testing List:
val list: List[Int] = List(1, 2, 3)
// should not compile
// list.add("Chicka-Chicka-Boom-Boom")
Does one of the existing testing libraries handle cases like this? Is there an approach that people use that works?
The approach I was considering was to embed code in a triple-quote string or an xml element and call the compiler in my test. Calling code looking something like this:
should {
notCompile(<code>
val list: List[Int] = List(1, 2, 3)
list.add("Chicka-Chicka-Boom-Boom")
</code>)
}
Or, something along the lines of an expect-type script called on the interpreter.
I have created some specs executing some code snippets and checking the results of the interpreter.
You can have a look at the Snippets trait. The idea is to store in some org.specs.util.Property[Snippet] the code to execute:
val it: Property[Snippet] = Property(Snippet(""))
"import scala.collection.List" prelude it // will be prepended to any code in the it snippet
"val list: List[Int] = List(1, 2, 3)" snip it // snip some code (keeping the prelude)
"list.add("Chicka-Chicka-Boom-Boom")" add it // add some code to the previously snipped code. A new snip would remove the previous code (except the prelude)
execute(it) must include("error: value add is not a member of List[Int]") // check the interpreter output
The main drawback I found with this approach was the slowness of the interpreter. I don't know yet how this could be sped up.
Eric.