Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .claude/skills/intellij-plugin-development/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
name: intellij-plugin-development
description: IntelliJ plugin development reference when working on extension points, decompiling bundled plugin JARs, finding API usage examples, navigating IntelliJ SDK, or investigating how other plugins implement a feature.
---

# IntelliJ Plugin Development

Quick reference for tools, APIs, and resources used when developing or investigating IntelliJ/PhpStorm plugins in this project.

---

## SDK & Documentation

- **SDK Docs:** https://plugins.jetbrains.com/docs/intellij/
- **Extension Point List:** https://plugins.jetbrains.com/docs/intellij/extension-point-list.html
- **IntelliJ Community Source:** https://github.com/JetBrains/intellij-community
- **Plugin Template:** https://github.com/JetBrains/intellij-platform-plugin-template

---

## Skills in this folder

| File | Purpose |
|---|---|
| `references/extension-point-explorer.md` | Find plugins by extension point; search open-source implementations; download plugins for decompilation |
| `references/decompilation.md` | Decompile plugin JARs with Vineflower; locate bundled JARs in Gradle cache; download ZIPs from Marketplace |

---

## Decompilation (quick reference)

Always use **Vineflower** — not IntelliJ's bundled Fernflower. A local copy is at `decompiled/vineflower.jar`.

```bash
java -jar decompiled/vineflower.jar input.jar output-src/
```

See [`references/decompilation.md`](./references/decompilation.md) for full usage, bundled JAR paths, and Marketplace ZIP downloads.

---

## Extension Point Explorer (quick reference)

Use the JetBrains Marketplace API to find plugins implementing a given extension point, get GitHub source search URLs or download plugin releases from the marketplace for decompilation.

See [`references/extension-point-explorer.md`](./references/extension-point-explorer.md) for step-by-step instructions.

Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Decompilation

Guide for decompiling IntelliJ plugin JARs to inspect features and implementation details.

---

## Vineflower (recommended)

Vineflower produces significantly better output than IntelliJ's bundled Fernflower. Always prefer it for decompiling plugin JARs.

- **GitHub:** https://github.com/Vineflower/vineflower
- **Download:** https://repo1.maven.org/maven2/org/vineflower/vineflower/1.11.2/vineflower-1.11.2.jar
- **Local copy in this project:** `decompiled/vineflower.jar`

```bash
# Decompile a single JAR into a source directory
java -jar decompiled/vineflower.jar input.jar output-src/

# Decompile all JARs in a directory
java -jar decompiled/vineflower.jar input-dir/ output-src/
```

---

## Bundled plugin JARs (IntelliJ/PhpStorm)

Gradle downloads plugin dependencies into the local cache. Typical path:

```
~/.gradle/caches/<gradle-version>/transforms/*/transformed/<plugin-id>-<intellij-version>/<plugin>/lib/<plugin>.jar
```

Examples:
```bash
# Twig plugin
~/.gradle/caches/9.3.0/transforms/*/transformed/com.jetbrains.twig-253.28294.322/twig/lib/twig.jar

# PHP plugin
~/.gradle/caches/9.3.0/transforms/*/transformed/com.jetbrains.php-253.*/php/lib/php.jar
```

---

## Downloading a plugin JAR from the Marketplace

Use the JetBrains Marketplace API to fetch the latest release ZIP for any plugin ID (see `extension-point-explorer.md` for how to find plugin IDs):

```bash
PLUGIN_ID="7219"

# Get the ZIP download path
curl -s "https://plugins.jetbrains.com/api/plugins/${PLUGIN_ID}/updates?size=1" \
| jq -r '"https://plugins.jetbrains.com/files/" + .[0].file'

# Download it directly
FILE=$(curl -s "https://plugins.jetbrains.com/api/plugins/${PLUGIN_ID}/updates?size=1" | jq -r '.[0].file')
curl -L -o plugin.zip "https://plugins.jetbrains.com/files/${FILE}"
unzip plugin.zip -d plugin-src/
```

Then decompile the extracted JAR:
```bash
java -jar decompiled/vineflower.jar plugin-src/lib/plugin.jar output-src/
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# IntelliJ Extension Point Explorer

Use this skill to find plugins that implement a given IntelliJ extension point and to get GitHub source code search URLs for usage examples.

This skill also covers **downloading any plugin for decompilation and feature investigation** — see Section 3.

> **Important:** Extension point names are **case-sensitive** (e.g., `com.intellij.psi.referenceContributor` ≠ `com.intellij.psi.ReferenceContributor`). Use the exact name as declared in `plugin.xml`.

---

## 1. Search for extension points by keyword

Before querying for plugins, find the **exact extension point name** by searching the JetBrains Marketplace extension point registry. Search is **case-insensitive** (the filtering is done client-side with `grep -i`), but the name you pass to Step 1 must be **exact and case-sensitive**.

```bash
# Partial search — find all extension points containing a keyword
KEYWORD="completion"

curl -s "https://plugins.jetbrains.com/api/extension-points" \
| jq -r '.[].implementationName' \
| grep -i "$KEYWORD" \
| sort
```

Examples:
- `KEYWORD="contributor"` → lists all `*contributor*` extension points
- `KEYWORD="completion.contributor"` → narrows to completion contributors
- `KEYWORD="inspection"` → lists all inspection-related extension points

Once you have the exact name (e.g., `com.intellij.completion.contributor`), use it in Step 2.

---

## 2. Find plugins implementing an extension point

Query the JetBrains Plugin Repository GraphQL API to find open-source plugins that use a specific extension point:

```bash
EXTENSION_POINT="com.intellij.psi.referenceContributor"

curl -s -X POST "https://plugins.jetbrains.com/api/search/graphql" \
-H "Content-Type: application/json" \
-d "{\"query\":\"{ plugins(search: { max: 24, offset: 0, filters: [{ field: \\\"fields.extensionPoints\\\", value: \\\"${EXTENSION_POINT}\\\" }, { field: \\\"hasSource\\\", value: \\\"true\\\" }, { field: \\\"family\\\", value: \\\"intellij\\\" }], sortBy: DOWNLOADS }) { total, plugins { id, name, downloads, sourceCodeUrl, lastUpdateDate, organization { id, verified } } } }\"}" \
| jq -r --arg ep "$EXTENSION_POINT" '
.data.plugins |
"Total plugins found: \(.total)\n",
(.plugins[] | select(.sourceCodeUrl != null and .sourceCodeUrl != "") |
"Plugin: \(.name)",
"ID: \(.id)",
"Downloads: \(.downloads)",
"Source: \(.sourceCodeUrl)",
"Updated: \(.lastUpdateDate)",
"Verified: \(.organization.verified // false)",
"Marketplace: https://plugins.jetbrains.com/plugin/\(.id)",
"Search: \("https://github.com/search?q=" + ("repo:" + (.sourceCodeUrl | ltrimstr("https://github.com/") | rtrimstr("/")) + " " + $ep | @uri) + "&type=code")",
"---"
)
'
```

## 3. Download a plugin for decompilation and feature investigation

> **Note:** This section is **not** limited to extension point research. Use it any time you want to download a plugin JAR/ZIP for decompilation, reverse engineering, or feature investigation — regardless of how you found the plugin ID.

The plugin ID can come from:
- **Step 2** results (`ID: 7219`)
- A Marketplace URL: `https://plugins.jetbrains.com/plugin/<ID>`

The `sourceCodeUrl` (GitHub URL) from Step 2 gives you two options:
- **Search the repo** for usage examples → use the `Search:` URL from Step 2 output, or browse `https://github.com/<owner>/<repo>`
- **Download the latest release** for decompilation → use the Marketplace API below to get the direct ZIP URL

Given a plugin ID, fetch its metadata and the direct ZIP download URL of the latest release:

```bash
PLUGIN_ID="7219"

# Plugin metadata
curl -s "https://plugins.jetbrains.com/api/plugins/${PLUGIN_ID}" \
| jq '{
id: .id,
name: .name,
xmlId: .xmlId,
downloads: .downloads,
source: .urls.sourceCodeUrl,
marketplace: ("https://plugins.jetbrains.com/plugin/" + (.id | tostring))
}'

# Latest release — includes direct ZIP download URL
curl -s "https://plugins.jetbrains.com/api/plugins/${PLUGIN_ID}/updates?size=1" \
| jq '.[0] | {
version: .version,
date: (.cdate | tonumber / 1000 | strftime("%Y-%m-%d")),
downloads: .downloads,
size_kb: (.size / 1024 | floor),
channel: (if .channel == "" then "stable" else .channel end),
download_url: ("https://plugins.jetbrains.com/files/" + .file),
notes: (.notes | gsub("<[^>]+>"; "") | gsub("&gt;"; ">") | gsub("&lt;"; "<") | gsub("&amp;"; "&") | split("\n") | map(select(length > 0)) | .[:5] | join("\n"))
}'
```

Once you have the ZIP URL, download and decompile with **vineflower** (see [`references.md`](./references.md)):
```bash
curl -L -o plugin.zip "https://plugins.jetbrains.com/files/7219/974671/Symfony_Plugin-2026.1.289.zip"
unzip plugin.zip -d plugin-extracted/
java -jar decompiled/vineflower.jar plugin-extracted/lib/plugin.jar decompiled-src/
```

---

## Notes

- **Case sensitivity:** `com.intellij.completion.contributor` ≠ `com.intellij.CompletionContributor` — always verify the exact name in `plugin.xml` or IntelliJ SDK docs.
- The API returns max 24 results per request; use `offset` to paginate.
- `sortBy` options: `DOWNLOADS`, `UPDATE_DATE`, `RATING`.
- Only plugins with `hasSource: true` and a non-empty `sourceCodeUrl` are useful for code examples.
- `jq` and `curl` are required; `jq` must support `@uri` (version ≥ 1.6).
- For decompilation tooling and API references, see [`references.md`](./references.md).
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ out/
/php-annotation.jar
/build
/.gradle
.intellijPlatform
.intellijPlatform
/decompiled
/.junie
*.hprof
.mcp.json
52 changes: 52 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is an IntelliJ IDEA/PhpStorm plugin that provides PHP annotation and PHP 8 Attribute support. The plugin extends the IDE to recognize annotation classes marked with `@Annotation`, provides code completion, navigation, inspections, and integrates with Doctrine ORM and Symfony frameworks.

**Plugin ID**: `de.espend.idea.php.annotation`

## Build Commands

### Build the plugin
```bash
./gradlew buildPlugin
```
The plugin ZIP will be in `build/distributions/`.

### Running Tests

```bash
# Run all tests
./gradlew test

# Run a specific test class
./gradlew test --tests "fr.adrienbrault.idea.symfony2plugin.tests.dic.SymfonyContainerTypeProviderTest"

# Run tests matching a pattern
./gradlew test --tests "*ContainerTest"
```

## Architecture

- Tests extend `AnnotationLightCodeInsightFixtureTestCase` which provides a test fixture framework.

Test data files are in `src/test/java/de/espend/idea/php/annotation/tests/fixtures/`.


## Decompiler Tools

For analyzing bundled plugins like Twig and PHP you MUST use **vineflower** and NOT **Fernflower** from IntelliJ (less quality):

**vineflower**

- **GitHub:** https://github.com/Vineflower/vineflower
- **Download:** https://repo1.maven.org/maven2/org/vineflower/vineflower/1.11.2/vineflower-1.11.2.jar
- **Local copy:** `decompiled/vineflower.jar`
- **Usage:** `java -jar vineflower.jar input.jar output/`

**Bundled Plugin JARs (for decompilation):**
- **Location:** `~/.gradle/caches/[gradle-version]/transforms/*/transformed/com.jetbrains.[plugin]-[intellij-version]/[plugin]/lib/[plugin].jar`
- **Example:** `~/.gradle/caches/9.3.0/transforms/*/transformed/com.jetbrains.twig-253.28294.322/twig/lib/twig.jar`
Loading
Loading