IDE Scripting console: Samples.groovy and .profile.groovy error under Intellij 2021.2.*

已回答

My dear friends:
I have installed Intellij 2021.1.3 and 2021.2.3 for testing IDE Scripting.
Samples.groovy and .profile.groovy ran well under Intellij 2021.1.3, but got the following errors under Intelli 2021.2.3:
MissingPropertyException: No such property: componentKeyToAdapterCache for class: com.intellij.openapi.project.impl.ProjectExImpl

Could you help me?
Many thanks to you!

Upload id: 2021_10_27_43AinrpW5e5P1Jdm (files: .profile.groovy and 2 more)

samples.groovy and .profile.groovy are in the path:C:\Users\abc\AppData\Roaming\JetBrains\IntelliJIdea2021.2\consoles\ide\

//samples.groovy
write { "PsiManager.java".firstFile().document().setText("Rollback!") }
pool { Thread.sleep(5000); IDE.print("123") }
action("TryMe!", "alt shift P") { e->
e = PSI_ELEMENT.from(e)
res = e != null && finds.canFindUsages(e)
IDE.print("can find usages of '" + e +"'? " + (res ? "Yes!" : "Nope"))
}
timer("bump", 500) {
IDE.print(System.currentTimeMillis() + ": bump!")
}
dispose("bump")
def ep = "com.intellij.iconLayerProvider".ep()
ep.registerExtension(new com.intellij.ide.IconLayerProvider() {
String getLayerDescription() { return "123" }
javax.swing.Icon getLayerIcon(com.intellij.openapi.util.Iconable element, boolean isLocked) {
"config".equals(element.getName()) ? com.intellij.icons.AllIcons.Nodes.FinalMark : null
}
})
ep.unregisterExtension(ep.getExtensions().last())
//.profile.groovy
import static com.intellij.openapi.actionSystem.LangDataKeys.*
//////////////////////////////////////////////////////////////////////////////////////////////
metaClass.propertyMissing = {name ->
switch (name) {
case "application": return com.intellij.openapi.application.ApplicationManager.getApplication()
case "project": return com.intellij.openapi.project.ProjectManager.getInstance().getOpenProjects()[0]
case "INDEX": return com.intellij.psi.search.FilenameIndex
case "GSS": return com.intellij.psi.search.GlobalSearchScope
case "EXT": return com.intellij.openapi.extensions.Extensions
default:
def variants = []
for (t in [IDE.project, IDE.application]) {
for (obj in t.picoContainer.componentKeyToAdapterCache.keySet()) {
def key = obj instanceof String ? obj : obj instanceof Class ? obj.getName() : null
if (key == null) continue
def match = key =~ /[\.]([^\.]+?)(Service|Manager|Helper|Factory)?$/
def groups = match.size()? match[0][1..-1] : [key, null]
def singular = groups[1..-1][0] == null
def words = com.intellij.psi.codeStyle.NameUtil.nameToWords(groups[0])
def short0 = [words[0].toLowerCase(), words.length==1? "" : words[1..-1]].flatten().join()
def shortName = singular? short0 : com.intellij.openapi.util.text.StringUtil.pluralize(short0)
if (shortName.equals(name)) return t.picoContainer.getComponentInstance(obj);
if (com.intellij.openapi.util.text.StringUtil.containsIgnoreCase(groups[0], name)) variants.add(shortName)
}
}
throw new MissingPropertyException("Service or Component '$name' not found. Variants: $variants")
}
}
String.class.metaClass.file = {-> virtualFiles.findFileByUrl(com.intellij.openapi.vfs.VfsUtil.pathToUrl(delegate))}
String.class.metaClass.file2 = {-> def name = delegate; fileEditors.getOpenFiles().find {file -> file.getName().equals(name) }}
String.class.metaClass.findPsi = {-> INDEX.getFilesByName(project, delegate, GSS.allScope(project)) }
String.class.metaClass.findFile = {-> INDEX.getVirtualFilesByName(project, delegate, GSS.allScope(project)) }
String.class.metaClass.firstPsi = {-> delegate.findPsi()[0] }
String.class.metaClass.firstFile = {-> delegate.findFile()[0] }
String.class.metaClass.ep = {-> EXT.getArea(null).getExtensionPoint(delegate) }
com.intellij.openapi.actionSystem.DataKey.class.metaClass.from = {e -> delegate.getData(e.getDataContext()) }
def virtualFileMetaClass = com.intellij.openapi.vfs.VirtualFile.class.metaClass
virtualFileMetaClass.psi = {-> psiManager.findFile(delegate)}
virtualFileMetaClass.document = {-> fileDocuments.getDocument(delegate)}
virtualFileMetaClass.editor = {-> fileEditors.getSelectedEditor(delegate)?.getEditor()}
def psiMetaClass = com.intellij.psi.PsiElement.class.metaClass
psiMetaClass.document = {-> psiDocuments.getDocument(delegate)}
psiMetaClass.file = {-> delegate.getContainingFile().getVirtualFile()}
psiMetaClass.editor = {-> fileEditors.getSelectedEditor(delegate.file())?.getEditor()}
write = { c -> application.runWriteAction(c)}
read = { c -> application.runReadAction(c)}
pool = { c -> application.executeOnPooledThread(c)}
swing = { c -> com.intellij.util.ui.UIUtil.invokeLaterIfNeeded(c)}
action = { name, shortcut = null, perform = null ->
actions.unregisterAction(name)
keymaps.getActiveKeymap().removeAllActionShortcuts(name)
if (perform == null) return
actions.registerAction(name, new com.intellij.openapi.actionSystem.AnAction(name, name, null) {
@Override
void actionPerformed(com.intellij.openapi.actionSystem.AnActionEvent e) {
perform(e)
} })
if (shortcut != null) {
keymaps.getActiveKeymap().addShortcut(name, new com.intellij.openapi.actionSystem.KeyboardShortcut(
javax.swing.KeyStroke.getKeyStroke(shortcut), null))
}
}
timer = {name, delay = 1, perform = null ->
dispose(name)
if (perform == null) return
def h = new com.intellij.util.Alarm(project)
def r = new Runnable() { public void run() {perform(); h.addRequest(this, delay); }}
h.addRequest(r, delay)
IDE.put(name, h)
}
dispose = { h ->
t = h instanceof com.intellij.openapi.Disposable ? h : IDE.put(h, null)
if (t != null) com.intellij.openapi.util.Disposer.dispose(t)
}
editor = { -> try {windows.getFocusedComponent(project).getEditor()} catch(e){}}
0
正式评论

This is a friendly reminder not to use private APIs. 

The field has been renamed to `componentKeyToAdapter`, it is defined in `com.intellij.util.pico.DefaultPicoContainer`, but `com.intellij.openapi.project.impl.ProjectExImpl` does not use it anymore. Instead it inherits `componentKeyToAdapter` field from `com.intellij.serviceContainer.ComponentManagerImpl`. For more info see https://github.com/JetBrains/intellij-community/commit/906264a105a0d22dd20dfc1d2482516910d54101 

Many thanks to you for your a lot of answers.

I thought it for 30 hours, but I can't handle this error. I viewed code of DefaultPicoContainer.java, ComponentManagerImpl.kt and ProjectExImpl.kt etc. Because of declaration of private componentKeyToAdapter, "t.picoContainer.componentKeyToAdapter.keySet()" can't be executed. But how can I access picoContainer.componentKeyToAdapter.keySet()? 

I can't write above code. How could I do? The following code is here:

//.profile.groovy
import static com.intellij.openapi.actionSystem.LangDataKeys.*
//////////////////////////////////////////////////////////////////////////////////////////////
metaClass.propertyMissing = {name ->
switch (name) {
case "application": return com.intellij.openapi.application.ApplicationManager.getApplication()
case "project": return com.intellij.openapi.project.ProjectManager.getInstance().getOpenProjects()[0]
case "INDEX": return com.intellij.psi.search.FilenameIndex
case "GSS": return com.intellij.psi.search.GlobalSearchScope
case "EXT": return com.intellij.openapi.extensions.Extensions
default:
def variants = []
for (t in [IDE.project, IDE.application]) {
for (obj in t.picoContainer.componentKeyToAdapterCache.keySet()) {
def key = obj instanceof String ? obj : obj instanceof Class ? obj.getName() : null
if (key == null) continue
def match = key =~ /[\.]([^\.]+?)(Service|Manager|Helper|Factory)?$/
def groups = match.size()? match[0][1..-1] : [key, null]
def singular = groups[1..-1][0] == null
def words = com.intellij.psi.codeStyle.NameUtil.nameToWords(groups[0])
def short0 = [words[0].toLowerCase(), words.length==1? "" : words[1..-1]].flatten().join()
def shortName = singular? short0 : com.intellij.openapi.util.text.StringUtil.pluralize(short0)
if (shortName.equals(name)) return t.picoContainer.getComponentInstance(obj);
if (com.intellij.openapi.util.text.StringUtil.containsIgnoreCase(groups[0], name)) variants.add(shortName)
}
}
throw new MissingPropertyException("Service or Component '$name' not found. Variants: $variants")
}
}
String.class.metaClass.file = {-> virtualFiles.findFileByUrl(com.intellij.openapi.vfs.VfsUtil.pathToUrl(delegate))}
String.class.metaClass.file2 = {-> def name = delegate; fileEditors.getOpenFiles().find {file -> file.getName().equals(name) }}
String.class.metaClass.findPsi = {-> INDEX.getFilesByName(project, delegate, GSS.allScope(project)) }
String.class.metaClass.findFile = {-> INDEX.getVirtualFilesByName(project, delegate, GSS.allScope(project)) }
String.class.metaClass.firstPsi = {-> delegate.findPsi()[0] }
String.class.metaClass.firstFile = {-> delegate.findFile()[0] }
String.class.metaClass.ep = {-> EXT.getArea(null).getExtensionPoint(delegate) }
com.intellij.openapi.actionSystem.DataKey.class.metaClass.from = {e -> delegate.getData(e.getDataContext()) }
def virtualFileMetaClass = com.intellij.openapi.vfs.VirtualFile.class.metaClass
virtualFileMetaClass.psi = {-> psiManager.findFile(delegate)}
virtualFileMetaClass.document = {-> fileDocuments.getDocument(delegate)}
virtualFileMetaClass.editor = {-> fileEditors.getSelectedEditor(delegate)?.getEditor()}
def psiMetaClass = com.intellij.psi.PsiElement.class.metaClass
psiMetaClass.document = {-> psiDocuments.getDocument(delegate)}
psiMetaClass.file = {-> delegate.getContainingFile().getVirtualFile()}
psiMetaClass.editor = {-> fileEditors.getSelectedEditor(delegate.file())?.getEditor()}
write = { c -> application.runWriteAction(c)}
read = { c -> application.runReadAction(c)}
pool = { c -> application.executeOnPooledThread(c)}
swing = { c -> com.intellij.util.ui.UIUtil.invokeLaterIfNeeded(c)}
action = { name, shortcut = null, perform = null ->
actions.unregisterAction(name)
keymaps.getActiveKeymap().removeAllActionShortcuts(name)
if (perform == null) return
actions.registerAction(name, new com.intellij.openapi.actionSystem.AnAction(name, name, null) {
@Override
void actionPerformed(com.intellij.openapi.actionSystem.AnActionEvent e) {
perform(e)
} })
if (shortcut != null) {
keymaps.getActiveKeymap().addShortcut(name, new com.intellij.openapi.actionSystem.KeyboardShortcut(
javax.swing.KeyStroke.getKeyStroke(shortcut), null))
}
}
timer = {name, delay = 1, perform = null ->
dispose(name)
if (perform == null) return
def h = new com.intellij.util.Alarm(project)
def r = new Runnable() { public void run() {perform(); h.addRequest(this, delay); }}
h.addRequest(r, delay)
IDE.put(name, h)
}
dispose = { h ->
t = h instanceof com.intellij.openapi.Disposable ? h : IDE.put(h, null)
if (t != null) com.intellij.openapi.util.Disposer.dispose(t)
}
editor = { -> try {windows.getFocusedComponent(project).getEditor()} catch(e){}}

//- samples.groovy
write { "PsiManager.java".firstFile().document().setText("Rollback!") }
/*
pool { Thread.sleep(5000); IDE.print("123") }
action("TryMe!", "alt shift P") { e->
e = PSI_ELEMENT.from(e)
res = e != null && finds.canFindUsages(e)
IDE.print("can find usages of '" + e +"'? " + (res ? "Yes!" : "Nope"))
}
timer("bump", 500) {
IDE.print(System.currentTimeMillis() + ": bump!")
}
dispose("bump")
def ep = "com.intellij.iconLayerProvider".ep()
ep.registerExtension(new com.intellij.ide.IconLayerProvider() {
String getLayerDescription() { return "123" }
javax.swing.Icon getLayerIcon(com.intellij.openapi.util.Iconable element, boolean isLocked) {
"config".equals(element.getName()) ? com.intellij.icons.AllIcons.Nodes.FinalMark : null
}
})
ep.unregisterExtension(ep.getExtensions().last())
*/
2

You should write a plugin with a plugin.xml which will be used to register extensions, this is a great place to start https://plugins.jetbrains.com/docs/intellij/welcome.html

 

 

0

Daniil Ovchinnikov Not sure if I get your point right.

The question is on defining basic reusable functions(like action, etc) via `.profile.groovy` . And the purpose of IDE scripting is an alternative to plugins(https://plugins.jetbrains.com/docs/intellij/plugin-alternatives.html).

 

Why do we have to start with `plugin.xml`. And is there an alternative for the aforementioned `.profile.groovy` ?

1

Any updates on this? Is the IDE Scripting Console still a supported feature? Documentation and examples remain scarce despite being around for years…

0

Please check https://plugins.jetbrains.com/docs/intellij/getting-help.html for the support resources available regarding plug-in development/scripting, etc.

0

I've looked at that page, and I've been through the GitHub repo with the code samples (https://github.com/JetBrains/intellij-sdk-code-samples), but everything seems to be for plugin development, not the IDE scripting console. On one of the first help pages for developing a plugin (https://plugins.jetbrains.com/docs/intellij/developing-plugins.html), there is a link to alternatives (https://plugins.jetbrains.com/docs/intellij/plugin-alternatives.html), and the second option listed on this page is IDE Scripting Console. 

So it seems that you are encouraging users to use more lightweight alternatives to plugins if possible (which makes sense), but I'm having a hard time finding documentation and examples for those alternatives (and the IDE Scripting Console in particular). 

If there are examples that are relevant/for the IDE Scripting Console in the GitHub repo (https://github.com/JetBrains/intellij-sdk-code-samples), please point them out and I'll take a look. 

0

请先登录再写评论。