Skip to content

Instantly share code, notes, and snippets.

@gregsh
Last active March 13, 2024 03:29
Show Gist options
  • Star 79 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save gregsh/b7ef2e4ebbc4c4c11ee9 to your computer and use it in GitHub Desktop.
Save gregsh/b7ef2e4ebbc4c4c11ee9 to your computer and use it in GitHub Desktop.
IDE Scripting

Here are my attempts to script an IntelliJ-based IDE using javax.script.* API (ex-JSR-223).

The list of available scripting languages and engines:

  1. Groovy - built-in, via Groovy jars and <app>/lib/groovy-jsr223-xxx.jar
  2. JavaScript (Nashorn) - built-in, via Java Runtime <app>/jbr/... (deprecated and will be removed soon)
  3. JavaScript (GraalJS) - https://plugins.jetbrains.com/plugin/12548-intellij-scripting-javascript
  4. JPython - https://plugins.jetbrains.com/plugin/12471-intellij-scripting-python
  5. JRuby - https://plugins.jetbrains.com/plugin/12549-intellij-scripting-ruby
  6. Clojure - https://plugins.jetbrains.com/plugin/12469-intellij-scripting-clojure
  7. Kotlin - https://plugins.jetbrains.com/plugin/6954-kotlin (bundled in IntelliJ IDEA)

Open IDE Scripting Console, type a statement, hit Ctrl-Enter to execute the current line or selection.

.profile.language-extension file in the same directory will be executed along with it if present.

CAUTION: Scripts exert full control over IDE VM so any damage is possible, e.g. System.exit(0).

(write #(. (document (firstFile "PsiManager.java")) (setText "Rollback!")))
(pool #(do (Thread/sleep 5000) (. IDE print "123")))
(action "TryMe!" "alt shift P" (fn [e] (let
[e (event-data e 'PSI_ELEMENT)
res (and (-> e nil? not) (.canFindUsages finds e)) ]
(. IDE print (str "can find usages of '" e "'? " (if res "Yes!" "Nope"))))))
(timer "bump" 500 #(. IDE (print (str (System/currentTimeMillis) ": bump!"))))
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())
(doseq [x (list (.project IDE) (.application IDE))]
(let [pico (.getPicoContainer x)
field (.getDeclaredField (.getClass pico) "componentKeyToAdapterCache")
services (do (.setAccessible field true) (.get field pico))]
(doseq [key (filter #(instance? String %) (.keySet services))]
(let [match (re-find (re-matcher #"[\.]([^\.]+?)(Service|Manager|Helper|Factory)?$" key))
groups (rest match)
singular (empty? (rest groups))
words (seq (com.intellij.psi.codeStyle.NameUtil/nameToWords (first groups)))
short0 (clojure.string/join (flatten (list (.toLowerCase (first words)) (rest words))))
shortName (if (false? singular) (com.intellij.openapi.util.text.StringUtil/pluralize short0) short0)]
(try
(intern *ns* (symbol shortName) (.getComponentInstance pico key))
(catch Exception e ()))
)
)
)
)
(defn file [^String x] (.findFileByUrl virtualFiles (com.intellij.openapi.vfs.VfsUtil/pathToUrl x)))
(defn file2 [^String x] (first (filter #( = x (.getName %)) (.getOpenFiles fileEditors))))
(defn all-scope [] (com.intellij.psi.search.GlobalSearchScope/allScope (.project IDE)))
(defn findPsi [^String x] (com.intellij.psi.search.FilenameIndex/getFilesByName (.project IDE), x, (all-scope)))
(defn findFile [^String x] (com.intellij.psi.search.FilenameIndex/getVirtualFilesByName (.project IDE) x, (all-scope)) )
(defn firstPsi [^String x] (first (findPsi x)))
(defn firstFile [^String x] (first (findFile x)))
(defn ep [^String x] (.getExtensionPoint (com.intellij.openapi.extensions.Extensions/getArea nil) x))
(defn psi [x] (.findFile psis x))
(defn document [x] (.getDocument fileDocuments x))
(defn editor ([x] (.getEditor (.getSelectedEditor fileEditors x)))
([] (try (.. windows (getFocusedComponent (. IDE project)) (getEditor)) (catch Exception e ()) )) )
(defn #^Runnable runnable [x] (proxy [Runnable] [] (run [] (x))))
(defn write [x] (.. IDE application (runWriteAction (runnable x))))
(defn read [x] (.. IDE application (runReadAction (runnable x))))
(defn pool [x] (.. IDE application (executeOnPooledThread (runnable x))))
(defn swing [x] (com.intellij.util.ui.UIUtil/invokeLaterIfNeeded (runnable x)))
(defn dumpe [e] (.print IDE (str e (clojure.string/replace (str (seq (.getStackTrace e))) #"#<StackTraceElement " "\n at "))))
(defn safe [x] (try (x) (catch Exception e (dumpe e))))
(defn data-key [e] (let [c ['com.intellij.openapi.actionSystem.LangDataKeys]]
(some #(try (. (. (Class/forName (str %)) (getField (str e))) (get nil)) (catch Exception e nil) ) c)))
(defn event-data [e key] (.getData (data-key key) (.getDataContext e)))
(defn action [name & x]
(.unregisterAction actions name)
(.. keymaps getActiveKeymap (removeAllActionShortcuts name))
(if (nil? (second x)) nil
(let [[shortcut, perform] x]
(. actions (registerAction name (proxy [com.intellij.openapi.actionSystem.AnAction] [name, name, nil]
(actionPerformed [e] (perform e)) )))
(if (= shortcut nil) nil
(.. keymaps (getActiveKeymap) (addShortcut name
(new com.intellij.openapi.actionSystem.KeyboardShortcut (javax.swing.KeyStroke/getKeyStroke shortcut) nil)) )
)
nil
)
)
)
(defn dispose [x] (let [t (if (instance? com.intellij.openapi.Disposable x) (x) (.put IDE x nil))]
(if (nil? t) nil (com.intellij.openapi.util.Disposer/dispose t)) ) )
(defn timer [name & x] (do
(dispose name)
(if (nil? (second x)) nil
(let [[delay, perform] x
h (new com.intellij.util.Alarm (.project IDE))
r (runnable (fn time_fun [] (do (perform) (. h (addRequest (runnable time_fun) delay)) ) ))]
(. h (addRequest r delay))
(. IDE (put name h))
)
) ))
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){}}
import com.intellij.openapi.ui.Messages
val b = bindings as Map<String, Any>
val IDE = b["IDE"] as com.intellij.ide.script.IDE
val name = System.getProperty("user.name")
IDE.print("$name>")
Messages.showInfoMessage("Hi, $name", IDE.project.name)
import com.intellij.notification.*
// Change the `pattern` and the `replacement` as needed
def pattern = ~/(.*)XXX\.(.*)/
def replacement = "\$1_xxx_.\$2"
// `Rename Multiple Files` action:
// 1. select some files in `Project` view
// 2. invoke it via Search Everywhere/Goto Action or a shortcut
// 3. see `Event Log` for the report
// Note: `action`, `write`, etc. are defined in `.profile.groovy`
action("Rename Multiple Files", "control alt R") { event ->
def files = VIRTUAL_FILE_ARRAY.getData(event.getDataContext())
def report = new StringBuilder()
for (def file : files) {
def curName = file.name
def matcher = curName =~ pattern
if (!matcher.matches()) {
report.append("$curName skipped\n")
}
else {
def newName = matcher.replaceFirst(replacement)
report.append("$curName -> $newName\n")
write {
file.rename(this, newName)
}
}
}
Notifications.Bus.notify(new Notification(
"test",
"${event.presentation.text}: ${files ? files.length : 0} file(s) processed",
report.toString(), NotificationType.INFORMATION))
}
@mnowotnik
Copy link

Getting current project and editor in Kotlin:

val dataContext = DataManager.getInstance().dataContextFromFocusAsync.blockingGet(1000)!!
val project = CommonDataKeys.PROJECT.getData(dataContext)!!
val editor = BaseCodeInsightAction.getInjectedEditor(project, CommonDataKeys.EDITOR.getData(dataContext))!!

@smaudet
Copy link

smaudet commented Jun 4, 2019

IDE.print is no longer functional. It does not display to the run toolwindow and no console appears. Additionally the static method is private and constructing the IDE instance manually yields no results.

Fallback, although not pretty, is to open up File I/O directly and e.g. tail -f <yourfile>

@smaudet
Copy link

smaudet commented Jun 4, 2019

I will also say from what I could tell it is not possible to gain console output from the scripting console into the run dialog, not without either:
a) Discovering the runtime console during run and injecting something into it
b) Collecting and dumping the console output internal to the script
c) Building a new Tool Window and manually outputting console output to it.

@ice1000
Copy link

ice1000 commented Jul 24, 2019

Kotlin example request

@shawkinaw
Copy link

Anybody know if there's a way to run an IDE script from the command line somehow? I'd like to trigger a script I've written from an external script.

@mgroth0
Copy link

mgroth0 commented Jun 15, 2020

I'd like to echo @shawkinaw 's question. Also, can we script the embedded terminal? It would be great if I could automatically open a terminal tab, name it, and run a command

@gregsh
Copy link
Author

gregsh commented Jun 16, 2020

Also, can we script the embedded terminal?

An IDE scripting console script, like the following:

com.intellij.openapi.components.ServiceManager.getService(IDE.project,
  com.intellij.sh.run.ShRunner.class).run("ls", "/", "title")

UPD Updated to address @skissane note below.

@gregsh
Copy link
Author

gregsh commented Jun 16, 2020

I've just added a Kotlin *.kts example to show the external bindings access which is tricky at the moment,
and updated IDE Scripting.md with the list of available languages/engines.

@skissane
Copy link

@gregsh I thought @shawkinaw's question was, how do I use the IntelliJ command line interface to run an IDE Console script from a shell script? You seem to be answering the opposite question of how I run a shell script from the IDE Console script?

@gregsh
Copy link
Author

gregsh commented Jul 13, 2020

Anybody know if there's a way to run an IDE script from the command line somehow?

No such thing now, but a simple plugin with a com.intellij.appStarter extension shall do the trick.

UPD I'll do that, watch for IDEA-245847.

@sesm
Copy link

sesm commented Oct 27, 2020

I've tried .project.clj but I get RuntimeException: Unable to resolve symbol: fileEditors in this context.
I guess this symbol should be added to namespace in the first loop. I checked which symbols are added and the closest I see is fileEditorProviders. Should I use that one to get fileEditors somehow?

@gregsh
Copy link
Author

gregsh commented Feb 5, 2021

Anybody know if there's a way to run an IDE script from the command line somehow?

IDEA-245847 is now included in 2021 EAP.
Usage: idea ideScript <files>...

@mvastola
Copy link

mvastola commented Mar 3, 2021

Any starter code for ruby? I.e. files we need to require

@mgroth0
Copy link

mgroth0 commented Mar 11, 2021

@mnowotnik

I want to get the editor object you referenced but my code is blocking

val dataContext = getInstance().dataContextFromFocusAsync.blockingGet(1000)!!
val project = CommonDataKeys.PROJECT.getData(dataContext)!!
val editor_data = CommonDataKeys.EDITOR.getData(dataContext)
IDE.print("here1")
val editor = BaseCodeInsightAction.getInjectedEditor(project, editor_data)!!
IDE.print("here2")

Output

here1 

I never see here2, nor any exceptions

@mnowotnik
Copy link

@mgroth0

Just checked, works without a problem on IDEA 2020.3

val dataContext = DataManager.getInstance().dataContextFromFocusAsync.blockingGet(10)!!
val project = CommonDataKeys.PROJECT.getData(dataContext)!!
val editor = BaseCodeInsightAction.getInjectedEditor(project, CommonDataKeys.EDITOR.getData(dataContext))!!
val ctx = SearchContext(project)

@mgroth0
Copy link

mgroth0 commented Mar 11, 2021

I've discovered part of my problem. If I run this code while focused on the editor:

val dataContext = DataManager.getInstance().dataContextFromFocusAsync.blockingGet(10)!!
IDE.print("${dataContext}")

I get this output:

component=EditorComponent file=file:///Users/matt/Library/Application Support/JetBrains/IntelliJIdea2020.3/consoles/ide/ide-scripting.kts

But for my use case, I need this to work when I'm not focused on the editor. So I'm actually focused on the embedded terminal. So as you might expect from the name of the function dataContextFromFocusAsync, I'm getting:

component=com.intellij.terminal.JBTerminalPanel[,0,0,699x249,alignmentX=0.0,alignmentY=0.0,border=,flags=1,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=699,height=243]]

@mgroth0
Copy link

mgroth0 commented Mar 11, 2021

To get the editor, I use

val projectMan = com.intellij.openapi.project.ProjectManager.getInstance()
val projects = projectMan.openProjects
val project = projects.first { it.name == "projectname" }
val editor = FileEditorManager.getInstance(project)

Then I can use editor.openFile(f, true) to open files. This works perfectly. However, I can not scroll to a specific line. Then I came across the code you posted @mnowotnik, and found that the editor class you demonstrated does have a scrollingModel.scrollTo method that works well. However, as I stated in my previous message, I just can't seem to get a reference to the com.intellij.openapi.editor.Editor (for a specific file, in a specific project, and without being focused on any particular component) yet, in the same way I could get a FileEditorManager instance.

@mgroth0
Copy link

mgroth0 commented Mar 11, 2021

Figured it out!
Using the project and editor values from my previous comment:

BaseCodeInsightAction.getInjectedEditor(project, editor.selectedTextEditor).scrollingModel.scrollTo(LogicalPosition(50,0), ScrollType.CENTER)

@dkandalov
Copy link

@boonshift
Copy link

I occasionally accidentally close my pinned tabs and wanted a quick and dirty way to re-pin them.
After reading this page, finally cobbled together a few lines to do just that.
Pasted below in case someone else has similar need.

https://gist.github.com/boonshift/2e241311c58e019b74b8f35d1ed28981

import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx

val b = bindings as Map<String, Any>
val IDE = b["IDE"] as com.intellij.ide.script.IDE

val editor = FileEditorManagerEx.getInstance(IDE.project) as FileEditorManagerEx
val filesToPin = editor.openFiles.filter { it.name.contains("Scratch") }
filesToPin.forEach { f -> editor.currentWindow.setFilePinned(f, true) }

@skissane
Copy link

@gregsh A huge thank you for IDEA-245847, I was really looking for that. I created a related PR to teach the launcher Python script how to invoke it. However, looking at the current implementation of IdeScriptStarter I can see a couple of gaps:

  • There is no way to pass arguments to scripts. If I call ideScript foo.groovy bar it tries to run bar as a second script (which it can't find) instead of passing it as an argument (somehow) to foo.groovy
  • There is zero feedback to the launcher about whether the script ran successfully. If the script doesn't exist, or contains a syntax error, the launcher still returns successfully, although the error does get logged in idea.log. If the script compiles successfully, but throws an exception during execution, you don't even get any error logged in idea.log

I can cook up some hacky workarounds to (mostly) solve the above two issues for my own purposes, but it would be great if one day there was some solution for them out of the box.

@fuxin-liu
Copy link

Dear Mr Shrago:
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!
屏幕截图(2)

@atorr0
Copy link

atorr0 commented Jun 30, 2022

@fuxin-liu , you'll need the Kotlin plugin activated in your IDE.

@AfzalivE
Copy link

AfzalivE commented Oct 5, 2022

Wrote a little script to create a text file based on the name of the current Git branch. We add changelogs this way and it was very tedious to copy over the branch name all the time.

Thanks to all of you sharing your scripts as examples!

import com.android.tools.idea.util.toVirtualFile
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.vcs.LocalFilePath
import git4idea.GitUtil
import java.io.File

val b = bindings as Map<String, Any>
val IDE = b["IDE"] as com.intellij.ide.script.IDE

main()

fun main() {
    val baseProjectPath = requireNotNull(IDE.project.basePath)
    IDE.print(baseProjectPath)
    val isVcs = GitUtil.isGitRoot(baseProjectPath)
    if (!isVcs) {
        IDE.print("File not under VCS")
        return
    }

    val repo = GitUtil.getRepositoryForFile(IDE.project, LocalFilePath(baseProjectPath, true))

    val currentBranch = requireNotNull(repo.currentBranch)
    val filename = currentBranch.name
    val file = createChangelogFile(baseProjectPath, filename)

    val editor = FileEditorManager.getInstance(IDE.project)
    val virtualFile = requireNotNull(file.toVirtualFile(true))

    editor.openFile(virtualFile, true, true)
}

fun createChangelogFile(baseProjectPath: String, filename: String): File {
    val sanitizedFilename = filename.replace("/", ".").plus(".txt")
    IDE.print("Creating changelog file: $filename")
    val changelogFolder = "$baseProjectPath/changelog"
    IDE.print("In folder: $changelogFolder")
    val file = File(changelogFolder, sanitizedFilename)
    val created = file.createNewFile()
    IDE.print("File created: $created")
    return file
}

@anton-kapelyushok
Copy link

Is there a way to execute ide script from console / using run configurations or something similar?

@piyushsoni
Copy link

Hi, so many examples and I'm still looking for one on how to get the filename of the currently open file in the Editor. Can someone please help me with that?

@piyushsoni
Copy link

I think I got a way to get the current file path. Can someone please help me with how to handle a "keyboard shortcut pressed" action in our kotlin script?

@piyushsoni
Copy link

@AfzalivE : Nice script, but how do you execute it quickly - (I mean other than opening the script itself and running it manually). Can you add a keyboard shortcut for the same, or add it to 'External Tools'? I tried to do that but failed.

@AfzalivE
Copy link

@piyushsoni Nice script, but how do you execute it quickly - (I mean other than opening the script itself and running it manually). Can you add a keyboard shortcut for the same, or add it to 'External Tools'? I tried to do that but failed.

Thanks. Yeah I have to open it, select all, and then cmd+enter :( Haven't explored any other way yet.

@abextm
Copy link

abextm commented Jul 6, 2023

Kotlin action example

import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.KeyboardShortcut
import com.intellij.openapi.keymap.KeymapManager
import javax.swing.KeyStroke

val IDE = bindings["IDE"] as com.intellij.ide.script.IDE
val project = IDE.project


action("Add Export", "ctrl COMMA") { ev ->
	val pi = CommonDataKeys.PSI_ELEMENT.getData(ev.dataContext)
	IDE.print(pi)
}

fun action(name: String, shortcut: String, action: (AnActionEvent) -> Unit) {
	val action = object : AnAction(name) {
		override fun actionPerformed(p0: AnActionEvent) {
			try {
				action(p0);
			} catch (e: Exception) {
				IDE.print(e.stackTraceToString())
				throw e;
			}
		}
	}

	val am = ActionManager.getInstance()
	val km = KeymapManager.getInstance()
	am.unregisterAction(name)
	km.activeKeymap.removeAllActionShortcuts(name)
	am.registerAction(name, action)
	km.activeKeymap.addShortcut(name, KeyboardShortcut(KeyStroke.getKeyStroke(shortcut), null))
}

@gschrader
Copy link

Is there a way to have Idea be able to access the com.intellij.openapi classes? Right now they appear red in the import statements so there ends up being no code completion. It seems to me it's probably easier to write an actual plugin than to use the scripting console.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment