|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This repository is an IntelliJ Platform plugin written in Kotlin. It provides a "Developer Tools" tool window, standalone dialog, editor popup actions, and intention actions for common developer utilities. |
| 4 | + |
| 5 | +Use this file as the working map for future AI agents. It explains where the important code lives, how tools are registered, how state is persisted, and what commands to run before handing work back. |
| 6 | + |
| 7 | +## Project Shape |
| 8 | + |
| 9 | +- Root Gradle project: `intellij-developer-tools-plugin` |
| 10 | +- Build system: Gradle Kotlin DSL with `org.jetbrains.intellij.platform` plugin. |
| 11 | +- Language/runtime: Kotlin/JVM on Java 21. |
| 12 | +- Minimum IDE build and platform are controlled from `gradle.properties`. |
| 13 | +- The default `platform=idea` includes Java- and Kotlin-dependent modules. Non-IDEA platforms only include the platform/common modules. |
| 14 | +- Plugin id is intentionally misspelled as `dev.turingcomplete.intellijdevelopertoolsplugins`; do not "fix" it. |
| 15 | + |
| 16 | +Important root files: |
| 17 | + |
| 18 | +- `build.gradle.kts`: root build, IntelliJ plugin packaging, signing, publishing, verification, common test/compiler config. |
| 19 | +- `settings.gradle.kts`: module inclusion; conditionally includes `java-dependent` and `kotlin-dependent` when `platform == "idea"`. |
| 20 | +- `gradle/libs.versions.toml`: dependency and plugin versions. |
| 21 | +- `gradle.properties`: plugin metadata, platform version, bundled plugins, Kotlin stdlib opt-out. |
| 22 | +- `src/main/resources/META-INF/plugin.xml`: main plugin descriptor and extension-point registry. |
| 23 | +- `src/main/resources/META-INF/dev.turingcomplete.intellijdevelopertoolsplugins-withJava.xml`: optional Java plugin integrations. |
| 24 | +- `src/main/resources/META-INF/dev.turingcomplete.intellijdevelopertoolsplugins-withKotlin.xml`: optional Kotlin plugin integrations. |
| 25 | + |
| 26 | +## Modules |
| 27 | + |
| 28 | +- `modules/common`: shared utilities, i18n bundle wrapper, plugin info, editor helpers, crypto/hash/text helpers, test fixtures. |
| 29 | +- `modules/settings`: application and instance settings, settings UI abstractions, persistence and legacy migration for tool configurations. |
| 30 | +- `modules/tools/editor`: editor popup actions and generic editor intentions for selected text. |
| 31 | +- `modules/tools/ui`: the main UI tool framework, tool window/dialog implementation, all UI tools, shared Swing/UI DSL components, test fixtures. |
| 32 | +- `modules/java-dependent`: Java PSI-specific editor actions and intentions. Only loaded through optional Java descriptor. |
| 33 | +- `modules/kotlin-dependent`: Kotlin PSI-specific editor actions and intentions. Only loaded through optional Kotlin descriptor. |
| 34 | +- `src/test`: root-level integration tests around plugin XML and cross-module tool behavior. |
| 35 | + |
| 36 | +## Plugin Entry Points |
| 37 | + |
| 38 | +The main descriptor is `src/main/resources/META-INF/plugin.xml`. |
| 39 | + |
| 40 | +It declares: |
| 41 | + |
| 42 | +- Required dependencies: platform, lang, json. |
| 43 | +- Optional dependencies: `com.intellij.java` and `org.jetbrains.kotlin`, each with its own descriptor. |
| 44 | +- Tool window: `MainToolWindowFactory`, id `Developer Tools`. |
| 45 | +- Standalone dialog action: `OpenMainDialogAction`, added to `ToolsMenu`. |
| 46 | +- Editor popup group: `DeveloperToolsActionGroup`, added to `EditorPopupMenu`. |
| 47 | +- Main selected-text intention: `DataGeneratorIntentionAction`. |
| 48 | +- Settings configurable: `GeneralSettingsConfigurable` with nested `JsonHandlingSettingsConfigurable`. |
| 49 | +- Keymap extension: `ShowDeveloperUiToolKeymapExtension`. |
| 50 | +- Custom extension points: |
| 51 | + - `developerUiTool`: registers tool factories. |
| 52 | + - `developerUiToolGroup`: registers menu groups. |
| 53 | + - `developerToolConfigurationEnumPropertyType`: registers enum types that can be persisted in tool settings. |
| 54 | + |
| 55 | +The Java/Kotlin optional descriptors add language-specific intentions and editor action groups. Keep those registrations out of the main descriptor unless they do not depend on Java/Kotlin APIs. |
| 56 | + |
| 57 | +## UI Tool Framework |
| 58 | + |
| 59 | +Most new user-facing utilities should be implemented as a `DeveloperUiTool` in `modules/tools/ui`. |
| 60 | + |
| 61 | +Core classes: |
| 62 | + |
| 63 | +- `DeveloperUiTool`: base class for a tool UI. Subclasses implement `Panel.buildUi()`. It wraps UI DSL output, registers validation, supports activation/deactivation, reset, disposal, scroll wrapping, and optional `DataProvider` data. |
| 64 | +- `DeveloperUiToolFactory<T>`: creates tools and returns `DeveloperUiToolPresentation`. |
| 65 | +- `DeveloperUiToolFactoryEp`: extension-point bean for `developerUiTool`; reads `id`, `implementationClass`, `groupId`, `preferredSelected`, and `internalTool` from `plugin.xml`. |
| 66 | +- `DeveloperUiToolContext`: carries the extension id and whether vertical layout should be preferred, mainly for tool-window layout. |
| 67 | +- `DeveloperUiToolPresentation`: titles/descriptions used in menu, grouped menu, and content panel. |
| 68 | +- `DeveloperUiToolGroup`: extension-point bean for grouping tools in the menu tree. |
| 69 | + |
| 70 | +Registration flow: |
| 71 | + |
| 72 | +1. `plugin.xml` registers a `<developerUiTool id="..." implementationClass="...$Factory"/>`. |
| 73 | +2. `ToolsMenuTree` reads `DeveloperUiToolFactoryEp.EP_NAME`. |
| 74 | +3. Each factory is instantiated and asked for a tool creator. |
| 75 | +4. `DeveloperToolNode` restores or creates `DeveloperToolConfiguration` workbenches. |
| 76 | +5. `DeveloperToolContentPanel` creates tabs, calls `DeveloperUiTool.createComponent()`, and drives `activated()`/`deactivated()`. |
| 77 | + |
| 78 | +If a factory returns `null` from `getDeveloperUiToolCreator`, the tool is hidden for that context. This is useful for project-dependent tools. |
| 79 | + |
| 80 | +## Dialog And Tool Window |
| 81 | + |
| 82 | +Two instances expose the same tool framework with different persistence scopes: |
| 83 | + |
| 84 | +- Dialog: |
| 85 | + - `OpenMainDialogAction` opens `MainDialogService`. |
| 86 | + - `MainDialog` uses `ContentPanelHandler` and `DeveloperToolsDialogSettings`. |
| 87 | + - Dialog inputs/configuration are application-level. |
| 88 | + |
| 89 | +- Tool window: |
| 90 | + - `MainToolWindowFactory` creates async tool-window content. |
| 91 | + - `MainToolWindowService` stores and opens/selects tool-window content. |
| 92 | + - `ToolWindowContentPanelHandler` uses `DeveloperToolsToolWindowSettings`. |
| 93 | + - Tool-window inputs/configuration are project-level. |
| 94 | + |
| 95 | +`ContentPanelHandler` is the shared coordinator. It owns the menu tree, switches group/tool panels, caches panels depending on `generalSettings.toolWindowUiCacheUi`, and implements `openTool()`/`showTool()`. |
| 96 | + |
| 97 | +## Settings And Persistence |
| 98 | + |
| 99 | +Application settings: |
| 100 | + |
| 101 | +- `DeveloperToolsApplicationSettings` is an app service persisted to `developer-tools.xml`. |
| 102 | +- It contains `GeneralSettings`, `InternalSettings`, and `JsonHandlingSettings`. |
| 103 | +- Settings interfaces use annotations from `modules/settings/.../base`. |
| 104 | + |
| 105 | +Tool instance settings: |
| 106 | + |
| 107 | +- `DeveloperToolsInstanceSettings` is the base `PersistentStateComponent`. |
| 108 | +- `DeveloperToolsDialogSettings` stores dialog state at app level. |
| 109 | +- `DeveloperToolsToolWindowSettings` stores tool-window state at project level. |
| 110 | +- Each UI tool workbench has a `DeveloperToolConfiguration`. |
| 111 | +- Tool properties are registered by calling `configuration.register("key", defaultValue, propertyType, example)`. |
| 112 | + |
| 113 | +Persistence details to respect: |
| 114 | + |
| 115 | +- Only changed properties are persisted. |
| 116 | +- `PropertyType.CONFIGURATION`, `INPUT`, and `SENSITIVE` are filtered by general settings. |
| 117 | +- Sensitive values are not saved unless `saveSensitiveInputs` is enabled. |
| 118 | +- Supported built-in persisted value types are in `DeveloperToolsInstanceSettings.builtInConfigurationPropertyTypes`. |
| 119 | +- Enum configuration values must be registered in `plugin.xml` via `<developerToolConfigurationEnumPropertyType ...>`. |
| 120 | +- If renaming property keys or moving enum classes, update `DeveloperToolsInstanceSettingsLegacy` and the legacy test resources under `src/test/resources/.../instancesettings`. |
| 121 | + |
| 122 | +## Tool Implementation Patterns |
| 123 | + |
| 124 | +Common base classes in `modules/tools/ui/src/main/kotlin/.../tool/ui`: |
| 125 | + |
| 126 | +- `converter/base/Converter`: two-pane conversion base with source/target handlers, live conversion, validation, diff support, file/text handlers, and background conversion for heavy work. |
| 127 | +- `converter/base/UndirectionalConverter`: one-way converter UI. |
| 128 | +- `EncoderDecoder`: bidirectional converter base for encoding/decoding tools. |
| 129 | +- `OneLineTextGenerator`: generator base for UUID/password/NanoID/etc.; handles generated value, copy, regenerate, and bulk generation. |
| 130 | +- `MultiLineTextGenerator`: generator base for multi-line output. |
| 131 | +- `AdvancedEditor`: shared editor component with input/output modes and diff support. |
| 132 | +- `AsyncTaskExecutor`: debounced async UI/background task helper. |
| 133 | +- `FileHandling`, `ErrorHolder`, validation helpers, regex helpers, and copy actions in `tool/ui/common`. |
| 134 | + |
| 135 | +Tool categories and representative files: |
| 136 | + |
| 137 | +- Converters: `tool/ui/converter`, including Base32/Base64, URL, ASCII, text format, date/time, CLI command, JWT, units. |
| 138 | +- Transformers: `tool/ui/transformer`, including hashing/HMAC, text case, sorting/filtering, JSON Path, SQL and code formatting. |
| 139 | +- Generators: `tool/ui/generator`, including UUID/ULID/NanoID/password/lorem/barcode. |
| 140 | +- Other tools: `tool/ui/other`, including regex matcher, JSON schema validator, unarchiver, color picker, server certificates, HTTP server, notes, text diff/statistics, cron, ASCII art. |
| 141 | + |
| 142 | +When adding a new UI tool: |
| 143 | + |
| 144 | +1. Choose the closest base class instead of starting from `DeveloperUiTool` directly. |
| 145 | +2. Put it in the matching package under `modules/tools/ui`. |
| 146 | +3. Add a nested `Factory : DeveloperUiToolFactory<YourTool>`. |
| 147 | +4. Register the factory in `plugin.xml` with a stable `id`. |
| 148 | +5. Add enum property type registrations for any persisted enum defaults. |
| 149 | +6. Use `configuration.register(...)` for all persisted controls. Pick stable keys. |
| 150 | +7. Add bundle entries if the surrounding package uses message bundles. |
| 151 | +8. Add or update tests when persistence, plugin XML registration, or conversion behavior changes. |
| 152 | + |
| 153 | +## Editor Actions And Intentions |
| 154 | + |
| 155 | +Generic selected-text actions live in `modules/tools/editor`. |
| 156 | + |
| 157 | +- `DeveloperToolsActionGroup` is the root editor popup group. |
| 158 | +- `EncodeDecodeActionGroup`, `EscapeUnescapeActionGroup`, `TextCaseConverterActionGroup`, `DataGeneratorActionGroup`, and `EditorTextStatisticAction` operate mostly on selected text. |
| 159 | +- Shared operation lists are in `EncodersDecoders`, `EscapersUnescapers`, and `DataGenerators`. |
| 160 | +- Editor mutations should go through `EditorUtils.executeWriteCommand`. |
| 161 | +- Error dialogs are shown via IntelliJ APIs and failures are logged. |
| 162 | + |
| 163 | +Generic intentions live in `modules/tools/editor/src/main/.../intention`. |
| 164 | + |
| 165 | +Java/Kotlin language-specific variants live in: |
| 166 | + |
| 167 | +- `modules/java-dependent/.../PsiJavaUtils.kt` |
| 168 | +- `modules/java-dependent/.../tool/editor/action` |
| 169 | +- `modules/java-dependent/.../tool/editor/intention` |
| 170 | +- `modules/kotlin-dependent/.../PsiKotlinUtils.kt` |
| 171 | +- `modules/kotlin-dependent/.../tool/editor/action` |
| 172 | +- `modules/kotlin-dependent/.../tool/editor/intention` |
| 173 | + |
| 174 | +Those modules are optional and must stay behind their optional plugin descriptors. |
| 175 | + |
| 176 | +## Testing |
| 177 | + |
| 178 | +Common commands: |
| 179 | + |
| 180 | +```bash |
| 181 | +./gradlew test |
| 182 | +./gradlew check |
| 183 | +./gradlew verifyPlugin |
| 184 | +./gradlew spotlessApply |
| 185 | +``` |
| 186 | + |
| 187 | +CI runs: |
| 188 | + |
| 189 | +```bash |
| 190 | +./gradlew check --stacktrace |
| 191 | +./gradlew verifyPlugin --stacktrace |
| 192 | +``` |
| 193 | + |
| 194 | +Focused examples: |
| 195 | + |
| 196 | +```bash |
| 197 | +./gradlew :tools-ui:test |
| 198 | +./gradlew :settings:test |
| 199 | +./gradlew test --tests '*PluginXmlTest' |
| 200 | +./gradlew test --tests '*DeveloperToolsInstanceSettingsTest' |
| 201 | +``` |
| 202 | + |
| 203 | +Test infrastructure: |
| 204 | + |
| 205 | +- `IdeaTest` sets up IntelliJ test application/project fixtures and Bouncy Castle. |
| 206 | +- `PluginXmlTest` validates descriptor class/file references. |
| 207 | +- `DeveloperUiToolsInstances` instantiates all registered UI tools from the extension point for integration tests. |
| 208 | +- `DeveloperUiToolUnderTest` randomizes and resets registered tool properties. |
| 209 | +- Intention description tests validate bundled intention descriptions/templates. |
| 210 | + |
| 211 | +Some tests need IntelliJ test infrastructure and can be slow. On Linux/CI, run under Xvfb as the workflow does. |
| 212 | + |
| 213 | +## Style And Conventions |
| 214 | + |
| 215 | +- Kotlin formatting is ktfmt Google style through Spotless. |
| 216 | +- `.editorconfig` uses 2-space Kotlin indentation and 100 character max line length. |
| 217 | +- The code often uses section comments like `// -- Properties --`; keep them when editing nearby code. |
| 218 | +- Prefer IntelliJ Platform APIs and the local helper classes over new abstractions. |
| 219 | +- Use IntelliJ UI DSL builder patterns already present in neighboring tools. |
| 220 | +- Register disposables with the passed `parentDisposable`. |
| 221 | +- Keep long or blocking work off the EDT. Existing code uses pooled threads, `Task.Backgroundable`, `AsyncTaskExecutor`, and `Alarm`. |
| 222 | +- Many UI components rely on `ValueProperty` or IntelliJ observable properties; bind controls rather than manually syncing when possible. |
| 223 | +- Do not change plugin ids, extension ids, or persisted property keys without migration/test updates. |
| 224 | + |
| 225 | +## External Processes And Downloads |
| 226 | + |
| 227 | +The HTTP Server tool downloads and runs WireMock standalone: |
| 228 | + |
| 229 | +- Implementation: `HttpServer.kt`. |
| 230 | +- Process tracking: `ExternalSystemProcessRegistry.kt`. |
| 231 | +- Download URL/version constants are at the bottom of `HttpServer.kt`. |
| 232 | +- The tool supports built-in and custom server modes and registers/stops process handlers. |
| 233 | + |
| 234 | +Be careful with lifecycle changes here: processes must be unregistered and stopped on disposal. |
| 235 | + |
| 236 | +## Release And Verification Notes |
| 237 | + |
| 238 | +- `publishPlugin` depends on `check` and requires `platform == "idea"`. |
| 239 | +- Signing reads certificate/private key from `~/.jetbrains` and a Gradle property password. |
| 240 | +- Marketplace token is read from Gradle properties. |
| 241 | +- `buildSearchableOptions` is disabled. |
| 242 | +- Plugin verification uses recommended IDEs plus additional IDEs from `pluginVerificationAdditionalIdes`. |
| 243 | +- Changelog rendering comes from `CHANGELOG.md`; `tools-ui` also generates a bundled `changelog.html`. |
| 244 | + |
| 245 | +## Agent Workflow |
| 246 | + |
| 247 | +Before editing: |
| 248 | + |
| 249 | +- Run `git status --short` and do not overwrite unrelated user changes. |
| 250 | +- Use `rg`/`rg --files` for navigation. |
| 251 | +- Read the closest existing implementation before adding a new pattern. |
| 252 | + |
| 253 | +For UI tools: |
| 254 | + |
| 255 | +- Start from the nearest tool in the same package. |
| 256 | +- Wire configuration through `DeveloperToolConfiguration`. |
| 257 | +- Register tool and enum property types in `plugin.xml`. |
| 258 | +- Run at least `./gradlew :tools-ui:test` or the smallest relevant module test, plus `PluginXmlTest` if descriptors changed. |
| 259 | + |
| 260 | +For settings persistence: |
| 261 | + |
| 262 | +- Check `DeveloperToolsInstanceSettings`, `DeveloperToolConfiguration`, and legacy migration tests. |
| 263 | +- Add enum registrations and migration entries as needed. |
| 264 | +- Run `DeveloperToolsInstanceSettingsTest`. |
| 265 | + |
| 266 | +For editor actions/intentions: |
| 267 | + |
| 268 | +- Keep generic selected-text logic in `tools-editor`. |
| 269 | +- Keep Java/Kotlin PSI logic in optional modules. |
| 270 | +- Add/update intention descriptions under `resources/intentionDescriptions`. |
| 271 | +- Run the relevant intention description tests. |
| 272 | + |
| 273 | +Before final response: |
| 274 | + |
| 275 | +- Run the narrowest meaningful Gradle tests. |
| 276 | +- If descriptor or broad registration changed, run `PluginXmlTest`. |
| 277 | +- If formatting changed, run `./gradlew spotlessApply` or `./gradlew spotlessCheck`. |
| 278 | +- Mention any tests that could not be run. |
0 commit comments