-
-
Notifications
You must be signed in to change notification settings - Fork 67
Scripting a macros
Dmitry Kandalov edited this page Apr 27, 2014
·
14 revisions
Almost all user actions in IntelliJ are implemented as objects of AnAction interface (including basic things like moving a cursor or deleting character). This means it is possible to simulate any user action in a script. Similar to recording a macros (Edit -> Macros) but more flexible.
The example below shows how to find action id, class and instance. It also automates enterprise best practice of null pointer driven development (write some multi-threaded code with exceptions, make it fail, fix until it works, add more exceptions).
import com.intellij.execution.*
import com.intellij.execution.executors.DefaultRunExecutor
import com.intellij.execution.filters.ConsoleInputFilterProvider
import com.intellij.execution.filters.InputFilter
import com.intellij.execution.ui.ConsoleViewContentType
import com.intellij.ide.DataManager
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Pair
import org.jetbrains.annotations.NotNull
import static FindActionUtil.*
import static com.intellij.execution.filters.ConsoleInputFilterProvider.INPUT_FILTER_PROVIDERS
import static liveplugin.PluginUtil.*
if (isIdeStartup) return
def searchForActions = false
if (searchForActions) {
// Example of finding actions:
show(allActionIds().findAll{ it.toLowerCase().contains("project") })
show(allActionClasses().findAll{ it.simpleName.toLowerCase().contains("project") })
// Once the action id or class is found, it can be invoked like this:
actionById("ActivateProjectToolWindow").actionPerformed(anActionEvent())
return
}
doInBackground {
def consoleListener = new ConsoleListener("myConsoleListener")
consoleListener.listen{ text ->
if (text.contains("NullPointerException")) {
invokeOnEDT{ actionById("Stop").actionPerformed(anActionEvent()) }
show("Oh, nooo!! Someone stopped the process!")
consoleListener.shutdown()
}
}
invokeOnEDT{ runConfiguration("VeryEnterpriseProjectMain") }
}
// there is no "Run" action for each run configuration, therefore has to be done in code
def runConfiguration(String configurationName) {
def settings = RunManager.getInstance(project).allSettings.find{ it.name.contains(configurationName) }
ProgramRunnerUtil.executeConfiguration(project, settings, DefaultRunExecutor.runExecutorInstance)
}
class FindActionUtil {
private static actionManager = ActionManager.instance
static Collection<String> allActionIds() {
actionManager.getActionIds("")
}
static Collection<Class> allActionClasses() {
actionManager.getActionIds("").collect{ actionManager.getAction(it).class }
}
static String actionIdByClass(Class aClass) {
allActionIds()
.collectEntries{ [it, actionManager.getAction(it)] }
.find{ it.value.class.isAssignableFrom(aClass) }?.key
}
static Class actionClassById(String id) {
actionManager.getAction(id).class
}
static AnAction actionById(String id) {
actionManager.getAction(id)
}
static AnAction actionByClass(Class aClass) {
actionById(actionIdByClass(aClass))
}
/**
* @see http://devnet.jetbrains.com/message/5195728#5195728
* https://github.com/JetBrains/intellij-community/blob/master/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/CheckboxAction.java#L60
*/
static anActionEvent(DataContext dataContext = DataManager.instance.dataContext, Presentation templatePresentation = new Presentation()) {
new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, templatePresentation, actionManager, 0)
}
}
/**
* @see https://github.com/dkandalov/live-plugin/wiki/Console-filtering
*/
class ConsoleListener {
private final extensionPoint = Extensions.rootArea.getExtensionPoint(INPUT_FILTER_PROVIDERS)
private final String id
ConsoleListener(String id) {
this.id = id
}
def listen(Closure callback) {
def inputFilterProvider = changeGlobalVar("myConsoleFilter") { lastInputFilterProvider ->
if (lastInputFilterProvider != null && extensionPoint.hasExtension(lastInputFilterProvider)) {
extensionPoint.unregisterExtension(lastInputFilterProvider)
}
def notFilteringListener = new InputFilter() {
@Override List<Pair<String, ConsoleViewContentType>> applyFilter(String consoleText, ConsoleViewContentType contentType) {
callback(consoleText)
null
}
}
new ConsoleInputFilterProvider() {
@Override InputFilter[] getDefaultFilters(@NotNull Project project) {
[notFilteringListener]
}
}
}
extensionPoint.registerExtension(inputFilterProvider)
this
}
def shutdown() {
def lastInputFilterProvider = removeGlobalVar("myConsoleFilter")
if (lastInputFilterProvider != null && extensionPoint.hasExtension(lastInputFilterProvider)) {
extensionPoint.unregisterExtension(lastInputFilterProvider)
}
}
}