### Groovy API Example with `PluginUtil`
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Demonstrates using the static `PluginUtil` class in Groovy plugins for registering actions, showing popups, and performing background tasks. Requires importing static methods from `liveplugin.PluginUtil`.
```groovy
// plugin.groovy
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.ide.BrowserUtil
import com.intellij.openapi.progress.ProgressIndicator
import groovy.json.JsonSlurper
import static liveplugin.PluginUtil.*
// Register a Google quick-search popup action
registerAction("GoogleSearchAction", "ctrl alt shift G") { AnActionEvent event ->
def itemProvider = { String pattern, ProgressIndicator indicator ->
def encoded = URLEncoder.encode(pattern, "UTF-8")
def json = "http://suggestqueries.google.com/complete/search?client=firefox&q=$encoded".toURL().text
new JsonSlurper().parseText(json)[1].toList()
}
showPopupSearch("Google quick search", event.project, itemProvider) { String item ->
BrowserUtil.browse("http://www.google.com/search?q=${URLEncoder.encode(item, 'UTF-8')}")
}
}
// Collect project file stats in background
registerAction("FileStats", "ctrl alt S") { AnActionEvent event ->
doInBackground("Collecting file stats") {
runReadAction {
def fileStats = com.intellij.openapi.fileTypes.FileTypeManager.instance
.registeredFileTypes.inject([:]) { stats, fileType ->
def scope = com.intellij.psi.search.GlobalSearchScope.projectScope(project)
int count = com.intellij.psi.search.FileTypeIndex.getFiles(fileType, scope).size()
if (count > 0) stats["'$fileType.defaultExtension'" ] = count
stats
}.sort { -it.value }
show("File count by type:
" + fileStats.entrySet().join("
"))
}
}
}
if (!isIdeStartup) show("Loaded Google Search and File Stats actions")
```
--------------------------------
### HTTP POST Request Example
Source: https://github.com/dkandalov/live-plugin/blob/master/src/test/liveplugin/implementation/actions/git/recorded_traffic/post-zgOK3DbuCdeHtIwqF43Agg+vumo=/request.txt
This snippet shows a sample HTTP POST request to the Live Plugin API. It includes common headers like Accept and Authorization, along with a JSON body for creating a resource.
```http
POST HTTP/1.1
Accept: application/vnd.github.v3+json
Authorization: Bearer dummy-token
{"description":"test","public":false}
```
--------------------------------
### Show Hello World Notification in Groovy
Source: https://github.com/dkandalov/live-plugin/blob/master/README.md
A simple Groovy script that displays a balloon notification popup with the text 'Hello world'. This is a basic example of using the `show` utility function.
```groovy
import static liveplugin.PluginUtil.show
show("Hello world") // Shows balloon notification popup with "Hello world" text
```
--------------------------------
### Automate NullPointerException Handling
Source: https://github.com/dkandalov/live-plugin/wiki/Scripting-a-macros
This script demonstrates a non-linear macro that automatically stops a running process if a NullPointerException is detected in the console output. It registers a console listener, starts a run configuration, and invokes the 'Stop' action if the exception occurs. Ensure you have the necessary imports from liveplugin.PluginUtil.
```groovy
import static liveplugin.PluginUtil.*
if (isIdeStartup) return
doInBackground {
registerConsoleListener("NPEConsoleListener") { consoleText ->
if (consoleText.contains("NullPointerException")) {
invokeOnEDT { actionById("Stop").actionPerformed(anActionEvent()) }
show("The process was stopped because of NullPointerException")
unregisterConsoleListener("NPEConsoleListener")
}
}
invokeOnEDT { executeRunConfiguration("VeryEnterpriseProjectMain", project) }
}
```
--------------------------------
### Register IDE or Project Tool Window
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Use `registerIdeToolWindow` for global registration or `registerProjectToolWindow` for project-specific registration. Both create a persistent tool window panel in the IDE sidebar.
```kotlin
// plugin.kts
import javax.swing.*
import liveplugin.registerIdeToolWindow
import liveplugin.show
registerIdeToolWindow("My Tool Window") {
val panel = JPanel()
val button = JButton("Click Me")
button.addActionListener { show("Button clicked in project: ${project.name}") }
panel.add(button)
panel
}
if (!isIdeStartup) show("Loaded 'My Tool Window' in the right sidebar")
```
```groovy
// plugin.groovy (Groovy equivalent)
import javax.swing.*
import static liveplugin.PluginUtil.registerToolWindow
registerToolWindow("HelloToolWindow", pluginDisposable) {
def panel = new JPanel()
def button = new JButton("Hello")
button.addActionListener({ panel.add(new JButton("World")); panel.revalidate() } as AbstractAction)
panel.add(button)
panel
}
```
--------------------------------
### Create and Show Action Popup Menu
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Use `PopupActionGroup` to construct a group of `AnAction` instances and `createPopup` to build a `ListPopup`. The popup can then be displayed in the current window.
```kotlin
// plugin.kts
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.Separator
import com.intellij.openapi.ui.Messages
import liveplugin.*
registerAction(id = "Show Actions Popup", keyStroke = "ctrl alt shift P") { event: AnActionEvent ->
PopupActionGroup("Developer Actions",
AnAction("Run Shell Command") {
val cmd = Messages.showInputDialog("Command:", "Shell", null)
if (cmd != null) show(runShellCommand(cmd).stdout)
},
AnAction("Show Project Name") { e ->
show("Project: ${e.project?.name}")
},
Separator.getInstance(),
PopupActionGroup("Open Docs",
AnAction("IntelliJ SDK Docs") { openInBrowser("https://plugins.jetbrains.com/docs/intellij/") },
AnAction("LivePlugin README") { openInBrowser("https://github.com/dkandalov/live-plugin") }
)
).createPopup(event.dataContext)
.showCenteredInCurrentWindow(event.project!!)
}
if (!isIdeStartup) show("Loaded popup — use ctrl+alt+shift+P")
```
--------------------------------
### Navigation Helpers: `openInBrowser`, `Project.openInIdeBrowser`, `Project.openInEditor`
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Helper functions to open URLs in the system browser, an internal IDE browser tab, or navigate to a file in the IDE editor. Ensure the project is available when calling `openInIdeBrowser` or `openInEditor`.
```kotlin
// plugin.kts
import liveplugin.*
import com.intellij.openapi.actionSystem.AnActionEvent
registerAction(id = "Open Docs", keyStroke = "ctrl alt shift D") { event: AnActionEvent ->
// Open in system browser
openInBrowser("https://plugins.jetbrains.com/docs/intellij/fundamentals.html")
// Open in IDE's built-in browser panel
event.project?.openInIdeBrowser("https://github.com/dkandalov/live-plugin", "LivePlugin Docs")
// Open a file in the code editor
event.project?.openInEditor("$pluginPath/plugin.kts")
}
if (!isIdeStartup) show("Docs actions loaded")
```
--------------------------------
### Register Project Open Listener
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Subscribes to project lifecycle events. The callback fires immediately for all currently open projects and then for each newly opened project. Automatically unsubscribed when the `disposable` is disposed.
```kotlin
import liveplugin.registerProjectOpenListener
import liveplugin.show
registerProjectOpenListener(pluginDisposable) { project ->
show("Project opened: ${project.name}")
// Set up project-specific tooling here, e.g. register actions or tool windows scoped to this project
}
```
--------------------------------
### Console Output with `Project.showInConsole`
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Prints messages to a dedicated Run console tab, supporting different content types like normal output and error output. The console tab is identified by a title.
```kotlin
// plugin.kts
import com.intellij.execution.ui.ConsoleViewContentType
import liveplugin.showInConsole
import liveplugin.show
registerAction(id = "Run Analysis", keyStroke = "ctrl alt R") { event ->
val proj = event.project ?: return@registerAction
val console = proj.showInConsole("Starting analysis...\n", consoleTitle = "My Plugin")
console.print("Found 42 issues\n", ConsoleViewContentType.ERROR_OUTPUT)
console.print("Done.\n", ConsoleViewContentType.NORMAL_OUTPUT)
}
```
--------------------------------
### Create Repository
Source: https://github.com/dkandalov/live-plugin/blob/master/src/test/liveplugin/implementation/actions/git/recorded_traffic/post-zgOK3DbuCdeHtIwqF43Agg+vumo=/request.txt
This endpoint allows you to create a new repository. You can specify details such as the repository name, description, and privacy settings.
```APIDOC
## POST /user/repos
### Description
Creates a new repository for the authenticated user.
### Method
POST
### Endpoint
/user/repos
### Request Body
- **description** (string) - Required - The description of the repository.
- **public** (boolean) - Required - Whether the repository is public or private.
```
--------------------------------
### Threading Utilities: runOnEdtWithWriteLock, runWithReadLock, runLaterOnEdt
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Helpers for IntelliJ's threading model. `runWithReadLock` safely reads PSI off-EDT. `runBackgroundTask` does heavy work in the background. `runLaterOnEdt` schedules UI updates on the EDT. `runOnEdtWithWriteLock` modifies documents synchronously on the EDT with a write lock.
```kotlin
import liveplugin.*
registerAction(id = "Threading Demo", keyStroke = "ctrl alt T") { event ->
// Read PSI off-EDT safely
val className = runWithReadLock {
event.psiFile?.name ?: "unknown"
}
// Do heavy work in background
runBackgroundTask("Processing") { _ ->
Thread.sleep(500) // simulate work
"Result for $className"
}.thenAccept { result ->
// Update UI on EDT
runLaterOnEdt {
show(result)
}
}
// Synchronous EDT + write lock: modify a document
runOnEdtWithWriteLock {
event.document?.insertString(0, "// processed\n")
}
}
```
--------------------------------
### registerIdeToolWindow / registerProjectToolWindow
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Creates a persistent tool window panel in the IDE sidebar. `registerIdeToolWindow` registers the window for all open and future projects; `registerProjectToolWindow` registers it only in the current project.
```APIDOC
## `registerIdeToolWindow` / `registerProjectToolWindow` — Register a custom tool window
### Description
Creates a persistent tool window panel in the IDE sidebar. `registerIdeToolWindow` registers the window for all open and future projects; `registerProjectToolWindow` registers it only in the current project.
### Usage
```kotlin
// plugin.kts
import javax.swing.*
import liveplugin.registerIdeToolWindow
import liveplugin.show
registerIdeToolWindow("My Tool Window") { project ->
val panel = JPanel()
val button = JButton("Click Me")
button.addActionListener { show("Button clicked in project: ${project.name}") }
panel.add(button)
panel
}
if (!isIdeStartup) show("Loaded 'My Tool Window' in the right sidebar")
```
```groovy
// plugin.groovy (Groovy equivalent)
import javax.swing.*
import static liveplugin.PluginUtil.registerToolWindow
registerToolWindow("HelloToolWindow", pluginDisposable) {
def panel = new JPanel()
def button = new JButton("Hello")
button.addActionListener({ panel.add(new JButton("World")); panel.revalidate() } as AbstractAction)
panel.add(button)
panel
}
```
```
--------------------------------
### registerProjectOpenListener
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Subscribes to project open and close events. The callback is triggered for all currently open projects and for each newly opened project. The listener is automatically unsubscribed when the provided `disposable` is disposed.
```APIDOC
## Project Lifecycle Events
### Description
Subscribes to project lifecycle events. The callback fires immediately for all currently open projects, and then again for each newly opened project. Automatically unsubscribed when the `disposable` is disposed.
### Method
`registerProjectOpenListener(disposable: Disposable, callback: (project: Project) -> Unit)`
### Parameters
* **disposable** (Disposable) - Required - The disposable object that will manage the lifecycle of the listener.
* **callback** (Function) - Required - A function that takes a `Project` object as input and is executed when a project is opened.
```
--------------------------------
### Find and Invoke IntelliJ Actions
Source: https://github.com/dkandalov/live-plugin/wiki/Scripting-a-macros
Use this script to find actions by name or ID and then invoke them. Ensure you have the necessary imports from liveplugin.PluginUtil and liveplugin.implementation.ActionSearch.
```groovy
import static liveplugin.PluginUtil.*
import static liveplugin.implementation.ActionSearch.allActionIds
if (isIdeStartup) return
show(allActions().findAll { it.class.simpleName.contains("ToolWindow") })
show(allActionIds().findAll { it.contains("ToolWindow") })
def action = actionById("ActivateProjectToolWindow")
// or ActionManager.instance.getAction("ActivateProjectToolWindow")
// Once you have instance of an action, you can invoke it like this
action.actionPerformed(anActionEvent())
```
--------------------------------
### Use functions from multiple files in plugin.kts
Source: https://context7.com/dkandalov/live-plugin/llms.txt
The main `plugin.kts` file can import and use functions defined in other `.kt` files, including those in sub-packages.
```kotlin
import bar.bar
import liveplugin.show
show(foo()) // "Hello from foo"
show(bar()) // "Hello from bar"
```
--------------------------------
### Threading Utilities: runOnEdtWithWriteLock, runWithReadLock, runLaterOnEdt
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Provides essential helpers for managing threads within IntelliJ's threading model. Safely reads PSI off-EDT, performs heavy work in the background, and updates the UI on the Event Dispatch Thread (EDT).
```APIDOC
## Threading Utilities
### Description
Helpers for IntelliJ's threading model: reads require a read lock (or EDT), writes require a write lock on EDT. `runLaterOnEdt` schedules work asynchronously on the Event Dispatch Thread.
### Methods
* **`runWithReadLock(task: () -> T): T`**: Executes a task under a read lock. Suitable for reading PSI or other data structures that require a read lock.
* **`runOnEdtWithWriteLock(task: () -> Unit)`**: Executes a task on the EDT under a write lock. Use for modifying documents or other mutable states that require a write lock on the EDT.
* **`runLaterOnEdt(task: () -> Unit)`**: Schedules a task to be executed asynchronously on the Event Dispatch Thread.
### Parameters
* **task** (Function) - The code block to execute on the appropriate thread with the required lock.
```
--------------------------------
### Define function in a subpackage bar/bar.kt
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Functions within sub-packages are accessible by importing the package. Ensure the file is placed in the correct directory structure.
```kotlin
package bar
fun bar() = "Hello from bar"
```
--------------------------------
### PopupActionGroup / ActionGroup.createPopup
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Creates a popup menu from a group of `AnAction` instances. `PopupActionGroup` constructs the group; `createPopup` builds a `ListPopup` that can be shown in the current window.
```APIDOC
## `PopupActionGroup` / `ActionGroup.createPopup` — Show an action popup menu
### Description
Creates a popup menu from a group of `AnAction` instances. `PopupActionGroup` constructs the group; `createPopup` builds a `ListPopup` that can be shown in the current window.
### Usage
```kotlin
// plugin.kts
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.Separator
import com.intellij.openapi.ui.Messages
import liveplugin.*
registerAction(id = "Show Actions Popup", keyStroke = "ctrl alt shift P") { event: AnActionEvent ->
PopupActionGroup("Developer Actions",
AnAction("Run Shell Command") {
val cmd = Messages.showInputDialog("Command:", "Shell", null)
if (cmd != null) show(runShellCommand(cmd).stdout)
},
AnAction("Show Project Name") { e ->
show("Project: ${e.project?.name}")
},
Separator.getInstance(),
PopupActionGroup("Open Docs",
AnAction("IntelliJ SDK Docs") { openInBrowser("https://plugins.jetbrains.com/docs/intellij/") },
AnAction("LivePlugin README") { openInBrowser("https://github.com/dkandalov/live-plugin") }
)
).createPopup(event.dataContext)
.showCenteredInCurrentWindow(event.project!!)
}
if (!isIdeStartup) show("Loaded popup — use ctrl+alt+shift+P")
```
```
--------------------------------
### Clone IntelliJ Community Repository
Source: https://github.com/dkandalov/live-plugin/blob/master/IntellijApiCheatSheet.md
Clone the IntelliJ Community Edition source code from GitHub to explore the API in detail.
```bash
git clone https://github.com/JetBrains/intellij-community.git
```
--------------------------------
### Run Background Task with Progress Indicator
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Executes a task on a background thread, showing a progress indicator in the IDE status bar. The callback runs off-EDT; use `runLaterOnEdt` to update the UI.
```kotlin
import liveplugin.runBackgroundTask
import liveplugin.show
import liveplugin.runLaterOnEdt
registerAction(id = "Analyze Project Files", keyStroke = "ctrl alt A") {
runBackgroundTask(taskTitle = "Counting project files", canBeCancelledInUI = true) { indicator ->
indicator.text = "Scanning..."
val path = java.io.File(project?.basePath ?: return@runBackgroundTask 0)
val count = path.walkTopDown()
.onEach { indicator.checkCanceled() }
.count { it.extension == "kt" }
count
}.thenAccept { count ->
runLaterOnEdt { show("Found $count Kotlin files") }
}
}
if (!isIdeStartup) show("Loaded background task action")
```
--------------------------------
### Define helper function in utils.kt
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Helper functions can be defined in separate `.kt` files and are accessible from `plugin.kts`.
```kotlin
fun foo() = "Hello from foo"
```
--------------------------------
### Execute Shell Commands or Scripts
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Use `runShellCommand` for external commands or `runShellScript` for inline scripts. Both return a `CommandResult` object containing stdout, stderr, and exit code. Handle potential errors by checking `exitCode`.
```kotlin
// plugin.kts
import liveplugin.runShellCommand
import liveplugin.runShellScript
import liveplugin.show
registerAction(id = "Git Log Summary", keyStroke = "ctrl alt G") {
val result = runShellCommand("git", "-C", project?.basePath ?: ".", "log", "--oneline", "-10")
if (result.exitCode == 0) {
show(result.stdout.replace("\n", "
"))
} else {
show("Error: ${result.stderr}", title = "Git Error")
}
}
registerAction(id = "Count Source Files", keyStroke = "ctrl alt F") {
val result = runShellScript("""
find ${project?.basePath} -name "*.kt" | wc -l
""".trimIndent())
show("Kotlin files: ${result.stdout.trim()}")
}
if (!isIdeStartup) show("Git and file actions loaded")
```
--------------------------------
### Display Balloon Notifications with `show`
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Use the `show` function to display popup notifications in the IDE. It supports plain text, HTML messages, custom titles, notification types, and group IDs. Implicit script variables like `isIdeStartup`, `project`, and `pluginPath` can be included in messages.
```kotlin
// plugin.kts
import liveplugin.show
import com.intellij.notification.NotificationType
// Simple message
show("Hello world")
// With HTML and title
show(
message = "Build succeeded in 3.2s",
title = "Build Result",
notificationType = NotificationType.INFORMATION,
groupDisplayId = "Live Plugin"
)
// Show implicit script variables
show("isIdeStartup: $isIdeStartup")
show("project: ${project?.name}")
show("pluginPath: $pluginPath")
```
--------------------------------
### runBackgroundTask
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Executes a task on a background thread, displaying a progress indicator in the IDE status bar. The task can be cancelled via the UI. Returns a CompletableFuture, and UI updates should be performed using `runLaterOnEdt`.
```APIDOC
## runBackgroundTask
### Description
Executes a task on a background thread with a progress indicator shown in the IDE status bar. Returns a `CompletableFuture`. The callback runs off-EDT; update UI inside `runLaterOnEdt`.
### Method
`runBackgroundTask(taskTitle: String, canBeCancelledInUI: Boolean = false, task: (indicator: ProgressIndicator) -> T): CompletableFuture`
### Parameters
* **taskTitle** (String) - Required - The title to display for the background task.
* **canBeCancelledInUI** (Boolean) - Optional - Whether the task can be cancelled by the user through the UI. Defaults to false.
* **task** (Function) - Required - The background task to execute. It receives a `ProgressIndicator` and should return a result of type `T`.
### Response
* **CompletableFuture** - A future that will complete with the result of the background task.
```
--------------------------------
### Modify Editor Document with Undo/Redo Support
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Wraps document modifications in a CommandProcessor command for undo/redo support. Must be called from within an action running on EDT. Use for inserting, replacing, or deleting text.
```kotlin
import com.intellij.openapi.actionSystem.AnActionEvent
import liveplugin.*
registerAction(id = "Insert Hello World", keyStroke = "ctrl shift W") { event: AnActionEvent ->
val project = event.project ?: return@registerAction
val editor = event.editor ?: return@registerAction
editor.document.executeCommand(project, description = "Insert Hello World") {
// 'this' is the Document inside the lambda
insertString(editor.caretModel.offset, "/* Hello world */")
}
}
if (!isIdeStartup) show("Loaded 'Insert Hello World' — use ctrl+shift+W")
```
--------------------------------
### Reorder New Kotlin File Action in IntelliJ IDEA
Source: https://github.com/dkandalov/live-plugin/blob/master/src/test/liveplugin/implementation/actions/git/recorded_traffic/d51de2311dfd92dfa56feb3e3f9f96a6/get-PBpuSBYgsBooJLVO2y4HQ2xv0Xs=/response.txt
Use this Kotlin code to reorder the 'New Kotlin File' action to the first position in the 'New' action group. This requires access to the ActionManager and specific action IDs.
```Kotlin
import com.intellij.openapi.actionSystem.*
val newElementActionGroup = ActionManager.getInstance().getAction(IdeActions.GROUP_NEW) as DefaultActionGroup
val newKotlinFileAction = ActionManager.getInstance().getAction("Kotlin.NewFile") as AnAction
newElementActionGroup.remove(newKotlinFileAction)
newElementActionGroup.add(newKotlinFileAction, Constraints.FIRST)
```
--------------------------------
### registerWidget
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Adds a custom widget to the IDE status bar. Accepts a `StatusBarWidget.WidgetPresentation` (e.g. `TextPresentation`) and is automatically removed when `pluginDisposable` is disposed.
```APIDOC
## `registerWidget` — Register a status bar widget
### Description
Adds a custom widget to the IDE status bar. Accepts a `StatusBarWidget.WidgetPresentation` (e.g. `TextPresentation`) and is automatically removed when `pluginDisposable` is disposed.
### Usage
```kotlin
// plugin.kts
import com.intellij.openapi.wm.StatusBarWidget
import liveplugin.registerWidget
import liveplugin.show
import java.awt.Component
var counter = 0
registerWidget(
widgetId = "MyCounterWidget",
disposable = pluginDisposable,
presentation = object : StatusBarWidget.TextPresentation {
override fun getText() = "Calls: $counter"
override fun getAlignment() = Component.CENTER_ALIGNMENT
override fun getTooltipText() = "Number of registered actions called"
override fun getClickConsumer() = null
}
)
registerAction(id = "Increment Counter", keyStroke = "ctrl alt I") {
counter++
// Call updateWidget("MyCounterWidget") to refresh display (Groovy API)
show("Counter is now $counter")
}
if (!isIdeStartup) show("Loaded counter widget and action")
```
```
--------------------------------
### Groovy Script for Reloading Java Plugins with Liveplugin
Source: https://github.com/dkandalov/live-plugin/wiki/Liveplugin-as-an-entry-point-for-standard-plugins
This Groovy script is used with Liveplugin to manage the lifecycle of a Java-based plugin. It ensures proper disposal of the previous plugin instance before initializing a new one. The `add-to-classpath` directive is crucial for including the compiled plugin JAR.
```groovy
import net.vektah.codeglance.CodeGlancePlugin
import static liveplugin.PluginUtil.changeGlobalVar
import static liveplugin.PluginUtil.show
// The path below should point to the jar file generated by IDEA
// add-to-classpath $HOME/Library/Application Support/IntelliJIdea13/live-plugins/CodeGlance/classes/artifacts/CodeGlance_jar/*.jar
if (isIdeStartup) return
changeGlobalVar("codeGlance") { previousPlugin ->
if (previousPlugin != null) {
previousPlugin.disposeComponent()
show("Disposed previous CodeGlancePlugin")
}
def plugin = new CodeGlancePlugin(project)
plugin.initComponent()
plugin
}
show("Reloaded CodeGlancePlugin")
```
--------------------------------
### Register Keyboard-Triggered Actions with `registerAction`
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Register custom IDE actions that can be triggered by keyboard shortcuts. Actions are automatically unregistered on plugin reload. Supports lambda-based actions and AnAction subclasses, with options for shortcuts, menu group placement, and dynamic enablement via `update()`.
```kotlin
// plugin.kts
import com.intellij.openapi.actionSystem.AnActionEvent
import liveplugin.*
// Lambda form — simplest usage
registerAction(id = "Insert New Line Above", keyStroke = "ctrl alt shift ENTER") { event: AnActionEvent ->
val project = event.project ?: return@registerAction
val editor = event.editor ?: return@registerAction
editor.document.executeCommand(project, "Insert New Line Above") {
val lineStart = getLineStartOffset(editor.caretModel.logicalPosition.line)
insertString(lineStart, "\n")
editor.caretModel.moveToOffset(editor.caretModel.offset + 1)
}
}
// AnAction subclass form — allows implementing update() for dynamic enablement
import com.intellij.openapi.project.DumbAware
class ShowProjectPathAction : AnAction("Show Project Path"), DumbAware {
override fun actionPerformed(event: AnActionEvent) =
show("Project path: ${event.project?.basePath}")
}
registerAction(id = "Show Project Path", keyStroke = "ctrl shift H", action = ShowProjectPathAction())
// Add action to a menu group (e.g., Tools menu)
registerAction(
id = "My Tools Action",
keyStroke = "ctrl alt M",
actionGroupId = ActionGroupIds.Menu.Tools
) { show("Running from Tools menu!") }
if (!isIdeStartup) show("Actions loaded")
```
--------------------------------
### Registering Custom Console Input Filters
Source: https://github.com/dkandalov/live-plugin/wiki/Console-filtering
This Groovy script registers custom input filters to modify console output. It defines filters to 'beautify' exceptions and hide lines containing 'INFO - '. The filters are then registered via the `INPUT_FILTER_PROVIDERS` extension point.
```groovy
import com.intellij.execution.filters.ConsoleInputFilterProvider
import com.intellij.execution.filters.InputFilter
import com.intellij.execution.ui.ConsoleViewContentType as ContentType
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Pair
import org.jetbrains.annotations.NotNull
import static liveplugin.PluginUtil.*
import com.intellij.openapi.extensions.Extensions
import static com.intellij.execution.filters.ConsoleInputFilterProvider.*
import static com.intellij.execution.ui.ConsoleViewContentType.NORMAL_OUTPUT
if (isIdeStartup) return
def beautifyExceptions() {
new InputFilter() {
@Override List> applyFilter(String consoleText, ContentType contentType) {
if (!consoleText.contains("Exception")) null
else [new Pair(consoleText.replace("Exception", "Usualness"), contentType)]
}
}
}
def linesWithout(String text) {
new InputFilter() {
@Override List> applyFilter(String consoleText, ContentType contentType) {
consoleText.contains(text) ? [] : null
}
}
}
def createInputFilterProvider() {
new ConsoleInputFilterProvider() {
@Override InputFilter[] getDefaultFilters(@NotNull Project project) {
[beautifyExceptions(), linesWithout("INFO - ")]
}
}
}
def extensionPoint = Extensions.rootArea.getExtensionPoint(INPUT_FILTER_PROVIDERS)
def inputFilterProvider = changeGlobalVar("myConsoleFilter") {
if (lastInputFilterProvider != null && extensionPoint.hasExtension(lastInputFilterProvider)) {
extensionPoint.unregisterExtension(lastInputFilterProvider)
}
createInputFilterProvider()
}
extensionPoint.registerExtension(inputFilterProvider)
def console = showInConsole("-----\\n", project)
console.print("INFO - which will be invisible\\n", NORMAL_OUTPUT)
console.print("ERROR - beautified java.lang.NullPointerException\\n", NORMAL_OUTPUT)
console.print("-----\\n", NORMAL_OUTPUT)
```
--------------------------------
### Register Google Auto-Complete Contributor in Kotlin
Source: https://github.com/dkandalov/live-plugin/wiki/Google-auto-complete
Registers a custom auto-completion contributor for Kotlin language and basic completion type. It fetches Google suggestions based on the current prefix and adds them to the result set. Ensure the plugin is not running during IDE startup to avoid issues.
```kotlin
import com.google.gson.Gson
import com.google.gson.JsonArray
import com.intellij.codeInsight.completion.*
import com.intellij.codeInsight.completion.CompletionType.BASIC
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.lang.Language
import com.intellij.lang.LanguageExtension
import com.intellij.openapi.Disposable
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.psi.PsiElement
import com.intellij.util.ProcessingContext
import liveplugin.PluginUtil.show
import liveplugin.getStaticField
import java.net.URL
import java.net.URLEncoder
if (!isIdeStartup) {
val language = Language.findLanguageByID("kotlin")!!
registerCompletionContributor(language, BASIC, psiElement(), pluginDisposable) { _, _, result ->
result.addAllElements(
findSuggestionsFor(result.prefixMatcher.prefix)
.map { LookupElementBuilder.create(it.toCamelCase()) }
)
}
show("Loaded auto-completion contributor")
}
fun registerCompletionContributor(
language: Language,
completionType: CompletionType,
elementPattern: ElementPattern,
disposable: Disposable,
callback: (CompletionParameters, ProcessingContext, CompletionResultSet) -> Unit
) {
val languageExtension = CompletionContributor::class.java.getStaticField>("INSTANCE")
// languageExtension.clearCache()
val contributor = object : CompletionContributor() {}
contributor.extend(completionType, elementPattern, object : CompletionProvider() {
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
callback(parameters, context, result)
}
})
languageExtension.addExplicitExtension(language, contributor, disposable)
}
val gson = Gson()
fun findSuggestionsFor(text: String): List {
val encodedText = URLEncoder.encode(text, "UTF-8")
val json = URL("https://suggestqueries.google.com/complete/search?client=firefox&q=$encodedText").readText()
return (gson.fromJson(json, JsonArray::class.java).get(1) as JsonArray).map { it.asString }
.filter { !it.equals(text, ignoreCase = true) }
}
fun String.toCamelCase() =
split(" ").joinToString("") { word -> word.replaceFirstChar { it.titlecase() } }
```
--------------------------------
### registerConsoleFilter / registerConsoleListener
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Allows interception and manipulation of console output in real time. `registerConsoleFilter` can transform or suppress lines, while `registerConsoleListener` observes lines without modification.
```APIDOC
## Console Output Interception
### Description
Intercepts console output in real time. `registerConsoleFilter` can transform or suppress console lines; `registerConsoleListener` observes lines without modifying them.
### Methods
* **`registerConsoleFilter(disposable: Disposable, filter: (text: String) -> String?)`**: Registers a filter for console output. The filter function receives a line of text and can return a modified string, an empty string to suppress the line, or null to leave it unchanged.
* **`registerConsoleListener(disposable: Disposable, listener: (text: String) -> Unit)`**: Registers a listener for console output. The listener function receives a line of text and can perform actions based on it, but cannot modify the output.
### Parameters
* **disposable** (Disposable) - Required - The disposable object that will manage the lifecycle of the listener/filter.
* **filter** (Function) - Required for `registerConsoleFilter` - A function that takes console output text and returns a modified string, an empty string, or null.
* **listener** (Function) - Required for `registerConsoleListener` - A function that takes console output text and performs an action.
```
--------------------------------
### Register 'Insert New Line Above' Action in Kotlin
Source: https://github.com/dkandalov/live-plugin/blob/master/README.md
A Kotlin script that registers a custom action to insert a new line above the current cursor position. It utilizes LivePlugin's `registerAction` and `executeCommand` utilities. The action is assigned a hotkey and provides feedback upon successful loading.
```kotlin
import com.intellij.openapi.actionSystem.AnActionEvent
import liveplugin.*
// Action to insert a new line above the current line.
// Based on this post https://martinfowler.com/bliki/InternalReprogrammability.html
// Note that there is also built-in "Start New Line Before Current" action (ctrl+alt+enter).
registerAction(id = "Insert New Line Above", keyStroke = "ctrl alt shift ENTER") { event: AnActionEvent ->
val project = event.project ?: return@registerAction
val editor = event.editor ?: return@registerAction
executeCommand(editor.document, project) { document ->
val caretModel = editor.caretModel
val lineStartOffset = document.getLineStartOffset(caretModel.logicalPosition.line)
document.insertString(lineStartOffset, "\n")
caretModel.moveToOffset(caretModel.offset + 1)
}
}
show("Loaded 'Insert New Line Above' action
Use 'ctrl+alt+shift+Enter' to run it")
```
--------------------------------
### Extend Classloader with `add-to-classpath` and `depends-on-plugin`
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Use special comment directives to add external JARs to the plugin's classloader or depend on other IDE plugin APIs. Paths support glob wildcards and environment variables.
```kotlin
// plugin.kts
// add-to-classpath $HOME/.gradle/caches/modules-2/files-2.1/org.http4k/http4k-core/4.17.0.0/*/*.jar
// depends-on-plugin Git4Idea
// depends-on-plugin org.jetbrains.kotlin
import liveplugin.show
import org.http4k.core.Request
import org.http4k.core.Method
import git4idea.GitUtil
registerAction(id = "HTTP and Git Demo", keyStroke = "ctrl alt D") {
// Use http4k from external classpath
val request = Request(Method.GET, "https://example.com")
show("Request created: $request")
// Use Git4Idea bundled plugin API
val repos = GitUtil.getRepositories(project!!)
show("Git repos: ${repos.map { it.root.name }}")
}
if (!isIdeStartup) show("Loaded HTTP + Git demo")
```
--------------------------------
### Reflection Access: getProperty, getField, invoke
Source: https://context7.com/dkandalov/live-plugin/llms.txt
Utility functions for accessing private fields, properties, and methods in IntelliJ Platform classes. Useful for exploratory hacking when no public API exists.
```kotlin
import liveplugin.getProperty
import liveplugin.getField
import liveplugin.invoke
import com.intellij.openapi.actionSystem.ActionManager
import liveplugin.show
// Access a private field by name and type
val actionManager = ActionManager.getInstance()
val actionMap = actionManager.getField