diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b5bf3f98..77c251a7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,12 +1,12 @@ -# GitHub Actions Workflow created for testing and preparing the plugin release in following steps: -# - validate Gradle Wrapper, -# - run 'test' and 'verifyPlugin' tasks, -# - run Qodana inspections, -# - run 'buildPlugin' task and prepare artifact for the further tests, -# - run 'runPluginVerifier' task, -# - create a draft release. +# GitHub Actions Workflow is created for testing and preparing the plugin release in the following steps: +# - Validate Gradle Wrapper. +# - Run 'test' and 'verifyPlugin' tasks. +# - Run Qodana inspections. +# - Run the 'buildPlugin' task and prepare artifact for further tests. +# - Run the 'runPluginVerifier' task. +# - Create a draft release. # -# Workflow is triggered on push and pull_request events. +# The workflow is triggered on push and pull_request events. # # GitHub Actions reference: https://help.github.com/en/actions # @@ -14,40 +14,49 @@ name: Build on: - # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g. for dependabot pull requests) + # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g., for dependabot pull requests) push: branches: [ main ] # Trigger the workflow on any pull request pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: - # Run Gradle Wrapper Validation Action to verify the wrapper's checksum - # Run verifyPlugin, IntelliJ Plugin Verifier, and test Gradle tasks - # Build plugin and provide the artifact for the next workflow jobs + # Prepare environment and build the plugin build: name: Build runs-on: ubuntu-latest outputs: version: ${{ steps.properties.outputs.version }} changelog: ${{ steps.properties.outputs.changelog }} + pluginVerifierHomeDir: ${{ steps.properties.outputs.pluginVerifierHomeDir }} steps: # Check out current repository - name: Fetch Sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v4 # Validate wrapper - name: Gradle Wrapper Validation - uses: gradle/wrapper-validation-action@v1.0.4 + uses: gradle/actions/wrapper-validation@v3 - # Setup Java 11 environment for the next steps + # Set up Java environment for the next steps - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: zulu java-version: 17 + # Setup Gradle + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + with: + gradle-home-cache-cleanup: true + # Set environment variables - name: Export Properties id: properties @@ -55,86 +64,182 @@ jobs: run: | PROPERTIES="$(./gradlew properties --console=plain -q)" VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')" - NAME="$(echo "$PROPERTIES" | grep "^pluginName:" | cut -f2- -d ' ')" CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)" - CHANGELOG="${CHANGELOG//'%'/'%25'}" - CHANGELOG="${CHANGELOG//$'\n'/'%0A'}" - CHANGELOG="${CHANGELOG//$'\r'/'%0D'}" - echo "::set-output name=version::$VERSION" - echo "::set-output name=name::$NAME" - echo "::set-output name=changelog::$CHANGELOG" - echo "::set-output name=pluginVerifierHomeDir::~/.pluginVerifier" + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "pluginVerifierHomeDir=~/.pluginVerifier" >> $GITHUB_OUTPUT + + echo "changelog<> $GITHUB_OUTPUT + echo "$CHANGELOG" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT ./gradlew listProductsReleases # prepare list of IDEs for Plugin Verifier + # Build plugin + - name: Build plugin + run: ./gradlew buildPlugin + + # Prepare plugin archive content for creating artifact + - name: Prepare Plugin Artifact + id: artifact + shell: bash + run: | + cd ${{ github.workspace }}/build/distributions + FILENAME=`ls *.zip` + unzip "$FILENAME" -d content + + echo "filename=${FILENAME:0:-4}" >> $GITHUB_OUTPUT + + # Store already-built plugin as an artifact for downloading + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.artifact.outputs.filename }} + path: ./build/distributions/content/*/* + + # Run tests and upload a code coverage report + test: + name: Test + needs: [ build ] + runs-on: ubuntu-latest + steps: + + # Check out current repository + - name: Fetch Sources + uses: actions/checkout@v4 + + # Set up Java environment for the next steps + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: zulu + java-version: 17 + + # Setup Gradle + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + with: + gradle-home-cache-cleanup: true + # Run tests - name: Run Tests - run: ./gradlew test + run: ./gradlew check # Collect Tests Result of failed tests - name: Collect Tests Result if: ${{ failure() }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: tests-result path: ${{ github.workspace }}/build/reports/tests + # Upload the Kover report to CodeCov + - name: Upload Code Coverage Report + uses: codecov/codecov-action@v4 + with: + files: ${{ github.workspace }}/build/reports/kover/report.xml + + # Run Qodana inspections and provide report + inspectCode: + name: Inspect code + needs: [ build ] + runs-on: ubuntu-latest + permissions: + contents: write + checks: write + pull-requests: write + steps: + + # Free GitHub Actions Environment Disk Space + - name: Maximize Build Space + uses: jlumbroso/free-disk-space@main + with: + tool-cache: false + large-packages: false + + # Check out current repository + - name: Fetch Sources + uses: actions/checkout@v4 + + # Set up Java environment for the next steps + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: zulu + java-version: 17 + + # Run Qodana inspections + - name: Qodana - Code Inspection + uses: JetBrains/qodana-action@v2024.1.5 + with: + cache-default-branch-only: true + + # Run plugin structure verification along with IntelliJ Plugin Verifier + verify: + name: Verify plugin + needs: [ build ] + runs-on: ubuntu-latest + steps: + + # Free GitHub Actions Environment Disk Space + - name: Maximize Build Space + uses: jlumbroso/free-disk-space@main + with: + tool-cache: false + large-packages: false + + # Check out current repository + - name: Fetch Sources + uses: actions/checkout@v4 + + # Set up Java environment for the next steps + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: zulu + java-version: 17 + + # Setup Gradle + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + with: + gradle-home-cache-cleanup: true + # Cache Plugin Verifier IDEs - name: Setup Plugin Verifier IDEs Cache - uses: actions/cache@v2.1.7 + uses: actions/cache@v4 with: - path: ${{ steps.properties.outputs.pluginVerifierHomeDir }}/ides + path: ${{ needs.build.outputs.pluginVerifierHomeDir }}/ides key: plugin-verifier-${{ hashFiles('build/listProductsReleases.txt') }} # Run Verify Plugin task and IntelliJ Plugin Verifier tool - name: Run Plugin Verification tasks - run: ./gradlew runPluginVerifier -Pplugin.verifier.home.dir=${{ steps.properties.outputs.pluginVerifierHomeDir }} + run: ./gradlew runPluginVerifier -Dplugin.verifier.home.dir=${{ needs.build.outputs.pluginVerifierHomeDir }} # Collect Plugin Verifier Result - name: Collect Plugin Verifier Result if: ${{ always() }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: pluginVerifier-result path: ${{ github.workspace }}/build/reports/pluginVerifier - # # Run Qodana inspections - # - name: Qodana - Code Inspection - # uses: JetBrains/qodana-action@v2022.2.4 - - # Prepare plugin archive content for creating artifact - - name: Prepare Plugin Artifact - id: artifact - shell: bash - run: | - cd ${{ github.workspace }}/build/distributions - FILENAME=`ls *.zip` - unzip "$FILENAME" -d content - - echo "::set-output name=filename::${FILENAME:0:-4}" - - # Store already-built plugin as an artifact for downloading - - name: Upload artifact - uses: actions/upload-artifact@v2.2.4 - with: - name: ${{ steps.artifact.outputs.filename }} - path: ./build/distributions/content/*/* - # Prepare a draft release for GitHub Releases page for the manual verification # If accepted and published, release workflow would be triggered releaseDraft: - name: Release Draft + name: Release draft if: github.event_name != 'pull_request' - needs: build + needs: [ build, test, inspectCode, verify ] runs-on: ubuntu-latest + permissions: + contents: write steps: # Check out current repository - name: Fetch Sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v4 - # Remove old release drafts by using the curl request for the available releases with draft flag + # Remove old release drafts by using the curl request for the available releases with a draft flag - name: Remove Old Release Drafts env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -143,12 +248,12 @@ jobs: --jq '.[] | select(.draft == true) | .id' \ | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{} - # Create new release draft - which is not publicly visible and requires manual acceptance + # Create a new release draft which is not publicly visible and requires manual acceptance - name: Create Release Draft env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - gh release create v${{ needs.build.outputs.version }} \ + gh release create "v${{ needs.build.outputs.version }}" \ --draft \ --title "v${{ needs.build.outputs.version }}" \ --notes "$(cat << 'EOM' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 81e2cf26..48987791 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,32 +1,42 @@ -# GitHub Actions Workflow created for handling the release process based on the draft release prepared -# with the Build workflow. Running the publishPlugin task requires the PUBLISH_TOKEN secret provided. +# GitHub Actions Workflow created for handling the release process based on the draft release prepared with the Build workflow. +# Running the publishPlugin task requires all following secrets to be provided: PUBLISH_TOKEN, PRIVATE_KEY, PRIVATE_KEY_PASSWORD, CERTIFICATE_CHAIN. +# See https://plugins.jetbrains.com/docs/intellij/plugin-signing.html for more information. name: Release on: release: - types: [ prereleased, released ] + types: [prereleased, released] jobs: - # Prepare and publish the plugin to the Marketplace repository + # Prepare and publish the plugin to JetBrains Marketplace repository release: name: Publish Plugin runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write steps: # Check out current repository - name: Fetch Sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v4 with: ref: ${{ github.event.release.tag_name }} - # Setup Java 11 environment for the next steps + # Set up Java environment for the next steps - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: zulu java-version: 17 + # Setup Gradle + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + with: + gradle-home-cache-cleanup: true + # Set environment variables - name: Export Properties id: properties @@ -37,11 +47,9 @@ jobs: EOM )" - CHANGELOG="${CHANGELOG//'%'/'%25'}" - CHANGELOG="${CHANGELOG//$'\n'/'%0A'}" - CHANGELOG="${CHANGELOG//$'\r'/'%0D'}" - - echo "::set-output name=changelog::$CHANGELOG" + echo "changelog<> $GITHUB_OUTPUT + echo "$CHANGELOG" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT # Update Unreleased section with the current release note - name: Patch Changelog @@ -51,10 +59,13 @@ jobs: run: | ./gradlew patchChangelog --release-note="$CHANGELOG" - # Publish the plugin to the Marketplace + # Publish the plugin to JetBrains Marketplace - name: Publish Plugin env: PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} + CERTIFICATE_CHAIN: ${{ secrets.CERTIFICATE_CHAIN }} + PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} + PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }} run: ./gradlew publishPlugin # Upload artifact as a release asset @@ -63,7 +74,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/* - # Create pull request + # Create a pull request - name: Create Pull Request if: ${{ steps.properties.outputs.changelog != '' }} env: @@ -71,6 +82,7 @@ jobs: run: | VERSION="${{ github.event.release.tag_name }}" BRANCH="changelog-update-$VERSION" + LABEL="release changelog" git config user.email "action@github.com" git config user.name "GitHub Action" @@ -78,9 +90,14 @@ jobs: git checkout -b $BRANCH git commit -am "Changelog update - $VERSION" git push --set-upstream origin $BRANCH + + gh label create "$LABEL" \ + --description "Pull requests with release changelog update" \ + --force \ + || true gh pr create \ --title "Changelog update - \`$VERSION\`" \ --body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \ - --base main \ - --head $BRANCH + --label "$LABEL" \ + --head $BRANCH \ No newline at end of file diff --git a/.run/Run IDE with Plugin.run.xml b/.run/Run IDE with Plugin.run.xml index ddd22adf..6d21d8a4 100644 --- a/.run/Run IDE with Plugin.run.xml +++ b/.run/Run IDE with Plugin.run.xml @@ -1,25 +1,25 @@ - - - - - - - true - true - false - false - - + + + + + + + true + true + false + false + + \ No newline at end of file diff --git a/.run/Run Plugin.run.xml b/.run/Run Plugin.run.xml new file mode 100644 index 00000000..02cf47e2 --- /dev/null +++ b/.run/Run Plugin.run.xml @@ -0,0 +1,30 @@ + + + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/Run Tests.run.xml b/.run/Run Tests.run.xml index bbf1f0a3..009fc459 100644 --- a/.run/Run Tests.run.xml +++ b/.run/Run Tests.run.xml @@ -1,30 +1,30 @@ - - - - - - - - true - true - false - false - - + + + + + + + + true + true + false + false + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2806aafe..9cf64514 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,17 +15,28 @@ ## 1.7.30 - 2023-12-08 - Changelog update - `v1.7.20` by @github-actions in https://github.com/devkanro/intellij-protobuf-plugin/pull/203 -- ⬆️ Bump org.jetbrains.intellij from 1.13.3 to 1.16.0 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/206 -- ⬆️ Bump org.jetbrains.grammarkit from 2022.3.1 to 2022.3.2 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/205 -- ⬆️ Bump org.jetbrains.changelog from 2.0.0 to 2.2.0 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/204 -- ⬆️ Bump org.jmailen.kotlinter from 4.0.1 to 4.1.0 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/207 -- ⬆️ Bump com.fasterxml.jackson.dataformat:jackson-dataformat-yaml from 2.15.3 to 2.16.0 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/208 -- ⬆️ Bump org.jetbrains.kotlin.jvm from 1.9.20 to 1.9.21 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/209 -- ⬆️ Bump com.bybutter.sisyphus:sisyphus-jackson-protobuf from 2.1.20 to 2.1.21 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/211 -- ⬆️ Bump io.grpc:grpc-netty from 1.59.0 to 1.59.1 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/212 -- ⬆️ Bump com.bybutter.sisyphus:sisyphus-grpc from 2.1.20 to 2.1.21 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/210 -- ⬆️ Bump org.jetbrains.intellij from 1.16.0 to 1.16.1 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/213 -- ⬆️ Bump io.grpc:grpc-netty from 1.59.1 to 1.60.0 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/215 +- ⬆️ Bump org.jetbrains.intellij from 1.13.3 to 1.16.0 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/206 +- ⬆️ Bump org.jetbrains.grammarkit from 2022.3.1 to 2022.3.2 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/205 +- ⬆️ Bump org.jetbrains.changelog from 2.0.0 to 2.2.0 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/204 +- ⬆️ Bump org.jmailen.kotlinter from 4.0.1 to 4.1.0 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/207 +- ⬆️ Bump com.fasterxml.jackson.dataformat:jackson-dataformat-yaml from 2.15.3 to 2.16.0 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/208 +- ⬆️ Bump org.jetbrains.kotlin.jvm from 1.9.20 to 1.9.21 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/209 +- ⬆️ Bump com.bybutter.sisyphus:sisyphus-jackson-protobuf from 2.1.20 to 2.1.21 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/211 +- ⬆️ Bump io.grpc:grpc-netty from 1.59.0 to 1.59.1 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/212 +- ⬆️ Bump com.bybutter.sisyphus:sisyphus-grpc from 2.1.20 to 2.1.21 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/210 +- ⬆️ Bump org.jetbrains.intellij from 1.16.0 to 1.16.1 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/213 +- ⬆️ Bump io.grpc:grpc-netty from 1.59.1 to 1.60.0 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/215 ## 1.7.20 - 2023-11-13 diff --git a/README.md b/README.md index 25653adb..a1081c72 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,10 @@ Analyzing features: ✅ Decompile from proto descriptor for golang ✅ Send gRPC native/transcoding requests via [Http Client](https://plugins.jetbrains.com/plugin/13121-http-client) ✅ Explore gRPC APIs via [Endpoints](https://plugins.jetbrains.com/plugin/16890-endpoints) -✅ [Buf](https://buf.build/) support via [Buf for Protocol Buffers](https://plugins.jetbrains.com/plugin/19147-buf-for-protocol-buffers) +✅ [Buf](https://buf.build/) support +via [Buf for Protocol Buffers](https://plugins.jetbrains.com/plugin/19147-buf-for-protocol-buffers) +✅ [Protobuf Editions](https://protobuf.dev/editions/overview/) support +✅ [Protobuf Text Format](https://protobuf.dev/reference/protobuf/textformat-spec/) support Editor features: @@ -49,10 +52,6 @@ Editor features: -Planned features: - -🙋 Proto text support - ## Screenshots ![screenshot](resources/screenshot.png) diff --git a/build.gradle.kts b/build.gradle.kts index 5ae34070..b16ede86 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,30 +1,27 @@ import org.jetbrains.changelog.Changelog import org.jetbrains.changelog.markdownToHTML +import org.jetbrains.grammarkit.tasks.GenerateLexerTask +import org.jetbrains.grammarkit.tasks.GenerateParserTask import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -fun properties(key: String) = project.findProperty(key).toString() +fun properties(key: String) = providers.gradleProperty(key) + +fun environment(key: String) = providers.environmentVariable(key) plugins { - // Java support - id("java") - // Kotlin support - id("org.jetbrains.kotlin.jvm") version "1.9.22" - // Gradle IntelliJ Plugin - id("org.jetbrains.intellij") version "1.17.2" - // Gradle Changelog Plugin - id("org.jetbrains.changelog") version "2.2.0" - // Gradle Qodana Plugin - id("org.jetbrains.qodana") version "0.1.13" - - id("org.jetbrains.grammarkit") version "2022.3.2.2" - - id("org.jmailen.kotlinter") version "4.3.0" + id("java") // Java support + alias(libs.plugins.kotlin) // Kotlin support + alias(libs.plugins.gradleIntelliJPlugin) // Gradle IntelliJ Plugin + alias(libs.plugins.changelog) // Gradle Changelog Plugin + alias(libs.plugins.qodana) // Gradle Qodana Plugin + alias(libs.plugins.kover) // Gradle Kover Plugin + alias(libs.plugins.grammarkit) // IntelliJ Grammark kit Plugin } -group = properties("pluginGroup") -version = properties("pluginVersion") +group = properties("pluginGroup").get() +version = properties("pluginVersion").get() +// Configure project's dependencies repositories { mavenLocal() mavenCentral() @@ -39,94 +36,126 @@ dependencies { implementation("io.grpc:grpc-netty:1.62.2") } -// Configure gradle-intellij-plugin plugin. -// Read more: https://github.com/JetBrains/gradle-intellij-plugin +// Set the JVM language level used to build the project. +kotlin { + jvmToolchain(17) + compilerOptions { + freeCompilerArgs.add("-Xjvm-default=all") + } +} + +// Configure Gradle IntelliJ Plugin - read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html intellij { - pluginName.set(properties("pluginName")) - version.set(properties("platformVersion")) - type.set(properties("platformType")) + pluginName = properties("pluginName") + version = properties("platformVersion") + type = properties("platformType") // Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file. - plugins.set(properties("platformPlugins").split(',').map(String::trim).filter(String::isNotEmpty)) + plugins = properties("platformPlugins").map { it.split(',').map(String::trim).filter(String::isNotEmpty) } } +// Configure Gradle Changelog Plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin changelog { - version.set(properties("pluginVersion")) - groups.set(emptyList()) -} - -qodana { - cachePath.set(projectDir.resolve(".qodana").canonicalPath) - reportPath.set(projectDir.resolve("build/reports/inspections").canonicalPath) - saveReport.set(true) - showReport.set(System.getenv("QODANA_SHOW_REPORT")?.toBoolean() ?: false) + groups.empty() + repositoryUrl = properties("pluginRepositoryUrl") } -tasks { - properties("javaVersion").let { - withType { - sourceCompatibility = it - targetCompatibility = it - } - withType { - kotlinOptions.jvmTarget = it - kotlinOptions.freeCompilerArgs += "-Xjvm-default=all" - dependsOn(named("generateLexer"), named("generateParser")) +// Configure Gradle Kover Plugin - read more: https://github.com/Kotlin/kotlinx-kover#configuration +kover { + reports { + total { + xml { + onCheck = true + } } } +} +tasks { wrapper { - gradleVersion = properties("gradleVersion") + gradleVersion = properties("gradleVersion").get() } patchPluginXml { - version.set(properties("pluginVersion")) - sinceBuild.set(properties("pluginSinceBuild")) - untilBuild.set(properties("pluginUntilBuild")) + version = properties("pluginVersion") + sinceBuild = properties("pluginSinceBuild") + untilBuild = properties("pluginUntilBuild") // Extract the section from README.md and provide for the plugin's manifest - pluginDescription.set( - projectDir.resolve("README.md").readText().lines().run { + pluginDescription = + providers.fileContents(layout.projectDirectory.file("README.md")).asText.map { val start = "" val end = "" - if (!containsAll(listOf(start, end))) { - throw GradleException("Plugin description section not found in README.md:\n$start ... $end") + with(it.lines()) { + if (!containsAll(listOf(start, end))) { + throw GradleException("Plugin description section not found in README.md:\n$start ... $end") + } + subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML) } - subList(indexOf(start) + 1, indexOf(end)) - }.joinToString("\n").run { markdownToHTML(this) }, - ) + } + val changelog = project.changelog // local variable for configuration cache compatibility // Get the latest available change notes from the changelog file - changeNotes.set( - provider { - changelog.renderItem( - changelog.run { - getOrNull(properties("pluginVersion")) ?: getLatest() - }, - Changelog.OutputType.HTML, - ) - }, - ) + changeNotes = + properties("pluginVersion").map { pluginVersion -> + with(changelog) { + renderItem( + (getOrNull(pluginVersion) ?: getUnreleased()) + .withHeader(false) + .withEmptySections(false), + Changelog.OutputType.HTML, + ) + } + } + } + + // Configure UI tests plugin + // Read more: https://github.com/JetBrains/intellij-ui-test-robot + runIdeForUiTests { + systemProperty("robot-server.port", "8082") + systemProperty("ide.mac.message.dialogs.as.sheets", "false") + systemProperty("jb.privacy.policy.text", "") + systemProperty("jb.consents.confirmation.enabled", "false") + } + + runIde { + jvmArguments.add("-Didea.ProcessCanceledException=disabled") } generateLexer { - sourceFile.set(projectDir.resolve("src/main/grammar/protobuf.flex")) - targetOutputDir.set(buildDir.resolve("generated/sources/grammar/io/kanro/idea/plugin/protobuf/lang/lexer")) - purgeOldFiles.set(true) + sourceFile = layout.projectDirectory.file("src/main/grammar/protobuf.flex") + targetOutputDir = + layout.buildDirectory.dir("generated/sources/grammar/io/kanro/idea/plugin/protobuf/lang/lexer/proto") + purgeOldFiles = true } generateParser { - sourceFile.set(projectDir.resolve("src/main/grammar/protobuf.bnf")) - targetRootOutputDir.set(buildDir.resolve("generated/sources/grammar")) - purgeOldFiles.set(true) - pathToParser.set("io/kanro/idea/plugin/protobuf/lang/parser/ProtobufParser.java") - pathToPsiRoot.set("io/kanro/idea/plugin/protobuf/lang/psi") + sourceFile = layout.projectDirectory.file("src/main/grammar/protobuf.bnf") + targetRootOutputDir = layout.buildDirectory.dir("generated/sources/grammar") + purgeOldFiles = true + pathToParser = "io/kanro/idea/plugin/protobuf/lang/psi/proto/parser/ProtobufParser.java" + pathToPsiRoot = "io/kanro/idea/plugin/protobuf/lang/psi/proto" + } + + create("generateTextParser") { + sourceFile = layout.projectDirectory.file("src/main/grammar/prototext.bnf") + targetRootOutputDir = layout.buildDirectory.dir("generated/sources/grammar") + purgeOldFiles = true + pathToParser = "io/kanro/idea/plugin/protobuf/lang/psi/text/parser/ProtoTextParser.java" + pathToPsiRoot = "io/kanro/idea/plugin/protobuf/lang/psi/text" + } + + create("generateTextLexer") { + sourceFile = layout.projectDirectory.file("src/main/grammar/prototext.flex") + targetOutputDir = + layout.buildDirectory.dir("generated/sources/grammar/io/kanro/idea/plugin/protobuf/lang/lexer/text") + purgeOldFiles = true } prepareSandbox { + val file = layout.buildDirectory.file("idea-sandbox/config/disabled_plugins.txt").get().asFile doLast { - val file = file(buildDir.resolve("idea-sandbox/config/disabled_plugins.txt")) file.ensureParentDirsCreated() file.writeText( buildString { @@ -139,18 +168,27 @@ tasks { publishPlugin { dependsOn("patchChangelog") - token.set(System.getenv("PUBLISH_TOKEN")) + token = environment("PUBLISH_TOKEN") // pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3 // Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more: // https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel - channels.set(listOf(properties("pluginVersion").split('-').getOrElse(1) { "default" }.split('.').first())) + channels = + properties("pluginVersion").map { + listOf( + it.substringAfter('-', "").substringBefore('.').ifEmpty { "default" }, + ) + } + } + + compileKotlin { + dependsOn(generateParser, named("generateTextParser"), generateLexer, named("generateTextLexer")) } } sourceSets { named("main") { java { - srcDir(buildDir.resolve("generated/sources/grammar")) + srcDir(layout.buildDirectory.dir("generated/sources/grammar")) } } } diff --git a/gradle.properties b/gradle.properties index 66a5ceeb..e75c65b1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,26 +1,24 @@ -# IntelliJ Platform Artifacts Repositories -# -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html +# IntelliJ Platform Artifacts Repositories -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html pluginGroup=io.kanro.idea.plugin.protobuf pluginName=IntelliJ Protobuf Language Plugin +pluginRepositoryUrl=https://github.com/devkanro/intellij-protobuf-plugin # SemVer format -> https://semver.org -pluginVersion=1.7.60 -# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html -# for insight into build numbers and IntelliJ Platform versions. +pluginVersion=2.0.0 +# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html pluginSinceBuild=241 -pluginUntilBuild=241.* -# IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties +pluginUntilBuild=242.* +# IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension platformType=IU -#platformVersion=241.14024-EAP-CANDIDATE-SNAPSHOT platformVersion=2024.1 # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 platformPlugins=com.intellij.java, org.jetbrains.kotlin, org.intellij.plugins.markdown, org.jetbrains.plugins.go:241.14494.240, com.jetbrains.restClient:241.14494.150, com.intellij.grpc:241.14494.150 -#platformPlugins=com.intellij.java, org.jetbrains.kotlin, org.jetbrains.plugins.yaml, org.intellij.plugins.markdown, org.jetbrains.plugins.go:232.8660.142, com.jetbrains.restClient:232.8660.88, com.intellij.grpc:232.8660.88 -# Java language level used to compile sources and to generate the files for - Java 11 is required since 2020.3 -javaVersion=17 # Gradle Releases -> https://github.com/gradle/gradle/releases -gradleVersion=8.0.2 -# Opt-out flag for bundling Kotlin standard library. -# See https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library for details. -# suppress inspection "UnusedProperty" +gradleVersion=8.7 +# Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib kotlin.stdlib.default.dependency=false +# Enable Gradle Configuration Cache -> https://docs.gradle.org/current/userguide/configuration_cache.html +org.gradle.configuration-cache=true +# Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html +org.gradle.caching=true +kotlin.daemon.jvmargs=-Xmx16G \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000..a6640f78 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,22 @@ +[versions] +# libraries +exampleLibrary = "24.1.0" + +# plugins +kotlin = "2.0.0" +changelog = "2.2.0" +gradleIntelliJPlugin = "1.17.3" +qodana = "2024.1.5" +kover = "0.8.0" +grammarkit = "2022.3.2.2" + +[libraries] +exampleLibrary = { group = "com.example", name = "exampleLibrary", version.ref = "exampleLibrary" } + +[plugins] +changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" } +gradleIntelliJPlugin = { id = "org.jetbrains.intellij", version.ref = "gradleIntelliJPlugin" } +kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } +qodana = { id = "org.jetbrains.qodana", version.ref = "qodana" } +grammarkit = { id = "org.jetbrains.grammarkit", version.ref = "grammarkit" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c0..ccebba77 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3796d3cd..d951fac2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0c..79a61d42 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 107acd32..93e3f59f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/qodana.yml b/qodana.yml index 8b73731b..0be93537 100644 --- a/qodana.yml +++ b/qodana.yml @@ -2,5 +2,11 @@ # https://www.jetbrains.com/help/qodana/qodana-yaml.html version: 1.0 +linter: jetbrains/qodana-jvm-community:latest +projectJDK: "17" profile: - name: qodana.recommended \ No newline at end of file + name: qodana.recommended +exclude: + - name: All + paths: + - .qodana \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 172ab2ab..7ad66d90 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1 +1,5 @@ +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" +} + rootProject.name = "idea-protobuf-plugin" diff --git a/src/main/grammar/protobuf.bnf b/src/main/grammar/protobuf.bnf index eb485918..0ec8dcd8 100644 --- a/src/main/grammar/protobuf.bnf +++ b/src/main/grammar/protobuf.bnf @@ -1,20 +1,20 @@ { generate=[names="long" psi="yes" tokens="no"] - parserClass="io.kanro.idea.plugin.protobuf.lang.parser.ProtobufParser" + parserClass="io.kanro.idea.plugin.protobuf.lang.psi.proto.parser.ProtobufParser" parserUtilClass="io.kanro.idea.plugin.protobuf.lang.parser.ProtobufParserUtil" parserImports=[ - "static io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens.*" + "static io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens.*" ] psiClassPrefix="Protobuf" psiImplClassSuffix="Impl" - psiPackage="io.kanro.idea.plugin.protobuf.lang.psi" - psiImplPackage="io.kanro.idea.plugin.protobuf.lang.psi.impl" + psiPackage="io.kanro.idea.plugin.protobuf.lang.psi.proto" + psiImplPackage="io.kanro.idea.plugin.protobuf.lang.psi.proto.impl" - implements="io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement" - extends="io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase" + implements="io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + extends="io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase" - elementTypeHolderClass="io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypes" - elementTypeClass="io.kanro.idea.plugin.protobuf.lang.psi.ProtobufElementType" + elementTypeHolderClass="io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypes" + elementTypeClass="io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementType" tokens = [ SKIPPED_WHITESPACE = "regexp:[ \n\t\r\f]+" @@ -38,16 +38,19 @@ LPAREN = '(' LT = '<' MINUS = '-' + PLUS = '+' RBRACE = '}' RBRACK = ']' RPAREN = ')' SEMI = ';' + SLASH = '/' + COLON = ':' SYMBOL = "regexp:[!#$%&()*+,-./:;<=>?@\[\\\]^`{|}~]" ] } -File ::= SyntaxStatement? FileElement* +File ::= (EditionStatement | SyntaxStatement)? FileElement* private FileElement ::= ImportStatement | PackageStatement | FileOption | TopLevelDefinition | ExtendDefinition | ';' { recoverWhile = FileElementRecovery @@ -57,36 +60,63 @@ private FileElementRecovery ::= !(message | enum | service | extend | import | p private TopLevelDefinition ::= MessageDefinition | EnumDefinition | ServiceDefinition /* File statements */ +EditionStatement ::= edition '=' StringValue ';' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + ] +} + SyntaxStatement ::= syntax '=' StringValue ';' { pin=1 - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement"] + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + ] } + PackageStatement ::= package PackageName ('.' PackageName)* ';' { pin=1 - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement"] + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + ] } + PackageName::= IdentifierWithKeyword { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufPackageName" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufPackageName" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufPackageNameMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufPackageNameStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufPackageNameMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufPackageNameStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } + ImportStatement ::= import ImportLabel? StringValue ';' { pin=1 - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement"] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufImportStatementMixin" + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufImportStatementMixin" } + ImportLabel ::= public | weak { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] } + FileOption ::= option OptionAssign ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] } @@ -94,45 +124,50 @@ FileOption ::= option OptionAssign ';' { OptionAssign ::= OptionName '=' Constant { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufOptionAssign" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufOptionAssign" ] recoverWhile=OptionAssignRecovery } + private OptionAssignRecovery ::= !(option | ',' | '}' | ']' | ';') -OptionName ::= (BuiltInOptionName | ExtensionOptionName) ('.' FieldName)* { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] -} -BuiltInOptionName ::= IdentifierWithKeyword { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufBuiltInOptionMixin" -} -ExtensionOptionName ::= '(' TypeName ')' { - pin=1 - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] +OptionName ::= OptionFieldName ('.' OptionName)? { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.QualifiedElement" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufOptionNameMixin" } +private OptionFieldName ::= SymbolName | '(' ExtensionFieldName ')' + /* Message */ MessageDefinition ::= message Identifier MessageBody { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufMessageDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufMessageDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufMessageDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufMessageDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } + MessageBody ::= '{' MessageElement* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } + private MessageElement ::= MessageDefinition | EnumDefinition @@ -151,8 +186,9 @@ private MessageElementRecovery ::= !(message | enum | extensions | reserved | ex MessageOption ::= option OptionAssign ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] } @@ -160,26 +196,31 @@ MessageOption ::= option OptionAssign ';' { FieldDefinition ::= FieldLabel? TypeName Identifier '=' IntegerValue FieldOptionBlock? ';' { pin=2 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufFieldDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufFieldDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufFieldDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufFieldStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufFieldDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufFieldStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } + FieldOptionBlock ::= '[' FieldOption (',' FieldOption)* ']' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } + FieldOption ::= OptionAssign { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] recoverWhile=OptionBlockRecovery } @@ -187,109 +228,157 @@ FieldOption ::= OptionAssign { private OptionBlockRecovery ::= !(',' | ']') FieldLabel ::= required | optional | repeated { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] } OneofDefinition ::= oneof Identifier OneofBody { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufOneofDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufOneofDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufOneofDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufOneofStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufOneofDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufOneofStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } + OneofBody ::= '{' OneofElement* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } + private OneofElement ::= OneofOption | GroupDefinition | FieldDefinition | ';' {recoverWhile=OneofElementRecovery} private OneofElementRecovery ::= !(FieldLabel | option | group | TypeName | ';' | '}') OneofOption ::= option OptionAssign ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] } MapFieldDefinition ::= map '<' TypeName ',' TypeName '>' Identifier '=' IntegerValue FieldOptionBlock? ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufMapFieldDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufMapFieldDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufMapFieldDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMapFieldStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufMapFieldDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMapFieldStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } GroupDefinition ::= FieldLabel? group Identifier '=' IntegerValue MessageBody { pin=2 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufGroupDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufGroupDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufGroupDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufGroupStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufGroupDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufGroupStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } -ExtensionStatement ::= extensions Ranges ';' { +ExtensionStatement ::= extensions ExtensionRanges ';' { pin = 1; implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + ] +} + +private ExtensionRanges ::= ExtensionRange (',' ExtensionRange)* + +ExtensionRange ::= IntegerValue (to (IntegerValue | max))? ExtensionRangeOptionBlock? { + recoverWhile=RangeRecovery + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" + ] +} + +ExtensionRangeOptionBlock ::= '[' ExtensionRangeOption (',' ExtensionRangeOption)* ']' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + ] +} +ExtensionRangeOption ::= OptionAssign { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] + recoverWhile=OptionBlockRecovery } ReservedStatement ::= reserved ReservedElement ';'{ pin = 1; implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" ] } -private ReservedElement ::= Ranges | FieldNames -private Ranges ::= ReservedRange (',' ReservedRange)* + +private ReservedElement ::= ReservedRanges | ReservedFieldNames +private ReservedRanges ::= ReservedRange (',' ReservedRange)* ReservedRange ::= IntegerValue (to (IntegerValue | max))? { recoverWhile=RangeRecovery implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" ] } + private RangeRecovery ::= !(IntegerValue | ',' | '[' | ';') MessageElementRecovery -private FieldNames ::= ReservedName (',' ReservedName)* -ReservedName ::= IdentifierWithKeyword { +private ReservedFieldNames ::= ReservedName (',' ReservedName)* +ReservedName ::= STRING_LITERAL | IdentifierWithKeyword { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" ] } EnumDefinition ::= enum Identifier EnumBody { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufEnumDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufEnumDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufEnumDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufEnumDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } EnumBody ::= '{' EnumElement* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } private EnumElement ::= EnumOption | ReservedStatement | EnumValueDefinition | ';' {recoverWhile=EnumElementRecovery} @@ -297,33 +386,40 @@ private EnumElementRecovery ::= !(option | reserved | EnumValueDefinition | ';' EnumOption ::= option OptionAssign ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] } + EnumValueDefinition ::= Identifier '=' IntegerValue EnumValueOptionBlock? ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufEnumValueDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufEnumValueDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufEnumValueDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumValueStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufEnumValueDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumValueStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } + EnumValueOptionBlock ::= '[' EnumValueOption (',' EnumValueOption)* ']' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } + EnumValueOption ::= OptionAssign { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] recoverWhile=OptionBlockRecovery } @@ -331,153 +427,273 @@ EnumValueOption ::= OptionAssign { ServiceDefinition ::= service Identifier ServiceBody { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufServiceDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufServiceDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufServiceDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufServiceDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } ServiceBody ::= '{' ServiceElement* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } + private ServiceElement ::= ServiceOption | RpcDefinition | ';' {recoverWhile=ServiceElementRecovery} private ServiceElementRecovery ::= !(option | stream | rpc | ';' | '}') ServiceOption ::= option OptionAssign ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] } RpcDefinition ::= rpc Identifier RpcIO returns RpcIO ( RpcBody | ';') { pin = 1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufRpcDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufRpcDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufRpcDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufRpcDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } + RpcIO ::= '(' stream? TypeName ')' { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock"] + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + ] } + RpcBody ::= '{' RpcElement* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } + private RpcElement ::= RpcOption | ';' { recoverWhile=RpcElementRecovery } private RpcElementRecovery ::= !(option | ';' | '}') RpcOption ::= option OptionAssign ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] } ExtendDefinition ::= extend TypeName ExtendBody { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufExtendDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufExtendDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufExtendDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufExtendStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufExtendDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufExtendStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } ExtendBody ::= '{' ExtendElement* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } private ExtendElement ::= GroupDefinition | FieldDefinition | ';' {recoverWhile=ExtendElementRecovery} private ExtendElementRecovery ::= !(FieldLabel | group | TypeName | ';' | '}') -Constant ::= (StringValue+) | NumberValue | BooleanValue | MessageValue | EnumValue | ArrayValue { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement"] -} -TypeName ::= '.'? SymbolName ('.' SymbolName)* { +TypeName ::= '.'? SymbolName ('.' TypeName)? { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufFileReferenceContributor" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.QualifiedElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufFileReferenceContributor" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufTypeNameMixin" -} -SymbolName ::= IdentifierWithKeyword { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufTypeNameMixin" } -FieldName ::= IdentifierWithKeyword { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufFieldNameMixin" + +ExtensionFieldName ::= '.'? SymbolName ('.' ExtensionFieldName)? { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.QualifiedElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufFileReferenceContributor" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufExtensionFieldNameMixin" } -EnumValue ::= IdentifierWithKeyword { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufEnumValueMixin" + +SymbolName::= IdentifierWithKeyword { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] } + Identifier::= IdentifierWithKeyword { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" ] } private IdentifierWithKeyword ::= IDENTIFIER_LITERAL | <> -StringValue ::= STRING_LITERAL { +StringValue ::= STRING_LITERAL+ { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufFileReferenceContributor" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufFileReferenceContributor" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.ReferenceElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.StringValue" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufStringValueMixin" + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufStringValueMixin" } -IntegerValue ::= '-'? INTEGER_LITERAL{ - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] + +IntegerValue ::= ('-' | '+')? INTEGER_LITERAL{ + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.IntegerValue" + ] } -NumberValue ::= '-'? (INTEGER_LITERAL | FLOAT_LITERAL | 'inf' | 'nan'){ - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] + +NumberValue ::= ('-' | '+')? (INTEGER_LITERAL | FLOAT_LITERAL | 'inf' | 'nan') { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.NumberValue" + ] } + + BooleanValue ::= (false | true) { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.BooleanValue" + ] +} + +EnumValue ::= IdentifierWithKeyword { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.EnumValue" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufEnumValueMixin" +} + +Constant ::= StringValue | BooleanValue | NumberValue | MessageValue | EnumValue { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.WrappedValue" + ] +} + +FieldName ::= SymbolName | ExtensionName | AnyName { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufFieldNameMixin" } -MessageValue ::= '{' FieldAssign* '}' { + +Domain ::= Identifier ( '.' Identifier )* { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + + +ExtensionName ::= '[' ExtensionFieldName ']' { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + +AnyName ::= '[' Domain '/' TypeName ']' { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + + +ScalarList ::= '[' ScalarValue (',' ScalarValue)* ']' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.ArrayValue" ] } -ArrayValue ::= '[' Constant (',' Constant)* ']' { + +ScalarValue ::= StringValue | NumberValue | BooleanValue | EnumValue { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.WrappedValue" + ] +} + +MessageValue ::= '{' Field* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue" ] } -FieldAssign ::= FieldName ':' Constant (';' | ',')? { + +MessageList ::= '[' MessageValue (',' MessageValue)* ']' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.ArrayValue" + ] +} + +Field ::= FieldName (MessageField | ScalarField) (";" | ",")? { pin = 1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufFieldAssign" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufFieldAssign" ] +} + +private MessageField ::= ':'? ( MessageValue | MessageList ) + +private ScalarField ::= ':' ( ScalarValue | ScalarList ) { + pin = 1 } \ No newline at end of file diff --git a/src/main/grammar/protobuf.flex b/src/main/grammar/protobuf.flex index c6dd9b0d..79f1acc6 100644 --- a/src/main/grammar/protobuf.flex +++ b/src/main/grammar/protobuf.flex @@ -1,6 +1,6 @@ -package io.kanro.idea.plugin.protobuf.lang.lexer; +package io.kanro.idea.plugin.protobuf.lang.lexer.proto; -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens; +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens; import com.intellij.lexer.FlexLexer; import com.intellij.psi.tree.IElementType; @@ -92,6 +92,7 @@ String = {SingleQuotedString} | {DoubleQuotedString} "(" { return ProtobufTokens.LPAREN; } "<" { return ProtobufTokens.LT; } "-" { return ProtobufTokens.MINUS; } + "+" { return ProtobufTokens.PLUS; } "}" { return ProtobufTokens.RBRACE; } "]" { return ProtobufTokens.RBRACK; } ")" { return ProtobufTokens.RPAREN; } @@ -121,6 +122,7 @@ String = {SingleQuotedString} | {DoubleQuotedString} "service" { return ProtobufTokens.SERVICE; } "stream" { return ProtobufTokens.STREAM; } "syntax" { return ProtobufTokens.SYNTAX; } + "edition" { return ProtobufTokens.EDITION; } "to" { return ProtobufTokens.TO; } "true" { return ProtobufTokens.TRUE; } "false" { return ProtobufTokens.FALSE; } diff --git a/src/main/grammar/prototext.bnf b/src/main/grammar/prototext.bnf new file mode 100644 index 00000000..0a134d00 --- /dev/null +++ b/src/main/grammar/prototext.bnf @@ -0,0 +1,205 @@ +{ + generate=[names="long" psi="yes" tokens="no"] + parserClass="io.kanro.idea.plugin.protobuf.lang.psi.text.parser.ProtoTextParser" + parserUtilClass="io.kanro.idea.plugin.protobuf.lang.parser.ProtobufParserUtil" + parserImports=[ + "static io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens.*" + ] + psiClassPrefix="ProtoText" + psiImplClassSuffix="Impl" + psiPackage="io.kanro.idea.plugin.protobuf.lang.psi.text" + psiImplPackage="io.kanro.idea.plugin.protobuf.lang.psi.text.impl" + + implements="io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + extends="io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElementBase" + + elementTypeHolderClass="io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextTypes" + elementTypeClass="io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElementType" + + tokens = [ + SKIPPED_WHITESPACE = "regexp:[ \n\t\r\f]+" + + SHARP_LINE_COMMENT = "regexp:#[^\n]*\n?" + + IDENTIFIER_LITERAL = "regexp:[a-zA-Z_][a-zA-Z0-9_]*" + + INTEGER_LITERAL = "regexp:(0|[1-9][0-9]*)|(0[xX][0-9a-fA-F]+)|(0[0-7]+)" + FLOAT_LITERAL = "regexp:(\.[0-9]+|(0|[1-9][0-9]*)\.[0-9]*|(0|[1-9][0-9]*))([eE][-+]?[0-9]+)?" + + STRING_LITERAL = "regexp:('(\\.|[^'\n])*')|(\"(\\.|[^\"\n])*\")" + + ASSIGN = '=' + COMMA = ',' + DOT = '.' + GT = '>' + LBRACE = '{' + LBRACK = '[' + LPAREN = '(' + LT = '<' + MINUS = '-' + PLUS = '+' + RBRACE = '}' + RBRACK = ']' + RPAREN = ')' + SEMI = ';' + SLASH = '/' + COLON = ':' + + SYMBOL = "regexp:[!#$%&()*+,-./:;<=>?@\[\\\]^`{|}~]" + ] +} + +File ::= Field* { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue" + ] +} + +Field ::= FieldName (MessageField | ScalarField) (";" | ",")? { + pin = 1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.text.feature.ProtoTextFieldAssign" + ] +} + +private MessageField ::= ':'? ( MessageValue | MessageList ) + +private ScalarField ::= ':' ( ScalarValue | ScalarList ) { + pin = 1 +} + +MessageList ::= '[' MessageValue (',' MessageValue)* ']' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.ArrayValue" + ] +} + +private MessageValue ::= BraceMessageValue | PointyMessageValue + +BraceMessageValue ::= '{' Field* '}' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue" + ] +} + +PointyMessageValue ::= '<' Field* '>' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue" + ] +} + +ScalarList ::= '[' ScalarValue (',' ScalarValue)* ']' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.ArrayValue" + ] +} + +ScalarValue ::= StringValue | NumberValue | BooleanValue | EnumValue { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.WrappedValue" + ] +} + +StringValue ::= STRING_LITERAL+ { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.StringValue" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.ReferenceElement" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.text.mixin.ProtoTextStringValueMixin" +} + +NumberValue ::= ('-' | '+')? (INTEGER_LITERAL | FLOAT_LITERAL | 'inf' | 'nan') { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.NumberValue" + ] +} + +BooleanValue ::= (false | true) { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.BooleanValue" + ] +} + +EnumValue ::= Identifier { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.EnumValue" + ] +} + +FieldName ::= SymbolName | ExtensionName | AnyName { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.text.mixin.ProtoTextFieldNameMixin" +} + +SymbolName ::= Identifier { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + +TypeName ::= SymbolName ('.' TypeName)? { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.QualifiedElement" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.text.mixin.ProtoTextTypeNameMixin" +} + +Domain ::= Identifier ( '.' Identifier )* { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + +ExtensionName ::= '[' TypeName ']' { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + +AnyName ::= '[' Domain '/' TypeName ']' { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + +private Identifier ::= IDENTIFIER_LITERAL diff --git a/src/main/grammar/prototext.flex b/src/main/grammar/prototext.flex new file mode 100644 index 00000000..de2e233a --- /dev/null +++ b/src/main/grammar/prototext.flex @@ -0,0 +1,130 @@ +package io.kanro.idea.plugin.protobuf.lang.lexer.text; + +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens; + +import com.intellij.lexer.FlexLexer; +import com.intellij.psi.tree.IElementType; + +%% + +%public +%class _ProtoTextLexer +%implements FlexLexer +%function advance +%type IElementType +%unicode +%state LINE_COMMENT, SHARP_LINE_COMMENT, BLOCK_COMMENT, AFTER_NUMBER + +// General classes +Alpha = [a-zA-Z_] +Digit = [0-9] +NonZeroDigit = [1-9] +HexDigit = [0-9a-fA-F] +OctDigit = [0-7] +Alphanumeric = {Alpha} | {Digit} + +// Catch-all for symbols not handled elsewhere. +// +// From tokenizer.h: +// Any other printable character, like '!' or '+'. Symbols are always a single character, so +// "!+$%" is four tokens. +Symbol = [!#$%&()*+,-./:;<=>?@\[\\\]\^`{|}~] + +// Whitespace. +WhitespaceNoNewline = [\ \t\r\f\x0b] // '\x0b' is '\v' (vertical tab) in C. +NewLine = "\n" +Whitespace = ({WhitespaceNoNewline} | {NewLine})+ + +// Comments. +SharpLineComments = ("#" [^\n]*) + +// Identifiers. +// +// From tokenizer.h: +// A sequence of letters, digits, and underscores, not starting with a digit. It is an error for +// a number to be followed by an identifier with no space in between. +Identifier = {Alpha} {Alphanumeric}* + +// Integers. +// +// From tokenizer.h: +// A sequence of digits representing an integer. Normally the digits are decimal, but a prefix of +// "0x" indicates a hex number and a leading zero indicates octal, just like with C numeric +// literals. A leading negative sign is NOT included in the token; it's up to the parser to +// interpret the unary minus operator on its own. +DecInteger = "0" | {NonZeroDigit} {Digit}* +OctInteger = "0" {OctDigit}+ +HexInteger = "0" [xX] {HexDigit}+ +Integer = {DecInteger} | {OctInteger} | {HexInteger} + +// Floats. +// +// From tokenizer.h: +// A floating point literal, with a fractional part and/or an exponent. Always in decimal. +// Again, never negative. +Float = ("." {Digit}+ {Exponent}? | {DecInteger} "." {Digit}* {Exponent}? | {DecInteger} {Exponent}) +Exponent = [eE] [-+]? {Digit}+ + +// Strings. +// +// From tokenizer.h: +// A quoted sequence of escaped characters. Either single or double quotes can be used, but they +// must match. A string literal cannot cross a line break. +SingleQuotedString = \' ([^\\\'\n] | \\[^\n])* (\' | \\)? +DoubleQuotedString = \" ([^\\\"\n] | \\[^\n])* (\" | \\)? +String = {SingleQuotedString} | {DoubleQuotedString} + +%% + + { + {Whitespace} { return com.intellij.psi.TokenType.WHITE_SPACE; } + + "=" { return ProtoTextTokens.ASSIGN; } + ":" { return ProtoTextTokens.COLON; } + "," { return ProtoTextTokens.COMMA; } + "." { return ProtoTextTokens.DOT; } + ">" { return ProtoTextTokens.GT; } + "{" { return ProtoTextTokens.LBRACE; } + "[" { return ProtoTextTokens.LBRACK; } + "(" { return ProtoTextTokens.LPAREN; } + "<" { return ProtoTextTokens.LT; } + "-" { return ProtoTextTokens.MINUS; } + "+" { return ProtoTextTokens.PLUS; } + "}" { return ProtoTextTokens.RBRACE; } + "]" { return ProtoTextTokens.RBRACK; } + ")" { return ProtoTextTokens.RPAREN; } + ";" { return ProtoTextTokens.SEMI; } + "/" { return ProtoTextTokens.SLASH; } + + "true" { return ProtoTextTokens.TRUE; } + "false" { return ProtoTextTokens.FALSE; } + + {Identifier} { return ProtoTextTokens.IDENTIFIER_LITERAL; } + {String} { return ProtoTextTokens.STRING_LITERAL; } + {Integer} { yybegin(AFTER_NUMBER); return ProtoTextTokens.INTEGER_LITERAL; } + {Float} { yybegin(AFTER_NUMBER); return ProtoTextTokens.FLOAT_LITERAL; } + + "#" { + yypushback(1); + yybegin(SHARP_LINE_COMMENT); + } + + // Additional unmatched symbols are matched individually as SYMBOL. + {Symbol} { return ProtoTextTokens.SYMBOL; } + + // All other unmatched characters. + [^] { return com.intellij.psi.TokenType.BAD_CHARACTER; } +} + + { + {SharpLineComments} { yybegin(YYINITIAL); return ProtoTextTokens.SHARP_LINE_COMMENT; } +} + + { + // An identifier immediately following a number (with no whitespace) is an error. We return + // the special IDENTIFIER_AFTER_NUMBER token type to signal this scenario. + {Identifier} { yybegin(YYINITIAL); return ProtoTextTokens.IDENTIFIER_AFTER_NUMBER; } + + // Any other token is valid. Push the token back and return to the initial state. + [^] { yybegin(YYINITIAL); yypushback(yylength()); } +} \ No newline at end of file diff --git a/src/main/java/io/kanro/idea/plugin/protobuf/lang/parser/ProtobufParserUtil.java b/src/main/java/io/kanro/idea/plugin/protobuf/lang/parser/ProtobufParserUtil.java index 9c425024..9703c6a8 100644 --- a/src/main/java/io/kanro/idea/plugin/protobuf/lang/parser/ProtobufParserUtil.java +++ b/src/main/java/io/kanro/idea/plugin/protobuf/lang/parser/ProtobufParserUtil.java @@ -2,11 +2,11 @@ import com.intellij.lang.PsiBuilder; import com.intellij.lang.parser.GeneratedParserUtilBase; -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufKeywordToken; -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens; +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufKeywordToken; +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens; public class ProtobufParserUtil extends GeneratedParserUtilBase { - static boolean parseKeyword(PsiBuilder builder, int level) { + public static boolean parseKeyword(PsiBuilder builder, int level) { if (builder.eof()) { return false; } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/ProtobufIcons.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/ProtobufIcons.kt index c63dc0a3..5c21541f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/ProtobufIcons.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/ProtobufIcons.kt @@ -21,6 +21,7 @@ object ProtobufIcons { val MESSAGE: Icon = loadIcon("message.svg") val RESOURCE_MESSAGE: Icon = loadIcon("resource_message.svg") val FILE: Icon = loadIcon("protobuf_file.svg") + val TEXT_FILE: Icon = loadIcon("protobuf_text_file.svg") val LOGO: Icon = loadIcon("logo.svg") val FOLDER: Icon = PlatformIcons.FOLDER_ICON diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/Extension.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/Extension.kt index 5971a325..2d1b6b12 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/Extension.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/Extension.kt @@ -3,10 +3,9 @@ package io.kanro.idea.plugin.protobuf.aip import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition import io.kanro.idea.plugin.protobuf.lang.psi.nullCachedValue -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition internal fun ProtobufRpcDefinition.transcodingBody(): String? { return CachedValuesManager.getCachedValue(this) { @@ -14,7 +13,7 @@ internal fun ProtobufRpcDefinition.transcodingBody(): String? { options(AipOptions.httpOption).lastOrNull() ?: return@getCachedValue nullCachedValue() - val result = option.value(AipOptions.httpRuleBodyField)?.stringValue() ?: "" + val result = option.value(AipOptions.httpRuleBodyField)?.toString() ?: "" CachedValueProvider.Result.create(result, PsiModificationTracker.MODIFICATION_COUNT) } } @@ -22,7 +21,7 @@ internal fun ProtobufRpcDefinition.transcodingBody(): String? { internal fun ProtobufRpcDefinition.resolveInput(): ProtobufMessageDefinition? { return CachedValuesManager.getCachedValue(this) { val input = - this.rpcIOList.firstOrNull()?.typeName?.reference?.resolve() as? ProtobufMessageDefinition + this.rpcIOList.firstOrNull()?.typeName?.resolve() as? ProtobufMessageDefinition ?: return@getCachedValue nullCachedValue() return@getCachedValue CachedValueProvider.Result.create(input, PsiModificationTracker.MODIFICATION_COUNT) } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/annotator/AipAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/annotator/AipAnnotator.kt index 6529ba8e..0e97e5b5 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/annotator/AipAnnotator.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/annotator/AipAnnotator.kt @@ -7,14 +7,13 @@ import com.intellij.lang.annotation.HighlightSeverity import com.intellij.psi.PsiElement import io.kanro.idea.plugin.protobuf.aip.quickfix.AddResourceImportFix import io.kanro.idea.plugin.protobuf.aip.reference.AipResourceReference +import io.kanro.idea.plugin.protobuf.aip.reference.AipTypeNameReference import io.kanro.idea.plugin.protobuf.aip.reference.ProtobufFieldReferenceInString import io.kanro.idea.plugin.protobuf.aip.reference.ProtobufRpcInputFieldReference import io.kanro.idea.plugin.protobuf.aip.reference.ProtobufRpcOutputFieldReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufVisitor -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufVisitor import io.kanro.idea.plugin.protobuf.lang.quickfix.AddImportFix -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufTypeNameReference class AipAnnotator : Annotator { override fun annotate( @@ -52,7 +51,7 @@ class AipAnnotator : Annotator { .create() } - is ProtobufTypeNameReference -> { + is AipTypeNameReference -> { holder.newAnnotation( HighlightSeverity.ERROR, "Type \"${o.value()}\" not found.", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/completion/AipCompletionContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/completion/AipCompletionContributor.kt index dad960f5..e187a89a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/completion/AipCompletionContributor.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/completion/AipCompletionContributor.kt @@ -15,10 +15,10 @@ import com.intellij.util.ProcessingContext import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.aip.reference.AipResourceResolver import io.kanro.idea.plugin.protobuf.lang.completion.AutoPopupInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIdentifier -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIdentifier +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition import io.kanro.idea.plugin.protobuf.string.plural class AipCompletionContributor : CompletionContributor() { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/method/AipSpecMethod.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/method/AipSpecMethod.kt index 817ce993..c590512a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/method/AipSpecMethod.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/method/AipSpecMethod.kt @@ -1,7 +1,7 @@ package io.kanro.idea.plugin.protobuf.aip.method import com.intellij.lang.annotation.AnnotationHolder -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition interface AipSpecMethod { val action: String diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/quickfix/AddResourceImportFix.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/quickfix/AddResourceImportFix.kt index 0083eda5..db05f417 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/quickfix/AddResourceImportFix.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/quickfix/AddResourceImportFix.kt @@ -8,12 +8,10 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile import com.intellij.psi.stubs.StubIndex -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ResourceTypeIndex -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ResourceTypeIndex import io.kanro.idea.plugin.protobuf.lang.quickfix.ProtobufAddImportAction import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver @@ -60,10 +58,10 @@ class AddResourceImportFix( private fun createAction( project: Project, editor: Editor, - host: ProtobufSymbolReferenceHost, + host: ProtobufStringValue, elements: Array, ): ProtobufAddImportAction { - return ProtobufAddImportAction(project, editor, host, null, elements) + return ProtobufAddImportAction(project, editor, host, elements) } override fun getText(): String { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceReference.kt index 2489ae10..b3261acc 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceReference.kt @@ -14,19 +14,17 @@ import io.kanro.idea.plugin.protobuf.aip.AipOptions import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler import io.kanro.idea.plugin.protobuf.lang.completion.ComposedInsertHandler import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFileOption -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.stringRangeInParent -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ResourceTypeIndex -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFileOption +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stringRangeInParent +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ResourceTypeIndex import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver class AipResourceReference(element: ProtobufStringValue) : PsiReferenceBase(element) { override fun resolve(): PsiElement? { - val resourceName = element.stringLiteral.text.trim('"') + val resourceName = element.value() return AipResourceResolver.resolveAbsolutely(element.file(), resourceName) } @@ -93,7 +91,7 @@ class AipResourceReference(element: ProtobufStringValue) : PsiReferenceBase { val resourceName = - element.value(AipOptions.resourceTypeField)?.stringValue() ?: return null + element.value(AipOptions.resourceTypeField)?.toString() ?: return null LookupElementBuilder.create( resourceName, ).withLookupString(resourceName.substringAfterLast('/')) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceResolver.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceResolver.kt index e93afd12..43def145 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceResolver.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceResolver.kt @@ -1,12 +1,11 @@ package io.kanro.idea.plugin.protobuf.aip.reference import io.kanro.idea.plugin.protobuf.aip.AipOptions -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.public -import io.kanro.idea.plugin.protobuf.lang.psi.resolve -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.public +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren import java.util.Stack @@ -37,7 +36,7 @@ object AipResourceResolver { resourceName: String, ): ProtobufElement? { file.resourceDefinitions().forEach { - if (it.value(AipOptions.resourceTypeField)?.stringValue() == resourceName) { + if (it.value(AipOptions.resourceTypeField)?.toString() == resourceName) { return it } } @@ -75,7 +74,7 @@ object AipResourceResolver { result: MutableList = mutableListOf(), ): ProtobufElement? { file.resourceDefinitions().forEach { - if (it.value(AipOptions.resourceTypeField)?.stringValue() != null) { + if (it.value(AipOptions.resourceTypeField)?.toString() != null) { result += it } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipTypeNameReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipTypeNameReference.kt new file mode 100644 index 00000000..f9b74362 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipTypeNameReference.kt @@ -0,0 +1,140 @@ +package io.kanro.idea.plugin.protobuf.aip.reference + +import com.intellij.codeInsight.completion.CompletionUtilCore +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.patterns.PlatformPatterns +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.stubs.StubIndex +import com.intellij.psi.util.PsiElementFilter +import com.intellij.psi.util.QualifiedName +import com.intellij.psi.util.parentOfType +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stringRangeInParent +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver +import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver +import io.kanro.idea.plugin.protobuf.lang.util.removeCommonPrefix + +class AipTypeNameReference(element: ProtobufStringValue) : PsiReferenceBase(element) { + override fun resolve(): PsiElement? { + val typeName = QualifiedName.fromDottedString(element.value()) + return ProtobufSymbolResolver.resolveRelatively(element, typeName, ProtobufSymbolFilters.message) + } + + override fun calculateDefaultRangeInElement(): TextRange { + return element.stringRangeInParent() + } + + override fun getVariants(): Array { + val result = mutableListOf() + val addedElements = mutableSetOf() + val filter = ProtobufSymbolFilters.messageTypeName + + getVariantsInCurrentScope(filter, result, addedElements) + getVariantsInStubIndex(filter, result, addedElements) + return result.toTypedArray() + } + + private fun getVariantsInCurrentScope( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ) { + val parent = element.value().substringBeforeLast('.', "").split('.').filter { it.isNotEmpty() } + val parentScope = QualifiedName.fromComponents(parent) + ProtobufSymbolResolver.collectRelatively(element, parentScope, filter).forEach { + if (it in elements) return@forEach + result += lookupFor(it, parentScope) ?: return@forEach + elements += it + } + } + + private fun getVariantsInStubIndex( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ): Array { + val value = element.value() + if (value.contains('.')) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + + val searchName = value.substringBefore(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED) + val scope = ProtobufRootResolver.searchScope(element) + val matcher = PlatformPatterns.string().contains(searchName) + val currentScope = element.parentOfType()?.scope() + + return StubIndex.getInstance().getAllKeys(ShortNameIndex.key, element.project).asSequence().filter { + matcher.accepts(it) + }.flatMap { + StubIndex.getElements(ShortNameIndex.key, it, element.project, scope, ProtobufElement::class.java) + .asSequence() + }.filter { + filter.isAccepted(it) + }.mapNotNull { + if (it in elements) return@mapNotNull null + result += lookupForStub(it, currentScope) ?: return@mapNotNull null + elements += it + }.toList().toTypedArray() + } + + private fun lookupFor( + element: ProtobufElement, + scope: QualifiedName, + ): LookupElement? { + val lookupElement = element as? LookupableElement ?: return null + val fullName = scope.append(lookupElement.name).toString() + var builder = lookupElement.lookup(fullName) ?: return null + if (element is ProtobufPackageName) { + builder = builder.withInsertHandler(packageInsertHandler) + } + return builder + } + + private fun lookupForStub( + element: ProtobufElement, + currentScope: QualifiedName?, + ): LookupElement? { + if (element !is ProtobufDefinition) return null + val qualifiedName = element.qualifiedName() ?: return null + + val targetName = + if (currentScope != null) { + qualifiedName.removeCommonPrefix(currentScope) + } else { + qualifiedName + } + return LookupElementBuilder.create(targetName).withLookupString(qualifiedName.lastComponent!!) + .withPresentableText(qualifiedName.lastComponent!!).withIcon(element.getIcon(false)) + .withTailText("${element.tailText() ?: ""} (${qualifiedName.removeTail(1)})", true) + .withTypeText(element.type()).withInsertHandler(AddImportInsertHandler(element)) + } + + override fun handleElementRename(newElementName: String): PsiElement { + val scope = element.value().substringBeforeLast('.', "") + val name = + if (scope.isEmpty()) { + newElementName + } else { + "$scope.$newElementName" + } + return element.replace(ProtobufPsiFactory.createStringValue(element.project, name)) + } + + companion object { + private val stringValueInsertHandler = SmartInsertHandler("\"") + + private val packageInsertHandler = SmartInsertHandler(".", 0, true) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/ProtobufFieldReferenceInString.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/ProtobufFieldReferenceInString.kt index 69af6d8b..7e6d2ecf 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/ProtobufFieldReferenceInString.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/ProtobufFieldReferenceInString.kt @@ -3,27 +3,26 @@ package io.kanro.idea.plugin.protobuf.aip.reference import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import com.intellij.psi.PsiReferenceBase -import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.psi.util.parentOfType import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stringRangeInParent +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike import io.kanro.idea.plugin.protobuf.lang.psi.realItems -import io.kanro.idea.plugin.protobuf.lang.psi.stringRangeInParent -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.text.feature.ProtoTextFieldAssign class ProtobufRpcInputFieldReference(field: ProtobufStringValue) : ProtobufFieldReferenceInString(field) { override fun message(): ProtobufMessageDefinition? { val rpc = element.parentOfType() as? ProtobufRpcDefinition ?: return null - return rpc.input()?.typeName?.reference?.resolve() as? ProtobufMessageDefinition + return rpc.input()?.typeName?.resolve() as? ProtobufMessageDefinition } } @@ -31,7 +30,7 @@ class ProtobufRpcOutputFieldReference(field: ProtobufStringValue) : ProtobufFieldReferenceInString(field) { override fun message(): ProtobufMessageDefinition? { val rpc = element.parentOfType() as? ProtobufRpcDefinition ?: return null - return rpc.output()?.typeName?.reference?.resolve() as? ProtobufMessageDefinition + return rpc.output()?.typeName?.resolve() as? ProtobufMessageDefinition } } @@ -57,7 +56,7 @@ abstract class ProtobufFieldReferenceInString(field: ProtobufStringValue) : return message()?.realItems()?.mapNotNull { (it as? ProtobufFieldLike)?.lookup()?.let { when (element.parent) { - is ProtobufFieldAssign -> it.withInsertHandler(insertHandler) + is ProtoTextFieldAssign -> it.withInsertHandler(insertHandler) is ProtobufOptionName -> it.withInsertHandler(insertHandler) else -> it } @@ -66,8 +65,7 @@ abstract class ProtobufFieldReferenceInString(field: ProtobufStringValue) : } override fun handleElementRename(newElementName: String): PsiElement { - (element.stringLiteral.node as? LeafElement)?.replaceWithText("\"$newElementName\"") - return element + return element.replace(ProtobufPsiFactory.createStringValue(element.project, newElementName)) } companion object { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/AipReferenceContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/AipReferenceContributor.kt index e7d1b331..e34694a9 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/AipReferenceContributor.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/AipReferenceContributor.kt @@ -10,14 +10,16 @@ import com.intellij.psi.util.parentOfType import com.intellij.util.ProcessingContext import io.kanro.idea.plugin.protobuf.aip.AipOptions import io.kanro.idea.plugin.protobuf.aip.reference.AipResourceReference +import io.kanro.idea.plugin.protobuf.aip.reference.AipTypeNameReference import io.kanro.idea.plugin.protobuf.aip.reference.ProtobufRpcInputFieldReference import io.kanro.idea.plugin.protobuf.aip.reference.ProtobufRpcOutputFieldReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOptionAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike class AipReferenceContributor : PsiReferenceContributor() { override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { @@ -34,6 +36,13 @@ class AipReferenceContributor : PsiReferenceContributor() { .inside(ProtobufOptionAssign::class.java), AipFieldReferenceProvider(), ) + + registrar.registerReferenceProvider( + PlatformPatterns.psiElement(ProtobufStringValue::class.java) + .inside(ProtobufRpcDefinition::class.java) + .inside(ProtobufOptionAssign::class.java), + AipTypeNameReferenceProvider(), + ) } } @@ -50,18 +59,17 @@ class AipResourceReferenceProvider : PsiReferenceProvider() { private fun getReference(element: ProtobufStringValue): PsiReference? { val hover = element.parentOfType() ?: return null if (!hover.isOption(AipOptions.resourceReferenceOption)) return null - if (hover.value(AipOptions.resourceTypeField)?.stringValueList?.firstOrNull() == element) { - return AipResourceReference( - element, - ) - } - if (hover.value(AipOptions.resourceChildTypeField)?.stringValueList?.firstOrNull() == element) { + if (element.value().matches(resourceTypePattern)) { return AipResourceReference( element, ) } return null } + + companion object { + private val resourceTypePattern = Regex("""^(\w+\.)*\w+/(\w+\.)*\w+$""") + } } class AipFieldReferenceProvider : PsiReferenceProvider() { @@ -76,10 +84,36 @@ class AipFieldReferenceProvider : PsiReferenceProvider() { private fun getReference(element: ProtobufStringValue): PsiReference? { if (element.textMatches("\"*\"")) return null - val assign = element.parentOfType() ?: return null - val targetField = assign.field()?.qualifiedName() + val assign = element.parentOfType() ?: return null + val targetField = (assign.field() as? ProtobufFieldLike)?.qualifiedName() if (targetField == AipOptions.httpRuleBodyName) return ProtobufRpcInputFieldReference(element) if (targetField == AipOptions.httpRuleResponseBodyName) return ProtobufRpcOutputFieldReference(element) return null } } + +class AipTypeNameReferenceProvider : PsiReferenceProvider() { + override fun getReferencesByElement( + element: PsiElement, + context: ProcessingContext, + ): Array { + val stringValue = element as? ProtobufStringValue ?: return PsiReference.EMPTY_ARRAY + val reference = getReference(stringValue) ?: return PsiReference.EMPTY_ARRAY + return arrayOf(reference) + } + + private fun getReference(element: ProtobufStringValue): PsiReference? { + val assign = element.parentOfType() ?: return null + when (assign.field()?.qualifiedName()) { + AipOptions.lroMetadataName -> { + return AipTypeNameReference(element) + } + + AipOptions.lroResponseName -> { + return AipTypeNameReference(element) + } + + else -> return null + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/ProtobufTypeNameInStringProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/ProtobufTypeNameInStringProvider.kt index 932f5016..41526a29 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/ProtobufTypeNameInStringProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/ProtobufTypeNameInStringProvider.kt @@ -1,120 +1,104 @@ package io.kanro.idea.plugin.protobuf.aip.reference.contributor -import com.intellij.openapi.util.TextRange -import com.intellij.psi.impl.source.tree.LeafElement -import com.intellij.psi.util.CachedValueProvider -import com.intellij.psi.util.CachedValuesManager -import com.intellij.psi.util.PsiElementFilter -import com.intellij.psi.util.PsiModificationTracker -import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.aip.AipOptions -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceProvider -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufValueAssign -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters -import io.kanro.idea.plugin.protobuf.string.splitToRange - -class ProtobufTypeNameInStringProvider : ProtobufSymbolReferenceProvider { - override fun hovers(element: ProtobufSymbolReferenceHost): ProtobufSymbolReferenceHover? { - if (element !is ProtobufStringValue) return null - return CachedValuesManager.getCachedValue(element) { - val assign = element.parentOfType() ?: return@getCachedValue null - val targetField = assign.field()?.qualifiedName() - return@getCachedValue when { - targetField == AipOptions.lroMetadataName -> { - CachedValueProvider.Result.create( - StringProtobufSymbolReferenceHover( - element, - ProtobufSymbolFilters.rpcTypeNameVariants, - ), - PsiModificationTracker.MODIFICATION_COUNT, - ) - } - targetField == AipOptions.lroResponseName -> { - CachedValueProvider.Result.create( - StringProtobufSymbolReferenceHover( - element, - ProtobufSymbolFilters.rpcTypeNameVariants, - ), - PsiModificationTracker.MODIFICATION_COUNT, - ) - } - else -> null - } - } - } -} - -class StringProtobufSymbolReferenceHover( - val element: ProtobufStringValue, - private val filter: PsiElementFilter, -) : ProtobufSymbolReferenceHover { - private var text = element.text - private val range: TextRange - private val parts: List - private val absolutely: Boolean - - init { - var range = element.textRange - var offset = 0 - if (text.startsWith('"')) { - text = text.substring(1) - offset += 1 - range = TextRange.create(range.startOffset + 1, range.endOffset) - } - if (text.startsWith('.')) { - absolutely = true - text = text.substring(1) - offset += 1 - range = TextRange.create(range.startOffset + 1, range.endOffset) - } else { - absolutely = false - } - if (text.endsWith('"')) { - text = text.substring(0, text.length - 1) - range = TextRange.create(range.startOffset, range.endOffset - 1) - } - this.range = range - - parts = - text.splitToRange('.').map { - val realRange = it.shiftRight(offset) - ProtobufSymbolReferenceHover.SymbolPart(realRange.startOffset, realRange.substring(element.text)) - } - } - - override fun textRange(): TextRange { - return range - } - - override fun symbolParts(): List { - return parts - } - - override fun renamePart( - index: Int, - newName: String, - ) { - val leaf = (element.stringLiteral.node as LeafElement) - val value = element.text - val part = symbolParts()[index] - val start = value.substring(0, part.startOffset) - val end = value.substring(part.startOffset + part.value.length, value.length) - leaf.replaceWithText("$start$newName$end") - } - - override fun rename(newName: String) { - val leaf = (element.stringLiteral.node as LeafElement) - leaf.replaceWithText("\"$newName\"") - } - - override fun absolutely(): Boolean { - return absolutely - } - - override fun variantFilter(): PsiElementFilter { - return filter - } -} +// class ProtobufTypeNameInStringProvider : ProtobufSymbolReferenceProvider { +// override fun hovers(element: ProtobufSymbolReferenceHost): ProtobufSymbolReferenceHover? { +// if (element !is ProtobufStringValue) return null +// return CachedValuesManager.getCachedValue(element) { +// val assign = element.parentOfType() ?: return@getCachedValue null +// val targetField = assign.field()?.qualifiedName() +// return@getCachedValue when { +// targetField == AipOptions.lroMetadataName -> { +// CachedValueProvider.Result.create( +// StringProtobufSymbolReferenceHover( +// element, +// ProtobufSymbolFilters.messageTypeName, +// ), +// PsiModificationTracker.MODIFICATION_COUNT, +// ) +// } +// +// targetField == AipOptions.lroResponseName -> { +// CachedValueProvider.Result.create( +// StringProtobufSymbolReferenceHover( +// element, +// ProtobufSymbolFilters.messageTypeName, +// ), +// PsiModificationTracker.MODIFICATION_COUNT, +// ) +// } +// +// else -> null +// } +// } +// } +// } +// +// class StringProtobufSymbolReferenceHover( +// val element: ProtobufStringValue, +// private val filter: PsiElementFilter, +// ) : ProtobufSymbolReferenceHover { +// private var text = element.text +// private val range: TextRange +// private val parts: List +// private val absolutely: Boolean +// +// init { +// var range = element.textRange +// var offset = 0 +// if (text.startsWith('"')) { +// text = text.substring(1) +// offset += 1 +// range = TextRange.create(range.startOffset + 1, range.endOffset) +// } +// if (text.startsWith('.')) { +// absolutely = true +// text = text.substring(1) +// offset += 1 +// range = TextRange.create(range.startOffset + 1, range.endOffset) +// } else { +// absolutely = false +// } +// if (text.endsWith('"')) { +// text = text.substring(0, text.length - 1) +// range = TextRange.create(range.startOffset, range.endOffset - 1) +// } +// this.range = range +// +// parts = +// text.splitToRange('.').map { +// val realRange = it.shiftRight(offset) +// ProtobufSymbolReferenceHover.SymbolPart(realRange.startOffset, realRange.substring(element.text)) +// } +// } +// +// override fun textRange(): TextRange { +// return range +// } +// +// override fun symbolParts(): List { +// return parts +// } +// +// override fun renamePart( +// index: Int, +// newName: String, +// ) { +// val value = element.value() +// val part = symbolParts()[index] +// val start = value.substring(0, part.startOffset) +// val end = value.substring(part.startOffset + part.value.length, value.length) +// element.replace(ProtobufPsiFactory.createStringValue(element.project, "$start$newName$end")) +// } +// +// override fun rename(newName: String) { +// element.replace(ProtobufPsiFactory.createStringValue(element.project, newName)) +// } +// +// override fun absolutely(): Boolean { +// return absolutely +// } +// +// override fun variantFilter(): PsiElementFilter { +// return filter +// } +// } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/Protoc.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/Protoc.kt index d58a555a..6745fefb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/Protoc.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/Protoc.kt @@ -7,9 +7,9 @@ import com.intellij.openapi.extensions.ExtensionPointName import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve import java.lang.reflect.ParameterizedType import java.util.Stack diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/States.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/States.kt index bed054b7..a39e8722 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/States.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/States.kt @@ -9,16 +9,16 @@ import com.bybutter.sisyphus.protobuf.primitives.internal.MutableFileDescriptorP import com.bybutter.sisyphus.protobuf.primitives.internal.MutableMethodDescriptorProto import com.bybutter.sisyphus.protobuf.primitives.internal.MutableOneofDescriptorProto import com.bybutter.sisyphus.protobuf.primitives.internal.MutableServiceDescriptorProto -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition interface ProtobufCompilingState, TPsi : ProtobufElement> { fun target(): TDesc diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/EnumCompiler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/EnumCompiler.kt index 29cde894..03d2f280 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/EnumCompiler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/EnumCompiler.kt @@ -5,7 +5,7 @@ import io.kanro.idea.plugin.protobuf.compile.BaseProtobufCompilerPlugin import io.kanro.idea.plugin.protobuf.compile.CompileContext import io.kanro.idea.plugin.protobuf.compile.EnumCompilingState import io.kanro.idea.plugin.protobuf.compile.EnumValueCompilingState -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition class EnumCompiler : BaseProtobufCompilerPlugin() { override fun compile( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/FileCompiler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/FileCompiler.kt index 298a6455..73ea1ffb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/FileCompiler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/FileCompiler.kt @@ -9,10 +9,9 @@ import io.kanro.idea.plugin.protobuf.compile.EnumCompilingState import io.kanro.idea.plugin.protobuf.compile.FileCompilingState import io.kanro.idea.plugin.protobuf.compile.MessageCompilingState import io.kanro.idea.plugin.protobuf.compile.ServiceCompilingState -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class FileCompiler : BaseProtobufCompilerPlugin() { override fun compile( @@ -38,6 +37,7 @@ class FileCompiler : BaseProtobufCompilerPlugin() { return@forEach } } + is ProtobufEnumDefinition -> { this.enumType += try { @@ -48,6 +48,7 @@ class FileCompiler : BaseProtobufCompilerPlugin() { return@forEach } } + is ProtobufServiceDefinition -> { this.service += try { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/MessageCompiler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/MessageCompiler.kt index 7af28f91..54a2ec3a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/MessageCompiler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/MessageCompiler.kt @@ -13,16 +13,15 @@ import io.kanro.idea.plugin.protobuf.compile.MessageFieldCompilingState import io.kanro.idea.plugin.protobuf.compile.MessageMapEntryCompilingState import io.kanro.idea.plugin.protobuf.compile.MessageMapFieldCompilingState import io.kanro.idea.plugin.protobuf.compile.MessageOneofCompilingState -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.jsonName -import io.kanro.idea.plugin.protobuf.lang.psi.key -import io.kanro.idea.plugin.protobuf.lang.psi.optional -import io.kanro.idea.plugin.protobuf.lang.psi.repeated -import io.kanro.idea.plugin.protobuf.lang.psi.required +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.key +import io.kanro.idea.plugin.protobuf.lang.psi.proto.optional +import io.kanro.idea.plugin.protobuf.lang.psi.proto.repeated +import io.kanro.idea.plugin.protobuf.lang.psi.proto.required import io.kanro.idea.plugin.protobuf.lang.support.BuiltInType import io.kanro.idea.plugin.protobuf.string.toPascalCase @@ -47,6 +46,7 @@ class MessageCompiler : BaseProtobufCompilerPlugin() { return@forEach } } + is ProtobufEnumDefinition -> { this.enumType += try { @@ -57,6 +57,7 @@ class MessageCompiler : BaseProtobufCompilerPlugin() { return@forEach } } + is ProtobufFieldDefinition -> { this.field += try { @@ -67,6 +68,7 @@ class MessageCompiler : BaseProtobufCompilerPlugin() { return@forEach } } + is ProtobufOneofDefinition -> { this.oneofDecl += try { @@ -77,6 +79,7 @@ class MessageCompiler : BaseProtobufCompilerPlugin() { return@forEach } } + is ProtobufMapFieldDefinition -> { this.nestedType += try { @@ -123,7 +126,7 @@ class MessageFieldCompiler : BaseProtobufCompilerPlugin { @@ -131,6 +134,7 @@ class MessageFieldCompiler : BaseProtobufCompilerPlugin { this.type = FieldDescriptorProto.Type.ENUM this.typeName = type.qualifiedName()?.let { ".$it" } @@ -204,7 +208,7 @@ class MessageMapEntryCompiler : BaseProtobufCompilerPlugin { @@ -225,11 +229,13 @@ class MessageMapEntryCompiler : BaseProtobufCompilerPlugin { this.type = FieldDescriptorProto.Type.ENUM this.typeName = type.qualifiedName()?.let { ".$it" } ?: throw IllegalStateException("Invalid field definition: unresolvable value type.") } + else -> throw IllegalStateException("Invalid field definition: invalid value type.") } } @@ -268,6 +274,7 @@ class MessageMapFieldCompiler : BaseProtobufCompilerPlugin throw IllegalStateException("Invalid map field definition: unsupported extension map field.") } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/ServiceCompiler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/ServiceCompiler.kt index 5d1dadb8..beb5ddfb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/ServiceCompiler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/ServiceCompiler.kt @@ -5,9 +5,9 @@ import io.kanro.idea.plugin.protobuf.compile.BaseProtobufCompilerPlugin import io.kanro.idea.plugin.protobuf.compile.CompileContext import io.kanro.idea.plugin.protobuf.compile.ServiceCompilingState import io.kanro.idea.plugin.protobuf.compile.ServiceMethodCompilingState -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stream +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stream class ServiceCompiler : BaseProtobufCompilerPlugin() { override fun compile( @@ -43,10 +43,10 @@ class ServiceMethodCompiler : BaseProtobufCompilerPlugin, + stub: io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub<*>, sink: IndexSink, ) { when (stub) { @@ -18,6 +17,7 @@ class GoIndexProvider : ProtobufIndexProvider { sink.occurrence(GoNameIndex.key, stub.unimplementedName() ?: return) sink.occurrence(GoUnimplementedServerNameIndex.key, stub.unimplementedName() ?: return) } + is ProtobufRpcStub -> { sink.occurrence(GoNameIndex.key, stub.funcName() ?: return) sink.occurrence( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoLineMarkerProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoLineMarkerProvider.kt index 12514dbd..b71b6985 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoLineMarkerProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoLineMarkerProvider.kt @@ -16,7 +16,7 @@ import com.intellij.psi.stubs.StubIndex import com.intellij.psi.util.elementType import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.lang.psi.firstLeaf -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class GoLineMarkerProvider : RelatedItemLineMarkerProvider() { override fun collectNavigationMarkers( @@ -53,6 +53,7 @@ class GoLineMarkerProvider : RelatedItemLineMarkerProvider() { .setTooltipText("Implementing") result.add(builder.createLineMarkerInfo(element.firstLeaf())) } + is GoSpecType -> { val spec = parent.parent as? GoTypeSpec ?: return val type = spec.getGoUnderlyingType(null) as? GoStructType ?: return @@ -76,6 +77,7 @@ class GoLineMarkerProvider : RelatedItemLineMarkerProvider() { .setTooltipText("Implementing") result.add(builder.createLineMarkerInfo(element.firstLeaf())) } + else -> return } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoNameIndex.kt index 3f1e17f9..acf54d66 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.golang import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class GoNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoUnimplementedServerNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoUnimplementedServerNameIndex.kt index c9e023de..c392163e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoUnimplementedServerNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoUnimplementedServerNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.golang import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class GoUnimplementedServerNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/Names.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/Names.kt index abe23e62..223889a3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/Names.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/Names.kt @@ -1,19 +1,18 @@ package io.kanro.idea.plugin.protobuf.golang -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumValueStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufFieldLikeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumValueStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufFieldLikeStub import io.kanro.idea.plugin.protobuf.string.toPascalCase fun ProtobufMessageDefinition.structName(): String? { @@ -26,7 +25,7 @@ fun ProtobufMessageDefinition.structName(): String? { fun ProtobufMessageStub.structName(): String? { return when (val owner = owner()) { - is ProtobufFileStub -> name() + is io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub -> name() is ProtobufMessageStub -> "${owner.structName()}_${name()}" else -> null } @@ -82,7 +81,7 @@ fun ProtobufEnumDefinition.typeName(): String? { fun ProtobufEnumStub.typeName(): String? { return when (val owner = owner()) { - is ProtobufFileStub -> name() + is io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub -> name() is ProtobufMessageStub -> "${owner.structName()}_${name()}" else -> null } @@ -103,7 +102,7 @@ fun ProtobufEnumValueStub.fieldName(): String? { val enum = owner() ?: return null val parent = when (val owner = enum.owner()) { - is ProtobufFileStub -> enum.name() + is io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub -> enum.name() is ProtobufMessageStub -> owner.structName() else -> null } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/Utils.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/Utils.kt index ed504b86..2e9e918e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/Utils.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/Utils.kt @@ -12,7 +12,7 @@ import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.parentOfType import io.kanro.idea.plugin.protobuf.grpc.index.ServiceMethodIndex import io.kanro.idea.plugin.protobuf.grpc.request.GrpcRequestExecutionSupport -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition fun JsonElement.injectedRequest(): HttpRequest? { val host = InjectedLanguageManager.getInstance(project).getInjectionHost(this) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/AipRunRequestGutterProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/AipRunRequestGutterProvider.kt index ef4e77f4..be1dbcfa 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/AipRunRequestGutterProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/AipRunRequestGutterProvider.kt @@ -14,11 +14,10 @@ import com.intellij.psi.PsiElement import com.intellij.psi.util.parentOfType import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.aip.AipOptions -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcOption import io.kanro.idea.plugin.protobuf.lang.psi.firstLeaf -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufField +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcOption import javax.swing.Icon class AipRunRequestGutterProvider : RelatedItemLineMarkerProvider() { @@ -39,14 +38,14 @@ class AipRunRequestGutterProvider : RelatedItemLineMarkerProvider() { element: PsiElement, result: MutableCollection>, ) { - if (element !is ProtobufFieldAssign) return + if (element !is ProtobufField) return val option = element.parentOfType() ?: return val grpcDefinition = element.parentOfType() ?: return if (!option.isOption(AipOptions.httpOption)) return val fieldName = element.field()?.qualifiedName() ?: return if (fieldName !in AipOptions.httpRulesName) return val httpMethod = fieldName.lastComponent?.uppercase() ?: return - val path = element.constant?.stringValue() ?: return + val path = element.value()?.toString() ?: return val service = grpcDefinition.owner() ?: return val serviceName = service.qualifiedName() ?: return @@ -83,10 +82,9 @@ class AipRunRequestGutterProvider : RelatedItemLineMarkerProvider() { methodName: String, hasBody: Boolean, ): HttpRequestUrlPathInfo.Computed { - val raw = info.compute() return if (hasBody) { HttpRequestUrlPathInfo.Computed( - raw.baseInfo, + info, requestBody = RequestBody.CustomRequestBodyTemplate( TemplateImpl( @@ -98,7 +96,7 @@ class AipRunRequestGutterProvider : RelatedItemLineMarkerProvider() { ) } else { HttpRequestUrlPathInfo.Computed( - raw.baseInfo, + info, requestBody = RequestBody.CustomRequestBodyTemplate( TemplateImpl( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/GrpcRunRequestGutterProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/GrpcRunRequestGutterProvider.kt index c6925d66..0fc304cd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/GrpcRunRequestGutterProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/GrpcRunRequestGutterProvider.kt @@ -9,9 +9,9 @@ import com.intellij.httpClient.executor.util.unwrap import com.intellij.httpClient.http.request.microservices.OpenInHttpClientLineMarkerBuilder import com.intellij.psi.PsiElement import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition import io.kanro.idea.plugin.protobuf.lang.psi.firstLeaf -import io.kanro.idea.plugin.protobuf.lang.psi.stream +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stream import javax.swing.Icon class GrpcRunRequestGutterProvider : RelatedItemLineMarkerProvider() { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/MessageShortNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/MessageShortNameIndex.kt index e4daeeed..f53b804b 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/MessageShortNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/MessageShortNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.grpc.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition class MessageShortNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndex.kt index c50a5476..5b5d07db 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.grpc.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition class ServiceMethodIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndexProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndexProvider.kt index 9b6ad4d4..638ddc86 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndexProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndexProvider.kt @@ -1,15 +1,14 @@ package io.kanro.idea.plugin.protobuf.grpc.index import com.intellij.psi.stubs.IndexSink -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufIndexProvider -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufIndexProvider +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub class ServiceMethodIndexProvider : ProtobufIndexProvider { override fun buildIndex( - stub: ProtobufStub<*>, + stub: io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub<*>, sink: IndexSink, ) { when (stub) { @@ -18,6 +17,7 @@ class ServiceMethodIndexProvider : ProtobufIndexProvider { sink.occurrence(MessageShortNameIndex.key, it) } } + is ProtobufServiceStub -> { stub.name()?.let { sink.occurrence(ServiceShortNameIndex.key, it) @@ -26,6 +26,7 @@ class ServiceMethodIndexProvider : ProtobufIndexProvider { sink.occurrence(ServiceQualifiedNameIndex.key, it.toString()) } } + is ProtobufRpcStub -> { sink.occurrence(ServiceMethodIndex.key, "${stub.owner()?.qualifiedName()}/${stub.name()}") } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceQualifiedNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceQualifiedNameIndex.kt index 23757c4f..9939ccad 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceQualifiedNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceQualifiedNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.grpc.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class ServiceQualifiedNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceShortNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceShortNameIndex.kt index a76f74cc..fbe08dfc 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceShortNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceShortNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.grpc.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class ServiceShortNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/Extensions.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/Extensions.kt index 66c3d5dd..d2dd76a5 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/Extensions.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/Extensions.kt @@ -16,11 +16,10 @@ import io.kanro.idea.plugin.protobuf.aip.resolveInput import io.kanro.idea.plugin.protobuf.grpc.injectedRequest import io.kanro.idea.plugin.protobuf.grpc.isTranscoding import io.kanro.idea.plugin.protobuf.grpc.resolveRpc -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition import io.kanro.idea.plugin.protobuf.lang.psi.nullCachedValue -import io.kanro.idea.plugin.protobuf.lang.psi.resolveField -import io.kanro.idea.plugin.protobuf.lang.psi.resolveFieldType -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolveField +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolveFieldType internal fun JsonProperty.contextJsonObject(): JsonObject? { return CachedValuesManager.getCachedValue(this) { @@ -46,7 +45,7 @@ internal fun HttpRequest.grpcBodyType(): ProtobufMessageDefinition? { rpcDefinition.options(AipOptions.httpOption).lastOrNull() ?: return@getCachedValue nullCachedValue() val body = - option.value(AipOptions.httpRuleBodyField)?.stringValue() ?: return@getCachedValue nullCachedValue() + option.value(AipOptions.httpRuleBodyField)?.toString() ?: return@getCachedValue nullCachedValue() if (body != "*") { input.resolveFieldType(QualifiedName.fromDottedString(body), true) as? ProtobufMessageDefinition } else { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageEnumValueReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageEnumValueReference.kt index 1fe2defd..2e16cc29 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageEnumValueReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageEnumValueReference.kt @@ -7,11 +7,11 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiReferenceBase import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition import io.kanro.idea.plugin.protobuf.lang.psi.filterItem import io.kanro.idea.plugin.protobuf.lang.psi.firstItemOrNull +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition class GrpcMessageEnumValueReference(value: JsonStringLiteral) : PsiReferenceBase(value), @@ -23,7 +23,7 @@ class GrpcMessageEnumValueReference(value: JsonStringLiteral) : override fun resolve(): PsiElement? { val property = element.parent as? JsonProperty ?: return null val field = property.resolve() as? ProtobufFieldDefinition ?: return null - val enum = field.typeName.reference?.resolve() as? ProtobufEnumDefinition ?: return null + val enum = field.typeName.resolve() as? ProtobufEnumDefinition ?: return null return enum.firstItemOrNull { it.name() == element.value } } @@ -31,7 +31,7 @@ class GrpcMessageEnumValueReference(value: JsonStringLiteral) : val property = element.parent as? JsonProperty ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY val field = property.resolve() as? ProtobufFieldDefinition ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY val enum = - field.typeName.reference?.resolve() as? ProtobufEnumDefinition ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + field.typeName.resolve() as? ProtobufEnumDefinition ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY return enum.filterItem { true }.mapNotNull { it.lookup()?.withInsertHandler(SmartInsertHandler("\",")) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageFieldReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageFieldReference.kt index 023a1dba..e7f32804 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageFieldReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageFieldReference.kt @@ -15,15 +15,14 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiReferenceBase import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition import io.kanro.idea.plugin.protobuf.lang.psi.filterItem import io.kanro.idea.plugin.protobuf.lang.psi.firstItemOrNull -import io.kanro.idea.plugin.protobuf.lang.psi.jsonName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.repeated +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.repeated +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike import io.kanro.idea.plugin.protobuf.lang.support.WellknownTypes import kotlin.math.max @@ -115,7 +114,7 @@ private class JsonFieldSmartInsertHandler(private val element: ProtobufFieldLike if (element.repeated()) { LIST_INSERT_HANDLER } else { - when (val type = element.typeName.reference?.resolve()) { + when (val type = element.typeName.resolve()) { is ProtobufMessageDefinition -> { val name = type.qualifiedName().toString() if (name in WellknownTypes.types) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMethodReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMethodReference.kt index 39ac4a77..87f41322 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMethodReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMethodReference.kt @@ -11,8 +11,8 @@ import com.intellij.psi.stubs.StubIndex import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.grpc.index.ServiceMethodIndex import io.kanro.idea.plugin.protobuf.grpc.index.ServiceQualifiedNameIndex -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class GrpcMethodReference(element: HttpRequestTarget, range: TextRange) : PsiReferenceBase(element, range) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcServiceReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcServiceReference.kt index d9cda53f..0d556ff7 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcServiceReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcServiceReference.kt @@ -15,9 +15,9 @@ import com.intellij.psi.stubs.StubIndex import io.kanro.idea.plugin.protobuf.grpc.index.ServiceQualifiedNameIndex import io.kanro.idea.plugin.protobuf.grpc.index.ServiceShortNameIndex import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex class GrpcServiceReference(element: HttpRequestTarget, range: TextRange) : PsiReferenceBase(element, range) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTranscodingQueryReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTranscodingQueryReference.kt index 11bbfd06..d91b9578 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTranscodingQueryReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTranscodingQueryReference.kt @@ -13,8 +13,7 @@ import io.kanro.idea.plugin.protobuf.aip.transcodingBody import io.kanro.idea.plugin.protobuf.grpc.resolveRpc import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler import io.kanro.idea.plugin.protobuf.lang.psi.filterItem -import io.kanro.idea.plugin.protobuf.lang.psi.jsonName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike class GrpcTranscodingQueryReference(private val name: String, element: HttpRequestTarget, range: TextRange) : PsiReferenceBase(element, range), GrpcReference { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTypeUrlReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTypeUrlReference.kt index d19a4b0d..5c8caa7a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTypeUrlReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTypeUrlReference.kt @@ -11,9 +11,9 @@ import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.stubs.StubIndex import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.grpc.index.MessageShortNameIndex -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex class GrpcTypeUrlReference(value: JsonStringLiteral) : PsiReferenceBase(value) { override fun calculateDefaultRangeInElement(): TextRange { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcUrlReferenceProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcUrlReferenceProvider.kt index 06687145..737a3b40 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcUrlReferenceProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcUrlReferenceProvider.kt @@ -48,7 +48,11 @@ class GrpcTranscodingQueryReferenceProvider : PsiReferenceProvider() { if (!request.isTranscoding()) return PsiReference.EMPTY_ARRAY return element.query?.queryParameterList?.map { - GrpcTranscodingQueryReference(it.queryParameterKey.text ?: "", element, it.queryParameterKey.textRangeIn(element)) + GrpcTranscodingQueryReference( + it.queryParameterKey.text ?: "", + element, + it.queryParameterKey.textRangeIn(element), + ) }?.toTypedArray() ?: PsiReference.EMPTY_ARRAY } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestConverter.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestConverter.kt index 4a295b7b..633ad27d 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestConverter.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestConverter.kt @@ -10,9 +10,9 @@ import com.intellij.openapi.project.DumbService import com.intellij.psi.SmartPsiElementPointer import io.grpc.Metadata import io.kanro.idea.plugin.protobuf.grpc.referece.GrpcMethodReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stream +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stream @Suppress("UnstableApiUsage") object GrpcRequestConverter : RequestConverter() { @@ -49,14 +49,15 @@ object GrpcRequestConverter : RequestConverter() { val rpc = element.requestTarget?.references?.filterIsInstance()?.firstOrNull() - ?.resolve() as? ProtobufRpcDefinition ?: throw IllegalStateException("Unsolvable rpc method '$method'.") + ?.resolve() as? ProtobufRpcDefinition + ?: throw IllegalStateException("Unsolvable rpc method '$method'.") val input = rpc.input() ?: throw IllegalStateException("Invalid rpc input.") val inputMessage = - rpc.input()?.typeName?.reference?.resolve() as? ProtobufMessageDefinition + rpc.input()?.typeName?.resolve() as? ProtobufMessageDefinition ?: throw IllegalStateException("Unsolvable rpc input '${input.typeName.text}'.") val output = rpc.output() ?: throw IllegalStateException("Invalid rpc input.") val outputMessage = - rpc.output()?.typeName?.reference?.resolve() as? ProtobufMessageDefinition + rpc.output()?.typeName?.resolve() as? ProtobufMessageDefinition ?: throw IllegalStateException("Unsolvable rpc input '${input.typeName.text}'.") GrpcRequest( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestHandler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestHandler.kt index 6f409fee..ff77d3c7 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestHandler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestHandler.kt @@ -19,7 +19,7 @@ import io.grpc.Metadata import io.grpc.MethodDescriptor import io.grpc.Status import io.kanro.idea.plugin.protobuf.grpc.referece.GrpcMethodReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow import java.util.concurrent.TimeUnit diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/ProtoFileReflection.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/ProtoFileReflection.kt index e27e2dd7..953715da 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/ProtoFileReflection.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/ProtoFileReflection.kt @@ -8,8 +8,8 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.stubs.StubIndex import io.kanro.idea.plugin.protobuf.compile.Protoc -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex class ProtoFileReflection(private val context: ProtobufElement) : LocalProtoReflection() { private val wellknownProtoFiles = diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Extension.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Extension.kt index b6281b91..41275a82 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Extension.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Extension.kt @@ -7,12 +7,12 @@ import com.intellij.psi.PsiEnumConstant import com.intellij.psi.PsiMethod import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike import io.kanro.idea.plugin.protobuf.sisyphus.isSisyphus fun PsiElement.findJavaClass(name: QualifiedName?): PsiClass? { @@ -37,6 +37,7 @@ fun ProtobufFieldLike.toGetters(): Array { is ProtobufMessageDefinition -> owner.toBuilderClass()?.findMethodsByName(getterName(), true) ?: PsiMethod.EMPTY_ARRAY + else -> PsiMethod.EMPTY_ARRAY } } @@ -46,6 +47,7 @@ fun ProtobufFieldLike.toSetters(): Array { is ProtobufMessageDefinition -> owner.toBuilderClass()?.findMethodsByName(setterName(), true) ?: PsiMethod.EMPTY_ARRAY + else -> PsiMethod.EMPTY_ARRAY } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/FileJavaOptionsProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/FileJavaOptionsProvider.kt index abc11faf..b564d6ef 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/FileJavaOptionsProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/FileJavaOptionsProvider.kt @@ -1,15 +1,11 @@ package io.kanro.idea.plugin.protobuf.java -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufStubExternalProvider -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufStubSupport -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufFieldLikeStub -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufStubExternalProvider +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufStubSupport +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufFieldLikeStub class FileJavaOptionsProvider : ProtobufStubExternalProvider { override fun mergeExternalData( @@ -43,14 +39,14 @@ class FileJavaOptionsProvider : ProtobufStubExternalProvider { fun ProtobufFieldLike.jsonName(): String? { return if (this is ProtobufOptionOwner) { - options("json_name").lastOrNull()?.value()?.stringValue() + options("json_name").lastOrNull()?.value()?.toString() } else { null } } fun ProtobufFieldLikeStub.jsonName(): String? { - return if (this is ProtobufStub<*>) { + return if (this is io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub<*>) { externalData("json_name") } else { null @@ -58,25 +54,25 @@ fun ProtobufFieldLikeStub.jsonName(): String? { } fun ProtobufFile.javaPackage(): String? { - return options("java_package").lastOrNull()?.value()?.stringValue() + return options("java_package").lastOrNull()?.value()?.toString() } fun ProtobufFile.javaOuterClassname(): String? { - return options("java_outer_classname").lastOrNull()?.value()?.stringValue() + return options("java_outer_classname").lastOrNull()?.value()?.toString() } fun ProtobufFile.javaMultipleFiles(): Boolean? { - return options("java_multiple_files").lastOrNull()?.value()?.booleanValue?.value() + return options("java_multiple_files").lastOrNull()?.value() as? Boolean } -fun ProtobufFileStub.javaPackage(): String? { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.javaPackage(): String? { return externalData("java_package") } -fun ProtobufFileStub.javaOuterClassname(): String? { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.javaOuterClassname(): String? { return externalData("java_outer_classname") } -fun ProtobufFileStub.javaMultipleFiles(): Boolean? { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.javaMultipleFiles(): Boolean? { return externalData("java_multiple_files")?.let { it == "true" } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaFindUsageFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaFindUsageFactory.kt index ea66bcbe..ba2aac1e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaFindUsageFactory.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaFindUsageFactory.kt @@ -3,13 +3,13 @@ package io.kanro.idea.plugin.protobuf.java import com.intellij.find.findUsages.FindUsagesHandler import com.intellij.find.findUsages.FindUsagesHandlerFactory import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike class JavaFindUsageFactory : FindUsagesHandlerFactory() { override fun canFindUsages(element: PsiElement): Boolean { @@ -35,9 +35,11 @@ class JavaFindUsageFactory : FindUsagesHandlerFactory() { ).toTypedArray(), ) } + is ProtobufEnumDefinition -> { ProtoDefinitionFindUsage(element, listOfNotNull(element.toClass()).toTypedArray()) } + is ProtobufServiceDefinition -> { ProtoDefinitionFindUsage( element, @@ -50,9 +52,11 @@ class JavaFindUsageFactory : FindUsagesHandlerFactory() { ).toTypedArray(), ) } + is ProtobufEnumValueDefinition -> { ProtoDefinitionFindUsage(element, listOfNotNull(element.toEnumConstant()).toTypedArray()) } + is ProtobufRpcDefinition -> { ProtoDefinitionFindUsage( element, @@ -65,12 +69,14 @@ class JavaFindUsageFactory : FindUsagesHandlerFactory() { ).toTypedArray(), ) } + is ProtobufFieldLike -> { ProtoDefinitionFindUsage( element, listOfNotNull(*element.toGetters(), *element.toSetters()).toTypedArray(), ) } + else -> null } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaIndexProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaIndexProvider.kt index 30726c49..6df0538a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaIndexProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaIndexProvider.kt @@ -1,14 +1,13 @@ package io.kanro.idea.plugin.protobuf.java import com.intellij.psi.stubs.IndexSink -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufIndexProvider -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufIndexProvider +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub class JavaIndexProvider : ProtobufIndexProvider { override fun buildIndex( - stub: ProtobufStub<*>, + stub: io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub<*>, sink: IndexSink, ) { when (stub) { @@ -22,6 +21,7 @@ class JavaIndexProvider : ProtobufIndexProvider { sink.occurrence(JavaNameIndex.key, stub.fullFutureStubName().toString()) sink.occurrence(JavaNameIndex.key, stub.fullCoroutineStubName().toString()) } + is ProtobufRpcStub -> { val methodName = stub.methodName() diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaLineMarkerProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaLineMarkerProvider.kt index 0fcf5405..fce7d447 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaLineMarkerProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaLineMarkerProvider.kt @@ -9,10 +9,10 @@ import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition import io.kanro.idea.plugin.protobuf.lang.psi.firstLeaf -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.uast.UClass @@ -39,6 +39,7 @@ class JavaLineMarkerProvider : RelatedItemLineMarkerProvider() { .setTooltipText("Implementing") result.add(builder.createLineMarkerInfo(element.firstLeaf())) } + is UMethod -> { val method = findMethodProtobufDefinition(parent) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaNameIndex.kt index 4b94d438..f9eab269 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.java import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class JavaNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Names.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Names.kt index 1943d688..9aeaf944 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Names.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Names.kt @@ -1,20 +1,19 @@ package io.kanro.idea.plugin.protobuf.java import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumValueStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufFieldLikeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumValueStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufFieldLikeStub import io.kanro.idea.plugin.protobuf.lang.util.toQualifiedName import io.kanro.idea.plugin.protobuf.string.toCamelCase @@ -22,7 +21,7 @@ fun ProtobufFile.fullPackageName(): QualifiedName? { return javaPackage()?.toQualifiedName() ?: scope() } -fun ProtobufFileStub.fullPackageName(): QualifiedName? { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.fullPackageName(): QualifiedName? { return javaPackage()?.toQualifiedName() ?: scope() } @@ -34,7 +33,7 @@ fun ProtobufFile.fullOuterClassName(): QualifiedName? { } } -fun ProtobufFileStub.fullOuterClassName(): QualifiedName? { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.fullOuterClassName(): QualifiedName? { return if (javaMultipleFiles() == true) { fullPackageName() } else { @@ -65,6 +64,7 @@ fun ProtobufMessageDefinition.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } @@ -76,6 +76,7 @@ fun ProtobufMessageStub.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } @@ -94,11 +95,13 @@ fun ProtobufMessageDefinition.fullMessageOrBuilderName(): QualifiedName? { owner.fullOuterClassName()?.append(messageOrBuilderName()) ?: QualifiedName.fromComponents( messageOrBuilderName(), ) + is ProtobufMessageDefinition -> owner.fullClassName()?.append(messageOrBuilderName()) ?: QualifiedName.fromComponents( messageOrBuilderName(), ) + else -> null } } @@ -109,11 +112,13 @@ fun ProtobufMessageStub.fullBuilderClassName(): QualifiedName? { owner.fullOuterClassName()?.append(messageOrBuilderName()) ?: QualifiedName.fromComponents( messageOrBuilderName(), ) + is ProtobufMessageDefinition -> owner.fullClassName()?.append(messageOrBuilderName()) ?: QualifiedName.fromComponents( messageOrBuilderName(), ) + else -> null } } @@ -285,6 +290,7 @@ fun ProtobufEnumDefinition.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } @@ -296,6 +302,7 @@ fun ProtobufEnumStub.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/ProtobufLineMarkerProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/ProtobufLineMarkerProvider.kt index 0de64b3a..abc33d07 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/ProtobufLineMarkerProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/ProtobufLineMarkerProvider.kt @@ -7,9 +7,9 @@ import com.intellij.psi.PsiElement import com.intellij.psi.search.searches.DirectClassInheritorsSearch import com.intellij.psi.search.searches.OverridingMethodsSearch import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIdentifier -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIdentifier +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class ProtobufLineMarkerProvider : RelatedItemLineMarkerProvider() { override fun collectNavigationMarkers( @@ -36,6 +36,7 @@ class ProtobufLineMarkerProvider : RelatedItemLineMarkerProvider() { .setTooltipText("Implemented") result.add(builder.createLineMarkerInfo(element.identifierLiteral ?: element)) } + is ProtobufServiceDefinition -> { val apis = owner.toImplBaseClass()?.let { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextFileType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextFileType.kt new file mode 100644 index 00000000..46939e58 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextFileType.kt @@ -0,0 +1,33 @@ +package io.kanro.idea.plugin.protobuf.lang + +import com.intellij.openapi.fileTypes.LanguageFileType +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes +import javax.swing.Icon + +class ProtoTextFileType : LanguageFileType(ProtoTextLanguage) { + companion object { + val INSTANCE = ProtoTextFileType() + + init { + // Workaround for issue #164 + ProtobufStubTypes + } + } + + override fun getName(): String { + return ProtoTextLanguage.id + } + + override fun getDescription(): String { + return "Protocol Buffer Text Format" + } + + override fun getDefaultExtension(): String { + return "txtpb" + } + + override fun getIcon(): Icon { + return ProtobufIcons.TEXT_FILE + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextLanguage.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextLanguage.kt new file mode 100644 index 00000000..c53f9155 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextLanguage.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang + +import com.intellij.lang.Language + +object ProtoTextLanguage : Language("prototext") diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextParserDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextParserDefinition.kt new file mode 100644 index 00000000..d5eed168 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextParserDefinition.kt @@ -0,0 +1,53 @@ +package io.kanro.idea.plugin.protobuf.lang + +import com.intellij.lang.ASTNode +import com.intellij.lang.ParserDefinition +import com.intellij.lang.PsiParser +import com.intellij.lexer.Lexer +import com.intellij.openapi.project.Project +import com.intellij.psi.FileViewProvider +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.tree.IFileElementType +import com.intellij.psi.tree.TokenSet +import io.kanro.idea.plugin.protobuf.lang.lexer.ProtoTextLexer +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFile +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextTypes +import io.kanro.idea.plugin.protobuf.lang.psi.text.impl.ProtoTextFileImpl +import io.kanro.idea.plugin.protobuf.lang.psi.text.parser.ProtoTextParser +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextParserDefinition : ParserDefinition { + override fun createLexer(project: Project): Lexer { + return ProtoTextLexer() + } + + override fun createParser(project: Project): PsiParser { + return ProtoTextParser() + } + + override fun getFileNodeType(): IFileElementType { + return ProtoTextFile.Type + } + + override fun getCommentTokens(): TokenSet { + return comments + } + + override fun getStringLiteralElements(): TokenSet { + return string + } + + override fun createElement(node: ASTNode): PsiElement { + return ProtoTextTypes.Factory.createElement(node) + } + + override fun createFile(viewProvider: FileViewProvider): PsiFile { + return ProtoTextFileImpl(viewProvider) + } + + companion object { + val comments = TokenSet.create(ProtoTextTokens.SHARP_LINE_COMMENT) + val string = TokenSet.create(ProtoTextTokens.STRING_LITERAL) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufFileType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufFileType.kt index 8eb1ad7a..4b30e01c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufFileType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufFileType.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.lang import com.intellij.openapi.fileTypes.LanguageFileType import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes import javax.swing.Icon class ProtobufFileType : LanguageFileType(ProtobufLanguage) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufParserDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufParserDefinition.kt index dba5cd55..943aae65 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufParserDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufParserDefinition.kt @@ -11,11 +11,11 @@ import com.intellij.psi.PsiFile import com.intellij.psi.tree.IFileElementType import com.intellij.psi.tree.TokenSet import io.kanro.idea.plugin.protobuf.lang.lexer.ProtobufLexer -import io.kanro.idea.plugin.protobuf.lang.parser.ProtobufParser -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypes -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufFileImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypes +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufFileImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.parser.ProtobufParser +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufParserDefinition : ParserDefinition { override fun createLexer(project: Project): Lexer { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/actions/ArrangeFieldsNumberAction.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/actions/ArrangeFieldsNumberAction.kt index 83c23911..219151c7 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/actions/ArrangeFieldsNumberAction.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/actions/ArrangeFieldsNumberAction.kt @@ -11,9 +11,9 @@ import com.intellij.openapi.editor.actionSystem.EditorActionHandler import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.psi.util.parentOfType import io.kanro.idea.plugin.protobuf.lang.ProtobufFileType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumberScope -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope abstract class ArrangeFieldsNumberActionHandler : EditorActionHandler() { private fun findItemsToSort( @@ -89,7 +89,7 @@ class ArrangeFieldsNumberToMaxHandler : ArrangeFieldsNumberActionHandler() { val maxInItems = items.maxOf { it.number() ?: -1 }.takeIf { it >= numbersNeed } var current = - if (items.first() is ProtobufEnumValue) { + if (items.first() is ProtobufEnumValueDefinition) { maxInItems ?: (numbersNeed - 1) } else { maxInItems ?: numbersNeed @@ -115,7 +115,7 @@ class ArrangeFieldsNumberToMaxHandler : ArrangeFieldsNumberActionHandler() { val numbersNeed = items.size.toLong() val maxInItems = items.maxOf { it.number() ?: -1 }.takeIf { it >= numbersNeed } var current = - if (items.first() is ProtobufEnumValue) { + if (items.first() is ProtobufEnumValueDefinition) { maxInItems ?: (numbersNeed - 1) } else { maxInItems ?: numbersNeed @@ -146,7 +146,7 @@ class ArrangeFieldsNumberFromMinHandler : ArrangeFieldsNumberActionHandler() { val minInItems = items.minOf { it.number() ?: -1 }.takeIf { it >= 0 } var current = - if (items.first() is ProtobufEnumValue) { + if (items.first() is ProtobufEnumValueDefinition) { minInItems ?: 0 } else { minInItems ?: 1 diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/FileTracker.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/FileTracker.kt index 1ac37967..5024e378 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/FileTracker.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/FileTracker.kt @@ -7,13 +7,13 @@ import com.intellij.psi.tree.TokenSet import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypes import io.kanro.idea.plugin.protobuf.lang.psi.findChildren -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufFileReferenceContributor -import io.kanro.idea.plugin.protobuf.lang.psi.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypes +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufFileReferenceContributor +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren import io.kanro.idea.plugin.protobuf.lang.quickfix.OptimizeImportsFix import io.kanro.idea.plugin.protobuf.lang.util.asFilter @@ -35,7 +35,7 @@ open class FileTracker(file: ProtobufFile) { statement: ProtobufImportStatement, holder: AnnotationHolder, ) { - val file = statement.stringValue?.stringLiteral?.text?.trim('"') ?: return + val file = statement.stringValue?.value() ?: return if ((imported[file]?.size ?: 0) > 1) { createDuplicate(statement, file, holder) return @@ -60,7 +60,7 @@ open class FileTracker(file: ProtobufFile) { } protected open fun record(statement: ProtobufImportStatement) { - val file = statement.stringValue?.stringLiteral?.text?.trim('"') ?: return + val file = statement.stringValue?.value() ?: return imported.getOrPut(file) { mutableSetOf() }.add(statement) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/NumberTracker.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/NumberTracker.kt index fa508f1f..f8e0dac3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/NumberTracker.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/NumberTracker.kt @@ -5,17 +5,18 @@ import com.intellij.lang.annotation.HighlightSeverity import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedRange -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumberScope -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumbered -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScopeItem -import io.kanro.idea.plugin.protobuf.lang.psi.range +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionRange +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedRange +import io.kanro.idea.plugin.protobuf.lang.psi.proto.range +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem import io.kanro.idea.plugin.protobuf.lang.psi.realItems -open class NumberTracker(scope: ProtobufNumberScope, val minValue: Long) { +open class NumberTracker(scope: ProtobufNumberScope) { private val numberMap = mutableMapOf>() - private val reservedNameMap = mutableMapOf() + private val reservedNameMap = mutableMapOf() private val allowAlias = scope.allowAlias() init { @@ -36,14 +37,17 @@ open class NumberTracker(scope: ProtobufNumberScope, val minValue: Long) { reservedNameMap[range] = reserved } + protected open fun record(reserved: ProtobufExtensionRange) { + val range = reserved.range() ?: return + reservedNameMap[range] = reserved + } + open fun visit( numbered: ProtobufNumbered, holder: AnnotationHolder, ) { val number = numbered.number() ?: return createError(numbered, buildMessage(number, numbered) ?: return, holder) - if (number < minValue) { - } } open fun visit( @@ -58,7 +62,6 @@ open class NumberTracker(scope: ProtobufNumberScope, val minValue: Long) { number: Long, numbered: ProtobufNumbered, ): String? { - if (number < minValue) return "Wrong number, the min value is $minValue" reservedNameMap.forEach { (range, element) -> if (range.contains(number)) { return "Number reserved: \"${element.text}\"" @@ -110,14 +113,8 @@ open class NumberTracker(scope: ProtobufNumberScope, val minValue: Long) { companion object { fun tracker(scope: ProtobufNumberScope): NumberTracker { return CachedValuesManager.getCachedValue(scope) { - val minValue = - if (scope is ProtobufMessageDefinition) { - 1L - } else { - 0L - } CachedValueProvider.Result.create( - NumberTracker(scope, minValue), + NumberTracker(scope), PsiModificationTracker.MODIFICATION_COUNT, ) } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtoTextAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtoTextAnnotator.kt new file mode 100644 index 00000000..ab0ca0ad --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtoTextAnnotator.kt @@ -0,0 +1,156 @@ +package io.kanro.idea.plugin.protobuf.lang.annotator + +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.lang.annotation.HighlightSeverity +import com.intellij.psi.PsiComment +import com.intellij.psi.PsiElement +import com.intellij.psi.util.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.items +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.repeated +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextAnyName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextField +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextVisitor +import io.kanro.idea.plugin.protobuf.lang.psi.text.enum +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextHeaderFileReference +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextHeaderMessageReference +import io.kanro.idea.plugin.protobuf.lang.psi.text.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.value.ArrayValue +import io.kanro.idea.plugin.protobuf.lang.support.WellknownTypes + +class ProtoTextAnnotator : Annotator { + override fun annotate( + element: PsiElement, + holder: AnnotationHolder, + ) { + if (element !is ProtoTextElement) { + return + } + element.accept( + object : ProtoTextVisitor() { + override fun visitComment(comment: PsiComment) { + when (val reference = comment.reference) { + is ProtoTextHeaderFileReference -> { + if (reference.resolve() == null) { + holder.newAnnotation( + HighlightSeverity.WARNING, + "Schema file '${reference.fileName()}' not found", + ).range(reference.absoluteRange).highlightType(ProblemHighlightType.WARNING).create() + } + } + + is ProtoTextHeaderMessageReference -> { + if (reference.resolve() == null) { + holder.newAnnotation( + HighlightSeverity.WARNING, + "Message '${reference.messageName()}' not found", + ).range(reference.absoluteRange).highlightType(ProblemHighlightType.WARNING).create() + } + } + } + } + + override fun visitEnumValue(o: ProtoTextEnumValue) { + if (o.file()?.schema() == null) return + + val enum = o.enum() ?: return + enum.items { + if (it.name() == o.text) { + return + } + } + holder.newAnnotation( + HighlightSeverity.ERROR, + "Enum value '${o.text}' not found", + ).range(o.textRange).highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL).create() + } + + override fun visitFieldName(o: ProtoTextFieldName) { + if (o.file()?.schema() == null) return + + if (o.resolve() == null) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${o.text}' not existed", + ).range(o.textRange).highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL).create() + } + } + + override fun visitField(o: ProtoTextField) { + visitValueAssign(o) + } + + private fun visitValueAssign(o: ValueAssign) { + val field = o.field() ?: return + val valueElement = o.valueElement() ?: return + + if (valueElement is ArrayValue) { + when (field) { + is ProtobufFieldDefinition -> { + if (!field.repeated()) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${field.name()}' is not a repeated field", + ).range(field.textRange).create() + } + } + + is ProtobufGroupDefinition -> { + if (!field.repeated()) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${field.name()}' is not a repeated field", + ).range(field.textRange).create() + } + } + } + + valueElement.values().forEach { + checkCompatibleType(it, field) + } + } else { + checkCompatibleType(valueElement, field) + } + } + + private fun checkCompatibleType( + value: ValueElement<*>, + field: ProtobufFieldLike, + ) { + val fieldType = field.fieldValueType() + val valueType = value.valueType() + if (valueType != fieldType) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${field.fieldName()}' required ${fieldType.name.lowercase()} value, but got ${valueType.name.lowercase()} value", + ).range(value.textRange).create() + } + } + + override fun visitAnyName(o: ProtoTextAnyName) { + if (o.file()?.schema() == null) return + + val parentField = o.parentOfType()?.parentOfType()?.field() + + if (parentField !is ProtobufFieldDefinition || (parentField.typeName.resolve() as? ProtobufMessageDefinition)?.qualifiedName()?.toString() != WellknownTypes.ANY) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${parentField?.name()}' is not a field with Any type", + ).range(o.textRange).highlightType(ProblemHighlightType.ERROR).create() + } + } + }, + ) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf2Annotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf2Annotator.kt index e74d2bcc..5b9e931f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf2Annotator.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf2Annotator.kt @@ -4,20 +4,22 @@ import com.intellij.lang.annotation.AnnotationHolder import com.intellij.lang.annotation.Annotator import com.intellij.lang.annotation.HighlightSeverity import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofBody -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufVisitor -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofBody +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufVisitor class Protobuf2Annotator : Annotator { override fun annotate( element: PsiElement, holder: AnnotationHolder, ) { + if (element.containingFile.originalFile !is ProtobufFile) return val file = (element as? ProtobufElement)?.file() ?: return val syntax = file.syntax() - if (syntax != null && syntax != "proto2") return + if ((syntax != null && syntax != "proto2") || file.edition() != null) return element.accept( object : ProtobufVisitor() { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf3Annotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf3Annotator.kt index 366f168d..b18ed6dd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf3Annotator.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf3Annotator.kt @@ -4,21 +4,22 @@ import com.intellij.lang.annotation.AnnotationHolder import com.intellij.lang.annotation.Annotator import com.intellij.lang.annotation.HighlightSeverity import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufBuiltInOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtensionStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofBody -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufVisitor -import io.kanro.idea.plugin.protobuf.lang.psi.isFieldDefaultOption -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.weak +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofBody +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufVisitor +import io.kanro.idea.plugin.protobuf.lang.psi.proto.isFieldDefaultOption +import io.kanro.idea.plugin.protobuf.lang.psi.proto.weak import io.kanro.idea.plugin.protobuf.lang.support.Options class Protobuf3Annotator : Annotator { @@ -26,6 +27,7 @@ class Protobuf3Annotator : Annotator { element: PsiElement, holder: AnnotationHolder, ) { + if (element.containingFile.originalFile !is ProtobufFile) return val file = (element as? ProtobufElement)?.file() ?: return if (file.syntax() != "proto3") return @@ -54,7 +56,7 @@ class Protobuf3Annotator : Annotator { override fun visitExtendDefinition(o: ProtobufExtendDefinition) { val typename = o.typeName ?: return - val name = (typename.reference?.resolve() as? ProtobufMessageDefinition)?.qualifiedName() ?: return + val name = (typename.resolve() as? ProtobufMessageDefinition)?.qualifiedName() ?: return if (Options.all.contains(name)) { return } @@ -95,7 +97,7 @@ class Protobuf3Annotator : Annotator { } } - override fun visitBuiltInOptionName(o: ProtobufBuiltInOptionName) { + override fun visitOptionName(o: ProtobufOptionName) { if (o.isFieldDefaultOption()) { holder.newAnnotation( HighlightSeverity.ERROR, @@ -121,7 +123,7 @@ class Protobuf3Annotator : Annotator { .create() } else if (zeroDefinition != first) { holder.newAnnotation( - HighlightSeverity.WARNING, + HighlightSeverity.WEAK_WARNING, "'${zeroDefinition.name()}' needs be first element in proto3 for compatibility with the proto2.", ) .range(o.textRange) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufAnnotator.kt index 669377ea..22540301 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufAnnotator.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufAnnotator.kt @@ -7,47 +7,48 @@ import com.intellij.lang.annotation.Annotator import com.intellij.lang.annotation.HighlightSeverity import com.intellij.psi.PsiElement import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.highligh.ProtobufHighlighter -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufArrayValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufBuiltInOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufConstant -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOptionAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedRange -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufVisitor -import io.kanro.idea.plugin.protobuf.lang.psi.enum -import io.kanro.idea.plugin.protobuf.lang.psi.field -import io.kanro.idea.plugin.protobuf.lang.psi.float -import io.kanro.idea.plugin.protobuf.lang.psi.int +import io.kanro.idea.plugin.protobuf.lang.highlight.ProtobufHighlighter +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.findChild import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.message -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumberScope -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumbered -import io.kanro.idea.plugin.protobuf.lang.psi.range -import io.kanro.idea.plugin.protobuf.lang.psi.uint +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufAnyName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufField +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedRange +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufVisitor +import io.kanro.idea.plugin.protobuf.lang.psi.proto.enum +import io.kanro.idea.plugin.protobuf.lang.psi.proto.range +import io.kanro.idea.plugin.protobuf.lang.psi.proto.repeated +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope +import io.kanro.idea.plugin.protobuf.lang.psi.value.ArrayValue +import io.kanro.idea.plugin.protobuf.lang.psi.value.IntegerValue import io.kanro.idea.plugin.protobuf.lang.quickfix.AddImportFix import io.kanro.idea.plugin.protobuf.lang.quickfix.RenameFix -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufTypeNameReference import io.kanro.idea.plugin.protobuf.lang.support.BuiltInType +import io.kanro.idea.plugin.protobuf.lang.support.WellknownTypes import io.kanro.idea.plugin.protobuf.string.case.CaseFormat import io.kanro.idea.plugin.protobuf.string.toCase import io.kanro.idea.plugin.protobuf.string.toScreamingSnakeCase @@ -85,12 +86,9 @@ class ProtobufAnnotator : Annotator { val name = o.name() ?: return if (name != name.toCase(case)) { holder.newAnnotation( - HighlightSeverity.WARNING, + HighlightSeverity.WEAK_WARNING, "$type should be ${case.name.toCase(case)}", - ) - .range(o.identifier()?.textRange ?: o.textRange) - .withFix(RenameFix(name.toCase(case))) - .create() + ).range(o.identifier()?.textRange ?: o.textRange).withFix(RenameFix(name.toCase(case))).create() } } @@ -111,10 +109,9 @@ class ProtobufAnnotator : Annotator { holder.newAnnotation( HighlightSeverity.ERROR, "$keyType is not a valid key type of map", - ) - .range(types[0].textRange) - .create() + ).range(types[0].textRange).create() } + visitFieldLike(o) } override fun visitImportStatement(o: ProtobufImportStatement) { @@ -122,200 +119,98 @@ class ProtobufAnnotator : Annotator { } override fun visitTypeName(o: ProtobufTypeName) { - if (o.symbolNameList.size == 1 && BuiltInType.isBuiltInType(o.text)) { - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(o.textRange) - .textAttributes(ProtobufHighlighter.KEYWORD) - .create() + if (o.typeName == null && BuiltInType.isBuiltInType(o.text)) { + holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY).range(o.textRange) + .textAttributes(ProtobufHighlighter.KEYWORD).create() return } - if (o.reference?.resolve() == null) { + if (o.parent !is ProtobufTypeName && o.resolve() == null) { holder.newAnnotation( HighlightSeverity.ERROR, "Symbol '${o.text}' not found", - ) - .range(o.textRange) - .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) - .withFix(AddImportFix(o)) - .create() + ).range(o.textRange).highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) + .withFix(AddImportFix(o)).create() } + } - o.references.forEach { - if (it !is ProtobufTypeNameReference) return@forEach - val result = it.resolve() ?: return@forEach - when (result) { - is ProtobufFieldLike -> - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(it.absoluteRange) - .textAttributes(ProtobufHighlighter.FIELD) - .create() - is ProtobufMessageDefinition -> - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(it.absoluteRange) - .textAttributes(ProtobufHighlighter.MESSAGE) - .create() - is ProtobufEnumDefinition -> - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(it.absoluteRange) - .textAttributes(ProtobufHighlighter.ENUM) - .create() - else -> - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(it.absoluteRange) - .textAttributes(ProtobufHighlighter.IDENTIFIER) - .create() - } + override fun visitAnyName(o: ProtobufAnyName) { + val parentField = o.parentOfType()?.parentOfType()?.field() + + if (parentField !is ProtobufFieldDefinition || (parentField.typeName.resolve() as? ProtobufMessageDefinition)?.qualifiedName() + ?.toString() != WellknownTypes.ANY + ) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${parentField?.name()}' is not a field with Any type", + ).range(o.textRange).highlightType(ProblemHighlightType.ERROR).create() } } - override fun visitBuiltInOptionName(o: ProtobufBuiltInOptionName) { - if (o.reference?.resolve() == null) { + override fun visitOptionName(o: ProtobufOptionName) { + val target: PsiElement = o.symbolName ?: o.extensionFieldName ?: return + + if (o.resolve() == null) { + val isRoot = o.parent !is ProtobufOptionName holder.newAnnotation( HighlightSeverity.ERROR, - "Built-in option '${o.text}' not found", - ) - .range(o.textRange) - .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) - .create() + "${if (isRoot) "Option" else "Field"} '${target.text}' not found", + ).range(target.textRange).highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL).create() } } - override fun visitFieldName(o: ProtobufFieldName) { - val message = o.message() ?: return - message.items { - if (it.name() == element.text) { - return - } - } - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(o.textRange) - .textAttributes(ProtobufHighlighter.FIELD) - .create() - holder.newAnnotation( - HighlightSeverity.ERROR, - "Field '${o.text}' not found", - ) - .range(o.textRange) - .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) - .create() + override fun visitField(o: ProtobufField) { + visitValueAssign(o) } - override fun visitEnumValue(o: ProtobufEnumValue) { - val enum = o.enum() ?: return - enum.items { - if (it.name() == element.text) { - return - } - } - holder.newAnnotation( - HighlightSeverity.ERROR, - "Enum value '${o.text}' not found", - ) - .range(o.textRange) - .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) - .create() + override fun visitOptionAssign(o: ProtobufOptionAssign) { + visitValueAssign(o) } - override fun visitConstant(o: ProtobufConstant) { - val parent = - when (val parent = o.parent) { - is ProtobufArrayValue -> { - parent.parent.parent + private fun visitValueAssign(o: ValueAssign) { + val field = o.field() ?: return + val valueElement = o.valueElement() ?: return + + if (valueElement is ArrayValue) { + when (field) { + is ProtobufFieldDefinition -> { + if (!field.repeated()) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${field.name()}' is not a repeated field", + ).range(field.textRange).create() + } } - else -> parent - } - val field = - when (parent) { - is ProtobufOptionAssign -> { - parent.optionName.field() as? ProtobufFieldDefinition ?: return - } - is ProtobufFieldAssign -> { - parent.fieldName.reference?.resolve() as? ProtobufFieldDefinition ?: return + is ProtobufGroupDefinition -> { + if (!field.repeated()) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${field.name()}' is not a repeated field", + ).range(field.textRange).create() + } } - else -> return } - if (o.arrayValue != null) { - if (field.fieldLabel?.textMatches("repeated") != true) { - holder.newAnnotation( - HighlightSeverity.ERROR, - "Field \"${field.name()}\" is not a repeated value", - ) - .range(o.textRange) - .create() + valueElement.values().forEach { + checkCompatibleType(it, field) } - return + } else { + checkCompatibleType(valueElement, field) } + } - val message = - when (val type = field.typeName.text) { - BuiltInType.BOOL.value() -> - if (o.booleanValue == null) { - "Field \"${field.name()}\" required a boolean value" - } else { - null - } - BuiltInType.STRING.value() -> - if (o.stringValueList.isEmpty()) { - "Field \"${field.name()}\" required a string value" - } else { - null - } - BuiltInType.FLOAT.value(), - BuiltInType.DOUBLE.value(), - -> - if (o.numberValue?.float() == null) { - "Field \"${field.name()}\" required a number value" - } else { - null - } - BuiltInType.UINT32.value(), - BuiltInType.UINT64.value(), - BuiltInType.FIXED32.value(), - BuiltInType.FIXED64.value(), - -> - if (o.numberValue?.uint() == null) { - "Field \"${field.name()}\" required a uint value" - } else { - null - } - BuiltInType.INT32.value(), - BuiltInType.INT64.value(), - BuiltInType.SINT32.value(), - BuiltInType.SINT64.value(), - BuiltInType.SFIXED32.value(), - BuiltInType.SFIXED64.value(), - -> - if (o.numberValue?.int() == null) { - "Field \"${field.name()}\" required a int value" - } else { - null - } - else -> { - when (val typeDefinition = field.typeName.reference?.resolve()) { - is ProtobufEnumDefinition -> - if (o.enumValue == null) { - "Field \"${field.name()}\" required a value of \"${typeDefinition.qualifiedName()}\"" - } else { - null - } - is ProtobufMessageDefinition -> - if (o.messageValue == null) { - "Field \"${field.name()}\" required \"${typeDefinition.qualifiedName()}\" value" - } else { - null - } - else -> null - } - } - } - - message?.let { - holder.newAnnotation(HighlightSeverity.ERROR, it) - .range(o.textRange) - .create() + private fun checkCompatibleType( + value: ValueElement<*>, + field: ProtobufFieldLike, + ) { + val fieldType = field.fieldValueType() + val valueType = value.valueType() + if (valueType != fieldType) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${field.fieldName()}' required ${fieldType.name.lowercase()} value, but got ${valueType.name.lowercase()} value", + ).range(value.textRange).create() } } @@ -325,9 +220,17 @@ class ProtobufAnnotator : Annotator { holder.newAnnotation( HighlightSeverity.ERROR, "Enum must not be empty", - ) - .range(o.body()?.textRange ?: o.textRange) - .create() + ).range(o.body()?.textRange ?: o.textRange).create() + } + } + + private fun visitFieldLike(o: ProtobufFieldLike) { + val value = o.number() ?: return + if (value < 1) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field number must be greater than 0", + ).range(o.findChild()?.textRange ?: o.textRange).create() } } @@ -337,12 +240,13 @@ class ProtobufAnnotator : Annotator { o.owner()?.let { ScopeTracker.tracker(it).visit(o, holder) } o.parentOfType()?.let { NumberTracker.tracker(it).visit(o, holder) } visitExtendItem(o) + visitFieldLike(o) } private fun visitExtendItem(o: ProtobufElement) { if (o.parentOfType() != null) return val extendMessage = - o.parentOfType()?.typeName?.reference?.resolve() as? ProtobufMessageDefinition + o.parentOfType()?.typeName?.resolve() as? ProtobufMessageDefinition ?: return val insideExtension = @@ -355,9 +259,7 @@ class ProtobufAnnotator : Annotator { holder.newAnnotation( HighlightSeverity.ERROR, "Extend field number must defined in extension range.", - ) - .range((o as? ProtobufNumbered)?.intValue()?.textRange ?: o.textRange) - .create() + ).range((o as? ProtobufNumbered)?.intValue()?.textRange ?: o.textRange).create() } ScopeTracker.tracker(extendMessage).visit(o as? ProtobufDefinition ?: return, holder) NumberTracker.tracker(extendMessage).visit(o as? ProtobufNumbered ?: return, holder) @@ -369,6 +271,7 @@ class ProtobufAnnotator : Annotator { o.owner()?.let { ScopeTracker.tracker(it).visit(o, holder) } o.parentOfType()?.let { NumberTracker.tracker(it).visit(o, holder) } visitExtendItem(o) + visitFieldLike(o) } override fun visitMessageDefinition(o: ProtobufMessageDefinition) { @@ -389,6 +292,27 @@ class ProtobufAnnotator : Annotator { o.owner()?.let { ScopeTracker.tracker(it).visit(o, holder) } } + override fun visitEnumValue(o: ProtobufEnumValue) { + o.enum()?.items { + if (it.name() == o.text) { + return + } + } + holder.newAnnotation( + HighlightSeverity.ERROR, + "Enum value '${o.text}' not found", + ).range(o.textRange).highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL).create() + } + + override fun visitFieldName(o: ProtobufFieldName) { + if (o.resolve() == null) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${o.text}' not existed", + ).range(o.textRange).highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL).create() + } + } + override fun visitEnumValueDefinition(o: ProtobufEnumValueDefinition) { requireCase("Enum value name", o, CaseFormat.SCREAMING_SNAKE_CASE) @@ -400,13 +324,19 @@ class ProtobufAnnotator : Annotator { val parentName = o.owner()?.name() ?: return if (!enumName.startsWith(parentName.toScreamingSnakeCase())) { holder.newAnnotation( - HighlightSeverity.WARNING, + HighlightSeverity.WEAK_WARNING, "Value name of root enum should be start with enum name", - ) - .range(o.identifier()?.textRange ?: o.textRange) - .create() + ).range(o.identifier()?.textRange ?: o.textRange).create() } } + + val number = o.number() ?: return + if (number < 0) { + holder.newAnnotation( + HighlightSeverity.WARNING, + "Enum value number should be greater than or equal to 0", + ).range(o.integerValue?.textRange ?: o.textRange).create() + } } override fun visitReservedName(o: ProtobufReservedName) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufEditionAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufEditionAnnotator.kt new file mode 100644 index 00000000..a2086fe5 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufEditionAnnotator.kt @@ -0,0 +1,17 @@ +package io.kanro.idea.plugin.protobuf.lang.annotator + +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.psi.PsiElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement + +class ProtobufEditionAnnotator : Annotator { + override fun annotate( + element: PsiElement, + holder: AnnotationHolder, + ) { + val file = (element as? ProtobufElement)?.file() ?: return + val syntax = file.edition() + if (syntax != null) return + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufFeature.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufFeature.kt new file mode 100644 index 00000000..570900b5 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufFeature.kt @@ -0,0 +1,73 @@ +package io.kanro.idea.plugin.protobuf.lang.annotator + +data class ProtobufFeature( + val enumType: ProtobufEnumType, + val fieldPresence: ProtobufFieldPresence, + val jsonFormat: ProtobufJsonFormat, + val messageEncoding: ProtobufMessageEncoding, + val repeatedFieldEncoding: ProtobufRepeatedFieldEncoding, + val utf8Validation: ProtobufUtf8Validation, +) { + companion object { + val PROTO3 = + ProtobufFeature( + ProtobufEnumType.OPEN, + ProtobufFieldPresence.IMPLICIT, + ProtobufJsonFormat.ALLOW, + ProtobufMessageEncoding.LENGTH_PREFIXED, + ProtobufRepeatedFieldEncoding.PACKED, + ProtobufUtf8Validation.VERIFY, + ) + + val PROTO2 = + ProtobufFeature( + ProtobufEnumType.CLOSED, + ProtobufFieldPresence.EXPLICIT, + ProtobufJsonFormat.LEGACY_BEST_EFFORT, + ProtobufMessageEncoding.LENGTH_PREFIXED, + ProtobufRepeatedFieldEncoding.EXPANDED, + ProtobufUtf8Validation.NONE, + ) + + val EDITION_2023 = + ProtobufFeature( + ProtobufEnumType.OPEN, + ProtobufFieldPresence.EXPLICIT, + ProtobufJsonFormat.ALLOW, + ProtobufMessageEncoding.LENGTH_PREFIXED, + ProtobufRepeatedFieldEncoding.PACKED, + ProtobufUtf8Validation.VERIFY, + ) + } +} + +enum class ProtobufEnumType { + CLOSED, + OPEN, +} + +enum class ProtobufFieldPresence { + LEGACY_REQUIRED, + EXPLICIT, + IMPLICIT, +} + +enum class ProtobufJsonFormat { + ALLOW, + LEGACY_BEST_EFFORT, +} + +enum class ProtobufMessageEncoding { + LENGTH_PREFIXED, + DELIMITED, +} + +enum class ProtobufRepeatedFieldEncoding { + PACKED, + EXPANDED, +} + +enum class ProtobufUtf8Validation { + VERIFY, + NONE, +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ScopeTracker.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ScopeTracker.kt index dbff337d..220ce3e8 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ScopeTracker.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ScopeTracker.kt @@ -5,12 +5,13 @@ import com.intellij.lang.annotation.HighlightSeverity import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedName import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufMultiNameDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScopeItem +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.name +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufMultiNameDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem open class ScopeTracker(scope: ProtobufScope) { private val nameMap = mutableMapOf>() @@ -37,7 +38,7 @@ open class ScopeTracker(scope: ProtobufScope) { } protected open fun record(reserved: ProtobufReservedName) { - val name = reserved.identifierLiteral?.text ?: return + val name = reserved.name() reservedNameMap.getOrPut(name) { mutableListOf() }.add(reserved) @@ -55,7 +56,7 @@ open class ScopeTracker(scope: ProtobufScope) { reserved: ProtobufReservedName, holder: AnnotationHolder, ) { - val name = reserved.identifierLiteral?.text ?: return + val name = reserved.name() createError(reserved, buildMessage(name, reserved) ?: return, holder) } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/AddImportInsertHandler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/AddImportInsertHandler.kt index f3acb32b..edeac507 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/AddImportInsertHandler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/AddImportInsertHandler.kt @@ -4,8 +4,8 @@ import com.intellij.codeInsight.completion.InsertHandler import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.LookupElement import com.intellij.psi.PsiDocumentManager -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile class AddImportInsertHandler(private val element: ProtobufElement) : InsertHandler { override fun handleInsert( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/EnumValueNameProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/EnumValueNameProvider.kt index 416a45ed..27163fcd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/EnumValueNameProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/EnumValueNameProvider.kt @@ -8,7 +8,7 @@ import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.psi.util.parentOfType import com.intellij.util.ProcessingContext -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition import io.kanro.idea.plugin.protobuf.string.toScreamingSnakeCase object EnumValueNameProvider : CompletionProvider() { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/FieldNameProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/FieldNameProvider.kt index f30bc40b..88132d79 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/FieldNameProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/FieldNameProvider.kt @@ -10,11 +10,11 @@ import com.intellij.patterns.PlatformPatterns import com.intellij.psi.PsiElement import com.intellij.psi.util.parentOfType import com.intellij.util.ProcessingContext -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtensionStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedStatement import io.kanro.idea.plugin.protobuf.lang.psi.forEachPrev -import io.kanro.idea.plugin.protobuf.lang.psi.range +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.range import io.kanro.idea.plugin.protobuf.lang.support.BuiltInType import io.kanro.idea.plugin.protobuf.string.case.CommonWordSplitter import io.kanro.idea.plugin.protobuf.string.case.SnakeCaseFormatter @@ -29,7 +29,7 @@ object FieldNameProvider : CompletionProvider() { ) { val element = parameters.position val field = element.parentOfType() ?: return - val type = field.typeName.symbolNameList.lastOrNull()?.text ?: return + val type = field.typeName.leaf()?.text ?: return val searchName = element.text.substringBeforeLast("_IntellijIdeaRulezzz", "") val prevNumber = prevFieldNumber(element) val inserter = fieldNumberInserter(prevNumber + 1) @@ -73,7 +73,8 @@ object FieldNameProvider : CompletionProvider() { is ProtobufReservedStatement -> return it.reservedRangeList.maxOf { it.range()?.last?.takeIf { it != Long.MAX_VALUE } ?: 0 }.takeIf { it != 0L } ?: return@forEachPrev - is ProtobufExtensionStatement -> return it.reservedRangeList.maxOf { + + is ProtobufExtensionStatement -> return it.extensionRangeList.maxOf { it.range()?.last?.takeIf { it != Long.MAX_VALUE } ?: 0 }.takeIf { it != 0L } ?: return@forEachPrev } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/ProtobufCompletionContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/ProtobufCompletionContributor.kt index 413ebe46..757c0348 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/ProtobufCompletionContributor.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/ProtobufCompletionContributor.kt @@ -4,16 +4,16 @@ import com.intellij.codeInsight.completion.CompletionContributor import com.intellij.codeInsight.completion.CompletionType import com.intellij.patterns.PlatformPatterns import com.intellij.psi.PsiErrorElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumBody -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIdentifier -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcBody -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufSyntaxStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumBody +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIdentifier +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcBody +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufSyntaxStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName class ProtobufCompletionContributor : CompletionContributor() { init { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/MarkdownSymbolReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/MarkdownSymbolReference.kt index f0f009c0..6db2ec5c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/MarkdownSymbolReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/MarkdownSymbolReference.kt @@ -16,12 +16,11 @@ import com.intellij.psi.util.parentOfType import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver import io.kanro.idea.plugin.protobuf.lang.util.AnyElement @@ -122,7 +121,7 @@ class MarkdownSymbolReference(element: MarkdownShortReferenceLink) : element: ProtobufElement, scope: QualifiedName, ): LookupElement? { - if (element !is ProtobufLookupItem) return null + if (element !is io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement) return null return if (element is ProtobufPackageName) { element.lookup()?.withLookupString(scope.append(element.name).toString()) ?.withInsertHandler(packageInsertHandler) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/ProtobufLineCommentsMarkdownInjector.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/ProtobufLineCommentsMarkdownInjector.kt index ff76a08e..ae88d3ed 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/ProtobufLineCommentsMarkdownInjector.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/ProtobufLineCommentsMarkdownInjector.kt @@ -3,7 +3,7 @@ package io.kanro.idea.plugin.protobuf.lang.docs import com.intellij.lang.injection.MultiHostInjector import com.intellij.lang.injection.MultiHostRegistrar import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufLineCommentImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufLineCommentImpl import io.kanro.idea.plugin.protobuf.string.lineCommentRanges import org.intellij.plugins.markdown.lang.MarkdownLanguage diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextPairedBraceMatcher.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextPairedBraceMatcher.kt new file mode 100644 index 00000000..0fec7bb8 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextPairedBraceMatcher.kt @@ -0,0 +1,37 @@ +package io.kanro.idea.plugin.protobuf.lang.edting + +import com.intellij.lang.BracePair +import com.intellij.lang.PairedBraceMatcher +import com.intellij.psi.PsiFile +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextPairedBraceMatcher : PairedBraceMatcher { + override fun getPairs(): Array { + return Companion.pairs + } + + override fun isPairedBracesAllowedBeforeType( + lbraceType: IElementType, + contextType: IElementType?, + ): Boolean { + return true + } + + override fun getCodeConstructStart( + file: PsiFile?, + openingBraceOffset: Int, + ): Int { + return 0 + } + + companion object { + private val pairs = + arrayOf( + BracePair(ProtoTextTokens.LBRACE, ProtoTextTokens.RBRACE, false), + BracePair(ProtoTextTokens.LBRACK, ProtoTextTokens.RBRACK, false), + BracePair(ProtoTextTokens.LPAREN, ProtoTextTokens.RPAREN, false), + BracePair(ProtoTextTokens.LT, ProtoTextTokens.GT, false), + ) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextQuoteHandler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextQuoteHandler.kt new file mode 100644 index 00000000..d69fdf1e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextQuoteHandler.kt @@ -0,0 +1,6 @@ +package io.kanro.idea.plugin.protobuf.lang.edting + +import com.intellij.codeInsight.editorActions.SimpleTokenSetQuoteHandler +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextQuoteHandler : SimpleTokenSetQuoteHandler(ProtoTextTokens.STRING_LITERAL) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextSpellcheckingStrategy.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextSpellcheckingStrategy.kt new file mode 100644 index 00000000..fc2e77f9 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextSpellcheckingStrategy.kt @@ -0,0 +1,21 @@ +package io.kanro.idea.plugin.protobuf.lang.edting + +import com.intellij.psi.PsiElement +import com.intellij.spellchecker.inspections.PlainTextSplitter +import com.intellij.spellchecker.tokenizer.SpellcheckingStrategy +import com.intellij.spellchecker.tokenizer.Tokenizer +import com.intellij.spellchecker.tokenizer.TokenizerBase +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextStringValue + +class ProtoTextSpellcheckingStrategy : SpellcheckingStrategy() { + override fun getTokenizer(element: PsiElement?): Tokenizer<*> { + if (element is ProtoTextStringValue) { + return plainTextTokenizer + } + return super.getTokenizer(element) + } + + companion object { + private val plainTextTokenizer = TokenizerBase.create(PlainTextSplitter.getInstance()) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufPairedBraceMatcher.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufPairedBraceMatcher.kt index 94b37320..5385874e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufPairedBraceMatcher.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufPairedBraceMatcher.kt @@ -4,7 +4,7 @@ import com.intellij.lang.BracePair import com.intellij.lang.PairedBraceMatcher import com.intellij.psi.PsiFile import com.intellij.psi.tree.IElementType -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufPairedBraceMatcher : PairedBraceMatcher { override fun getPairs(): Array { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufQuoteHandler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufQuoteHandler.kt index 185584b7..dcbc1864 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufQuoteHandler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufQuoteHandler.kt @@ -1,6 +1,6 @@ package io.kanro.idea.plugin.protobuf.lang.edting import com.intellij.codeInsight.editorActions.SimpleTokenSetQuoteHandler -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufQuoteHandler : SimpleTokenSetQuoteHandler(ProtobufTokens.STRING_LITERAL) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufSpellcheckingStrategy.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufSpellcheckingStrategy.kt index 9056a656..7864e418 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufSpellcheckingStrategy.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufSpellcheckingStrategy.kt @@ -5,7 +5,7 @@ import com.intellij.spellchecker.inspections.PlainTextSplitter import com.intellij.spellchecker.tokenizer.SpellcheckingStrategy import com.intellij.spellchecker.tokenizer.Tokenizer import com.intellij.spellchecker.tokenizer.TokenizerBase -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue class ProtobufSpellcheckingStrategy : SpellcheckingStrategy() { override fun getTokenizer(element: PsiElement?): Tokenizer<*> { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/folding/ProtobufFoldingBuilder.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/folding/ProtobufFoldingBuilder.kt index 9f1a5a3b..b4a33ebb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/folding/ProtobufFoldingBuilder.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/folding/ProtobufFoldingBuilder.kt @@ -11,10 +11,9 @@ import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement import com.intellij.psi.PsiWhiteSpace -import com.intellij.refactoring.suggested.startOffset -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufFolding +import io.kanro.idea.plugin.protobuf.lang.psi.feature.FoldingElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren import java.util.Stack @@ -28,7 +27,7 @@ class ProtobufFoldingBuilder : FoldingBuilderEx(), DumbAware { val file = (root.containingFile as? ProtobufFile) ?: return arrayOf() result += buildFoldingDescriptorForFile(file) - root.walkChildren { + root.walkChildren { it.folding()?.let { result += it } } return result.toTypedArray() @@ -54,6 +53,7 @@ class ProtobufFoldingBuilder : FoldingBuilderEx(), DumbAware { is PsiComment, -> { } + else -> { if (stack.size >= 2) { val start = stack.firstElement() @@ -61,8 +61,8 @@ class ProtobufFoldingBuilder : FoldingBuilderEx(), DumbAware { stack.clear() val range = TextRange.create( - start.stringValue?.startOffset ?: return@forEach, - end.startOffset + end.textLength, + start.stringValue?.textRange?.startOffset ?: return@forEach, + end.textRange.startOffset + end.textLength, ) result += diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextCommenter.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextCommenter.kt new file mode 100644 index 00000000..0c2557aa --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextCommenter.kt @@ -0,0 +1,61 @@ +package io.kanro.idea.plugin.protobuf.lang.formatter + +import com.intellij.lang.CodeDocumentationAwareCommenterEx +import com.intellij.psi.PsiComment +import com.intellij.psi.PsiElement +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextCommenter : CodeDocumentationAwareCommenterEx { + override fun getBlockCommentPrefix(): String? { + return null + } + + override fun getBlockCommentSuffix(): String? { + return null + } + + override fun getLineCommentPrefix(): String { + return "#" + } + + override fun getCommentedBlockCommentPrefix(): String? { + return null + } + + override fun getCommentedBlockCommentSuffix(): String? { + return null + } + + override fun getLineCommentTokenType(): IElementType { + return ProtoTextTokens.SHARP_LINE_COMMENT + } + + override fun getBlockCommentTokenType(): IElementType? { + return null + } + + override fun getDocumentationCommentTokenType(): IElementType? { + return null + } + + override fun getDocumentationCommentPrefix(): String? { + return null + } + + override fun getDocumentationCommentLinePrefix(): String? { + return null + } + + override fun getDocumentationCommentSuffix(): String? { + return null + } + + override fun isDocumentationComment(element: PsiComment?): Boolean { + return false + } + + override fun isDocumentationCommentText(element: PsiElement?): Boolean { + return false + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextFormattingModelBuilder.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextFormattingModelBuilder.kt new file mode 100644 index 00000000..6ab44735 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextFormattingModelBuilder.kt @@ -0,0 +1,60 @@ +package io.kanro.idea.plugin.protobuf.lang.formatter + +import com.intellij.formatting.FormattingContext +import com.intellij.formatting.FormattingModel +import com.intellij.formatting.FormattingModelBuilder +import com.intellij.formatting.SpacingBuilder +import com.intellij.formatting.Wrap +import com.intellij.formatting.WrapType +import com.intellij.psi.codeStyle.CodeStyleSettings +import com.intellij.psi.codeStyle.CommonCodeStyleSettings +import com.intellij.psi.formatter.FormattingDocumentModelImpl +import com.intellij.psi.formatter.PsiBasedFormattingModel +import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextFormattingModelBuilder : FormattingModelBuilder { + override fun createModel(formattingContext: FormattingContext): FormattingModel { + val file = formattingContext.containingFile + return PsiBasedFormattingModel( + file, + ProtobufBlock( + BlockType.BODY, + formattingContext.node, + Wrap.createWrap(WrapType.NONE, false), + null, + spacingBuilder(formattingContext.codeStyleSettings), + ), + FormattingDocumentModelImpl.createOn(file), + ) + } + + companion object { + private fun spacingBuilder(settings: CodeStyleSettings): SpacingBuilder { + val commonSettings: CommonCodeStyleSettings = settings.getCommonSettings(ProtobufLanguage) + return SpacingBuilder(commonSettings) + .before(ProtoTextTokens.SEMI) + .none() + .around(ProtoTextTokens.ASSIGN) + .spaces(1) + .after(ProtoTextTokens.COMMA) + .spaces(1) + .withinPair(ProtoTextTokens.LBRACE, ProtoTextTokens.RBRACE) + .spaceIf(commonSettings.SPACE_WITHIN_BRACES, false) + .withinPair(ProtoTextTokens.LBRACK, ProtoTextTokens.RBRACK) + .spaceIf(commonSettings.SPACE_WITHIN_BRACKETS, false) + .withinPair(ProtoTextTokens.LPAREN, ProtoTextTokens.RPAREN) + .spaceIf(commonSettings.SPACE_WITHIN_PARENTHESES, false) + .before(ProtoTextTokens.COMMA) + .spaceIf(commonSettings.SPACE_BEFORE_COMMA) + .after(ProtoTextTokens.COMMA) + .spaceIf(commonSettings.SPACE_AFTER_COMMA) + .around(ProtoTextTokens.ASSIGN) + .spaceIf(commonSettings.SPACE_AROUND_ASSIGNMENT_OPERATORS) + .before(ProtoTextTokens.COLON) + .spaceIf(commonSettings.SPACE_BEFORE_COLON) + .after(ProtoTextTokens.COLON) + .spaceIf(commonSettings.SPACE_AFTER_COLON) + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextLanguageCodeStyleSettingsProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextLanguageCodeStyleSettingsProvider.kt new file mode 100644 index 00000000..7a7bca4d --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextLanguageCodeStyleSettingsProvider.kt @@ -0,0 +1,112 @@ +package io.kanro.idea.plugin.protobuf.lang.formatter + +import com.intellij.application.options.IndentOptionsEditor +import com.intellij.application.options.SmartIndentOptionsEditor +import com.intellij.lang.Language +import com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable +import com.intellij.psi.codeStyle.CodeStyleSettingsCustomizableOptions +import com.intellij.psi.codeStyle.CommonCodeStyleSettings +import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage + +class ProtoTextLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvider() { + override fun getLanguage(): Language { + return ProtoTextLanguage + } + + override fun getIndentOptionsEditor(): IndentOptionsEditor { + return SmartIndentOptionsEditor() + } + + override fun getCodeSample(settingsType: SettingsType): String { + return """# This is an example of Protocol Buffer's text format. +# Unlike .proto files, only shell-style line comments are supported. + +name: "John Smith" + +pet { + kind: DOG + name: "Fluffy" + tail_wagginess: 0.65f +} + +pet < + kind: LIZARD + name: "Lizzy" + legs: 4 +> + +string_value_with_escape: "valid \n escape" +repeated_values: [ "one", "two", "three" ]""" + } + + override fun customizeDefaults( + commonSettings: CommonCodeStyleSettings, + indentOptions: CommonCodeStyleSettings.IndentOptions, + ) { + commonSettings.SPACE_BEFORE_COLON = false + commonSettings.KEEP_BLANK_LINES_BETWEEN_PACKAGE_DECLARATION_AND_HEADER = 1 + } + + override fun customizeSettings( + consumer: CodeStyleSettingsCustomizable, + settingsType: SettingsType, + ) { + when (settingsType) { + SettingsType.SPACING_SETTINGS -> { + consumer.showStandardOptions("SPACE_WITHIN_BRACES") + consumer.showStandardOptions("SPACE_WITHIN_BRACKETS") + consumer.showStandardOptions("SPACE_WITHIN_PARENTHESES") + consumer.showStandardOptions("SPACE_BEFORE_COMMA") + consumer.showStandardOptions("SPACE_AFTER_COMMA") + consumer.showStandardOptions("SPACE_BEFORE_COLON") + consumer.moveStandardOption("SPACE_BEFORE_COLON", "Assignment") + consumer.showStandardOptions("SPACE_AFTER_COLON") + consumer.moveStandardOption("SPACE_AFTER_COLON", "Assignment") + consumer.showStandardOptions("SPACE_AROUND_ASSIGNMENT_OPERATORS") + consumer.renameStandardOption("SPACE_AROUND_ASSIGNMENT_OPERATORS", "Around '='") + consumer.moveStandardOption("SPACE_AROUND_ASSIGNMENT_OPERATORS", "Assignment") + consumer.showStandardOptions("SPACE_BEFORE_CLASS_LBRACE") + consumer.renameStandardOption("SPACE_BEFORE_CLASS_LBRACE", "Body left brace") + consumer.moveStandardOption("SPACE_BEFORE_CLASS_LBRACE", "Before block") + consumer.showStandardOptions("SPACE_BEFORE_METHOD_LBRACE") + consumer.renameStandardOption("SPACE_BEFORE_METHOD_LBRACE", "Option left bracket") + consumer.moveStandardOption("SPACE_BEFORE_METHOD_LBRACE", "Before block") + } + + SettingsType.BLANK_LINES_SETTINGS -> { + val blankLines = CodeStyleSettingsCustomizableOptions.getInstance().BLANK_LINES + consumer.showCustomOption( + ProtobufCodeStyleSettings::class.java, + ProtobufCodeStyleSettings::BLANK_LINES_AFTER_SYNTAX.name, + "After syntax statement", + blankLines, + ) + consumer.showStandardOptions("BLANK_LINES_AFTER_PACKAGE") + consumer.showStandardOptions("BLANK_LINES_AFTER_IMPORTS") + consumer.showCustomOption( + ProtobufCodeStyleSettings::class.java, + ProtobufCodeStyleSettings::BLANK_LINES_AFTER_FILE_OPTIONS.name, + "After file options", + blankLines, + ) + + val blankLinesKeep = CodeStyleSettingsCustomizableOptions.getInstance().BLANK_LINES_KEEP + consumer.showCustomOption( + ProtobufCodeStyleSettings::class.java, + ProtobufCodeStyleSettings::KEEP_BLANK_LINES_BETWEEN_IMPORTS.name, + "Between imports", + blankLinesKeep, + ) + consumer.showCustomOption( + ProtobufCodeStyleSettings::class.java, + ProtobufCodeStyleSettings::KEEP_BLANK_LINES_BETWEEN_FILE_OPTIONS.name, + "Between file options", + blankLinesKeep, + ) + } + + else -> {} + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufBlock.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufBlock.kt index 4023d269..d9361167 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufBlock.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufBlock.kt @@ -7,13 +7,15 @@ import com.intellij.formatting.Spacing import com.intellij.formatting.SpacingBuilder import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode +import com.intellij.psi.PsiFile import com.intellij.psi.TokenType import com.intellij.psi.formatter.common.AbstractBlock -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufCommentToken -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufCommentToken +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextCommentToken +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens +import io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement +import io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement enum class BlockType { BODY, @@ -46,13 +48,12 @@ class ProtobufBlock( override fun getIndent(): Indent { return when (type) { BlockType.BODY -> Indent.getNoneIndent() - BlockType.STATEMENT -> { - if (node.treeParent.psi is ProtobufFile) { - Indent.getNoneIndent() - } else { - Indent.getNormalIndent() + BlockType.STATEMENT -> + when (node.treeParent.psi) { + is PsiFile -> Indent.getNoneIndent() + else -> Indent.getNormalIndent() } - } + BlockType.FRAGMENT -> { if (node.treePrev == null) return Indent.getNoneIndent() when (node.elementType) { @@ -66,7 +67,18 @@ class ProtobufBlock( ProtobufTokens.RBRACK, ProtobufTokens.LT, ProtobufTokens.GT, + ProtoTextTokens.SEMI, + ProtoTextTokens.COMMA, + ProtoTextTokens.LBRACE, + ProtoTextTokens.RBRACE, + ProtoTextTokens.LPAREN, + ProtoTextTokens.RPAREN, + ProtoTextTokens.LBRACK, + ProtoTextTokens.RBRACK, + ProtoTextTokens.LT, + ProtoTextTokens.GT, -> Indent.getNoneIndent() + else -> Indent.getContinuationWithoutFirstIndent() } } @@ -76,14 +88,20 @@ class ProtobufBlock( override fun getChildIndent(): Indent? { return when (type) { BlockType.BODY -> { - if (node.psi is ProtobufFile) { - Indent.getNoneIndent() - } else { - Indent.getNormalIndent() + when (node.psi) { + is PsiFile -> Indent.getNoneIndent() + + else -> Indent.getNormalIndent() } } - BlockType.STATEMENT -> Indent.getContinuationWithoutFirstIndent() - BlockType.FRAGMENT -> Indent.getContinuationWithoutFirstIndent() + + BlockType.STATEMENT -> { + Indent.getContinuationWithoutFirstIndent() + } + + BlockType.FRAGMENT -> { + Indent.getContinuationWithoutFirstIndent() + } } } @@ -103,15 +121,18 @@ class ProtobufBlock( private fun buildChild(child: ASTNode): Block { val psi = child.psi - if (psi is ProtobufBlock) { + if (psi is BlockElement) { return ProtobufBlock(BlockType.BODY, child, wrap, alignment, spacingBuilder) } - if (psi is ProtobufStatement) { + if (psi is StatementElement) { return ProtobufBlock(BlockType.STATEMENT, child, wrap, alignment, spacingBuilder) } if (child.elementType is ProtobufCommentToken) { return ProtobufBlock(BlockType.STATEMENT, child, wrap, alignment, spacingBuilder) } + if (child.elementType is ProtoTextCommentToken) { + return ProtobufBlock(BlockType.STATEMENT, child, wrap, alignment, spacingBuilder) + } return ProtobufBlock(BlockType.FRAGMENT, child, wrap, alignment, spacingBuilder) } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufCommenter.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufCommenter.kt index 58596afd..c30a6f9f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufCommenter.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufCommenter.kt @@ -4,7 +4,7 @@ import com.intellij.lang.CodeDocumentationAwareCommenterEx import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement import com.intellij.psi.tree.IElementType -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufCommenter : CodeDocumentationAwareCommenterEx { override fun getBlockCommentPrefix(): String { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufFormattingModelBuilder.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufFormattingModelBuilder.kt index a44e7bae..09ef3423 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufFormattingModelBuilder.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufFormattingModelBuilder.kt @@ -10,9 +10,10 @@ import com.intellij.psi.codeStyle.CodeStyleSettings import com.intellij.psi.codeStyle.CommonCodeStyleSettings import com.intellij.psi.formatter.FormattingDocumentModelImpl import com.intellij.psi.formatter.PsiBasedFormattingModel +import com.intellij.psi.tree.TokenSet import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypes -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypes +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufFormattingModelBuilder : FormattingModelBuilder { override fun createModel(formattingContext: FormattingContext): FormattingModel { @@ -75,7 +76,7 @@ class ProtobufFormattingModelBuilder : FormattingModelBuilder { .spacing(0, 0, 1, true, customSettings.KEEP_BLANK_LINES_BETWEEN_IMPORTS) .between(ProtobufTypes.FILE_OPTION, ProtobufTypes.FILE_OPTION) .spacing(0, 0, 1, true, customSettings.KEEP_BLANK_LINES_BETWEEN_FILE_OPTIONS) - .after(ProtobufTypes.SYNTAX_STATEMENT) + .after(TokenSet.create(ProtobufTypes.SYNTAX_STATEMENT, ProtobufTypes.EDITION_STATEMENT)) .blankLines(customSettings.BLANK_LINES_AFTER_SYNTAX) .after(ProtobufTypes.PACKAGE_STATEMENT) .blankLines(commonSettings.BLANK_LINES_AFTER_PACKAGE) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufImportOptimizer.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufImportOptimizer.kt index d2d29cc7..e4bd2ade 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufImportOptimizer.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufImportOptimizer.kt @@ -3,13 +3,12 @@ package io.kanro.idea.plugin.protobuf.lang.formatter import com.intellij.lang.ImportOptimizer import com.intellij.psi.PsiFile import io.kanro.idea.plugin.protobuf.lang.annotator.FileTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufSyntaxStatement import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.resolve -import io.kanro.idea.plugin.protobuf.lang.psi.value -import io.kanro.idea.plugin.protobuf.lang.util.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufSyntaxStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve class ProtobufImportOptimizer : ImportOptimizer { override fun supports(file: PsiFile): Boolean { @@ -18,49 +17,47 @@ class ProtobufImportOptimizer : ImportOptimizer { override fun processFile(file: PsiFile): Runnable { return Runnable { - ProtobufImportOptimizer.processFile(file) + optimizeImportProtobufFile(file) } } +} - companion object { - fun processFile(file: PsiFile) { - if (file !is ProtobufFile) return - val imports = file.imports() - if (imports.count() == 0) return - val tracker = FileTracker.tracker(file) - val optimizedImports = - imports.mapNotNull { - val resolved = it.resolve() ?: return@mapNotNull it - if (tracker.isUnused(resolved)) { - null - } else { - it - } - }.sortedBy { - it.stringValue?.value() ?: "" - }.joinToString("\n") { - it.text - } - - imports.forEach { - it.delete() +fun optimizeImportProtobufFile(file: PsiFile) { + if (file !is ProtobufFile) return + val imports = file.imports().toList() + if (imports.isEmpty()) return + val tracker = FileTracker.tracker(file) + val optimizedImports = + imports.mapNotNull { + val resolved = it.resolve() ?: return@mapNotNull it + if (tracker.isUnused(resolved)) { + null + } else { + it } + }.sortedBy { + it.stringValue?.value() ?: "" + }.joinToString("\n") { + it.text + } - file.findChild()?.let { - val tempFile = ProtobufPsiFactory.createFile(file.project, "\n\n$optimizedImports") - file.addRangeAfter(tempFile.firstChild, tempFile.lastChild, it) - return - } + imports.forEach { + it.delete() + } - file.findChild()?.let { - val tempFile = ProtobufPsiFactory.createFile(file.project, "\n\n$optimizedImports") - file.addRangeAfter(tempFile.firstChild, tempFile.lastChild, it) - return - } + file.findChild()?.let { + val tempFile = ProtobufPsiFactory.createFile(file.project, "\n\n$optimizedImports") + file.addRangeAfter(tempFile.firstChild, tempFile.lastChild, it) + return + } - val tempFile = ProtobufPsiFactory.createFile(file.project, "$optimizedImports\n\n") - file.addRangeBefore(tempFile.firstChild, tempFile.lastChild, file.firstChild) - return - } + file.findChild()?.let { + val tempFile = ProtobufPsiFactory.createFile(file.project, "\n\n$optimizedImports") + file.addRangeAfter(tempFile.firstChild, tempFile.lastChild, it) + return } + + val tempFile = ProtobufPsiFactory.createFile(file.project, "$optimizedImports\n\n") + file.addRangeBefore(tempFile.firstChild, tempFile.lastChild, file.firstChild) + return } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufLanguageCodeStyleSettingsProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufLanguageCodeStyleSettingsProvider.kt index 51946522..b44b975b 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufLanguageCodeStyleSettingsProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufLanguageCodeStyleSettingsProvider.kt @@ -103,6 +103,7 @@ message GetMessageRequest { consumer.renameStandardOption("SPACE_BEFORE_METHOD_LBRACE", "Option left bracket") consumer.moveStandardOption("SPACE_BEFORE_METHOD_LBRACE", "Before block") } + SettingsType.BLANK_LINES_SETTINGS -> { val blankLines = CodeStyleSettingsCustomizableOptions.getInstance().BLANK_LINES consumer.showCustomOption( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightingAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightingAnnotator.kt deleted file mode 100644 index d0734277..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightingAnnotator.kt +++ /dev/null @@ -1,90 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.highligh - -import com.intellij.codeInsight.daemon.impl.HighlightInfoType -import com.intellij.lang.annotation.AnnotationHolder -import com.intellij.lang.annotation.Annotator -import com.intellij.openapi.editor.colors.TextAttributesKey -import com.intellij.psi.PsiComment -import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIdentifier -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufNumberValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufVisitor -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocument - -class ProtobufHighlightingAnnotator : Annotator { - override fun annotate( - element: PsiElement, - holder: AnnotationHolder, - ) { - element.accept(ProtobufHighlightingVisitor(holder)) - } - - private class ProtobufHighlightingVisitor(val holder: AnnotationHolder) : ProtobufVisitor() { - override fun visitEnumValueDefinition(o: ProtobufEnumValueDefinition) { - createHighlight(o.identifier() ?: return, ProtobufHighlighter.ENUM_VALUE) - } - - override fun visitEnumValue(o: ProtobufEnumValue) { - createHighlight(o, ProtobufHighlighter.ENUM_VALUE) - } - - override fun visitNumberValue(o: ProtobufNumberValue) { - if (o.floatLiteral == null && o.integerLiteral == null) { - createHighlight(o, ProtobufHighlighter.KEYWORD) - } - } - - override fun visitPackageName(o: ProtobufPackageName) { - createHighlight(o, ProtobufHighlighter.IDENTIFIER) - } - - override fun visitIdentifier(o: ProtobufIdentifier) { - when (o.parent) { - is ProtobufMessageDefinition -> createHighlight(o, ProtobufHighlighter.MESSAGE) - is ProtobufFieldDefinition -> createHighlight(o, ProtobufHighlighter.FIELD) - is ProtobufMapFieldDefinition -> createHighlight(o, ProtobufHighlighter.FIELD) - is ProtobufOneofDefinition -> createHighlight(o, ProtobufHighlighter.FIELD) - is ProtobufGroupDefinition -> createHighlight(o, ProtobufHighlighter.MESSAGE) - is ProtobufFieldAssign -> createHighlight(o, ProtobufHighlighter.FIELD) - is ProtobufEnumDefinition -> createHighlight(o, ProtobufHighlighter.ENUM) - is ProtobufServiceDefinition -> createHighlight(o, ProtobufHighlighter.SERVICE) - is ProtobufRpcDefinition -> createHighlight(o, ProtobufHighlighter.METHOD) - } - } - - override fun visitFieldName(o: ProtobufFieldName) { - createHighlight(o, ProtobufHighlighter.IDENTIFIER) - } - - override fun visitComment(comment: PsiComment) { - if (comment is ProtobufDocument) { - if (comment.owner != null) { - createHighlight(comment, ProtobufHighlighter.DOC_COMMENT) - } - } - } - - private fun createHighlight( - element: PsiElement, - textAttributesKey: TextAttributesKey, - ) { - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(element.textRange) - .textAttributes(textAttributesKey) - .create() - } - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextColorSettingsPage.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextColorSettingsPage.kt new file mode 100644 index 00000000..465deec4 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextColorSettingsPage.kt @@ -0,0 +1,80 @@ +package io.kanro.idea.plugin.protobuf.lang.highlight + +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.fileTypes.SyntaxHighlighter +import com.intellij.openapi.options.colors.AttributesDescriptor +import com.intellij.openapi.options.colors.ColorDescriptor +import com.intellij.openapi.options.colors.ColorSettingsPage +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import javax.swing.Icon + +class ProtoTextColorSettingsPage : ColorSettingsPage { + override fun getAttributeDescriptors(): Array { + return DESCRIPTORS + } + + override fun getColorDescriptors(): Array { + return ColorDescriptor.EMPTY_ARRAY + } + + override fun getDisplayName(): String { + return "ProtoText" + } + + override fun getIcon(): Icon { + return ProtobufIcons.TEXT_FILE + } + + override fun getHighlighter(): SyntaxHighlighter { + return ProtoTextHighlighter() + } + + override fun getDemoText(): String { + return """ + # proto-file: google/protobuf/unittest_custom_options.proto + # proto-message: Aggregate + + s: 'FileAnnotation' + i: 100 + sub { s: 'NestedFileAnnotation' } + file { + [protobuf_unittest.fileopt] { s: 'FileExtensionAnnotation' } + } + mset { + [protobuf_unittest.AggregateMessageSetElement.message_set_extension] { + s: 'EmbeddedMessageSetElement' + } + } + any { + [type.googleapis.com/protobuf_unittest.AggregateMessageSetElement] { + s: 'EmbeddedMessageSetElement' + } + } + """.trimIndent() + } + + override fun getAdditionalHighlightingTagToDescriptorMap(): MutableMap? { + return mutableMapOf() + } + + companion object { + val DESCRIPTORS = + arrayOf( + AttributesDescriptor("Braces and Operators//Braces", ProtoTextHighlighter.BRACES), + AttributesDescriptor("Braces and Operators//Brackets", ProtoTextHighlighter.BRACKETS), + AttributesDescriptor("Braces and Operators//Comma", ProtoTextHighlighter.COMMA), + AttributesDescriptor("Braces and Operators//Dot", ProtoTextHighlighter.DOT), + AttributesDescriptor("Braces and Operators//Operator sign", ProtoTextHighlighter.OPERATION_SIGN), + AttributesDescriptor("Braces and Operators//Parentheses", ProtoTextHighlighter.PARENTHESES), + AttributesDescriptor("Braces and Operators//Semicolon", ProtoTextHighlighter.SEMICOLON), + AttributesDescriptor("Comments//Block comment", ProtoTextHighlighter.BLOCK_COMMENT), + AttributesDescriptor("Comments//Line comment", ProtoTextHighlighter.LINE_COMMENT), + AttributesDescriptor("Identifiers//Default", ProtoTextHighlighter.IDENTIFIER), + AttributesDescriptor("Identifiers//Field", ProtoTextHighlighter.FIELD), + AttributesDescriptor("Identifiers//Enum value", ProtoTextHighlighter.ENUM_VALUE), + AttributesDescriptor("Keyword", ProtoTextHighlighter.KEYWORD), + AttributesDescriptor("Number", ProtoTextHighlighter.NUMBER), + AttributesDescriptor("String", ProtoTextHighlighter.STRING), + ) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlighter.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlighter.kt new file mode 100644 index 00000000..a23a90e0 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlighter.kt @@ -0,0 +1,122 @@ +package io.kanro.idea.plugin.protobuf.lang.highlight + +import com.intellij.lexer.Lexer +import com.intellij.openapi.editor.DefaultLanguageHighlighterColors +import com.intellij.openapi.editor.HighlighterColors +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.fileTypes.SyntaxHighlighterBase +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.lexer.ProtoTextLexer +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextHighlighter : SyntaxHighlighterBase() { + override fun getHighlightingLexer(): Lexer { + return ProtoTextLexer() + } + + override fun getTokenHighlights(tokenType: IElementType): Array { + return pack(attributesMap[tokenType]) + } + + companion object { + val IDENTIFIER = + TextAttributesKey.createTextAttributesKey( + "TXTPB_IDENTIFIER", + DefaultLanguageHighlighterColors.IDENTIFIER, + ) + val FIELD = + TextAttributesKey.createTextAttributesKey( + "TXTPB_FIELD", + DefaultLanguageHighlighterColors.INSTANCE_FIELD, + ) + val NUMBER = + TextAttributesKey.createTextAttributesKey( + "TXTPB_NUMBER", + DefaultLanguageHighlighterColors.NUMBER, + ) + val KEYWORD = + TextAttributesKey.createTextAttributesKey( + "TXTPB_KEYWORD", + DefaultLanguageHighlighterColors.KEYWORD, + ) + val STRING = + TextAttributesKey.createTextAttributesKey( + "TXTPB_STRING", + DefaultLanguageHighlighterColors.STRING, + ) + val ENUM_VALUE = + TextAttributesKey.createTextAttributesKey( + "TXTPB_ENUM_VALUE", + DefaultLanguageHighlighterColors.CONSTANT, + ) + val BLOCK_COMMENT = + TextAttributesKey.createTextAttributesKey( + "TXTPB_BLOCK_COMMENT", + DefaultLanguageHighlighterColors.BLOCK_COMMENT, + ) + val LINE_COMMENT = + TextAttributesKey.createTextAttributesKey( + "TXTPB_LINE_COMMENT", + DefaultLanguageHighlighterColors.LINE_COMMENT, + ) + val OPERATION_SIGN = + TextAttributesKey.createTextAttributesKey( + "TXTPB_OPERATION_SIGN", + DefaultLanguageHighlighterColors.OPERATION_SIGN, + ) + val BRACES = + TextAttributesKey.createTextAttributesKey( + "TXTPB_BRACES", + DefaultLanguageHighlighterColors.BRACES, + ) + val DOT = TextAttributesKey.createTextAttributesKey("TXTPB_DOT", DefaultLanguageHighlighterColors.DOT) + val SEMICOLON = + TextAttributesKey.createTextAttributesKey("TXTPB_SEMICOLON", DefaultLanguageHighlighterColors.SEMICOLON) + val COMMA = TextAttributesKey.createTextAttributesKey("TXTPB_COMMA", DefaultLanguageHighlighterColors.COMMA) + val PARENTHESES = + TextAttributesKey.createTextAttributesKey( + "TXTPB_PARENTHESES", + DefaultLanguageHighlighterColors.PARENTHESES, + ) + val BRACKETS = + TextAttributesKey.createTextAttributesKey( + "TXTPB_BRACKETS", + DefaultLanguageHighlighterColors.BRACKETS, + ) + + // Invalid characters. + val BAD_CHARACTER = + TextAttributesKey.createTextAttributesKey( + "TXTPB_BAD_CHARACTER", + HighlighterColors.BAD_CHARACTER, + ) + + val attributesMap = + mapOf( + ProtoTextTokens.IDENTIFIER_LITERAL to IDENTIFIER, + ProtoTextTokens.ASSIGN to OPERATION_SIGN, + ProtoTextTokens.COLON to OPERATION_SIGN, + ProtoTextTokens.COMMA to COMMA, + ProtoTextTokens.DOT to DOT, + ProtoTextTokens.GT to BRACES, + ProtoTextTokens.LBRACE to BRACES, + ProtoTextTokens.LBRACK to BRACKETS, + ProtoTextTokens.LPAREN to PARENTHESES, + ProtoTextTokens.LT to BRACES, + ProtoTextTokens.MINUS to OPERATION_SIGN, + ProtoTextTokens.PLUS to OPERATION_SIGN, + ProtoTextTokens.RBRACE to BRACES, + ProtoTextTokens.RBRACK to BRACKETS, + ProtoTextTokens.RPAREN to PARENTHESES, + ProtoTextTokens.SEMI to SEMICOLON, + ProtoTextTokens.SLASH to OPERATION_SIGN, + ProtoTextTokens.FLOAT_LITERAL to NUMBER, + ProtoTextTokens.INTEGER_LITERAL to NUMBER, + ProtoTextTokens.STRING_LITERAL to STRING, + ProtoTextTokens.SHARP_LINE_COMMENT to LINE_COMMENT, + ProtoTextTokens.BUILT_IN_TYPE to KEYWORD, + ProtoTextTokens.FALSE to KEYWORD, + ProtoTextTokens.TRUE to KEYWORD, + ) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlightingAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlightingAnnotator.kt new file mode 100644 index 00000000..86377efe --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlightingAnnotator.kt @@ -0,0 +1,57 @@ +package io.kanro.idea.plugin.protobuf.lang.highlight + +import com.intellij.codeInsight.daemon.impl.HighlightInfoType +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.psi.PsiElement +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextNumberValue +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextVisitor + +class ProtoTextHighlightingAnnotator : Annotator { + override fun annotate( + element: PsiElement, + holder: AnnotationHolder, + ) { + ProtoTextHighlightingAnnotator.annotate(element, holder) + } + + companion object : Annotator { + override fun annotate( + element: PsiElement, + holder: AnnotationHolder, + ) { + element.accept( + object : ProtoTextVisitor() { + override fun visitEnumValue(o: ProtoTextEnumValue) { + createHighlight(o, ProtoTextHighlighter.ENUM_VALUE) + } + + override fun visitNumberValue(o: ProtoTextNumberValue) { + if (o.floatLiteral == null && o.integerLiteral == null) { + createHighlight(o, ProtoTextHighlighter.NUMBER) + } + } + + override fun visitFieldName(o: ProtoTextFieldName) { + if (o.symbolName != null) { + createHighlight(o, ProtoTextHighlighter.FIELD) + } + } + + private fun createHighlight( + element: PsiElement, + textAttributesKey: TextAttributesKey, + ) { + holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) + .range(element.textRange) + .textAttributes(textAttributesKey) + .create() + } + }, + ) + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufColorSettingsPage.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufColorSettingsPage.kt new file mode 100644 index 00000000..d1a383df --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufColorSettingsPage.kt @@ -0,0 +1,98 @@ +package io.kanro.idea.plugin.protobuf.lang.highlight + +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.fileTypes.SyntaxHighlighter +import com.intellij.openapi.options.colors.AttributesDescriptor +import com.intellij.openapi.options.colors.ColorDescriptor +import com.intellij.openapi.options.colors.ColorSettingsPage +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import javax.swing.Icon + +class ProtobufColorSettingsPage : ColorSettingsPage { + override fun getAttributeDescriptors(): Array { + return DESCRIPTORS + } + + override fun getColorDescriptors(): Array { + return ColorDescriptor.EMPTY_ARRAY + } + + override fun getDisplayName(): String { + return "Protobuf" + } + + override fun getIcon(): Icon { + return ProtobufIcons.FILE + } + + override fun getHighlighter(): SyntaxHighlighter { + return ProtobufHighlighter() + } + + override fun getDemoText(): String { + return """ + /* + * Block Comments + */ + syntax = "proto3"; + + package protobuf_unittest; // Line Comment + + import "google/protobuf/any.proto"; + + option java_outer_classname = "TestAnyProto"; + + // Doc Comment + message TestMessage { + int32 int32_value = 1 [default = 10086]; + google.protobuf.Any any_value = 2; + repeated google.protobuf.Any repeated_any_value = 3; + string text = 4 [default = "test_default"]; + } + + enum TestEnum { + UNKNOWN = 0, + VALUE = 1 + } + + service TestService { + rpc TestMethod(TestMessage) returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/v1/test" + body: "*" + }; + } + } + """.trimIndent() + } + + override fun getAdditionalHighlightingTagToDescriptorMap(): MutableMap? { + return mutableMapOf() + } + + companion object { + val DESCRIPTORS = + arrayOf( + AttributesDescriptor("Braces and Operators//Braces", ProtobufHighlighter.BRACES), + AttributesDescriptor("Braces and Operators//Brackets", ProtobufHighlighter.BRACKETS), + AttributesDescriptor("Braces and Operators//Comma", ProtobufHighlighter.COMMA), + AttributesDescriptor("Braces and Operators//Dot", ProtobufHighlighter.DOT), + AttributesDescriptor("Braces and Operators//Operator sign", ProtobufHighlighter.OPERATION_SIGN), + AttributesDescriptor("Braces and Operators//Parentheses", ProtobufHighlighter.PARENTHESES), + AttributesDescriptor("Braces and Operators//Semicolon", ProtobufHighlighter.SEMICOLON), + AttributesDescriptor("Comments//Block comment", ProtobufHighlighter.BLOCK_COMMENT), + AttributesDescriptor("Comments//Line comment", ProtobufHighlighter.LINE_COMMENT), + AttributesDescriptor("Comments//Doc comment", ProtobufHighlighter.DOC_COMMENT), + AttributesDescriptor("Identifiers//Default", ProtobufHighlighter.IDENTIFIER), + AttributesDescriptor("Identifiers//Message", ProtobufHighlighter.MESSAGE), + AttributesDescriptor("Identifiers//Field", ProtobufHighlighter.FIELD), + AttributesDescriptor("Identifiers//Enum", ProtobufHighlighter.ENUM), + AttributesDescriptor("Identifiers//Enum value", ProtobufHighlighter.ENUM_VALUE), + AttributesDescriptor("Identifiers//Service", ProtobufHighlighter.SERVICE), + AttributesDescriptor("Identifiers//Method", ProtobufHighlighter.METHOD), + AttributesDescriptor("Keyword", ProtobufHighlighter.KEYWORD), + AttributesDescriptor("Number", ProtobufHighlighter.NUMBER), + AttributesDescriptor("String", ProtobufHighlighter.STRING), + ) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightLexer.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightLexer.kt similarity index 81% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightLexer.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightLexer.kt index d041cb1e..bf0583f4 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightLexer.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightLexer.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.highligh +package io.kanro.idea.plugin.protobuf.lang.highlight import com.intellij.lexer.DelegateLexer import com.intellij.lexer.Lexer import com.intellij.psi.tree.IElementType -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens import io.kanro.idea.plugin.protobuf.lang.support.BuiltInType class ProtobufHighlightLexer(delegate: Lexer) : DelegateLexer(delegate) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlighter.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlighter.kt similarity index 96% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlighter.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlighter.kt index 7cd9ad43..911ecdf3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlighter.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlighter.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.highligh +package io.kanro.idea.plugin.protobuf.lang.highlight import com.intellij.lexer.Lexer import com.intellij.openapi.editor.DefaultLanguageHighlighterColors @@ -7,7 +7,7 @@ import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.fileTypes.SyntaxHighlighterBase import com.intellij.psi.tree.IElementType import io.kanro.idea.plugin.protobuf.lang.lexer.ProtobufLexer -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufHighlighter : SyntaxHighlighterBase() { override fun getHighlightingLexer(): Lexer { @@ -129,6 +129,7 @@ class ProtobufHighlighter : SyntaxHighlighterBase() { ProtobufTokens.LPAREN to PARENTHESES, ProtobufTokens.LT to BRACES, ProtobufTokens.MINUS to OPERATION_SIGN, + ProtobufTokens.PLUS to OPERATION_SIGN, ProtobufTokens.RBRACE to BRACES, ProtobufTokens.RBRACK to BRACKETS, ProtobufTokens.RPAREN to PARENTHESES, @@ -164,6 +165,7 @@ class ProtobufHighlighter : SyntaxHighlighterBase() { ProtobufTokens.SERVICE to KEYWORD, ProtobufTokens.STREAM to KEYWORD, ProtobufTokens.SYNTAX to KEYWORD, + ProtobufTokens.EDITION to KEYWORD, ProtobufTokens.TO to KEYWORD, ProtobufTokens.TRUE to KEYWORD, ProtobufTokens.WEAK to KEYWORD, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightingAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightingAnnotator.kt new file mode 100644 index 00000000..c4c50083 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightingAnnotator.kt @@ -0,0 +1,99 @@ +package io.kanro.idea.plugin.protobuf.lang.highlight + +import com.intellij.codeInsight.daemon.impl.HighlightInfoType +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.psi.PsiComment +import com.intellij.psi.PsiElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIdentifier +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufNumberValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufVisitor + +class ProtobufHighlightingAnnotator : Annotator { + override fun annotate( + element: PsiElement, + holder: AnnotationHolder, + ) { + ProtobufHighlightingAnnotator.annotate(element, holder) + } + + companion object : Annotator { + override fun annotate( + element: PsiElement, + holder: AnnotationHolder, + ) { + element.accept( + object : ProtobufVisitor() { + override fun visitEnumValueDefinition(o: ProtobufEnumValueDefinition) { + createHighlight(o.identifier() ?: return, ProtobufHighlighter.ENUM_VALUE) + } + + override fun visitPackageName(o: ProtobufPackageName) { + createHighlight(o, ProtobufHighlighter.IDENTIFIER) + } + + override fun visitIdentifier(o: ProtobufIdentifier) { + when (o.parent) { + is ProtobufMessageDefinition -> createHighlight(o, ProtobufHighlighter.MESSAGE) + is ProtobufFieldDefinition -> createHighlight(o, ProtobufHighlighter.FIELD) + is ProtobufMapFieldDefinition -> createHighlight(o, ProtobufHighlighter.FIELD) + is ProtobufOneofDefinition -> createHighlight(o, ProtobufHighlighter.FIELD) + is ProtobufGroupDefinition -> createHighlight(o, ProtobufHighlighter.MESSAGE) + is ProtobufEnumDefinition -> createHighlight(o, ProtobufHighlighter.ENUM) + is ProtobufServiceDefinition -> createHighlight(o, ProtobufHighlighter.SERVICE) + is ProtobufRpcDefinition -> createHighlight(o, ProtobufHighlighter.METHOD) + } + } + + override fun visitComment(comment: PsiComment) { + if (comment is DocumentElement) { + if (comment.owner != null) { + createHighlight(comment, ProtobufHighlighter.DOC_COMMENT) + } + } + } + + override fun visitEnumValue(o: ProtobufEnumValue) { + createHighlight(o, ProtobufHighlighter.ENUM_VALUE) + } + + override fun visitNumberValue(o: ProtobufNumberValue) { + if (o.floatLiteral == null && o.integerLiteral == null) { + createHighlight(o, ProtobufHighlighter.KEYWORD) + } + } + + override fun visitExtensionFieldName(o: ProtobufExtensionFieldName) { + if (o.extensionFieldName == null) { + createHighlight(o.symbolName, ProtobufHighlighter.FIELD) + } + } + + private fun createHighlight( + element: PsiElement, + textAttributesKey: TextAttributesKey, + ) { + holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) + .range(element.textRange) + .textAttributes(textAttributesKey) + .create() + } + }, + ) + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtoTextLexer.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtoTextLexer.kt new file mode 100644 index 00000000..ce1cc762 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtoTextLexer.kt @@ -0,0 +1,6 @@ +package io.kanro.idea.plugin.protobuf.lang.lexer + +import com.intellij.lexer.FlexAdapter +import io.kanro.idea.plugin.protobuf.lang.lexer.text._ProtoTextLexer + +class ProtoTextLexer : FlexAdapter(_ProtoTextLexer(null)) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtobufLexer.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtobufLexer.kt index 38880d1a..08de3131 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtobufLexer.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtobufLexer.kt @@ -1,5 +1,6 @@ package io.kanro.idea.plugin.protobuf.lang.lexer import com.intellij.lexer.FlexAdapter +import io.kanro.idea.plugin.protobuf.lang.lexer.proto._ProtobufLexer class ProtobufLexer : FlexAdapter(_ProtobufLexer(null)) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/BaseElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/BaseElement.kt new file mode 100644 index 00000000..bac01d9f --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/BaseElement.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi + +import com.intellij.psi.PsiElement + +interface BaseElement : PsiElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/Extension.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/Extension.kt index e46286f3..70b5162c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/Extension.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/Extension.kt @@ -1,27 +1,14 @@ package io.kanro.idea.plugin.protobuf.lang.psi -import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import com.intellij.psi.util.CachedValueProvider -import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiElementFilter import com.intellij.psi.util.PsiModificationTracker -import com.intellij.psi.util.QualifiedName -import com.intellij.psi.util.elementType -import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScopeItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScopeItemContainer -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufVirtualScope -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufKeywordToken -import io.kanro.idea.plugin.protobuf.lang.support.WellknownTypes -import io.kanro.idea.plugin.protobuf.string.parseDoubleOrNull -import io.kanro.idea.plugin.protobuf.string.parseLongOrNull -import io.kanro.idea.plugin.protobuf.string.toCamelCase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItemContainer +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufVirtualScope import java.util.Stack fun PsiElement.firstLeaf(): PsiElement { @@ -156,125 +143,6 @@ inline fun PsiElement.forEachPrev(block: (PsiElement) -> Unit) { } } -fun ProtobufImportStatement.public(): Boolean { - return importLabel?.textMatches("public") == true -} - -fun ProtobufImportStatement.weak(): Boolean { - return importLabel?.textMatches("weak") == true -} - -fun ProtobufImportStatement.resolve(): ProtobufFile? { - return reference?.resolve() as? ProtobufFile -} - -fun ProtobufOptionName.field(): ProtobufFieldLike? { - this.fieldNameList.lastOrNull()?.let { - return it.reference?.resolve() as? ProtobufFieldLike - } - this.extensionOptionName?.let { - return it.typeName?.reference?.resolve() as? ProtobufFieldLike - } - this.builtInOptionName?.let { - return it.reference?.resolve() as? ProtobufFieldLike - } - return null -} - -fun ProtobufFieldName.message(): ProtobufScope? { - val parent = - when (val parent = this.parent) { - is ProtobufArrayValue -> { - parent.parent.parent - } - - else -> parent - } - - val field = - when (parent) { - is ProtobufOptionName -> { - val prevField = this.prev() - if (prevField == null) { - parent.extensionOptionName?.typeName?.reference?.resolve() - } else { - prevField.reference?.resolve() - } - } - - is ProtobufFieldAssign -> { - val messageValue = parent.parent as? ProtobufMessageValue ?: return null - val assign = - when (val assign = messageValue.parent.parent) { - is ProtobufArrayValue -> { - assign.parent.parent - } - - else -> assign - } - - when (assign) { - is ProtobufOptionAssign -> { - assign.optionName.field() - } - - is ProtobufFieldAssign -> { - assign.fieldName.reference?.resolve() as? ProtobufDefinition - } - - else -> null - } - } - - else -> null - } ?: return null - - return when (field) { - is ProtobufGroupDefinition -> field - is ProtobufFieldDefinition -> field.typeName.reference?.resolve() as? ProtobufMessageDefinition - else -> null - } -} - -fun ProtobufBuiltInOptionName.isFieldDefaultOption(): Boolean { - return this.textMatches("default") && parentOfType() is ProtobufFieldDefinition -} - -fun ProtobufBuiltInOptionName.isFieldJsonNameOption(): Boolean { - return this.textMatches("json_name") && parentOfType() is ProtobufFieldDefinition -} - -fun ProtobufEnumValue.enum(): ProtobufEnumDefinition? { - val field = - when (val parent = this.parent.parent) { - is ProtobufOptionAssign -> { - parent.optionName.field() as? ProtobufFieldDefinition - } - - is ProtobufFieldAssign -> { - parent.fieldName.reference?.resolve() as? ProtobufFieldDefinition - } - - else -> null - } ?: return null - return field.typeName.reference?.resolve() as? ProtobufEnumDefinition -} - -fun ProtobufReservedRange.range(): LongRange? { - val numbers = integerValueList.map { it.text.toLong() } - return when (numbers.size) { - 1 -> - if (lastChild.textMatches("max")) { - LongRange(numbers[0], Long.MAX_VALUE) - } else { - LongRange(numbers[0], numbers[0]) - } - - 2 -> LongRange(numbers[0], numbers[1]) - else -> null - } -} - operator fun ProtobufScope.iterator(): Iterator { return realItems().iterator() } @@ -342,215 +210,5 @@ fun ProtobufScope.realItems(): Array { return result.toTypedArray() } -fun ProtobufStringValue.value(): String? { - return stringLiteral.text?.trim('"') -} - -fun ProtobufStringValue.stringRange(): TextRange { - return stringRange(textRange) -} - -fun ProtobufStringValue.stringRangeInParent(): TextRange { - return stringRange(textRangeInParent) -} - -private fun ProtobufStringValue.stringRange(relativelyRange: TextRange): TextRange { - var textRange = relativelyRange - val text = text - - if (textRange.length == 0) return textRange - if (text.startsWith('"')) { - textRange = TextRange.create(textRange.startOffset + 1, textRange.endOffset) - } - if (textRange.length == 0) return textRange - if (text.endsWith('"')) { - textRange = TextRange.create(textRange.startOffset, textRange.endOffset - 1) - } - return textRange -} - -fun ProtobufNumberValue.float(): Double? { - return floatLiteral?.text?.parseDoubleOrNull() - ?: integerLiteral?.text?.parseLongOrNull()?.toDouble() -} - -fun ProtobufNumberValue.int(): Long? { - return integerLiteral?.text?.parseLongOrNull() -} - -fun ProtobufNumberValue.uint(): Long? { - return int() -} - -fun ProtobufBooleanValue.value(): Boolean { - return textMatches("true") -} - -fun ProtobufConstant.stringValue(): String? { - if (stringValueList.isEmpty()) return null - return stringValueList.joinToString("") { it.value() ?: "" } -} - -fun ProtobufRpcIO.stream(): Boolean { - this.walkChildren(false) { - if (it.elementType is ProtobufKeywordToken && it.textMatches("stream")) { - return true - } - } - return false -} - -fun ProtobufFieldLike.jsonName(): String? { - return CachedValuesManager.getCachedValue(this) { - val option = (this as? ProtobufOptionOwner)?.options("json_name")?.lastOrNull() - val result = - option?.value()?.stringValue() - ?: name()?.toCamelCase() - CachedValueProvider.Result.create( - result, - PsiModificationTracker.MODIFICATION_COUNT, - ) - } -} - -/** - * Resolve type of qualified field for a message definition. - * It could be returning a [ProtobufMessageDefinition] for message field. - * returning a [ProtobufEnumDefinition] for enum field. - * returning a [ProtobufMapFieldDefinition] for map field. - * returning a [ProtobufGroupDefinition] for group field. - */ -fun ProtobufMessageDefinition.resolveFieldType( - qualifiedName: QualifiedName, - jsonSpec: Boolean = false, -): ProtobufElement? { - if (qualifiedName.components.isEmpty()) return this - - val q = - Stack().apply { - addAll(qualifiedName.components.asReversed()) - } - - var scope: ProtobufScope = this - - while (q.isNotEmpty()) { - val field = q.pop() - - if (jsonSpec) { - if (scope is ProtobufMessageDefinition) { - val message = scope.qualifiedName().toString() - if (message == WellknownTypes.ANY && field == "@type") { - return scope.firstItemOrNull { - it.name() == "type_url" - } - } else if (message in WellknownTypes.types) { - return null - } - } - } - - val fieldDefinition = - scope.firstItemOrNull { - it.name() == field || it.jsonName() == field - } ?: return null - - when (fieldDefinition) { - is ProtobufFieldDefinition -> { - val type = fieldDefinition.typeName.reference?.resolve() as? ProtobufElement ?: return null - if (q.isEmpty()) return type - scope = type as? ProtobufMessageDefinition ?: return null - } - - is ProtobufMapFieldDefinition -> { - if (q.isEmpty()) return fieldDefinition - q.pop() - val type = - fieldDefinition.typeNameList.lastOrNull()?.reference?.resolve() as? ProtobufElement - ?: return null - if (q.isEmpty()) return type - scope = type as? ProtobufMessageDefinition ?: return null - } - - is ProtobufGroupDefinition -> { - scope = fieldDefinition - if (q.isEmpty()) return scope - } - } - } - return null -} - -/** - * Resolve qualified field for a message definition. - * It could be returning any [ProtobufFieldLike]. - */ -fun ProtobufMessageDefinition.resolveField( - qualifiedName: QualifiedName, - jsonSpec: Boolean = false, -): ProtobufFieldLike? { - val field = qualifiedName.lastComponent ?: return null - val parentField = qualifiedName.removeTail(1) - val parentType = resolveFieldType(parentField, jsonSpec) ?: return null - - if (jsonSpec) { - if (parentType is ProtobufMessageDefinition) { - val message = parentType.qualifiedName().toString() - if (message == WellknownTypes.ANY && field == "@type") { - return parentType.firstItemOrNull { - it.name() == "type_url" - } - } else if (message in WellknownTypes.types) { - return null - } - } - } - - return when (parentType) { - is ProtobufMessageDefinition -> { - parentType.firstItemOrNull { it.name() == field || it.jsonName() == field } - } - - is ProtobufGroupDefinition -> { - parentType.firstItemOrNull { it.name() == field || it.jsonName() == field } - } - - else -> null - } -} - -fun ProtobufFieldDefinition.repeated(): Boolean { - return this.fieldLabel?.textMatches("repeated") == true -} - -fun ProtobufGroupDefinition.repeated(): Boolean { - return this.fieldLabel?.textMatches("repeated") == true -} - -fun ProtobufFieldDefinition.required(): Boolean { - return this.fieldLabel?.textMatches("required") == true -} - -fun ProtobufGroupDefinition.required(): Boolean { - return this.fieldLabel?.textMatches("required") == true -} - -fun ProtobufFieldDefinition.optional(): Boolean { - return this.fieldLabel?.textMatches("optional") == true -} - -fun ProtobufGroupDefinition.optional(): Boolean { - return this.fieldLabel?.textMatches("optional") == true -} - -fun ProtobufMapFieldDefinition.key(): ProtobufTypeName? { - if (typeNameList.size < 2) return null - return typeNameList[0] -} - -fun ProtobufMapFieldDefinition.value(): ProtobufTypeName? { - if (typeNameList.size < 2) return null - return typeNameList[1] -} - fun nullCachedValue(): CachedValueProvider.Result = CachedValueProvider.Result.create(null, PsiModificationTracker.MODIFICATION_COUNT) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufElementType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufElementType.kt deleted file mode 100644 index 47936fab..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufElementType.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi - -import com.intellij.psi.tree.IElementType -import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage - -open class ProtobufElementType(name: String) : IElementType(name, ProtobufLanguage) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBody.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyElement.kt similarity index 68% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBody.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyElement.kt index 9def505b..ca708921 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBody.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyElement.kt @@ -1,11 +1,10 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify +package io.kanro.idea.plugin.protobuf.lang.psi.feature import com.intellij.lang.folding.FoldingDescriptor import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufFolding -interface ProtobufBody : ProtobufFolding { - fun owner(): ProtobufBodyOwner { +interface BodyElement : FoldingElement { + fun owner(): BodyOwner { return parentOfType() ?: throw IllegalStateException() } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyOwner.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyOwner.kt new file mode 100644 index 00000000..09163cac --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyOwner.kt @@ -0,0 +1,10 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement +import io.kanro.idea.plugin.protobuf.lang.psi.findChild + +interface BodyOwner : BaseElement { + fun body(): BodyElement? { + return findChild() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufDocument.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/DocumentElement.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufDocument.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/DocumentElement.kt index f823cdc5..9ab01e66 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufDocument.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/DocumentElement.kt @@ -1,11 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature +package io.kanro.idea.plugin.protobuf.lang.psi.feature import com.intellij.psi.PsiDocCommentBase import com.intellij.psi.PsiElement import com.intellij.psi.PsiWhiteSpace -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition -interface ProtobufDocument : PsiDocCommentBase { +interface DocumentElement : PsiDocCommentBase { override fun getOwner(): PsiElement? { var next = nextSibling var newLine = 0 diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufDocumented.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/DocumentOwner.kt similarity index 59% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufDocumented.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/DocumentOwner.kt index 38d97787..9e4f67f6 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufDocumented.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/DocumentOwner.kt @@ -1,15 +1,15 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature +package io.kanro.idea.plugin.protobuf.lang.psi.feature -import com.intellij.psi.PsiElement +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement import io.kanro.idea.plugin.protobuf.lang.psi.prev -interface ProtobufDocumented : PsiElement { +interface DocumentOwner : BaseElement { fun navigateInfo(): String? { return null } fun document(): String? { - val document = this.prev() + val document = this.prev() if (document?.owner != this) return null return document.render() } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/FoldingElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/FoldingElement.kt new file mode 100644 index 00000000..e7251028 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/FoldingElement.kt @@ -0,0 +1,8 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import com.intellij.lang.folding.FoldingDescriptor +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement + +interface FoldingElement : BaseElement { + fun folding(): FoldingDescriptor? +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/LookupableElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/LookupableElement.kt new file mode 100644 index 00000000..3b5b342d --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/LookupableElement.kt @@ -0,0 +1,9 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.navigation.NavigationItem +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement + +interface LookupableElement : BaseElement, NavigationItem { + fun lookup(name: String? = null): LookupElementBuilder? +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/NamedElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/NamedElement.kt new file mode 100644 index 00000000..9e7a2b2e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/NamedElement.kt @@ -0,0 +1,7 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement + +interface NamedElement : BaseElement { + fun name(): String? +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufNumbered.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ProtobufNumbered.kt similarity index 61% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufNumbered.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ProtobufNumbered.kt index 7604d2af..a46f9453 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufNumbered.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ProtobufNumbered.kt @@ -1,7 +1,8 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.feature -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIntegerValue import io.kanro.idea.plugin.protobuf.lang.psi.findChild +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIntegerValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition import io.kanro.idea.plugin.protobuf.string.parseLongOrNull interface ProtobufNumbered : ProtobufDefinition { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/QualifiedElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/QualifiedElement.kt new file mode 100644 index 00000000..381c8878 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/QualifiedElement.kt @@ -0,0 +1,13 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import com.intellij.psi.PsiElement + +interface QualifiedElement> : ReferenceElement { + fun root(): T + + fun leaf(): T + + override fun resolve(): PsiElement? { + return leaf().reference?.resolve() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ReferenceElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ReferenceElement.kt new file mode 100644 index 00000000..57f666ac --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ReferenceElement.kt @@ -0,0 +1,14 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import com.intellij.psi.PsiElement +import com.intellij.psi.util.QualifiedName + +interface ReferenceElement : PsiElement { + fun symbol(): QualifiedName? + + fun rename(qualifiedName: QualifiedName) + + fun resolve(): PsiElement? { + return reference?.resolve() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueAssign.kt new file mode 100644 index 00000000..ebf0dfad --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueAssign.kt @@ -0,0 +1,9 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.value.WrappedValue + +interface ValueAssign : BaseElement, WrappedValue { + fun field(): ProtobufFieldLike? +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueElement.kt new file mode 100644 index 00000000..54e5286b --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueElement.kt @@ -0,0 +1,19 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement + +interface ValueElement : BaseElement { + fun value(): T + + fun valueType(): ValueType +} + +enum class ValueType { + UNKNOWN, + STRING, + NUMBER, + BOOLEAN, + ENUM, + MESSAGE, + LIST, +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufBuiltInOptionMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufBuiltInOptionMixin.kt deleted file mode 100644 index 0179074b..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufBuiltInOptionMixin.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin - -import com.intellij.lang.ASTNode -import com.intellij.psi.PsiReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufBuiltInOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufBuiltInOptionReference - -abstract class ProtobufBuiltInOptionMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufBuiltInOptionName { - override fun getReference(): PsiReference { - return ProtobufBuiltInOptionReference(this) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufEnumValueMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufEnumValueMixin.kt deleted file mode 100644 index e8c6de90..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufEnumValueMixin.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin - -import com.intellij.lang.ASTNode -import com.intellij.psi.PsiReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufEnumValueReference - -abstract class ProtobufEnumValueMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufEnumValue { - override fun getReference(): PsiReference { - return ProtobufEnumValueReference(this) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufFieldNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufFieldNameMixin.kt deleted file mode 100644 index 60bd22fa..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufFieldNameMixin.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin - -import com.intellij.lang.ASTNode -import com.intellij.psi.PsiReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufFieldReference - -abstract class ProtobufFieldNameMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufFieldName { - override fun getReference(): PsiReference { - return ProtobufFieldReference(this) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufStringValueMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufStringValueMixin.kt deleted file mode 100644 index 433a0802..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufStringValueMixin.kt +++ /dev/null @@ -1,17 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin - -import com.intellij.lang.ASTNode -import com.intellij.psi.PsiReference -import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase - -abstract class ProtobufStringValueMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufStringValue { - override fun getReference(): PsiReference? { - return references.firstOrNull() - } - - override fun getReferences(): Array { - return ReferenceProvidersRegistry.getReferencesFromProviders(this) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufTypeNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufTypeNameMixin.kt deleted file mode 100644 index a720fc56..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufTypeNameMixin.kt +++ /dev/null @@ -1,74 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin - -import com.intellij.lang.ASTNode -import com.intellij.openapi.util.TextRange -import com.intellij.psi.PsiReference -import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry -import com.intellij.psi.impl.source.tree.LeafElement -import com.intellij.psi.util.PsiElementFilter -import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtensionOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcIO -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufSymbolName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHover -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters -import io.kanro.idea.plugin.protobuf.lang.util.ProtobufPsiFactory - -abstract class ProtobufTypeNameMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufTypeName { - private val hover = - object : ProtobufSymbolReferenceHover { - override fun symbolParts(): List { - return symbolNameList.map { - ProtobufSymbolReferenceHover.SymbolPart(it.startOffsetInParent, it.text) - } - } - - override fun textRange(): TextRange { - return textRange - } - - override fun renamePart( - index: Int, - newName: String, - ) { - (symbolNameList[index].identifierLiteral?.node as? LeafElement)?.replaceWithText(newName) - } - - override fun rename(newName: String) { - replace(ProtobufPsiFactory.createTypeName(project, newName)) - } - - override fun absolutely(): Boolean { - return firstChild !is ProtobufSymbolName - } - - override fun variantFilter(): PsiElementFilter { - return when (parent) { - is ProtobufExtensionOptionName -> ProtobufSymbolFilters.extensionOptionNameVariants(parentOfType()) - is ProtobufFieldDefinition, - is ProtobufMapFieldDefinition, - -> ProtobufSymbolFilters.fieldTypeNameVariants - is ProtobufRpcIO -> ProtobufSymbolFilters.rpcTypeNameVariants - is ProtobufExtendDefinition -> ProtobufSymbolFilters.extendTypeNameVariants - else -> ProtobufSymbolFilters.alwaysFalse - } - } - } - - override fun referencesHover(): ProtobufSymbolReferenceHover { - return hover - } - - override fun getReference(): PsiReference? { - return references.firstOrNull() - } - - override fun getReferences(): Array { - return ReferenceProvidersRegistry.getReferencesFromProviders(this) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldAssign.kt deleted file mode 100644 index 8b9f1802..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldAssign.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element - -import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldName -import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufValueAssign - -interface ProtobufFieldAssign : ProtobufValueAssign { - override fun field(): ProtobufFieldLike? { - val targetField = findChild()?.text ?: return null - val parentAssign = parentOfType() ?: return null - val message = - (parentAssign.field() as? ProtobufFieldDefinition)?.typeName?.reference?.resolve() as? ProtobufMessageDefinition - ?: return null - - message.items { - if (it.name() == targetField) return it - } - return null - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldDefinition.kt deleted file mode 100644 index 6711af7e..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldDefinition.kt +++ /dev/null @@ -1,51 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element - -import com.intellij.psi.util.CachedValueProvider -import com.intellij.psi.util.CachedValuesManager -import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.aip.AipOptions -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName -import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.jsonName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufMultiNameDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue -import javax.swing.Icon - -interface ProtobufFieldDefinition : ProtobufFieldLike, ProtobufMultiNameDefinition { - override fun type(): String { - return "field" - } - - override fun getIcon(unused: Boolean): Icon? { - return ProtobufIcons.FIELD - } - - fun resourceType(): String? { - if (this !is ProtobufOptionOwner) return null - return CachedValuesManager.getCachedValue(this) { - options(AipOptions.resourceReferenceOption).forEach { - it.value(AipOptions.resourceTypeField)?.stringValue()?.let { - return@getCachedValue CachedValueProvider.Result.create( - it, - PsiModificationTracker.MODIFICATION_COUNT, - ) - } - } - return@getCachedValue CachedValueProvider.Result.create(null, PsiModificationTracker.MODIFICATION_COUNT) - } - } - - override fun fieldType(): String? { - resourceType()?.let { - return it - } - return findChild()?.symbolNameList?.lastOrNull()?.text - } - - override fun names(): Set { - return setOfNotNull(name(), jsonName()) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMapFieldDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMapFieldDefinition.kt deleted file mode 100644 index 860f2a93..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMapFieldDefinition.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element - -import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName -import io.kanro.idea.plugin.protobuf.lang.psi.findChildren -import io.kanro.idea.plugin.protobuf.lang.psi.jsonName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufMultiNameDefinition -import javax.swing.Icon - -interface ProtobufMapFieldDefinition : ProtobufFieldLike, ProtobufMultiNameDefinition { - override fun type(): String { - return "field" - } - - override fun getIcon(unused: Boolean): Icon? { - return ProtobufIcons.FIELD - } - - override fun fieldType(): String? { - val typeNames = findChildren() - if (typeNames.size != 2) return "map" - val key = typeNames[0].symbolNameList.lastOrNull()?.text ?: return "map" - val value = typeNames[1].symbolNameList.lastOrNull()?.text ?: return "map" - - return "map<$key, $value>" - } - - override fun names(): Set { - return setOfNotNull(name(), jsonName()) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOptionAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOptionAssign.kt deleted file mode 100644 index 6916f595..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOptionAssign.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element - -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.field -import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufValueAssign - -interface ProtobufOptionAssign : ProtobufValueAssign { - override fun field(): ProtobufFieldLike? { - return findChild()?.field() - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFileReferenceContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFileReferenceContributor.kt deleted file mode 100644 index 86a4a1ab..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFileReferenceContributor.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature - -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufFileReferenceContributor : ProtobufElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFolding.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFolding.kt deleted file mode 100644 index 4c4e6357..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFolding.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature - -import com.intellij.lang.folding.FoldingDescriptor -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufFolding : ProtobufElement { - fun folding(): FoldingDescriptor? -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufLookupItem.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufLookupItem.kt deleted file mode 100644 index 41ec4b97..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufLookupItem.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature - -import com.intellij.codeInsight.lookup.LookupElementBuilder -import com.intellij.navigation.NavigationItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufLookupItem : ProtobufElement, NavigationItem { - fun lookup(name: String? = null): LookupElementBuilder? -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufNamedElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufNamedElement.kt deleted file mode 100644 index f8de01cf..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufNamedElement.kt +++ /dev/null @@ -1,7 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature - -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufNamedElement : ProtobufElement { - fun name(): String? -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufSymbolReferenceHost.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufSymbolReferenceHost.kt deleted file mode 100644 index 71bbf74f..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufSymbolReferenceHost.kt +++ /dev/null @@ -1,54 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature - -import com.intellij.openapi.extensions.ExtensionPointName -import com.intellij.openapi.util.TextRange -import com.intellij.psi.util.PsiElementFilter -import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufSymbolReferenceHost : ProtobufElement { - fun referencesHover(): ProtobufSymbolReferenceHover? { - return ProtobufSymbolReferenceProvider.hovers(this) - } -} - -interface ProtobufSymbolReferenceProvider { - fun hovers(element: ProtobufSymbolReferenceHost): ProtobufSymbolReferenceHover? - - companion object : ProtobufSymbolReferenceProvider { - var extensionPoint: ExtensionPointName = - ExtensionPointName.create("io.kanro.idea.plugin.protobuf.symbolReferenceProvider") - - override fun hovers(element: ProtobufSymbolReferenceHost): ProtobufSymbolReferenceHover? { - extensionPoint.extensionList.forEach { - it.hovers(element)?.let { - return it - } - } - return null - } - } -} - -interface ProtobufSymbolReferenceHover { - fun symbol(): QualifiedName { - return QualifiedName.fromComponents(symbolParts().map { it.value }) - } - - fun textRange(): TextRange - - fun symbolParts(): List - - fun renamePart( - index: Int, - newName: String, - ) - - fun rename(newName: String) - - fun absolutely(): Boolean - - fun variantFilter(): PsiElementFilter - - data class SymbolPart(val startOffset: Int, val value: String) -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBodyOwner.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBodyOwner.kt deleted file mode 100644 index a557bc28..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBodyOwner.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify - -import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufBodyOwner : ProtobufElement { - fun body(): ProtobufBody? { - return findChild() - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionHover.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionHover.kt deleted file mode 100644 index d1ccdfab..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionHover.kt +++ /dev/null @@ -1,50 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify - -import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufConstant -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOptionAssign -import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufOptionHover : ProtobufElement { - fun option(): ProtobufOptionAssign? { - return findChild() - } - - fun isOption(extensionOptionName: QualifiedName): Boolean { - val option = option() ?: return false - val field = - option.optionName.extensionOptionName?.typeName?.reference?.resolve() as? ProtobufFieldDefinition - ?: return false - return field.qualifiedName() == extensionOptionName - } - - fun isOption(builtinOptionName: String): Boolean { - val option = option() ?: return false - return option.optionName.builtInOptionName?.textMatches(builtinOptionName) == true - } - - fun value(): ProtobufConstant? { - return option()?.findChild() - } - - fun value(field: QualifiedName): ProtobufConstant? { - if (field.componentCount == 0) return value() - val optionName = option()?.optionName ?: return null - var findName = field - optionName.fieldNameList.forEach { - if (!it.textMatches(findName.firstComponent ?: return null)) return null - findName = findName.removeHead(1) - } - var value = value() ?: return null - while (findName.componentCount != 0) { - val messageValue = value.messageValue ?: return null - value = messageValue.fieldAssignList.firstOrNull { - it.fieldName.textMatches(findName.firstComponent ?: return null) - }?.constant ?: return null - findName = findName.removeHead(1) - } - return value - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufFieldLike.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufFieldLike.kt deleted file mode 100644 index 563718c5..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufFieldLike.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure - -interface ProtobufFieldLike : ProtobufDefinition, ProtobufNumbered { - fun fieldName(): String? { - return name() - } - - fun fieldType(): String? - - override fun tailText(): String? { - return ": ${fieldType()} = ${number()}" - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufValueAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufValueAssign.kt deleted file mode 100644 index 72427a65..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufValueAssign.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure - -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufConstant -import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufValueAssign : ProtobufElement { - fun value(): ProtobufConstant? { - return findChild() - } - - fun field(): ProtobufFieldLike? -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufVirtualScope.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufVirtualScope.kt deleted file mode 100644 index bb1800ff..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufVirtualScope.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure - -interface ProtobufVirtualScope : ProtobufScopeItemContainer diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufBlock.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufBlock.kt deleted file mode 100644 index 3d0baa78..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufBlock.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.type - -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufBlock : ProtobufElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufFragment.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufFragment.kt deleted file mode 100644 index 064f3f22..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufFragment.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.type - -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufFragment : ProtobufElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufStatement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufStatement.kt deleted file mode 100644 index a5ecb4e4..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufStatement.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.type - -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufStatement : ProtobufElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufASTFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufASTFactory.kt similarity index 72% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufASTFactory.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufASTFactory.kt index 15695799..2aeaeb9c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufASTFactory.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufASTFactory.kt @@ -1,11 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi +package io.kanro.idea.plugin.protobuf.lang.psi.proto import com.intellij.lang.DefaultASTFactoryImpl import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.psi.impl.source.tree.PsiCommentImpl import com.intellij.psi.tree.IElementType -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufLineCommentImpl -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufLineCommentImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufASTFactory : DefaultASTFactoryImpl() { override fun createComment( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/ProtobufElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElement.kt similarity index 64% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/ProtobufElement.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElement.kt index 7047b9da..b7594dd2 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/ProtobufElement.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElement.kt @@ -1,10 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive +package io.kanro.idea.plugin.protobuf.lang.psi.proto -import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver -interface ProtobufElement : PsiElement { +interface ProtobufElement : BaseElement { fun file(): ProtobufFile { return containingFile.originalFile as ProtobufFile } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/ProtobufElementBase.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementBase.kt similarity index 83% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/ProtobufElementBase.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementBase.kt index 2b6a4c67..d6777ac8 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/ProtobufElementBase.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementBase.kt @@ -1,11 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive +package io.kanro.idea.plugin.protobuf.lang.psi.proto import com.intellij.extapi.psi.ASTWrapperPsiElement import com.intellij.lang.ASTNode import com.intellij.navigation.ItemPresentation import com.intellij.psi.PsiElement import com.intellij.psi.PsiNameIdentifierOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement abstract class ProtobufElementBase(node: ASTNode) : ASTWrapperPsiElement(node) { override fun getPresentation(): ItemPresentation? { @@ -24,7 +24,7 @@ abstract class ProtobufElementBase(node: ASTNode) : ASTWrapperPsiElement(node) { } override fun getName(): String? { - if (this is ProtobufNamedElement) return name() + if (this is NamedElement) return name() return null } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementType.kt new file mode 100644 index 00000000..3535eb07 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementType.kt @@ -0,0 +1,14 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.lang.ASTNode +import com.intellij.psi.tree.IElementType +import com.intellij.psi.tree.ILazyParseableElementType +import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage + +open class ProtobufElementType(name: String) : IElementType(name, ProtobufLanguage) + +open class ProtoTextInjectionElementType(name: String) : ILazyParseableElementType(name, ProtobufLanguage) { + override fun parseContents(chameleon: ASTNode): ASTNode { + return super.parseContents(chameleon) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufEnumValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufEnumValue.kt new file mode 100644 index 00000000..6d6fea80 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufEnumValue.kt @@ -0,0 +1,26 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.psi.util.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign + +fun ProtobufEnumValue.enum(): ProtobufEnumDefinition? { + val assign = parentOfType() ?: return null + val field = assign.field() ?: return null + + return when (field) { + is ProtobufFieldDefinition -> { + field.typeName.resolve() as? ProtobufEnumDefinition + } + + is ProtobufMapFieldDefinition -> { + val targetField = assign.field()?.text ?: return null + when (targetField) { + "key" -> field.key()?.resolve() as? ProtobufEnumDefinition + "value" -> field.value()?.resolve() as? ProtobufEnumDefinition + else -> null + } + } + + else -> null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionFieldName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionFieldName.kt new file mode 100644 index 00000000..0d089949 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionFieldName.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +fun ProtobufExtensionFieldName.absolutely(): Boolean { + return this.firstChild !is ProtobufSymbolName +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionRange.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionRange.kt new file mode 100644 index 00000000..ce99e340 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionRange.kt @@ -0,0 +1,16 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +fun ProtobufExtensionRange.range(): LongRange? { + val numbers = integerValueList.map { it.text.toLong() } + return when (numbers.size) { + 1 -> + if (lastChild.textMatches("max")) { + LongRange(numbers[0], Long.MAX_VALUE) + } else { + LongRange(numbers[0], numbers[0]) + } + + 2 -> LongRange(numbers[0], numbers[1]) + else -> null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFieldName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFieldName.kt new file mode 100644 index 00000000..ac8831d5 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFieldName.kt @@ -0,0 +1,43 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.psi.util.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue + +fun ProtobufFieldName.resolve(): ProtobufElement? { + symbolName?.let { + return reference?.resolve() as? ProtobufElement + } + + extensionName?.let { + return it.extensionFieldName.leaf().reference?.resolve() as? ProtobufElement + } + + anyName?.let { + return it.typeName.leaf().reference?.resolve() as? ProtobufElement + } + + return null +} + +fun ProtobufFieldName.ownerMessage(): ProtobufScope? { + val field = parent as? ProtobufField ?: return null + val message = field.parent as? MessageValue ?: return null + + val parentField = + when (val parentAssign = message.parentOfType()) { + is ProtobufOptionAssign -> parentAssign.field() + + is ProtobufField -> { + parentAssign.fieldName.resolve() + } + + else -> return null + } ?: return null + + if (parentField is ProtobufScope) return parentField + if (parentField is ProtobufFieldDefinition) return parentField.typeName.resolve() as? ProtobufScope + + return null +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufFile.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFile.kt similarity index 64% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufFile.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFile.kt index 52cb3eac..0fc478dc 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufFile.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFile.kt @@ -1,23 +1,22 @@ -package io.kanro.idea.plugin.protobuf.lang.psi +package io.kanro.idea.plugin.protobuf.lang.psi.proto import com.intellij.navigation.ItemPresentation import com.intellij.psi.PsiFile import com.intellij.psi.tree.IFileElementType import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufStubExternalProvider -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufStubExternalProvider +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope interface ProtobufFile : PsiFile, - ProtobufNamedElement, + NamedElement, ProtobufScope, - ProtobufLookupItem, + LookupableElement, ProtobufOptionOwner, ItemPresentation { fun messages(): Iterable @@ -34,6 +33,8 @@ interface ProtobufFile : fun syntax(): String? + fun edition(): String? + fun addImport(protobufElement: ProtobufElement): Boolean fun addImport(path: String): Boolean diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufImportStatement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufImportStatement.kt new file mode 100644 index 00000000..0f15cb72 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufImportStatement.kt @@ -0,0 +1,13 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +fun ProtobufImportStatement.public(): Boolean { + return importLabel?.textMatches("public") == true +} + +fun ProtobufImportStatement.weak(): Boolean { + return importLabel?.textMatches("weak") == true +} + +fun ProtobufImportStatement.resolve(): ProtobufFile? { + return reference?.resolve() as? ProtobufFile +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMapFieldDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMapFieldDefinition.kt new file mode 100644 index 00000000..8899fbba --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMapFieldDefinition.kt @@ -0,0 +1,11 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +fun ProtobufMapFieldDefinition.key(): ProtobufTypeName? { + if (typeNameList.size < 2) return null + return typeNameList[0] +} + +fun ProtobufMapFieldDefinition.value(): ProtobufTypeName? { + if (typeNameList.size < 2) return null + return typeNameList[1] +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMessageDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMessageDefinition.kt new file mode 100644 index 00000000..25a8754f --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMessageDefinition.kt @@ -0,0 +1,137 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.firstItemOrNull +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.support.WellknownTypes +import java.util.Stack + +/** + * Resolve type of qualified field for a message definition. + * It could be returning a [ProtobufMessageDefinition] for message field. + * returning a [ProtobufEnumDefinition] for enum field. + * returning a [ProtobufMapFieldDefinition] for map field. + * returning a [ProtobufGroupDefinition] for group field. + */ +fun ProtobufMessageDefinition.resolveFieldType( + qualifiedName: QualifiedName, + jsonSpec: Boolean = false, +): ProtobufElement? { + if (qualifiedName.components.isEmpty()) return this + + val q = + Stack().apply { + addAll(qualifiedName.components.asReversed()) + } + + var scope: ProtobufScope = this + + while (q.isNotEmpty()) { + val field = q.pop() + + if (jsonSpec) { + if (scope is ProtobufMessageDefinition) { + val message = scope.qualifiedName().toString() + if (message == WellknownTypes.ANY && field == "@type") { + return scope.firstItemOrNull { + it.name() == "type_url" + } + } else if (message in WellknownTypes.types) { + return null + } + } + } + + val fieldDefinition = + scope.firstItemOrNull { + it.name() == field || it.jsonName() == field + } ?: return null + + when (fieldDefinition) { + is ProtobufFieldDefinition -> { + val type = fieldDefinition.typeName.resolve() as? ProtobufElement ?: return null + if (q.isEmpty()) return type + scope = type as? ProtobufMessageDefinition ?: return null + } + + is ProtobufMapFieldDefinition -> { + if (q.isEmpty()) return fieldDefinition + q.pop() + val type = + fieldDefinition.typeNameList.lastOrNull()?.reference?.resolve() as? ProtobufElement + ?: return null + if (q.isEmpty()) return type + scope = type as? ProtobufMessageDefinition ?: return null + } + + is ProtobufGroupDefinition -> { + scope = fieldDefinition + if (q.isEmpty()) return scope + } + } + } + return null +} + +/** + * Resolve qualified field for a message definition. + * It could be returning any [ProtobufFieldLike]. + */ +fun ProtobufMessageDefinition.resolveField( + qualifiedName: QualifiedName, + jsonSpec: Boolean = false, +): ProtobufFieldLike? { + val field = qualifiedName.lastComponent ?: return null + val parentField = qualifiedName.removeTail(1) + val parentType = resolveFieldType(parentField, jsonSpec) ?: return null + + if (jsonSpec) { + if (parentType is ProtobufMessageDefinition) { + val message = parentType.qualifiedName().toString() + if (message == WellknownTypes.ANY && field == "@type") { + return parentType.firstItemOrNull { + it.name() == "type_url" + } + } else if (message in WellknownTypes.types) { + return null + } + } + } + + return when (parentType) { + is ProtobufMessageDefinition -> { + parentType.firstItemOrNull { it.name() == field || it.jsonName() == field } + } + + is ProtobufGroupDefinition -> { + parentType.firstItemOrNull { it.name() == field || it.jsonName() == field } + } + + else -> null + } +} + +fun ProtobufFieldDefinition.repeated(): Boolean { + return this.fieldLabel?.textMatches("repeated") == true +} + +fun ProtobufGroupDefinition.repeated(): Boolean { + return this.fieldLabel?.textMatches("repeated") == true +} + +fun ProtobufFieldDefinition.required(): Boolean { + return this.fieldLabel?.textMatches("required") == true +} + +fun ProtobufGroupDefinition.required(): Boolean { + return this.fieldLabel?.textMatches("required") == true +} + +fun ProtobufFieldDefinition.optional(): Boolean { + return this.fieldLabel?.textMatches("optional") == true +} + +fun ProtobufGroupDefinition.optional(): Boolean { + return this.fieldLabel?.textMatches("optional") == true +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufOptionName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufOptionName.kt new file mode 100644 index 00000000..68d3ed89 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufOptionName.kt @@ -0,0 +1,32 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.psi.util.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.support.Options + +fun ProtobufOptionName.field(): ProtobufFieldLike? { + return this.leaf().reference?.resolve() as? ProtobufFieldLike +} + +fun ProtobufOptionName.isFieldDefaultOption(): Boolean { + return this.textMatches("default") && parentOfType() is ProtobufFieldDefinition +} + +fun ProtobufOptionName.isFieldJsonNameOption(): Boolean { + return this.textMatches("json_name") && parentOfType() is ProtobufFieldDefinition +} + +fun ProtobufOptionName.optionType(): Options? = + when (parentOfType()) { + is ProtobufFile -> Options.FILE_OPTIONS + is ProtobufMessageDefinition, is ProtobufGroupDefinition -> Options.MESSAGE_OPTIONS + is ProtobufFieldDefinition, is ProtobufMapFieldDefinition -> Options.FIELD_OPTIONS + is ProtobufOneofDefinition -> Options.ONEOF_OPTIONS + is ProtobufEnumDefinition -> Options.ENUM_OPTIONS + is ProtobufEnumValueDefinition -> Options.ENUM_VALUE_OPTIONS + is ProtobufServiceDefinition -> Options.SERVICE_OPTIONS + is ProtobufRpcDefinition -> Options.METHOD_OPTIONS + is ProtobufExtensionRange -> Options.EXTENSION_RANGE_OPTIONS + else -> null + } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/ProtobufPsiFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufPsiFactory.kt similarity index 65% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/ProtobufPsiFactory.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufPsiFactory.kt index 9a6c8435..d759d97e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/ProtobufPsiFactory.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufPsiFactory.kt @@ -1,13 +1,10 @@ -package io.kanro.idea.plugin.protobuf.lang.util +package io.kanro.idea.plugin.protobuf.lang.psi.proto +import com.bybutter.sisyphus.string.escape import com.intellij.openapi.project.Project import com.intellij.psi.PsiFileFactory import com.intellij.psi.PsiWhiteSpace import io.kanro.idea.plugin.protobuf.lang.ProtobufFileType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName import io.kanro.idea.plugin.protobuf.lang.psi.findChild import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren @@ -38,11 +35,31 @@ object ProtobufPsiFactory { throw IllegalStateException("Wrong type name '$text'") } + fun createExtensionFieldName( + project: Project, + text: String, + ): ProtobufExtensionFieldName { + createFile(project, "option ($text) = 1;").walkChildren { + return it + } + throw IllegalStateException("Wrong extension field name '$text'") + } + + fun createFieldName( + project: Project, + text: String, + ): ProtobufFieldName { + createFile(project, "option test = { $text : 1 };").walkChildren { + return it + } + throw IllegalStateException("Wrong extension field name '$text'") + } + fun createStringValue( project: Project, text: String, ): ProtobufStringValue { - createFile(project, "import \"$text\";").walkChildren { + createFile(project, "import \"${text.escape()}\";").walkChildren { return it.stringValue!! } throw IllegalStateException("Wrong type name '$text'") diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedName.kt new file mode 100644 index 00000000..284afd48 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedName.kt @@ -0,0 +1,13 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.psi.util.elementType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.value.decodeStringFromStringLiteral + +fun ProtobufReservedName.name(): String { + return if (firstChild.elementType == ProtobufTokens.STRING_LITERAL) { + decodeStringFromStringLiteral(firstChild) + } else { + text + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedRange.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedRange.kt new file mode 100644 index 00000000..5dcd6a31 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedRange.kt @@ -0,0 +1,16 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +fun ProtobufReservedRange.range(): LongRange? { + val numbers = integerValueList.map { it.text.toLong() } + return when (numbers.size) { + 1 -> + if (lastChild.textMatches("max")) { + LongRange(numbers[0], Long.MAX_VALUE) + } else { + LongRange(numbers[0], numbers[0]) + } + + 2 -> LongRange(numbers[0], numbers[1]) + else -> null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufRpcIO.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufRpcIO.kt new file mode 100644 index 00000000..d0d226aa --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufRpcIO.kt @@ -0,0 +1,15 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.psi.PsiElement +import com.intellij.psi.util.elementType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufKeywordToken +import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren + +fun ProtobufRpcIO.stream(): Boolean { + this.walkChildren(false) { + if (it.elementType is ProtobufKeywordToken && it.textMatches("stream")) { + return true + } + } + return false +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufStringValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufStringValue.kt new file mode 100644 index 00000000..7caa6dbf --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufStringValue.kt @@ -0,0 +1,26 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.openapi.util.TextRange + +fun ProtobufStringValue.stringRange(): TextRange { + return stringRange(textRange) +} + +fun ProtobufStringValue.stringRangeInParent(): TextRange { + return stringRange(textRangeInParent) +} + +private fun ProtobufStringValue.stringRange(relativelyRange: TextRange): TextRange { + var textRange = relativelyRange + val text = text + + if (textRange.length == 0) return textRange + if (text.startsWith('"')) { + textRange = TextRange.create(textRange.startOffset + 1, textRange.endOffset) + } + if (textRange.length == 0) return textRange + if (text.endsWith('"')) { + textRange = TextRange.create(textRange.startOffset, textRange.endOffset - 1) + } + return textRange +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufTypeName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufTypeName.kt new file mode 100644 index 00000000..2bd5a73e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufTypeName.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +fun ProtobufTypeName.absolutely(): Boolean { + return firstChild !is ProtobufSymbolName +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufEnumDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufEnumDefinition.kt similarity index 61% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufEnumDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufEnumDefinition.kt index 6b195a44..2cf31580 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufEnumDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufEnumDefinition.kt @@ -1,10 +1,10 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumberScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope import javax.swing.Icon interface ProtobufEnumDefinition : ProtobufNumberScope, ProtobufDefinition, ProtobufOptionOwner { @@ -21,6 +21,6 @@ interface ProtobufEnumDefinition : ProtobufNumberScope, ProtobufDefinition, Prot } override fun allowAlias(): Boolean { - return this.options("allow_alias").firstOrNull()?.value()?.booleanValue?.text == "true" + return this.options("allow_alias").firstOrNull()?.value() == true } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufEnumValueDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufEnumValueDefinition.kt similarity index 70% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufEnumValueDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufEnumValueDefinition.kt index 6ac1535d..85a3abf6 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufEnumValueDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufEnumValueDefinition.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.psi.util.parentOfType import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition import javax.swing.Icon interface ProtobufEnumValueDefinition : ProtobufNumbered { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufExtendDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufExtendDefinition.kt similarity index 63% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufExtendDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufExtendDefinition.kt index 7e1333cd..f5213780 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufExtendDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufExtendDefinition.kt @@ -1,20 +1,20 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.psi.PsiElement import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentOwner import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocumented -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufVirtualScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufVirtualScope import javax.swing.Icon interface ProtobufExtendDefinition : ProtobufVirtualScope, ProtobufDefinition, - ProtobufDocumented { + DocumentOwner { override fun type(): String { return "extend" } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufFieldDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufFieldDefinition.kt new file mode 100644 index 00000000..b6c2592f --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufFieldDefinition.kt @@ -0,0 +1,79 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element + +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import io.kanro.idea.plugin.protobuf.aip.AipOptions +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType +import io.kanro.idea.plugin.protobuf.lang.psi.findChild +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufMultiNameDefinition +import io.kanro.idea.plugin.protobuf.lang.support.BuiltInType +import javax.swing.Icon + +interface ProtobufFieldDefinition : ProtobufFieldLike, ProtobufMultiNameDefinition { + override fun type(): String { + return "field" + } + + override fun getIcon(unused: Boolean): Icon? { + return ProtobufIcons.FIELD + } + + fun resourceType(): String? { + if (this !is ProtobufOptionOwner) return null + return CachedValuesManager.getCachedValue(this) { + options(AipOptions.resourceReferenceOption).forEach { + it.value(AipOptions.resourceTypeField)?.toString()?.let { + return@getCachedValue CachedValueProvider.Result.create( + it, + PsiModificationTracker.MODIFICATION_COUNT, + ) + } + } + return@getCachedValue CachedValueProvider.Result.create(null, PsiModificationTracker.MODIFICATION_COUNT) + } + } + + override fun fieldValueType(): ValueType { + val typeName = findChild() ?: return ValueType.UNKNOWN + + when(typeName.text) { + BuiltInType.BOOL.value() -> return ValueType.BOOLEAN + BuiltInType.STRING.value(), + BuiltInType.BYTES.value() -> return ValueType.STRING + BuiltInType.INT32.value(), + BuiltInType.INT64.value(), + BuiltInType.UINT32.value(), + BuiltInType.UINT64.value(), + BuiltInType.FIXED32.value(), + BuiltInType.FIXED64.value(), + BuiltInType.SFIXED32.value(), + BuiltInType.SFIXED64.value(), + BuiltInType.SINT32.value(), + BuiltInType.SINT64.value(), + BuiltInType.FLOAT.value(), + BuiltInType.DOUBLE.value() -> return ValueType.NUMBER + } + + return when(typeName.resolve()) { + is ProtobufMessageDefinition -> ValueType.MESSAGE + is ProtobufEnumDefinition -> ValueType.ENUM + else -> ValueType.UNKNOWN + } + } + + override fun fieldType(): String? { + resourceType()?.let { + return it + } + return findChild()?.leaf()?.text + } + + override fun names(): Set { + return setOfNotNull(name(), jsonName()) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufGroupDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufGroupDefinition.kt similarity index 65% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufGroupDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufGroupDefinition.kt index 847a1aac..b85afefd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufGroupDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufGroupDefinition.kt @@ -1,10 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufMultiNameDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumberScope +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufMultiNameDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope import io.kanro.idea.plugin.protobuf.string.toCamelCase import io.kanro.idea.plugin.protobuf.string.toSnakeCase import javax.swing.Icon @@ -26,12 +27,14 @@ interface ProtobufGroupDefinition : ProtobufFieldLike, ProtobufNumberScope, Prot return identifier()?.text } + override fun fieldValueType(): ValueType = ValueType.MESSAGE + override fun name(): String? { return identifier()?.text } override fun names(): Set { val groupName = identifier()?.text ?: return emptySet() - return setOf(groupName, groupName.toSnakeCase(), groupName.toCamelCase()) + return setOf(groupName, groupName.toSnakeCase(), groupName.toCamelCase(), groupName.lowercase()) } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMapFieldDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMapFieldDefinition.kt new file mode 100644 index 00000000..27721c1e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMapFieldDefinition.kt @@ -0,0 +1,73 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element + +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType +import io.kanro.idea.plugin.protobuf.lang.psi.findChildren +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufMultiNameDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem +import io.kanro.idea.plugin.protobuf.string.toPascalCase +import javax.swing.Icon + +interface ProtobufMapFieldDefinition : ProtobufFieldLike, ProtobufNumberScope, ProtobufMultiNameDefinition { + fun entryName(): String? { + return "${name()} Entry".toPascalCase() + } + + override fun scope(): QualifiedName? { + return owner()?.scope()?.append(entryName()) + } + + override fun items(): Array { + return emptyArray() + } + + override fun fieldValueType(): ValueType = ValueType.MESSAGE + + fun entryFields(): Array { + val typeNames = findChildren() + val key = typeNames.getOrNull(0) + val value = typeNames.getOrNull(1) + + val keyTypeName = key?.leaf()?.text ?: "?" + val valueTypeName = value?.leaf()?.text ?: "?" + + return arrayOf( + LookupElementBuilder.create("key") + .withIcon(ProtobufIcons.FIELD) + .withTailText(": $keyTypeName = 1", true) + .withTypeText("field") + .withPsiElement(key), + LookupElementBuilder.create("value") + .withIcon(ProtobufIcons.FIELD) + .withTailText(": $valueTypeName = 2", true) + .withTypeText("field") + .withPsiElement(value), + ) + } + + override fun type(): String { + return "field" + } + + override fun getIcon(unused: Boolean): Icon? { + return ProtobufIcons.FIELD + } + + override fun fieldType(): String? { + val typeNames = findChildren() + if (typeNames.size != 2) return "map" + val key = typeNames[0].leaf().text ?: return "map" + val value = typeNames[1].leaf().text ?: return "map" + + return "map<$key, $value>" + } + + override fun names(): Set { + return setOfNotNull(name(), jsonName(), entryName()) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMessageDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMessageDefinition.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMessageDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMessageDefinition.kt index b3c2198f..dea1635c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMessageDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMessageDefinition.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager @@ -6,10 +6,9 @@ import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.aip.AipOptions -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumberScope -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope import javax.swing.Icon interface ProtobufMessageDefinition : ProtobufNumberScope, ProtobufDefinition { @@ -35,7 +34,7 @@ interface ProtobufMessageDefinition : ProtobufNumberScope, ProtobufDefinition { if (this !is ProtobufOptionOwner) return null return CachedValuesManager.getCachedValue(this) { options(AipOptions.resourceOption).forEach { - it.value(AipOptions.resourceTypeField)?.stringValue()?.let { + it.value(AipOptions.resourceTypeField)?.toString()?.let { return@getCachedValue CachedValueProvider.Result.create( it, PsiModificationTracker.MODIFICATION_COUNT, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOneofDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOneofDefinition.kt similarity index 62% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOneofDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOneofDefinition.kt index 330247a9..a716eeff 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOneofDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOneofDefinition.kt @@ -1,8 +1,8 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufVirtualScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufVirtualScope import javax.swing.Icon interface ProtobufOneofDefinition : ProtobufVirtualScope, ProtobufDefinition { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOptionAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOptionAssign.kt new file mode 100644 index 00000000..d38dff36 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOptionAssign.kt @@ -0,0 +1,18 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.findChild +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufConstant +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike + +interface ProtobufOptionAssign : ValueAssign { + override fun field(): ProtobufFieldLike? { + return findChild()?.leaf()?.resolve() as? ProtobufFieldLike + } + + override fun valueElement(): ValueElement<*>? { + return findChild() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufPackageName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufPackageName.kt similarity index 82% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufPackageName.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufPackageName.kt index a7d2395c..032fa8cd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufPackageName.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufPackageName.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.navigation.ItemPresentation @@ -8,19 +8,21 @@ import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocumented -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentOwner +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement import io.kanro.idea.plugin.protobuf.lang.util.doc import javax.swing.Icon interface ProtobufPackageName : - ProtobufNamedElement, - ProtobufLookupItem, - ProtobufDocumented, + NamedElement, + LookupableElement, + DocumentOwner, NavigatablePsiElement, ItemPresentation, - PsiNameIdentifierOwner { + PsiNameIdentifierOwner, + ProtobufElement { override fun name(): String? { return nameIdentifier?.text } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufRpcDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufRpcDefinition.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufRpcDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufRpcDefinition.kt index 175cffe2..38539fc3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufRpcDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufRpcDefinition.kt @@ -1,14 +1,14 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.psi.util.parentOfType import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcIO -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition import io.kanro.idea.plugin.protobuf.lang.psi.findChild import io.kanro.idea.plugin.protobuf.lang.psi.findChildren import io.kanro.idea.plugin.protobuf.lang.psi.findLastChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stream +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcIO +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stream +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition import javax.swing.Icon interface ProtobufRpcDefinition : ProtobufDefinition { @@ -45,8 +45,8 @@ interface ProtobufRpcDefinition : ProtobufDefinition { override fun tailText(): String? { val parameters = findChildren() if (parameters.size != 2) return "()" - var input = parameters[0].typeName.symbolNameList.lastOrNull()?.text ?: return "()" - var output = parameters[1].typeName.symbolNameList.lastOrNull()?.text ?: return "()" + var input = parameters[0].typeName.leaf().text ?: return "()" + var output = parameters[1].typeName.leaf().text ?: return "()" if (parameters[0].stream()) { input = "stream $input" } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufServiceDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufServiceDefinition.kt similarity index 63% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufServiceDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufServiceDefinition.kt index d80a4a5a..d5729095 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufServiceDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufServiceDefinition.kt @@ -1,10 +1,10 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope import javax.swing.Icon interface ProtobufServiceDefinition : ProtobufScope, ProtobufDefinition { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFieldAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFieldAssign.kt new file mode 100644 index 00000000..5d5aa20c --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFieldAssign.kt @@ -0,0 +1,19 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.findChild +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike + +interface ProtobufFieldAssign : ValueAssign { + override fun field(): ProtobufFieldLike? { + val field = findChild() ?: return null + return field.resolve() as? ProtobufFieldLike + } + + override fun valueElement(): ValueElement<*>? { + return findChild>() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFileReferenceContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFileReferenceContributor.kt new file mode 100644 index 00000000..d1f5ede9 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFileReferenceContributor.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement + +interface ProtobufFileReferenceContributor : ProtobufElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufIndexProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufIndexProvider.kt similarity index 82% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufIndexProvider.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufIndexProvider.kt index 21a1e7ba..c5cef19a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufIndexProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufIndexProvider.kt @@ -1,8 +1,8 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature import com.intellij.openapi.extensions.ExtensionPointName import com.intellij.psi.stubs.IndexSink -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub interface ProtobufIndexProvider { companion object { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionHover.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionHover.kt new file mode 100644 index 00000000..9242a87e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionHover.kt @@ -0,0 +1,40 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature + +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.findChild +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionAssign +import io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue + +interface ProtobufOptionHover : ProtobufElement { + fun option(): ProtobufOptionAssign? { + return findChild() + } + + fun isOption(extensionOptionName: QualifiedName): Boolean { + val option = option() ?: return false + return option.optionName.extensionFieldName?.textMatches(extensionOptionName.toString()) == true + } + + fun isOption(builtinOptionName: String): Boolean { + val option = option() ?: return false + return option.optionName.symbolName?.textMatches(builtinOptionName) == true + } + + fun value(): Any? { + return option()?.constant?.value() + } + + fun value(field: QualifiedName): Any? { + if (field.componentCount == 0) return value() + + val value = value() ?: return null + if (field.componentCount == 0) return value + + if (value is MessageValue) { + return value.value(field) + } + + return null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionOwner.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionOwner.kt similarity index 76% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionOwner.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionOwner.kt index b291e565..15df6ce3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionOwner.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionOwner.kt @@ -1,12 +1,13 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner import io.kanro.idea.plugin.protobuf.lang.psi.findChildren -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement interface ProtobufOptionOwner : ProtobufElement { fun options(): Array { - return if (this is ProtobufBodyOwner) { + return if (this is BodyOwner) { body()?.findChildren() ?: arrayOf() } else { findChildren() @@ -18,7 +19,7 @@ interface ProtobufOptionOwner : ProtobufElement { */ fun options(name: QualifiedName): Array { val target = - if (this is ProtobufBodyOwner) { + if (this is BodyOwner) { body() ?: return arrayOf() } else { this @@ -34,7 +35,7 @@ interface ProtobufOptionOwner : ProtobufElement { */ fun options(name: String): Array { val target = - if (this is ProtobufBodyOwner) { + if (this is BodyOwner) { body() ?: return arrayOf() } else { this diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufStubExternalProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufStubExternalProvider.kt similarity index 81% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufStubExternalProvider.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufStubExternalProvider.kt index 33441c6c..f6b63cbd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufStubExternalProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufStubExternalProvider.kt @@ -1,7 +1,7 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature import com.intellij.openapi.extensions.ExtensionPointName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile interface ProtobufStubExternalProvider { companion object { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufStubSupport.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufStubSupport.kt similarity index 68% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufStubSupport.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufStubSupport.kt index c2489066..1cf583bd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufStubSupport.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufStubSupport.kt @@ -1,8 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature import com.intellij.psi.StubBasedPsiElement import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement interface ProtobufStubSupport, TPsi : ProtobufElement> : StubBasedPsiElement { fun stubData(): Array { @@ -10,7 +11,7 @@ interface ProtobufStubSupport, TPsi : ProtobufElement> } fun stubExternalData(): Map { - if (this !is ProtobufNamedElement) return mapOf() + if (this !is NamedElement) return mapOf() val result = mutableMapOf() ProtobufStubExternalProvider.extensionPoint.extensionList.forEach { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/impl/ProtobufFileImpl.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/impl/ProtobufFileImpl.kt similarity index 78% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/impl/ProtobufFileImpl.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/impl/ProtobufFileImpl.kt index 66a4309a..b71d73fb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/impl/ProtobufFileImpl.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/impl/ProtobufFileImpl.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.impl import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.extapi.psi.PsiFileBase @@ -16,21 +16,21 @@ import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.aip.AipOptions import io.kanro.idea.plugin.protobuf.lang.ProtobufFileType import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufSyntaxStatement import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope -import io.kanro.idea.plugin.protobuf.lang.psi.value -import io.kanro.idea.plugin.protobuf.lang.util.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEditionStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufSyntaxStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope import javax.swing.Icon class ProtobufFileImpl(viewProvider: FileViewProvider) : PsiFileBase(viewProvider, ProtobufLanguage), ProtobufFile { @@ -89,6 +89,7 @@ class ProtobufFileImpl(viewProvider: FileViewProvider) : PsiFileBase(viewProvide } "${system.getLocalByEntry(virtualFile)?.name}" } + is LocalFileSystem -> { val project = ProjectLocator.getInstance().guessProjectForFile(virtualFile) if (project != null) { @@ -101,6 +102,7 @@ class ProtobufFileImpl(viewProvider: FileViewProvider) : PsiFileBase(viewProvide } "(external)" } + else -> "(unsupported)" } } @@ -114,13 +116,19 @@ class ProtobufFileImpl(viewProvider: FileViewProvider) : PsiFileBase(viewProvide } override fun syntax(): String? { - val syntax = this.findChildByClass(ProtobufSyntaxStatement::class.java) ?: return null - val text = syntax.stringValue?.text ?: return null + val syntax = this.findChild() ?: return null + val text = syntax.stringValue?.value() ?: return null + return text.substring(1, text.length - 1) + } + + override fun edition(): String? { + val edition = this.findChild() ?: return null + val text = edition.stringValue?.value() ?: return null return text.substring(1, text.length - 1) } override fun packageParts(): Array { - return findChildByClass(ProtobufPackageStatement::class.java)?.packageNameList?.toTypedArray() ?: arrayOf() + return findChild()?.packageNameList?.toTypedArray() ?: arrayOf() } override fun resourceDefinitions(): Array { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/impl/ProtobufLineCommentImpl.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/impl/ProtobufLineCommentImpl.kt similarity index 74% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/impl/ProtobufLineCommentImpl.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/impl/ProtobufLineCommentImpl.kt index 7118f690..ac27fe0f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/impl/ProtobufLineCommentImpl.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/impl/ProtobufLineCommentImpl.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.impl import com.intellij.lang.folding.FoldingDescriptor import com.intellij.psi.PsiElement @@ -9,12 +9,13 @@ import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker import com.intellij.refactoring.suggested.endOffset -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocument -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufFolding +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.FoldingElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement import io.kanro.idea.plugin.protobuf.lang.util.renderDoc class ProtobufLineCommentImpl(type: IElementType, text: CharSequence) : - PsiCommentImpl(type, text), ProtobufDocument, ProtobufFolding { + PsiCommentImpl(type, text), DocumentElement, FoldingElement, ProtobufElement { override fun getOwner(): PsiElement? { this.prevSibling?.let { if (it !is PsiWhiteSpace) return null @@ -31,10 +32,11 @@ class ProtobufLineCommentImpl(type: IElementType, text: CharSequence) : } override fun folding(): FoldingDescriptor? { + val range = textRange return FoldingDescriptor( this, - startOffset, - endOffset, + range.startOffset, + range.endOffset, null, "//...", ) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufEnumValueMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufEnumValueMixin.kt new file mode 100644 index 00000000..10fc485d --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufEnumValueMixin.kt @@ -0,0 +1,17 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.reference.ProtobufEnumValueReference + +abstract class ProtobufEnumValueMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufEnumValue { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return arrayOf(ProtobufEnumValueReference(this)) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufExtensionFieldNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufExtensionFieldNameMixin.kt new file mode 100644 index 00000000..44f24131 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufExtensionFieldNameMixin.kt @@ -0,0 +1,49 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.reference.ProtobufExtensionFieldReference + +abstract class ProtobufExtensionFieldNameMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufExtensionFieldName { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return arrayOf(ProtobufExtensionFieldReference(this)) + } + + override fun symbol(): QualifiedName? { + return buildList { + var parent = this@ProtobufExtensionFieldNameMixin as? ProtobufExtensionFieldName + while (parent != null) { + add(parent.symbolName.text) + parent = parent.parent as? ProtobufExtensionFieldName + } + }.reversed().let { QualifiedName.fromComponents(it) } + } + + override fun rename(qualifiedName: QualifiedName) { + replace(ProtobufPsiFactory.createExtensionFieldName(project, qualifiedName.toString())) + } + + override fun leaf(): ProtobufExtensionFieldName { + var result: ProtobufExtensionFieldName = this + while (true) { + result = result.extensionFieldName ?: break + } + return result + } + + override fun root(): ProtobufExtensionFieldName { + var result: ProtobufExtensionFieldName = this + while (true) { + result = result.parent as? ProtobufExtensionFieldName ?: break + } + return result + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufFieldNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufFieldNameMixin.kt new file mode 100644 index 00000000..b27b84a5 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufFieldNameMixin.kt @@ -0,0 +1,29 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.reference.ProtobufFieldReference + +abstract class ProtobufFieldNameMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufFieldName { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return CachedValuesManager.getCachedValue(this) { + CachedValueProvider.Result( + if (symbolName != null) { + arrayOf(ProtobufFieldReference(this)) + } else { + emptyArray() + }, + PsiModificationTracker.MODIFICATION_COUNT, + ) + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufImportStatementMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufImportStatementMixin.kt similarity index 66% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufImportStatementMixin.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufImportStatementMixin.kt index 6baee6b7..faff515f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufImportStatementMixin.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufImportStatementMixin.kt @@ -1,13 +1,13 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin import com.intellij.lang.ASTNode import com.intellij.psi.PsiReference import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufImportReference +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.reference.ProtobufImportReference abstract class ProtobufImportStatementMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufImportStatement { override fun getReference(): PsiReference { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufMessageDefinitionMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufMessageDefinitionMixin.kt similarity index 70% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufMessageDefinitionMixin.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufMessageDefinitionMixin.kt index 9889b42f..2950136f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufMessageDefinitionMixin.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufMessageDefinitionMixin.kt @@ -1,31 +1,32 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin import com.intellij.lang.ASTNode import com.intellij.psi.stubs.IStubElementType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.StubBasedProtobufElementBase -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufStubSupport -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumValueStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufExtendStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufFieldStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufGroupStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMapFieldStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufOneofStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufPackageNameStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufStubSupport +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.StubBasedProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumValueStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufExtendStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufFieldStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufGroupStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMapFieldStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufOneofStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufPackageNameStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.string.toCamelCase abstract class ProtobufMessageDefinitionMixin : StubBasedProtobufElementBase, @@ -87,6 +88,10 @@ abstract class ProtobufGroupDefinitionMixin : constructor(stub: ProtobufGroupStub, type: IStubElementType<*, *>) : super(stub, type) + override fun fieldName(): String? { + return name()?.lowercase() + } + override fun stubData(): Array { return arrayOf(identifier?.text ?: "") } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufOptionNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufOptionNameMixin.kt new file mode 100644 index 00000000..8c4d70e0 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufOptionNameMixin.kt @@ -0,0 +1,54 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.reference.ProtobufOptionNameReference + +abstract class ProtobufOptionNameMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufOptionName { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return if (symbolName != null) { + arrayOf(ProtobufOptionNameReference(this)) + } else { + emptyArray() + } + } + + override fun symbol(): QualifiedName? { + return null + } + + override fun rename(qualifiedName: QualifiedName) { + } + + override fun resolve(): PsiElement? { + extensionFieldName?.let { + return it.resolve() + } + + return reference?.resolve() + } + + override fun leaf(): ProtobufOptionName { + var result: ProtobufOptionName = this + while (true) { + result = result.optionName ?: break + } + return result + } + + override fun root(): ProtobufOptionName { + var result: ProtobufOptionName = this + while (true) { + result = result.parent as? ProtobufOptionName ?: break + } + return result + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufStringValueMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufStringValueMixin.kt new file mode 100644 index 00000000..d8b2d29d --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufStringValueMixin.kt @@ -0,0 +1,27 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue + +abstract class ProtobufStringValueMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufStringValue { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return ReferenceProvidersRegistry.getReferencesFromProviders(this) + } + + override fun symbol(): QualifiedName? { + return value().takeIf { it.isNotEmpty() }?.let { QualifiedName.fromDottedString(it) } + } + + override fun rename(qualifiedName: QualifiedName) { + replace(ProtobufPsiFactory.createStringValue(project, qualifiedName.toString())) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufTypeNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufTypeNameMixin.kt new file mode 100644 index 00000000..f98e4c1c --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufTypeNameMixin.kt @@ -0,0 +1,49 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.reference.ProtobufTypeNameReference + +abstract class ProtobufTypeNameMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufTypeName { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return arrayOf(ProtobufTypeNameReference(this)) + } + + override fun symbol(): QualifiedName? { + return buildList { + var parent = this@ProtobufTypeNameMixin as? ProtobufTypeName + while (parent != null) { + add(parent.symbolName.text) + parent = parent.parent as? ProtobufTypeName + } + }.reversed().let { QualifiedName.fromComponents(it) } + } + + override fun rename(qualifiedName: QualifiedName) { + replace(ProtobufPsiFactory.createTypeName(project, qualifiedName.toString())) + } + + override fun leaf(): ProtobufTypeName { + var result: ProtobufTypeName = this + while (true) { + result = result.typeName ?: break + } + return result + } + + override fun root(): ProtobufTypeName { + var result: ProtobufTypeName = this + while (true) { + result = result.parent as? ProtobufTypeName ?: break + } + return result + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufEnumValueReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufEnumValueReference.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufEnumValueReference.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufEnumValueReference.kt index bf0f4cf8..897ec8f6 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufEnumValueReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufEnumValueReference.kt @@ -1,15 +1,15 @@ -package io.kanro.idea.plugin.protobuf.lang.reference +package io.kanro.idea.plugin.protobuf.lang.psi.proto.reference import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import com.intellij.psi.PsiReferenceBase import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.util.ArrayUtilRt -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.enum +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.enum import io.kanro.idea.plugin.protobuf.lang.psi.realItems class ProtobufEnumValueReference(field: ProtobufEnumValue) : @@ -30,7 +30,7 @@ class ProtobufEnumValueReference(field: ProtobufEnumValue) : override fun getVariants(): Array { return element.enum()?.realItems()?.mapNotNull { if (it !is ProtobufEnumValueDefinition) return@mapNotNull null - (it as? ProtobufLookupItem)?.lookup() + (it as? LookupableElement)?.lookup() }?.toTypedArray() ?: ArrayUtilRt.EMPTY_OBJECT_ARRAY } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufExtensionFieldReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufExtensionFieldReference.kt new file mode 100644 index 00000000..b97bf566 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufExtensionFieldReference.kt @@ -0,0 +1,224 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.reference + +import com.intellij.codeInsight.completion.CompletionUtilCore +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.patterns.PlatformPatterns +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.impl.source.resolve.ResolveCache +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.stubs.StubIndex +import com.intellij.psi.util.PsiElementFilter +import com.intellij.psi.util.QualifiedName +import com.intellij.psi.util.parentOfType +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.prev +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufField +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.absolutely +import io.kanro.idea.plugin.protobuf.lang.psi.proto.optionType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver +import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver +import io.kanro.idea.plugin.protobuf.lang.util.or +import io.kanro.idea.plugin.protobuf.lang.util.removeCommonPrefix + +class ProtobufExtensionFieldReference(fieldName: ProtobufExtensionFieldName) : + PsiReferenceBase(fieldName) { + private object Resolver : ResolveCache.Resolver { + override fun resolve( + ref: PsiReference, + incompleteCode: Boolean, + ): PsiElement? { + ref as ProtobufExtensionFieldReference + + val extendMessage = ref.extendMessage() ?: return null + val qualifiedName = ref.element.leaf().symbol() ?: return null + return if (ref.element.absolutely()) { + ProtobufSymbolResolver.resolveAbsolutely( + ref.element, + qualifiedName, + ProtobufSymbolFilters.extensionField(extendMessage), + ) + } else { + ProtobufSymbolResolver.resolveRelatively( + ref.element, + qualifiedName, + ProtobufSymbolFilters.extensionField(extendMessage), + ) + } + } + } + + override fun resolve(): PsiElement? { + element.extensionFieldName?.let { + return when (val item = it.reference?.resolve()) { + is ProtobufScopeItem -> { + when (val owner = item.owner()) { + is ProtobufFile -> owner.packageParts().lastOrNull() + else -> owner + } + } + + is ProtobufPackageName -> item.prev() + else -> null + } + } + + return ResolveCache.getInstance(element.project).resolveWithCaching(this, Resolver, false, false) + } + + override fun getCanonicalText(): String { + return element.text + } + + override fun calculateDefaultRangeInElement(): TextRange { + return element.symbolName.textRangeInParent + } + + override fun handleElementRename(newElementName: String): PsiElement { + (element.symbolName.identifierLiteral as? LeafPsiElement)?.replaceWithText(newElementName) + return element + } + + private fun extendMessage(): QualifiedName? { + val host = element.root().parent ?: return null + return when (host) { + is ProtobufOptionName -> { + return when (val parent = host.parent) { + is ProtobufOptionName -> { + val field = parent.resolve() as? ProtobufFieldDefinition ?: return null + val message = field.typeName.resolve() as? ProtobufMessageDefinition ?: return null + message.qualifiedName() + } + + is ProtobufOptionAssign -> { + val optionType = host.optionType() ?: return null + optionType.qualifiedName + } + + else -> null + } + + } + + is ProtobufExtensionName -> { + val assign = host.parentOfType()?.parentOfType() ?: return null + return when (val field = assign.field()) { + is ProtobufGroupDefinition -> field.scope() + is ProtobufFieldDefinition -> (field.typeName.resolve() as? ProtobufMessageDefinition)?.qualifiedName() + else -> null + } + } + + else -> null + } + } + + override fun getVariants(): Array { + val result = mutableListOf() + val addedElements = mutableSetOf() + val extendMessage = extendMessage() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + val filter = ProtobufSymbolFilters.extensionField(extendMessage) + + getVariantsInCurrentScope(filter or ProtobufSymbolFilters.packageName, result, addedElements) + getVariantsInStubIndex(filter, result, addedElements) + return result.toTypedArray() + } + + private fun getVariantsInCurrentScope( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ) { + val parentScope = element.symbol() ?: return + ProtobufSymbolResolver.collectAbsolute(element, parentScope, filter).forEach { + if (it in elements) return@forEach + result += lookupFor(it, parentScope) ?: return@forEach + elements += it + } + } + + private fun getVariantsInStubIndex( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ): Array { + if (element.parent is ProtobufExtensionFieldName) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (element.extensionFieldName != null) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (!element.text.endsWith(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED)) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + + val searchName = element.text.substringBefore(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED) + val scope = ProtobufRootResolver.searchScope(element) + val matcher = PlatformPatterns.string().contains(searchName) + val currentScope = element.parentOfType()?.scope() + + return StubIndex.getInstance().getAllKeys(ShortNameIndex.key, element.project).asSequence().filter { + matcher.accepts(it) + }.flatMap { + StubIndex.getElements(ShortNameIndex.key, it, element.project, scope, ProtobufElement::class.java) + .asSequence() + }.filter { + filter.isAccepted(it) + }.mapNotNull { + if (it in elements) return@mapNotNull null + result += lookupForStub(it, currentScope) ?: return@mapNotNull null + elements += it + }.toList().toTypedArray() + } + + private fun lookupFor( + element: ProtobufElement, + scope: QualifiedName, + ): LookupElement? { + var builder = (element as? LookupableElement)?.lookup() ?: return null + builder = builder.withLookupString(scope.append(builder.lookupString).toString()) + if (element is ProtobufPackageName) { + builder = builder.withInsertHandler(packageInsertHandler) + } + return builder + } + + private fun lookupForStub( + element: ProtobufElement, + currentScope: QualifiedName?, + ): LookupElement? { + if (element !is ProtobufDefinition) return null + val qualifiedName = element.qualifiedName() ?: return null + + val targetName = + if (currentScope != null) { + qualifiedName.removeCommonPrefix(currentScope) + } else { + qualifiedName + } + return LookupElementBuilder.create(targetName).withLookupString(qualifiedName.lastComponent!!) + .withPresentableText(qualifiedName.lastComponent!!).withIcon(element.getIcon(false)) + .withTailText("${element.tailText() ?: ""} (${qualifiedName.removeTail(1)})", true) + .withTypeText(element.type()).withInsertHandler(AddImportInsertHandler(element)) + } + + companion object { + private val packageInsertHandler = SmartInsertHandler(".", 0, true) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufFieldReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufFieldReference.kt new file mode 100644 index 00000000..a67b800e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufFieldReference.kt @@ -0,0 +1,79 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.reference + +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReferenceBase +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.items +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.key +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ownerMessage +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.value +import io.kanro.idea.plugin.protobuf.lang.psi.realItems + +class ProtobufFieldReference(field: ProtobufFieldName) : + PsiReferenceBase(field) { + override fun resolve(): PsiElement? { + val message = element.ownerMessage() ?: return null + if (message is ProtobufMapFieldDefinition) { + when (element.text) { + "key" -> return message.key() + "value" -> return message.value() + } + } + message.items { + if (it.fieldName() == element.text) { + return it + } + } + return null + } + + override fun calculateDefaultRangeInElement(): TextRange { + return TextRange.create(0, element.textLength) + } + + override fun getVariants(): Array { + val message = element.ownerMessage() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (message is ProtobufMapFieldDefinition) { + return message.entryFields().map { + when (it.psiElement?.reference?.resolve()) { + is ProtobufGroupDefinition, + is ProtobufMessageDefinition, + -> it.withInsertHandler(messageFieldInsertHandler) + + else -> it.withInsertHandler(fieldInsertHandler) + } + }.toTypedArray() + } + return message.realItems().mapNotNull { + (it as? ProtobufFieldLike)?.lookup()?.let { + when (it.psiElement?.reference?.resolve()) { + is ProtobufGroupDefinition, + is ProtobufMessageDefinition, + -> it.withInsertHandler(messageFieldInsertHandler) + + else -> it.withInsertHandler(fieldInsertHandler) + } + } + }.toTypedArray() + } + + override fun handleElementRename(newElementName: String): PsiElement { + ProtobufPsiFactory.createFieldName(element.project, newElementName).let { + return element.replace(it) + } + } + + companion object { + private val fieldInsertHandler = SmartInsertHandler(": ") + + private val messageFieldInsertHandler = SmartInsertHandler(" {}", -1) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufImportReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufImportReference.kt similarity index 92% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufImportReference.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufImportReference.kt index 633fd5d6..599da48f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufImportReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufImportReference.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.reference +package io.kanro.idea.plugin.protobuf.lang.psi.proto.reference import com.intellij.codeInsight.lookup.AutoCompletionPolicy import com.intellij.codeInsight.lookup.LookupElement @@ -13,11 +13,10 @@ import com.intellij.psi.impl.source.resolve.ResolveCache import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.stringRangeInParent -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stringRangeInParent import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver -import io.kanro.idea.plugin.protobuf.lang.util.ProtobufPsiFactory class ProtobufImportReference(import: ProtobufImportStatement) : PsiReferenceBase(import) { private object Resolver : ResolveCache.Resolver { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufOptionNameReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufOptionNameReference.kt new file mode 100644 index 00000000..675965c9 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufOptionNameReference.kt @@ -0,0 +1,138 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.reference + +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.impl.source.resolve.ResolveCache +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.util.QualifiedName +import com.intellij.psi.util.parentOfType +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.items +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.optionType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.realItems +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver +import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver +import io.kanro.idea.plugin.protobuf.lang.support.Options + +class ProtobufOptionNameReference(optionName: ProtobufOptionName) : PsiReferenceBase(optionName) { + private object Resolver : ResolveCache.Resolver { + override fun resolve( + ref: PsiReference, + incompleteCode: Boolean, + ): PsiElement? { + ref as ProtobufOptionNameReference + val search = ref.element.symbolName?.text ?: return null + val message = ref.ownerMessage() ?: return null + + if (message.scope() == Options.FIELD_OPTIONS.qualifiedName) { + if (search == "default") { + return ref.element.parentOfType() + } + if (search == "json_name") { + return ProtobufSymbolResolver.resolveAbsolutelyInFile( + ref.descriptor() ?: return null, + QualifiedName.fromDottedString("google.protobuf.FieldDescriptorProto.json_name"), + ) + } + } + + message.items { + if (it.fieldName() == search) { + return it + } + } + + return null + } + } + + override fun resolve(): PsiElement? { + return ResolveCache.getInstance(element.project).resolveWithCaching(this, Resolver, false, false) + } + + private fun descriptor(): ProtobufFile? { + return ProtobufRootResolver.findFile("google/protobuf/descriptor.proto", element).firstOrNull()?.let { + PsiManager.getInstance(element.project).findFile(it) as? ProtobufFile + } + } + + private fun ownerMessage(): ProtobufScope? { + when (val parent = element.parent) { + is ProtobufOptionAssign -> { + return ProtobufSymbolResolver.resolveAbsolutelyInFile( + descriptor() ?: return null, + element.optionType()?.qualifiedName ?: return null, + ) as? ProtobufScope ?: return null + } + + is ProtobufOptionName -> { + return when (val field = parent.resolve() as? ProtobufFieldLike) { + is ProtobufGroupDefinition -> field + is ProtobufFieldDefinition -> field.typeName.resolve() as? ProtobufScope + else -> null + } + } + + else -> return null + } + } + + override fun getCanonicalText(): String { + return element.text + } + + override fun calculateDefaultRangeInElement(): TextRange { + return element.symbolName?.textRangeInParent ?: TextRange.EMPTY_RANGE + } + + override fun handleElementRename(newElementName: String): PsiElement { + (element.symbolName?.identifierLiteral as? LeafPsiElement)?.replaceWithText(newElementName) + return element + } + + override fun getVariants(): Array { + val message = ownerMessage() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + val result = + message.realItems().mapNotNull { + (it as? ProtobufFieldDefinition)?.lookup()?.let { + when (it.psiElement?.reference?.resolve()) { + is ProtobufGroupDefinition, + is ProtobufMessageDefinition, + -> it + + else -> it.withInsertHandler(fieldInsertHandler) + } + } + }.toMutableList() + + if (Options.FIELD_OPTIONS.qualifiedName == message.scope()) { + result += + LookupElementBuilder.create("default").withTypeText("option").withIcon(ProtobufIcons.FIELD) + .withInsertHandler(fieldInsertHandler) + result += + LookupElementBuilder.create("json_name").withTypeText("option").withIcon(ProtobufIcons.FIELD) + .withInsertHandler(fieldInsertHandler) + } + + return result.toTypedArray() + } + + companion object { + private val fieldInsertHandler = SmartInsertHandler(" = ") + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufTypeNameReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufTypeNameReference.kt new file mode 100644 index 00000000..e54b3129 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufTypeNameReference.kt @@ -0,0 +1,191 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.reference + +import com.intellij.codeInsight.completion.CompletionUtilCore +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.patterns.PlatformPatterns +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.impl.source.resolve.ResolveCache +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.stubs.StubIndex +import com.intellij.psi.util.PsiElementFilter +import com.intellij.psi.util.QualifiedName +import com.intellij.psi.util.parentOfType +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.prev +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.absolutely +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver +import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver +import io.kanro.idea.plugin.protobuf.lang.util.or +import io.kanro.idea.plugin.protobuf.lang.util.removeCommonPrefix + +class ProtobufTypeNameReference(typeName: ProtobufTypeName) : PsiReferenceBase(typeName) { + private object Resolver : ResolveCache.Resolver { + override fun resolve( + ref: PsiReference, + incompleteCode: Boolean, + ): PsiElement? { + ref as ProtobufTypeNameReference + val qualifiedName = ref.element.leaf().symbol() ?: return null + return if (ref.element.absolutely()) { + ProtobufSymbolResolver.resolveAbsolutely( + ref.element, + qualifiedName, + ref.filter(), + ) + } else { + ProtobufSymbolResolver.resolveRelatively( + ref.element, + qualifiedName, + ref.filter(), + ) + } + } + } + + private fun filter(): PsiElementFilter { + return when (element.root().parent) { + is ProtobufMapFieldDefinition, + is ProtobufFieldDefinition, + -> ProtobufSymbolFilters.fieldType + + is ProtobufExtendDefinition -> ProtobufSymbolFilters.extendMessage + + else -> ProtobufSymbolFilters.message + } + } + + override fun resolve(): PsiElement? { + element.typeName?.let { + return when (val item = it.reference?.resolve()) { + is ProtobufScopeItem -> { + when (val owner = item.owner()) { + is ProtobufFile -> owner.packageParts().lastOrNull() + else -> owner + } + } + + is ProtobufPackageName -> item.prev() + else -> null + } + } + + return ResolveCache.getInstance(element.project).resolveWithCaching(this, Resolver, false, false) + } + + override fun getCanonicalText(): String { + return element.text + } + + override fun calculateDefaultRangeInElement(): TextRange { + return element.symbolName.textRangeInParent + } + + override fun handleElementRename(newElementName: String): PsiElement { + (element.symbolName.identifierLiteral as? LeafPsiElement)?.replaceWithText(newElementName) + return element + } + + override fun getVariants(): Array { + val result = mutableListOf() + val addedElements = mutableSetOf() + val filter = filter() or ProtobufSymbolFilters.packageName + getVariantsInCurrentScope(filter, result, addedElements) + getVariantsInStubIndex(filter, result, addedElements) + return result.toTypedArray() + } + + private fun getVariantsInCurrentScope( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ) { + val parentScope = element.symbol() ?: return + ProtobufSymbolResolver.collectAbsolute(element, parentScope, filter).forEach { + if (it in elements) return@forEach + result += lookupFor(it, parentScope) ?: return@forEach + elements += it + } + } + + private fun getVariantsInStubIndex( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ): Array { + if (element.parent is ProtobufTypeName) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (element.typeName != null) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (!element.text.endsWith(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED)) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + + val searchName = element.text.substringBefore(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED) + val scope = ProtobufRootResolver.searchScope(element) + val matcher = PlatformPatterns.string().contains(searchName) + val currentScope = element.parentOfType()?.scope() + + return StubIndex.getInstance().getAllKeys(ShortNameIndex.key, element.project).asSequence().filter { + matcher.accepts(it) + }.flatMap { + StubIndex.getElements(ShortNameIndex.key, it, element.project, scope, ProtobufElement::class.java) + .asSequence() + }.filter { + filter.isAccepted(it) + }.mapNotNull { + if (it in elements) return@mapNotNull null + result += lookupForStub(it, currentScope) ?: return@mapNotNull null + elements += it + }.toList().toTypedArray() + } + + private fun lookupFor( + element: ProtobufElement, + scope: QualifiedName, + ): LookupElement? { + var builder = (element as? LookupableElement)?.lookup() ?: return null + builder = builder.withLookupString(scope.append(builder.lookupString).toString()) + if (element is ProtobufPackageName) { + builder = builder.withInsertHandler(packageInsertHandler) + } + return builder + } + + private fun lookupForStub( + element: ProtobufElement, + currentScope: QualifiedName?, + ): LookupElement? { + if (element !is ProtobufDefinition) return null + val qualifiedName = element.qualifiedName() ?: return null + + val targetName = + if (currentScope != null) { + qualifiedName.removeCommonPrefix(currentScope) + } else { + qualifiedName + } + return LookupElementBuilder.create(targetName).withLookupString(qualifiedName.lastComponent!!) + .withPresentableText(qualifiedName.lastComponent!!).withIcon(element.getIcon(false)) + .withTailText("${element.tailText() ?: ""} (${qualifiedName.removeTail(1)})", true) + .withTypeText(element.type()).withInsertHandler(AddImportInsertHandler(element)) + } + + companion object { + private val packageInsertHandler = SmartInsertHandler(".", 0, true) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufDefinition.kt similarity index 83% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufDefinition.kt index 71d98d83..a168cce1 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufDefinition.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.navigation.ItemPresentation @@ -7,20 +7,20 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIdentifier +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentOwner +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocumented -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIdentifier import io.kanro.idea.plugin.protobuf.lang.util.doc import javax.swing.Icon interface ProtobufDefinition : ProtobufScopeItem, PsiNameIdentifierOwner, - ProtobufNamedElement, - ProtobufLookupItem, - ProtobufDocumented, + NamedElement, + LookupableElement, + DocumentOwner, NavigatablePsiElement, ItemPresentation { fun type(): String diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufFieldLike.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufFieldLike.kt new file mode 100644 index 00000000..5a76bf4a --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufFieldLike.kt @@ -0,0 +1,36 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure + +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.string.toCamelCase + +interface ProtobufFieldLike : ProtobufDefinition, ProtobufNumbered { + fun fieldName(): String? { + return name() + } + + fun fieldType(): String? + + fun fieldValueType(): ValueType + + fun jsonName(): String? { + return CachedValuesManager.getCachedValue(this) { + val option = (this as? ProtobufOptionOwner)?.options("json_name")?.lastOrNull() + val result = + option?.value()?.toString() + ?: fieldName()?.toCamelCase() + CachedValueProvider.Result.create( + result, + PsiModificationTracker.MODIFICATION_COUNT, + ) + } + } + + override fun tailText(): String? { + return ": ${fieldType()} = ${number()}" + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufMultiNameDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufMultiNameDefinition.kt similarity index 58% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufMultiNameDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufMultiNameDefinition.kt index 0240748c..434708aa 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufMultiNameDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufMultiNameDefinition.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure interface ProtobufMultiNameDefinition : ProtobufDefinition { fun names(): Set diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufNumberScope.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufNumberScope.kt similarity index 50% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufNumberScope.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufNumberScope.kt index cd818d47..ffb6145a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufNumberScope.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufNumberScope.kt @@ -1,14 +1,15 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtensionStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedRange -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedStatement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner import io.kanro.idea.plugin.protobuf.lang.psi.findChildren -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionRange +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedRange +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedStatement interface ProtobufNumberScope : ProtobufScope { fun reservedRange(): Array { - return if (this is ProtobufBodyOwner) { + return if (this is BodyOwner) { this.body()?.findChildren() ?: arrayOf() } else { findChildren() @@ -17,13 +18,13 @@ interface ProtobufNumberScope : ProtobufScope { }.toTypedArray() } - fun extensionRange(): Array { - return if (this is ProtobufBodyOwner) { + fun extensionRange(): Array { + return if (this is BodyOwner) { this.body()?.findChildren() ?: arrayOf() } else { findChildren() }.flatMap { - it.reservedRangeList + it.extensionRangeList }.toTypedArray() } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScope.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScope.kt similarity index 58% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScope.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScope.kt index 83dfaef0..898d7ed7 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScope.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScope.kt @@ -1,16 +1,16 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedStatement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner import io.kanro.idea.plugin.protobuf.lang.psi.findChildren -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedStatement interface ProtobufScope : ProtobufScopeItemContainer, ProtobufScopeItem { fun scope(): QualifiedName? fun reservedNames(): Array { - return if (this is ProtobufBodyOwner) { + return if (this is BodyOwner) { this.body()?.findChildren() ?: arrayOf() } else { findChildren() diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScopeItem.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScopeItem.kt similarity index 54% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScopeItem.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScopeItem.kt index 571405e9..5521776c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScopeItem.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScopeItem.kt @@ -1,7 +1,7 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement interface ProtobufScopeItem : ProtobufElement { fun owner(): ProtobufScope? { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScopeItemContainer.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScopeItemContainer.kt similarity index 50% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScopeItemContainer.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScopeItemContainer.kt index a590c9c7..19ae5bf2 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScopeItemContainer.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScopeItemContainer.kt @@ -1,12 +1,12 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure +import io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner import io.kanro.idea.plugin.protobuf.lang.psi.findChildren -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement interface ProtobufScopeItemContainer : ProtobufElement { fun items(): Array { - return if (this is ProtobufBodyOwner) { + return if (this is BodyOwner) { this.body()?.findChildren() ?: arrayOf() } else { findChildren() diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufVirtualScope.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufVirtualScope.kt new file mode 100644 index 00000000..8be30e08 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufVirtualScope.kt @@ -0,0 +1,3 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure + +interface ProtobufVirtualScope : ProtobufScopeItemContainer diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/ProtobufStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/ProtobufStub.kt similarity index 85% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/ProtobufStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/ProtobufStub.kt index a6e8614f..5b1add0e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/ProtobufStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/ProtobufStub.kt @@ -1,8 +1,7 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile -import com.intellij.psi.StubBuilder import com.intellij.psi.stubs.DefaultStubBuilder import com.intellij.psi.stubs.PsiFileStub import com.intellij.psi.stubs.StubElement @@ -10,9 +9,9 @@ import com.intellij.psi.stubs.StubInputStream import com.intellij.psi.stubs.StubOutputStream import com.intellij.psi.tree.IStubFileElementType import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufFileStubImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufFileStubImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufScopeStub interface ProtobufStub : StubElement { fun data(index: Int): String @@ -22,7 +21,10 @@ interface ProtobufStub : StubElement { fun writeTo(dataStream: StubOutputStream) } -interface ProtobufFileStub : PsiFileStub, ProtobufStub, ProtobufScopeStub { +interface ProtobufFileStub : + PsiFileStub, + ProtobufStub, + ProtobufScopeStub { object Type : IStubFileElementType("PROTO_FILE", ProtobufLanguage) { override fun getStubVersion(): Int { return 1 diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/StubBasedProtobufElementBase.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/StubBasedProtobufElementBase.kt similarity index 78% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/StubBasedProtobufElementBase.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/StubBasedProtobufElementBase.kt index f5d68a0e..a62048df 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/StubBasedProtobufElementBase.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/StubBasedProtobufElementBase.kt @@ -1,12 +1,12 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub import com.intellij.extapi.psi.StubBasedPsiElementBase import com.intellij.lang.ASTNode import com.intellij.navigation.ItemPresentation import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.stubs.IStubElementType -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufStubBase +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufStubBase abstract class StubBasedProtobufElementBase> : StubBasedPsiElementBase { constructor(node: ASTNode) : super(node) @@ -29,7 +29,7 @@ abstract class StubBasedProtobufElementBase> : StubBased } override fun getName(): String? { - if (this is ProtobufNamedElement) return name() + if (this is NamedElement) return name() return null } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufEnumStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufEnumStub.kt similarity index 54% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufEnumStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufEnumStub.kt index 5f4352be..4c3658eb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufEnumStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufEnumStub.kt @@ -1,12 +1,12 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufScopeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufEnumStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufEnumStubType class ProtobufEnumStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufEnumValueStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufEnumValueStub.kt similarity index 52% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufEnumValueStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufEnumValueStub.kt index 8db09e0d..c414c3ea 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufEnumValueStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufEnumValueStub.kt @@ -1,11 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufEnumValueStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufEnumValueStubType class ProtobufEnumValueStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufExtendStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufExtendStub.kt new file mode 100644 index 00000000..688ee78e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufExtendStub.kt @@ -0,0 +1,15 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl + +import com.intellij.psi.stubs.StubElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufVirtualScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufExtendStubType + +class ProtobufExtendStub( + data: Array, + external: Map, + parent: StubElement<*>?, +) : ProtobufStubBase(data, external, parent, ProtobufExtendStubType), + ProtobufStub, + ProtobufVirtualScopeStub diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufFieldStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufFieldStub.kt similarity index 52% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufFieldStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufFieldStub.kt index e76b7ed2..977cd541 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufFieldStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufFieldStub.kt @@ -1,10 +1,10 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufFieldLikeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufFieldStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufFieldLikeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufFieldStubType class ProtobufFieldStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufFileStubImpl.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufFileStubImpl.kt similarity index 71% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufFileStubImpl.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufFileStubImpl.kt index 526cdee8..2e0d9cfb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufFileStubImpl.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufFileStubImpl.kt @@ -1,12 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.PsiFileStubImpl import com.intellij.psi.stubs.StubOutputStream import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.writeMap -import io.kanro.idea.plugin.protobuf.lang.psi.stub.writeStringArray +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.writeMap +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.writeStringArray class ProtobufFileStubImpl( file: ProtobufFile?, @@ -14,7 +13,7 @@ class ProtobufFileStubImpl( private val external: Map = file?.stubExternalData() ?: mapOf(), ) : PsiFileStubImpl(file), - ProtobufFileStub { + io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub { override fun scope(): QualifiedName { return QualifiedName.fromComponents(childrenStubs.filterIsInstance().map { it.name() }) } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufGroupStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufGroupStub.kt similarity index 54% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufGroupStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufGroupStub.kt index d41ec771..494b6681 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufGroupStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufGroupStub.kt @@ -1,12 +1,12 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufScopeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufGroupStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufGroupStubType class ProtobufGroupStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufMapFieldStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufMapFieldStub.kt similarity index 52% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufMapFieldStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufMapFieldStub.kt index b51e4d4d..7eae0579 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufMapFieldStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufMapFieldStub.kt @@ -1,10 +1,10 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufFieldLikeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufMapFieldStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufFieldLikeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufMapFieldStubType class ProtobufMapFieldStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufMessageStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufMessageStub.kt similarity index 58% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufMessageStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufMessageStub.kt index 28bda162..090b4230 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufMessageStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufMessageStub.kt @@ -1,12 +1,12 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufScopeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufMessageStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufMessageStubType class ProtobufMessageStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufOneofStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufOneofStub.kt new file mode 100644 index 00000000..c8a9d5b8 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufOneofStub.kt @@ -0,0 +1,20 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl + +import com.intellij.psi.stubs.StubElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufVirtualScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufOneofStubType + +class ProtobufOneofStub( + data: Array, + external: Map, + parent: StubElement<*>?, +) : ProtobufStubBase(data, external, parent, ProtobufOneofStubType), + io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub, + ProtobufDefinitionStub, + ProtobufVirtualScopeStub { + override fun name(): String? { + return data(0).takeIf { it.isNotEmpty() } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufPackageNameStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufPackageNameStub.kt similarity index 52% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufPackageNameStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufPackageNameStub.kt index 66c35c25..698517cf 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufPackageNameStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufPackageNameStub.kt @@ -1,16 +1,15 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufPackageNameStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufPackageNameStubType class ProtobufPackageNameStub( data: Array, external: Map, parent: StubElement<*>?, ) : ProtobufStubBase(data, external, parent, ProtobufPackageNameStubType), - ProtobufStub { + io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub { fun name(): String? { return data(0).takeIf { it.isNotEmpty() } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufRpcStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufRpcStub.kt similarity index 51% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufRpcStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufRpcStub.kt index b178aa48..b297f3a0 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufRpcStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufRpcStub.kt @@ -1,11 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufRpcStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufRpcStubType class ProtobufRpcStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufServiceStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufServiceStub.kt similarity index 51% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufServiceStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufServiceStub.kt index 5a0a2b9a..a31f93a2 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufServiceStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufServiceStub.kt @@ -1,14 +1,14 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufScopeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufServiceStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufServiceStubType class ProtobufServiceStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufStubBase.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufStubBase.kt similarity index 70% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufStubBase.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufStubBase.kt index 05da6172..9dec60f8 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufStubBase.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufStubBase.kt @@ -1,20 +1,19 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.PsiElement import com.intellij.psi.stubs.IStubElementType import com.intellij.psi.stubs.StubBase import com.intellij.psi.stubs.StubElement import com.intellij.psi.stubs.StubOutputStream -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.writeMap -import io.kanro.idea.plugin.protobuf.lang.psi.stub.writeStringArray +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.writeMap +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.writeStringArray abstract class ProtobufStubBase( private val data: Array, private val externalData: Map, parent: StubElement<*>?, type: IStubElementType<*, *>, -) : StubBase(parent, type), ProtobufStub { +) : StubBase(parent, type), io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub { override fun data(index: Int): String { return data[index] } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/QualifiedNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/QualifiedNameIndex.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/QualifiedNameIndex.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/QualifiedNameIndex.kt index 6884f9ff..3432a015 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/QualifiedNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/QualifiedNameIndex.kt @@ -1,8 +1,8 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.index +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class QualifiedNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/ResourceTypeIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/ResourceTypeIndex.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/ResourceTypeIndex.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/ResourceTypeIndex.kt index 5fa1b243..3d519adb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/ResourceTypeIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/ResourceTypeIndex.kt @@ -1,8 +1,8 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.index +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class ResourceTypeIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/ShortNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/ShortNameIndex.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/ShortNameIndex.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/ShortNameIndex.kt index 8e16e47c..3687d8c3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/ShortNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/ShortNameIndex.kt @@ -1,8 +1,8 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.index +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class ShortNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/primitive/ProtobufNamedStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/primitive/ProtobufNamedStub.kt similarity index 94% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/primitive/ProtobufNamedStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/primitive/ProtobufNamedStub.kt index 9b956064..b41fdabb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/primitive/ProtobufNamedStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/primitive/ProtobufNamedStub.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive import com.intellij.psi.stubs.Stub import com.intellij.psi.util.QualifiedName diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufEnumStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufEnumStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufEnumStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufEnumStubType.kt index 849e8f96..a28dd35b 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufEnumStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufEnumStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufEnumDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufEnumDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumStub object ProtobufEnumStubType : ProtobufStubTypeBase( "ENUM_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufEnumValueStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufEnumValueStubType.kt similarity index 68% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufEnumValueStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufEnumValueStubType.kt index bcb2a80b..df529472 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufEnumValueStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufEnumValueStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufEnumValueDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumValueStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufEnumValueDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumValueStub object ProtobufEnumValueStubType : ProtobufStubTypeBase( "ENUM_VALUE_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufExtendStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufExtendStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufExtendStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufExtendStubType.kt index 5334ed3b..c80c1a7c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufExtendStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufExtendStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufExtendDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufExtendStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufExtendDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufExtendStub object ProtobufExtendStubType : ProtobufStubTypeBase( "EXTEND_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufFieldStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufFieldStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufFieldStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufFieldStubType.kt index 16b181b2..df17a1f3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufFieldStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufFieldStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufFieldDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufFieldStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufFieldDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufFieldStub object ProtobufFieldStubType : ProtobufStubTypeBase( "FIELD_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufGroupStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufGroupStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufGroupStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufGroupStubType.kt index 6accdb3e..20f8f3af 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufGroupStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufGroupStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufGroupDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufGroupStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufGroupDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufGroupStub object ProtobufGroupStubType : ProtobufStubTypeBase( "GROUP_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufMapFieldStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufMapFieldStubType.kt similarity index 68% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufMapFieldStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufMapFieldStubType.kt index d9a50ce1..9226ea7b 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufMapFieldStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufMapFieldStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufMapFieldDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMapFieldStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufMapFieldDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMapFieldStub object ProtobufMapFieldStubType : ProtobufStubTypeBase( "MAP_FIELD_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufMessageStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufMessageStubType.kt similarity index 70% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufMessageStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufMessageStubType.kt index 710e14ce..ebea2d57 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufMessageStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufMessageStubType.kt @@ -1,11 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.IndexSink import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufMessageDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ResourceTypeIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufMessageDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ResourceTypeIndex object ProtobufMessageStubType : ProtobufStubTypeBase( "MESSAGE_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufOneofStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufOneofStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufOneofStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufOneofStubType.kt index 3da28d13..6b1a70a7 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufOneofStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufOneofStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufOneofDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufOneofStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufOneofDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufOneofStub object ProtobufOneofStubType : ProtobufStubTypeBase( "ONEOF_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufPackageNameStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufPackageNameStubType.kt similarity index 68% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufPackageNameStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufPackageNameStubType.kt index e70b21be..31854610 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufPackageNameStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufPackageNameStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufPackageNameImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufPackageNameStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufPackageNameImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufPackageNameStub object ProtobufPackageNameStubType : ProtobufStubTypeBase( "PACKAGE_NAME", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufRpcStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufRpcStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufRpcStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufRpcStubType.kt index a5de8d8f..cbf368f3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufRpcStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufRpcStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufRpcDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufRpcDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub object ProtobufRpcStubType : ProtobufStubTypeBase( "RPC_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufServiceStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufServiceStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufServiceStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufServiceStubType.kt index b3e2bf47..290d1854 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufServiceStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufServiceStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufServiceDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufServiceDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub object ProtobufServiceStubType : ProtobufStubTypeBase( "SERVICE_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufStubTypeBase.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufStubTypeBase.kt similarity index 71% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufStubTypeBase.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufStubTypeBase.kt index a334cad5..c4c8cccb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufStubTypeBase.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufStubTypeBase.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.PsiElement import com.intellij.psi.stubs.IStubElementType @@ -7,14 +7,14 @@ import com.intellij.psi.stubs.StubElement import com.intellij.psi.stubs.StubInputStream import com.intellij.psi.stubs.StubOutputStream import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufIndexProvider -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufStubSupport -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufStubBase -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.QualifiedNameIndex -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ShortNameIndex -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.readMap -import io.kanro.idea.plugin.protobuf.lang.psi.stub.readStringArray +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufIndexProvider +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufStubSupport +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufStubBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.readMap +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.readStringArray abstract class ProtobufStubTypeBase, TPsi : PsiElement>( name: String, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufStubTypes.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufStubTypes.kt similarity index 96% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufStubTypes.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufStubTypes.kt index 92c4a9da..0656b77a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufStubTypes.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufStubTypes.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.tree.IElementType diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufCommentToken.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufCommentToken.kt similarity index 76% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufCommentToken.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufCommentToken.kt index 9520e058..e3a277c4 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufCommentToken.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufCommentToken.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.token +package io.kanro.idea.plugin.protobuf.lang.psi.proto.token import com.intellij.psi.tree.IElementType import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufKeywordToken.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufKeywordToken.kt similarity index 76% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufKeywordToken.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufKeywordToken.kt index 1c0252c8..13f1c884 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufKeywordToken.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufKeywordToken.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.token +package io.kanro.idea.plugin.protobuf.lang.psi.proto.token import com.intellij.psi.tree.IElementType import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufToken.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufToken.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufToken.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufToken.kt index 51051062..9b4a6896 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufToken.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufToken.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.token +package io.kanro.idea.plugin.protobuf.lang.psi.proto.token import com.intellij.psi.tree.IElementType import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufTokens.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufTokens.kt similarity index 95% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufTokens.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufTokens.kt index cc0bd1c8..a287b0dd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufTokens.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufTokens.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.token +package io.kanro.idea.plugin.protobuf.lang.psi.proto.token import com.intellij.psi.tree.IElementType @@ -52,6 +52,9 @@ object ProtobufTokens { @JvmField val MINUS = put(ProtobufToken("-")) + @JvmField + val PLUS = put(ProtobufToken("+")) + @JvmField val RBRACE = put(ProtobufToken("}")) @@ -106,6 +109,9 @@ object ProtobufTokens { @JvmField val EXTENSIONS = put(ProtobufKeywordToken("extensions")) + @JvmField + val EDITION = put(ProtobufKeywordToken("edition")) + @JvmField val FALSE = put(ProtobufKeywordToken("false")) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufExtendStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufExtendStub.kt deleted file mode 100644 index c5b8f32d..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufExtendStub.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl - -import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufVirtualScopeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufExtendStubType - -class ProtobufExtendStub( - data: Array, - external: Map, - parent: StubElement<*>?, -) : ProtobufStubBase(data, external, parent, ProtobufExtendStubType), - ProtobufStub, - ProtobufVirtualScopeStub diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufOneofStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufOneofStub.kt deleted file mode 100644 index 967a8c29..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufOneofStub.kt +++ /dev/null @@ -1,21 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl - -import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufVirtualScopeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufOneofStubType - -class ProtobufOneofStub( - data: Array, - external: Map, - parent: StubElement<*>?, -) : ProtobufStubBase(data, external, parent, ProtobufOneofStubType), - ProtobufStub, - ProtobufDefinitionStub, - ProtobufVirtualScopeStub { - override fun name(): String? { - return data(0).takeIf { it.isNotEmpty() } - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextASTFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextASTFactory.kt new file mode 100644 index 00000000..4b859a6c --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextASTFactory.kt @@ -0,0 +1,21 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.intellij.lang.DefaultASTFactoryImpl +import com.intellij.psi.impl.source.tree.LeafElement +import com.intellij.psi.impl.source.tree.PsiCommentImpl +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.psi.text.impl.ProtoTextSharpLineCommentImpl +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextASTFactory : DefaultASTFactoryImpl() { + override fun createComment( + type: IElementType, + text: CharSequence, + ): LeafElement { + return if (type == ProtoTextTokens.SHARP_LINE_COMMENT) { + ProtoTextSharpLineCommentImpl(type, text) + } else { + PsiCommentImpl(type, text) + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElement.kt new file mode 100644 index 00000000..f6a3596e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElement.kt @@ -0,0 +1,17 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile + +interface ProtoTextElement : BaseElement { + fun schemaFile(): ProtobufFile? { + return file()?.schemaFile() + } + + fun file(): ProtoTextFile? { + return when (val file = containingFile.originalFile) { + is ProtoTextFile -> file + else -> null + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementBase.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementBase.kt new file mode 100644 index 00000000..8f6c798d --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementBase.kt @@ -0,0 +1,32 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.intellij.extapi.psi.ASTWrapperPsiElement +import com.intellij.lang.ASTNode +import com.intellij.navigation.ItemPresentation +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiNameIdentifierOwner + +abstract class ProtoTextElementBase(node: ASTNode) : ASTWrapperPsiElement(node) { + override fun getPresentation(): ItemPresentation? { + if (this is ItemPresentation) return this + return null + } + + override fun getTextOffset(): Int { + if (this is PsiNameIdentifierOwner) { + if (this.nameIdentifier == this) { + return super.getTextOffset() + } + return this.nameIdentifier?.textOffset ?: super.getTextOffset() + } + return super.getTextOffset() + } + + override fun getNavigationElement(): PsiElement { + return if (this is PsiNameIdentifierOwner) { + this.nameIdentifier ?: this + } else { + this + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementType.kt new file mode 100644 index 00000000..10dc41d2 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementType.kt @@ -0,0 +1,6 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage + +open class ProtoTextElementType(name: String) : IElementType(name, ProtoTextLanguage) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextEnumValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextEnumValue.kt new file mode 100644 index 00000000..1c4bdbb1 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextEnumValue.kt @@ -0,0 +1,31 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.intellij.psi.util.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.key +import io.kanro.idea.plugin.protobuf.lang.psi.proto.value + +fun ProtoTextEnumValue.enum(): ProtobufEnumDefinition? { + val assign = parentOfType() ?: return null + val field = assign.field() ?: return null + + return when (field) { + is ProtobufFieldDefinition -> { + field.typeName.resolve() as? ProtobufEnumDefinition + } + + is ProtobufMapFieldDefinition -> { + val targetField = assign.field()?.text ?: return null + when (targetField) { + "key" -> field.key()?.resolve() as? ProtobufEnumDefinition + "value" -> field.value()?.resolve() as? ProtobufEnumDefinition + else -> null + } + } + + else -> null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFieldName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFieldName.kt new file mode 100644 index 00000000..65de2965 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFieldName.kt @@ -0,0 +1,39 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.intellij.psi.util.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue + +fun ProtoTextFieldName.resolve(): ProtobufElement? { + symbolName?.let { + return reference?.resolve() as? ProtobufElement + } + + extensionName?.let { + return it.typeName.leaf().reference?.resolve() as? ProtobufElement + } + + anyName?.let { + return it.typeName.leaf().reference?.resolve() as? ProtobufElement + } + + return null +} + +fun ProtoTextFieldName.ownerMessage(): ProtobufScope? { + val field = parent as? ProtoTextField ?: return null + val message = field.parent as? MessageValue ?: return null + + if (message is ProtoTextFile) { + return message.schema() + } + + val parentField = message.parentOfType()?.fieldName?.resolve() ?: return null + + if (parentField is ProtobufScope) return parentField + if (parentField is ProtobufFieldDefinition) return parentField.typeName.resolve() as? ProtobufScope + + return null +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFile.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFile.kt new file mode 100644 index 00000000..5dcf4e1b --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFile.kt @@ -0,0 +1,48 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.intellij.navigation.ItemPresentation +import com.intellij.psi.PsiFile +import com.intellij.psi.tree.IFileElementType +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.text.impl.ProtoTextSharpLineCommentImpl +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextHeaderFileReference +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextHeaderMessageReference +import io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue + +interface ProtoTextFile : + PsiFile, + NamedElement, + ItemPresentation, + MessageValue { + fun schemaFile(): ProtobufFile? { + children.forEach { + if (it is ProtoTextSharpLineCommentImpl) { + when (val reference = it.reference) { + is ProtoTextHeaderFileReference -> return reference.resolve() as? ProtobufFile + } + } + } + return null + } + + fun schema(): ProtobufMessageDefinition? { + children.forEach { + if (it is ProtoTextSharpLineCommentImpl) { + when (val reference = it.reference) { + is ProtoTextHeaderMessageReference -> return reference.resolve() as? ProtobufMessageDefinition + } + } + } + return null + } + + object Type : IFileElementType("PROTOTEXT_FILE", ProtoTextLanguage) + + companion object { + const val PROTOTEXT_HEADER_FILE = "# proto-file:" + const val PROTOTEXT_HEADER_MESSAGE = "# proto-message:" + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextPsiFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextPsiFactory.kt new file mode 100644 index 00000000..8c88c5b1 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextPsiFactory.kt @@ -0,0 +1,50 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.bybutter.sisyphus.string.escape +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFileFactory +import io.kanro.idea.plugin.protobuf.lang.ProtoTextFileType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren + +object ProtoTextPsiFactory { + fun createFile( + project: Project, + text: String, + ): ProtoTextFile { + val name = "dummy.txtpb" + return PsiFileFactory.getInstance(project) + .createFileFromText(name, ProtoTextFileType.INSTANCE, text) as ProtoTextFile + } + + fun createFieldName( + project: Project, + text: String, + ): ProtoTextFieldName { + ProtobufPsiFactory.createFile(project, "$text = 1;").walkChildren { + return it.fieldName + } + throw IllegalStateException("Wrong type name '$text'") + } + + fun createTypeName( + project: Project, + text: String, + ): ProtoTextTypeName { + ProtobufPsiFactory.createFile(project, "[$text] = 1;").walkChildren { + return it + } + throw IllegalStateException("Wrong type name '$text'") + } + + fun createStringValue( + project: Project, + text: String, + ): ProtobufStringValue { + ProtobufPsiFactory.createFile(project, "a = \"${text.escape()}\";").walkChildren { + return it + } + throw IllegalStateException("Wrong string value '$text'") + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextTypeName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextTypeName.kt new file mode 100644 index 00000000..ea0c897e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextTypeName.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +fun ProtoTextTypeName.scope(): ProtoTextElement { + return root().parent as ProtoTextElement +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/feature/ProtoTextFieldAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/feature/ProtoTextFieldAssign.kt new file mode 100644 index 00000000..fcd96e58 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/feature/ProtoTextFieldAssign.kt @@ -0,0 +1,19 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.findChild +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.text.resolve + +interface ProtoTextFieldAssign : ValueAssign { + override fun field(): ProtobufFieldLike? { + val field = findChild() ?: return null + return field.resolve() as? ProtobufFieldLike + } + + override fun valueElement(): ValueElement<*>? { + return findChild>() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextFileImpl.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextFileImpl.kt new file mode 100644 index 00000000..3cc644f4 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextFileImpl.kt @@ -0,0 +1,43 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.impl + +import com.intellij.extapi.psi.PsiFileBase +import com.intellij.navigation.ItemPresentation +import com.intellij.openapi.fileTypes.FileType +import com.intellij.psi.FileViewProvider +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import io.kanro.idea.plugin.protobuf.lang.ProtoTextFileType +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFile +import javax.swing.Icon + +class ProtoTextFileImpl(viewProvider: FileViewProvider) : + PsiFileBase(viewProvider, ProtoTextLanguage), + ProtoTextFile { + override fun getFileType(): FileType { + return ProtoTextFileType.INSTANCE + } + + override fun toString(): String { + return "Protobuf File Text Format" + } + + override fun getPresentableText(): String? { + return name() + } + + override fun name(): String { + return this.name + } + + override fun getPresentation(): ItemPresentation? { + return this + } + + override fun getLocationString(): String? { + return null + } + + override fun getIcon(unused: Boolean): Icon? { + return ProtobufIcons.TEXT_FILE + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextSharpLineCommentImpl.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextSharpLineCommentImpl.kt new file mode 100644 index 00000000..a155bfe5 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextSharpLineCommentImpl.kt @@ -0,0 +1,22 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.impl + +import com.intellij.psi.PsiReference +import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry +import com.intellij.psi.impl.source.tree.PsiCommentImpl +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement + +class ProtoTextSharpLineCommentImpl(type: IElementType, text: CharSequence) : + PsiCommentImpl(type, text), ProtoTextElement { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return ReferenceProvidersRegistry.getReferencesFromProviders(this) + } + + override fun toString(): String { + return "ProtoTextSharpLineComment($elementType)" + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextEnumValueMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextEnumValueMixin.kt new file mode 100644 index 00000000..35202b88 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextEnumValueMixin.kt @@ -0,0 +1,13 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextEnumValueReference + +abstract class ProtoTextEnumValueMixin(node: ASTNode) : ProtobufElementBase(node), ProtoTextEnumValue { + override fun getReference(): PsiReference { + return ProtoTextEnumValueReference(this) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextFieldNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextFieldNameMixin.kt new file mode 100644 index 00000000..becec474 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextFieldNameMixin.kt @@ -0,0 +1,31 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextFieldReference + +abstract class ProtoTextFieldNameMixin(node: ASTNode) : + ProtoTextElementBase(node), + ProtoTextFieldName { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return CachedValuesManager.getCachedValue(this) { + CachedValueProvider.Result( + if (symbolName != null) { + arrayOf(ProtoTextFieldReference(this)) + } else { + emptyArray() + }, + PsiModificationTracker.MODIFICATION_COUNT, + ) + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextStringValueMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextStringValueMixin.kt new file mode 100644 index 00000000..5b317374 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextStringValueMixin.kt @@ -0,0 +1,28 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextStringValue + +abstract class ProtoTextStringValueMixin(node: ASTNode) : ProtobufElementBase(node), ProtoTextStringValue { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return ReferenceProvidersRegistry.getReferencesFromProviders(this) + } + + override fun symbol(): QualifiedName? { + return (reference?.resolve() as? ProtobufScope)?.scope() + } + + override fun rename(qualifiedName: QualifiedName) { + replace(ProtoTextPsiFactory.createStringValue(project, qualifiedName.toString())) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextTypeNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextTypeNameMixin.kt new file mode 100644 index 00000000..42262ba3 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextTypeNameMixin.kt @@ -0,0 +1,57 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextTypeNameReference + +abstract class ProtoTextTypeNameMixin(node: ASTNode) : ProtoTextElementBase(node), ProtoTextTypeName { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return CachedValuesManager.getCachedValue(this) { + CachedValueProvider.Result( + arrayOf(ProtoTextTypeNameReference(this)), + PsiModificationTracker.MODIFICATION_COUNT, + ) + } + } + + override fun symbol(): QualifiedName? { + return buildList { + var parent = this@ProtoTextTypeNameMixin as? ProtoTextTypeName + while (parent != null) { + add(parent.symbolName.text) + parent = parent.parent as? ProtoTextTypeName + } + }.reversed().let { QualifiedName.fromComponents(it) } + } + + override fun rename(qualifiedName: QualifiedName) { + replace(ProtoTextPsiFactory.createTypeName(project, qualifiedName.toString())) + } + + override fun leaf(): ProtoTextTypeName { + var result: ProtoTextTypeName = this + while (true) { + result = result.typeName ?: break + } + return result + } + + override fun root(): ProtoTextTypeName { + var result: ProtoTextTypeName = this + while (true) { + result = result.parent as? ProtoTextTypeName ?: break + } + return result + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextEnumValueReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextEnumValueReference.kt new file mode 100644 index 00000000..93d409d1 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextEnumValueReference.kt @@ -0,0 +1,41 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.reference + +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.impl.source.tree.LeafElement +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.items +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.realItems +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.text.enum + +class ProtoTextEnumValueReference(field: ProtoTextEnumValue) : + PsiReferenceBase(field) { + override fun resolve(): PsiElement? { + element.enum()?.items { + if (it.name() == element.text) { + return it + } + } + return null + } + + override fun calculateDefaultRangeInElement(): TextRange { + return TextRange.create(0, element.textLength) + } + + override fun getVariants(): Array { + return element.enum()?.realItems()?.mapNotNull { + if (it !is ProtobufEnumValueDefinition) return@mapNotNull null + (it as? LookupableElement)?.lookup() + }?.toTypedArray() ?: ArrayUtilRt.EMPTY_OBJECT_ARRAY + } + + override fun handleElementRename(newElementName: String): PsiElement { + (element.identifierLiteral?.node as? LeafElement)?.replaceWithText(newElementName) + return element + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextFieldReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextFieldReference.kt new file mode 100644 index 00000000..f64dabf8 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextFieldReference.kt @@ -0,0 +1,92 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.reference + +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReferenceBase +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.items +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.key +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.value +import io.kanro.idea.plugin.protobuf.lang.psi.realItems +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.text.ownerMessage + +class ProtoTextFieldReference(field: ProtoTextFieldName) : + PsiReferenceBase(field) { + override fun resolve(): PsiElement? { + val message = element.ownerMessage() ?: return null + if (message is ProtobufMapFieldDefinition) { + when (element.text) { + "key" -> return message.key() + "value" -> return message.value() + } + } + message.items { + if (it.fieldName() == element.text) { + return it + } + } + return null + } + + override fun calculateDefaultRangeInElement(): TextRange { + return TextRange.create(0, element.textLength) + } + + override fun getVariants(): Array { + val message = element.ownerMessage() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + return when (message) { + is ProtobufMapFieldDefinition -> { + message.entryFields().map { + when (it.psiElement?.reference?.resolve()) { + is ProtobufGroupDefinition, + is ProtobufMessageDefinition, + -> it.withInsertHandler(messageFieldInsertHandler) + + else -> it.withInsertHandler(fieldInsertHandler) + } + }.toTypedArray() + } + + else -> { + message.realItems().mapNotNull { + when (it) { + is ProtobufFieldDefinition -> + when (it.typeName.resolve()) { + is ProtobufMessageDefinition -> { + it.lookup()?.withInsertHandler(messageFieldInsertHandler) + } + + else -> it.lookup()?.withInsertHandler(fieldInsertHandler) + } + + is ProtobufMapFieldDefinition -> it.lookup()?.withInsertHandler(messageFieldInsertHandler) + + is ProtobufGroupDefinition -> it.lookup()?.withInsertHandler(messageFieldInsertHandler) + + else -> null + } + }.toTypedArray() + } + } + } + + override fun handleElementRename(newElementName: String): PsiElement { + ProtoTextPsiFactory.createFieldName(element.project, newElementName).let { + return element.replace(it) + } + } + + companion object { + private val fieldInsertHandler = SmartInsertHandler(": ") + + private val messageFieldInsertHandler = SmartInsertHandler(" {}", -1) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderFileReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderFileReference.kt new file mode 100644 index 00000000..e2a9d28a --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderFileReference.kt @@ -0,0 +1,91 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.reference + +import com.intellij.codeInsight.lookup.AutoCompletionPolicy +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiReferenceBase +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import io.kanro.idea.plugin.protobuf.lang.ProtobufFileType +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFile +import io.kanro.idea.plugin.protobuf.lang.psi.text.impl.ProtoTextSharpLineCommentImpl +import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver + +class ProtoTextHeaderFileReference(comment: ProtoTextSharpLineCommentImpl) : + PsiReferenceBase(comment) { + override fun resolve(): PsiElement? { + val fileName = fileName() + return if (fileName.startsWith(".")) { + element.containingFile.originalFile.virtualFile.parent?.findFileByRelativePath(fileName)?.let { + PsiManager.getInstance(element.project).findFile(it) + } + } else { + ProtobufRootResolver.findFile(fileName, element).firstOrNull()?.let { + PsiManager.getInstance(element.project).findFile(it) + } + } + } + + override fun getRangeInElement(): TextRange { + val text = element.text + val fileName = fileName() + val start = text.indexOf(fileName) + return TextRange.create(start, start + fileName.length) + } + + fun fileName(): String { + return element.text.substringAfter(ProtoTextFile.PROTOTEXT_HEADER_FILE).trim() + } + + override fun getVariants(): Array { + val imported = fileName() + val parent = imported.substringBeforeLast('/', "") + return if (parent.startsWith(".")) { + element.containingFile.originalFile.virtualFile?.parent?.findFileByRelativePath(parent) + ?.children?.mapNotNull { + fileLookup(parent, it) + }?.toTypedArray() ?: emptyArray() + } else { + ProtobufRootResolver.collectProtobuf(parent, element).mapNotNull { + fileLookup(parent, it) + }.toTypedArray() + } + } + + companion object { + private val nextImportInsert = SmartInsertHandler("/", 0, true) + + private fun fileLookup( + parent: String, + file: VirtualFile, + ): LookupElement? { + val completionText = + if (parent == "") { + file.name + } else { + "$parent/${file.name}".trim('/') + } + + return if (file.isDirectory) { + LookupElementBuilder.create(completionText) + .withTypeText("directory") + .withIcon(ProtobufIcons.FOLDER) + .withPresentableText(file.name) + .withInsertHandler { context, item -> + nextImportInsert.handleInsert(context, item) + } + .withAutoCompletionPolicy(AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE) + } else { + if (file.fileType !is ProtobufFileType) return null + LookupElementBuilder.create(completionText) + .withTypeText("proto") + .withIcon(ProtobufIcons.FILE) + .withPresentableText(file.name) + } + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderMessageReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderMessageReference.kt new file mode 100644 index 00000000..b0bf3420 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderMessageReference.kt @@ -0,0 +1,60 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.reference + +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.util.QualifiedName +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFile +import io.kanro.idea.plugin.protobuf.lang.psi.text.impl.ProtoTextSharpLineCommentImpl +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver + +class ProtoTextHeaderMessageReference(comment: ProtoTextSharpLineCommentImpl) : + PsiReferenceBase(comment) { + override fun resolve(): PsiElement? { + val messageName = messageName() + return ProtobufSymbolResolver.resolveInScope( + element.schemaFile() ?: return null, + QualifiedName.fromDottedString(messageName), + ) as? ProtobufMessageDefinition + } + + override fun getRangeInElement(): TextRange { + val text = element.text + val messageName = messageName() + val start = text.indexOf(messageName) + return TextRange.create(start, start + messageName.length) + } + + override fun getVariants(): Array { + val result = mutableListOf() + val filter = ProtobufSymbolFilters.messageTypeName + val messageName = messageName() + val parentScope = + messageName.substringBeforeLast('.', "").takeIf { it.isNotEmpty() } + ?.let { QualifiedName.fromDottedString(it) } ?: QualifiedName.fromComponents() + val scopeElement = element.schemaFile() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + ProtobufSymbolResolver.collectInScope(scopeElement, parentScope, filter).forEach { + result += lookupFor(it, parentScope) ?: return@forEach + } + return result.toTypedArray() + } + + private fun lookupFor( + element: ProtobufElement, + scope: QualifiedName, + ): LookupElement? { + val lookupElement = element as? LookupableElement ?: return null + val fullName = scope.append(lookupElement.name).toString() + return lookupElement.lookup(fullName) + } + + fun messageName(): String { + return element.text.substringAfter(ProtoTextFile.PROTOTEXT_HEADER_MESSAGE).trim() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextSharpCommentReferenceContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextSharpCommentReferenceContributor.kt new file mode 100644 index 00000000..c74abfea --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextSharpCommentReferenceContributor.kt @@ -0,0 +1,43 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.reference + +import com.intellij.patterns.PlatformPatterns +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiReferenceContributor +import com.intellij.psi.PsiReferenceProvider +import com.intellij.psi.PsiReferenceRegistrar +import com.intellij.util.ProcessingContext +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFile +import io.kanro.idea.plugin.protobuf.lang.psi.text.impl.ProtoTextSharpLineCommentImpl + +class ProtoTextSharpCommentReferenceContributor : PsiReferenceContributor() { + override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { + registrar.registerReferenceProvider( + PlatformPatterns.psiElement(ProtoTextSharpLineCommentImpl::class.java) + .withParent(ProtoTextFile::class.java), + ProtoTextSharpCommentReferenceProvider(), + ) + } +} + +class ProtoTextSharpCommentReferenceProvider : PsiReferenceProvider() { + override fun getReferencesByElement( + element: PsiElement, + context: ProcessingContext, + ): Array { + val stringValue = element as? ProtoTextSharpLineCommentImpl ?: return PsiReference.EMPTY_ARRAY + val reference = getReference(stringValue) ?: return PsiReference.EMPTY_ARRAY + return arrayOf(reference) + } + + private fun getReference(element: ProtoTextSharpLineCommentImpl): PsiReference? { + val text = element.text + if (text.startsWith(ProtoTextFile.PROTOTEXT_HEADER_FILE)) { + return ProtoTextHeaderFileReference(element) + } + if (text.startsWith(ProtoTextFile.PROTOTEXT_HEADER_MESSAGE)) { + return ProtoTextHeaderMessageReference(element) + } + return null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextTypeNameReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextTypeNameReference.kt new file mode 100644 index 00000000..9dd4d2cb --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextTypeNameReference.kt @@ -0,0 +1,193 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.reference + +import com.intellij.codeInsight.completion.CompletionUtilCore +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.patterns.PlatformPatterns +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.impl.source.resolve.ResolveCache +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.stubs.StubIndex +import com.intellij.psi.util.PsiElementFilter +import com.intellij.psi.util.QualifiedName +import com.intellij.psi.util.parentOfType +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.prev +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextAnyName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextExtensionName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.text.scope +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver +import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver +import io.kanro.idea.plugin.protobuf.lang.util.removeCommonPrefix + +class ProtoTextTypeNameReference(typeName: ProtoTextTypeName) : PsiReferenceBase(typeName) { + private object Resolver : ResolveCache.Resolver { + override fun resolve( + ref: PsiReference, + incompleteCode: Boolean, + ): PsiElement? { + ref as ProtoTextTypeNameReference + val qualifiedName = ref.element.leaf().symbol() ?: return null + + return when (ref.element.scope()) { + is ProtoTextAnyName -> { + StubIndex.getElements( + QualifiedNameIndex.key, + qualifiedName.toString(), + ref.element.project, + GlobalSearchScope.allScope(ref.element.project), + ProtobufElement::class.java, + ).firstOrNull { it is ProtobufMessageDefinition } as? ProtobufMessageDefinition + } + + is ProtoTextExtensionName -> { + val scope = ref.element.schemaFile() ?: return null + ProtobufSymbolResolver.resolveAbsolutely(scope, qualifiedName, ProtobufSymbolFilters.extensionField) + } + + else -> null + } + } + } + + override fun resolve(): PsiElement? { + element.typeName?.let { + return when (val item = it.reference?.resolve()) { + is ProtobufScopeItem -> { + when (val owner = item.owner()) { + is ProtobufFile -> owner.packageParts().lastOrNull() + else -> owner + } + } + is ProtobufPackageName -> item.prev() + else -> null + } + } + + return ResolveCache.getInstance(element.project).resolveWithCaching(this, Resolver, false, false) + } + + override fun getCanonicalText(): String { + return element.text + } + + override fun calculateDefaultRangeInElement(): TextRange { + return element.symbolName.textRangeInParent + } + + override fun handleElementRename(newElementName: String): PsiElement { + (element.symbolName.identifierLiteral as? LeafPsiElement)?.replaceWithText(newElementName) + return element + } + + override fun getVariants(): Array { + val result = mutableListOf() + val addedElements = mutableSetOf() + val filter = + when (val scope = element.scope()) { + is ProtoTextAnyName -> ProtobufSymbolFilters.messageTypeName + is ProtoTextExtensionName -> ProtobufSymbolFilters.extensionFieldQualifiedName + else -> return ArrayUtilRt.EMPTY_OBJECT_ARRAY + } + + getVariantsInCurrentScope(filter, result, addedElements) + getVariantsInStubIndex(filter, result, addedElements) + return result.toTypedArray() + } + + private fun getVariantsInCurrentScope( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ) { + val parentScope = element.symbol() ?: return + val scopeElement = element.schemaFile() ?: return + ProtobufSymbolResolver.collectAbsolute(scopeElement, parentScope, filter).forEach { + if (it in elements) return@forEach + result += lookupFor(it, parentScope) ?: return@forEach + elements += it + } + } + + private fun getVariantsInStubIndex( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ): Array { + if (element.parent is ProtoTextTypeName) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (element.typeName != null) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (!element.text.endsWith(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED)) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + + val searchName = element.text.substringBefore(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED) + val scope = ProtobufRootResolver.searchScope(element) + val matcher = PlatformPatterns.string().contains(searchName) + val currentScope = element.parentOfType()?.scope() + + return StubIndex.getInstance().getAllKeys(ShortNameIndex.key, element.project).asSequence().filter { + matcher.accepts(it) + }.flatMap { + StubIndex.getElements(ShortNameIndex.key, it, element.project, scope, ProtobufElement::class.java) + .asSequence() + }.filter { + filter.isAccepted(it) + }.mapNotNull { + if (it in elements) return@mapNotNull null + result += lookupForStub(it, currentScope) ?: return@mapNotNull null + elements += it + }.toList().toTypedArray() + } + + private fun lookupFor( + element: ProtobufElement, + scope: QualifiedName, + ): LookupElement? { + var builder = + (element as? LookupableElement)?.lookup() ?: return null + builder = builder.withLookupString(scope.append(builder.lookupString).toString()) + if (element is ProtobufPackageName) { + builder = builder.withInsertHandler(packageInsertHandler) + } + return builder + } + + private fun lookupForStub( + element: ProtobufElement, + currentScope: QualifiedName?, + ): LookupElement? { + if (element !is ProtobufDefinition) return null + val qualifiedName = element.qualifiedName() ?: return null + + val targetName = + if (currentScope != null) { + qualifiedName.removeCommonPrefix(currentScope) + } else { + qualifiedName + } + return LookupElementBuilder.create(targetName).withLookupString(qualifiedName.lastComponent!!) + .withPresentableText(qualifiedName.lastComponent!!).withIcon(element.getIcon(false)) + .withTailText("${element.tailText() ?: ""} (${qualifiedName.removeTail(1)})", true) + .withTypeText(element.type()).withInsertHandler(AddImportInsertHandler(element)) + } + + companion object { + private val packageInsertHandler = SmartInsertHandler(".", 0, true) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextCommentToken.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextCommentToken.kt new file mode 100644 index 00000000..74fe9187 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextCommentToken.kt @@ -0,0 +1,6 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.token + +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage + +open class ProtoTextCommentToken(name: String) : IElementType(name, ProtoTextLanguage) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextKeywordToken.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextKeywordToken.kt new file mode 100644 index 00000000..4c342c3b --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextKeywordToken.kt @@ -0,0 +1,6 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.token + +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage + +open class ProtoTextKeywordToken(name: String) : IElementType(name, ProtoTextLanguage) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextToken.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextToken.kt new file mode 100644 index 00000000..ccac1ea8 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextToken.kt @@ -0,0 +1,6 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.token + +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage + +open class ProtoTextToken(name: String) : IElementType(name, ProtoTextLanguage) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtobufTokens.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtobufTokens.kt new file mode 100644 index 00000000..04b12e42 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtobufTokens.kt @@ -0,0 +1,102 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.token + +import com.intellij.psi.tree.IElementType + +object ProtoTextTokens { + private val types: MutableMap = mutableMapOf() + + private fun put(element: IElementType): IElementType { + return put(element.toString(), element) + } + + private fun put( + name: String, + element: IElementType, + ): IElementType { + return types.getOrPut(name) { + element + } + } + + fun get(token: String): IElementType { + return types[token] ?: throw AssertionError("Unknown token type: $token") + } + + @JvmField + val ASSIGN = put(ProtoTextToken("=")) + + @JvmField + val COLON = put(ProtoTextToken(":")) + + @JvmField + val COMMA = put(ProtoTextToken(",")) + + @JvmField + val DOT = put(ProtoTextToken(".")) + + @JvmField + val GT = put(ProtoTextToken(">")) + + @JvmField + val LBRACE = put(ProtoTextToken("{")) + + @JvmField + val LBRACK = put(ProtoTextToken("[")) + + @JvmField + val LPAREN = put(ProtoTextToken("(")) + + @JvmField + val LT = put(ProtoTextToken("<")) + + @JvmField + val MINUS = put(ProtoTextToken("-")) + + @JvmField + val PLUS = put(ProtoTextToken("+")) + + @JvmField + val RBRACE = put(ProtoTextToken("}")) + + @JvmField + val RBRACK = put(ProtoTextToken("]")) + + @JvmField + val RPAREN = put(ProtoTextToken(")")) + + @JvmField + val SEMI = put(ProtoTextToken(";")) + + @JvmField + val SLASH = put(ProtoTextToken("/")) + + @JvmField + val FLOAT_LITERAL = put("FLOAT_LITERAL", ProtoTextToken("float")) + + @JvmField + val IDENTIFIER_LITERAL = put("IDENTIFIER_LITERAL", ProtoTextToken("identifier")) + + @JvmField + val INTEGER_LITERAL = put("INTEGER_LITERAL", ProtoTextToken("integer")) + + @JvmField + val STRING_LITERAL = put("STRING_LITERAL", ProtoTextToken("string")) + + @JvmField + val BUILT_IN_TYPE = put("BUILT_IN_TYPE", ProtoTextToken("BUILT_IN_TYPE")) + + @JvmField + val IDENTIFIER_AFTER_NUMBER = put(ProtoTextToken("IDENTIFIER_AFTER_NUMBER")) + + @JvmField + val SHARP_LINE_COMMENT = put(ProtoTextCommentToken("SHARP_LINE_COMMENT")) + + @JvmField + val SYMBOL = put(ProtoTextToken("SYMBOL")) + + @JvmField + val FALSE = put(ProtoTextKeywordToken("false")) + + @JvmField + val TRUE = put(ProtoTextKeywordToken("true")) +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/BlockElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/BlockElement.kt new file mode 100644 index 00000000..adac98c1 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/BlockElement.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.type + +import com.intellij.psi.PsiElement + +interface BlockElement : PsiElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/FragmentElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/FragmentElement.kt new file mode 100644 index 00000000..e7caacef --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/FragmentElement.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.type + +import com.intellij.psi.PsiElement + +interface FragmentElement : PsiElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/StatementElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/StatementElement.kt new file mode 100644 index 00000000..e262958e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/StatementElement.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.type + +import com.intellij.psi.PsiElement + +interface StatementElement : PsiElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ArrayValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ArrayValue.kt new file mode 100644 index 00000000..410096ae --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ArrayValue.kt @@ -0,0 +1,19 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import com.intellij.psi.util.childrenOfType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType + +interface ArrayValue : ValueElement> { + override fun value(): Array = this.childrenOfType>().map { + it.value() + }.toTypedArray() + + fun value(index: Int): Any? = valueElement(index)?.value() + + fun values(): Array> = this.childrenOfType>().toTypedArray() + + fun valueElement(index: Int): ValueElement<*>? = this.childrenOfType>().getOrNull(index) + + override fun valueType(): ValueType = ValueType.LIST +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/BooleanValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/BooleanValue.kt new file mode 100644 index 00000000..21c52784 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/BooleanValue.kt @@ -0,0 +1,10 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType + +interface BooleanValue : ValueElement { + override fun value(): Boolean = this.text.toBoolean() + + override fun valueType(): ValueType = ValueType.BOOLEAN +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/EnumValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/EnumValue.kt new file mode 100644 index 00000000..f35bbf93 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/EnumValue.kt @@ -0,0 +1,10 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType + +interface EnumValue : ValueElement { + override fun value(): String = this.text + + override fun valueType(): ValueType = ValueType.ENUM +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/IntegerValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/IntegerValue.kt new file mode 100644 index 00000000..c9c40733 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/IntegerValue.kt @@ -0,0 +1,10 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType + +interface IntegerValue : ValueElement { + override fun value(): Int = this.text.toInt() + + override fun valueType(): ValueType = ValueType.NUMBER +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/MessageValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/MessageValue.kt new file mode 100644 index 00000000..93170ea7 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/MessageValue.kt @@ -0,0 +1,38 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import com.intellij.psi.util.QualifiedName +import com.intellij.psi.util.childrenOfType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType + +interface MessageValue : ValueElement { + override fun value(): Any = this + + override fun valueType(): ValueType = ValueType.MESSAGE + + fun value(field: QualifiedName): Any? { + return valueElement(field)?.value() + } + + fun valueElement(field: QualifiedName): ValueElement<*>? { + if (field.componentCount == 0) return this + + val fields = childrenOfType() + fields.forEach { + if (it.field()?.name() != field.firstComponent) { + return null + } + val next = field.removeHead(1) + + if (next.componentCount == 0) { + return it + } + + if (it is MessageValue) { + return it.valueElement(next) + } + } + return null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/NumberValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/NumberValue.kt new file mode 100644 index 00000000..ba69fe5a --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/NumberValue.kt @@ -0,0 +1,22 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType + +interface NumberValue : ValueElement { + override fun value(): Number { + val text = this.text.lowercase() + return when { + text == "inf" -> Double.POSITIVE_INFINITY + text == "-inf" -> Double.NEGATIVE_INFINITY + text == "nan" -> Double.NaN + text.contains('e', true) -> this.text.toDouble() + text.startsWith("0x") -> this.text.substring(2).toLong(16) + text.startsWith("0") -> this.text.toLong(8) + this.text.contains('.') -> this.text.toDouble() + else -> this.text.toLong() + } + } + + override fun valueType(): ValueType = ValueType.NUMBER +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/StringValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/StringValue.kt new file mode 100644 index 00000000..f5e32a26 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/StringValue.kt @@ -0,0 +1,21 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import com.intellij.psi.util.elementType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens + +interface StringValue : ValueElement { + override fun value(): String = + buildString { + var child = firstChild + while (child != null) { + if (child.elementType == ProtobufTokens.STRING_LITERAL) { + append(decodeStringFromStringLiteral(child)) + } + child = child.nextSibling + } + } + + override fun valueType(): ValueType = ValueType.STRING +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ValueUtils.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ValueUtils.kt new file mode 100644 index 00000000..ac59ee46 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ValueUtils.kt @@ -0,0 +1,61 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import com.intellij.psi.PsiElement +import com.intellij.psi.util.elementType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens + +fun decodeStringFromStringLiteral(textElement: PsiElement): String { + if (textElement.elementType != ProtobufTokens.STRING_LITERAL) { + throw IllegalArgumentException("Element is not a string literal") + } + + return decodeString(textElement.text.trim('"', '\'')) +} + +fun decodeString(text: String): String = + buildString { + var index = 0 + while (index < text.length) { + val char = text[index] + if (char == '\\') { + index++ + if (index >= text.length) { + break + } + val next = text[index] + when (next) { + 'a' -> append('\u0007') + 'b' -> append('\b') + 'f' -> append('\u000C') + 'n' -> append('\n') + 'r' -> append('\r') + 't' -> append('\t') + 'v' -> append('\u000B') + 'x' -> { + index++ + if (index >= text.length) { + break + } + val hex = text.substring(index, index + 2) + index += 2 + append(hex.toInt(16).toChar()) + } + + 'u' -> { + index++ + if (index >= text.length) { + break + } + val hex = text.substring(index, index + 4) + index += 4 + append(hex.toInt(16).toChar()) + } + + else -> append(next) + } + } else { + append(char) + } + index++ + } + } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/WrappedValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/WrappedValue.kt new file mode 100644 index 00000000..86be0988 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/WrappedValue.kt @@ -0,0 +1,15 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType +import io.kanro.idea.plugin.protobuf.lang.psi.findChild + +interface WrappedValue : ValueElement { + override fun value(): Any? = valueElement()?.value() + + fun valueElement(): ValueElement<*>? { + return this.findChild>() + } + + override fun valueType(): ValueType = valueElement()?.valueType() ?: ValueType.UNKNOWN +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/AddImportFix.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/AddImportFix.kt index 6531d88b..97cdc392 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/AddImportFix.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/AddImportFix.kt @@ -8,21 +8,18 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile import com.intellij.psi.stubs.StubIndex -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ReferenceElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver import io.kanro.idea.plugin.protobuf.lang.util.matchesSuffix class AddImportFix( - private val host: ProtobufSymbolReferenceHost, -) : BaseIntentionAction(), - HintAction, - HighPriorityAction { + private val host: ReferenceElement, +) : BaseIntentionAction(), HintAction, HighPriorityAction { private lateinit var elements: Array - private lateinit var hover: ProtobufSymbolReferenceHover override fun getFamilyName(): String { return "Import" @@ -34,25 +31,24 @@ class AddImportFix( file: PsiFile, ): Boolean { if (!host.isValid) return false - hover = host.referencesHover() ?: return false - val parts = hover.symbolParts() - val name = hover.symbol() - if (hover.absolutely() || parts.size > 1) { + if (host.containingFile.originalFile !is ProtobufFile) return false + val symbol = host.symbol() ?: return false + if (symbol.componentCount > 1) { this.elements = StubIndex.getElements( ShortNameIndex.key, - name.lastComponent!!, + symbol.lastComponent!!, project, ProtobufRootResolver.searchScope(host), ProtobufElement::class.java, ).filterIsInstance().filter { - it.qualifiedName()?.matchesSuffix(name) == true + it.qualifiedName()?.matchesSuffix(symbol) == true }.toTypedArray() } else { this.elements = StubIndex.getElements( ShortNameIndex.key, - name.lastComponent!!, + symbol.lastComponent!!, project, ProtobufRootResolver.searchScope(host), ProtobufElement::class.java, @@ -68,29 +64,28 @@ class AddImportFix( file: PsiFile?, ) { CommandProcessor.getInstance().runUndoTransparentAction { - createAction(project, editor, host, hover, elements).execute() + createAction(project, editor, elements).execute() } } private fun createAction( project: Project, editor: Editor, - host: ProtobufSymbolReferenceHost, - hover: ProtobufSymbolReferenceHover, elements: Array, ): ProtobufAddImportAction { - return ProtobufAddImportAction(project, editor, host, hover, elements) + return ProtobufAddImportAction(project, editor, host, elements) } override fun getText(): String { + val protobufFile = host.containingFile.originalFile as ProtobufFile return if (elements.size == 1) { - "Import from \"${elements[0].importPath(host.file())}\"" + "Import from \"${elements[0].importPath(protobufFile)}\"" } else { - "Import from \"${elements[0].importPath(host.file())}\" or other ${elements.size - 1} files" + "Import from \"${elements[0].importPath(protobufFile)}\" or other ${elements.size - 1} files" } } override fun showHint(editor: Editor): Boolean { - return createAction(editor.project ?: return false, editor, host, hover, elements).showHint() + return createAction(editor.project ?: return false, editor, elements).showHint() } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/OptimizeImportsFix.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/OptimizeImportsFix.kt index bf0f1f51..167736e5 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/OptimizeImportsFix.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/OptimizeImportsFix.kt @@ -4,8 +4,8 @@ import com.intellij.codeInsight.intention.impl.BaseIntentionAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile -import io.kanro.idea.plugin.protobuf.lang.formatter.ProtobufImportOptimizer -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.formatter.optimizeImportProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile class OptimizeImportsFix : BaseIntentionAction() { init { @@ -30,6 +30,6 @@ class OptimizeImportsFix : BaseIntentionAction() { file: PsiFile?, ) { if (file !is ProtobufFile) return - ProtobufImportOptimizer.processFile(file) + optimizeImportProtobufFile(file) } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/ProtobufAddImportAction.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/ProtobufAddImportAction.kt index 01733073..d3c24373 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/ProtobufAddImportAction.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/ProtobufAddImportAction.kt @@ -11,10 +11,12 @@ import com.intellij.openapi.ui.popup.ListPopupStep import com.intellij.openapi.ui.popup.PopupStep import com.intellij.openapi.ui.popup.util.BaseListPopupStep import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.util.parentOfType import com.intellij.ui.popup.list.ListPopupImpl -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ReferenceElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope import io.kanro.idea.plugin.protobuf.lang.util.removeCommonPrefix import java.awt.BorderLayout import javax.swing.JPanel @@ -23,8 +25,7 @@ import javax.swing.ListCellRenderer class ProtobufAddImportAction( private val project: Project, private val editor: Editor, - private val host: ProtobufSymbolReferenceHost, - private val hover: ProtobufSymbolReferenceHover?, + private val host: ReferenceElement, private val elements: Array, ) : QuestionAction { private fun hintText(): String { @@ -106,24 +107,24 @@ class ProtobufAddImportAction( project, { ApplicationManager.getApplication().runWriteAction { - val file = host.file() - val targetName = name.removeCommonPrefix(file.scope()).toString() + val currentScope = host.parentOfType() ?: return@runWriteAction + val file = currentScope.file() + val targetName = name.removeCommonPrefix(currentScope.scope()) file.addImport(element) - if (hover != null) { - val parts = hover.symbolParts() - if (!hover.absolutely() && parts.size == 1) { - if (parts.first().value != targetName) { - hover.rename(targetName) - } + val symbol = host.symbol() + if (symbol != null) { + val parts = symbol.components + if (parts.size == 1) { + host.rename(targetName) } } PsiDocumentManager.getInstance(project).commitAllDocuments() } }, - "Import ${element.importPath(host.file())}", + "Import ${element.importPath(host.containingFile.originalFile as ProtobufFile)}", null, ) return true diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/RenameFix.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/RenameFix.kt index 43b5c386..d5f394af 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/RenameFix.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/RenameFix.kt @@ -7,8 +7,8 @@ import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement import com.intellij.psi.util.parentOfType import com.intellij.refactoring.RefactoringFactory -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition class RenameFix(private val newName: String) : PsiElementBaseIntentionAction() { init { @@ -33,7 +33,7 @@ class RenameFix(private val newName: String) : PsiElementBaseIntentionAction() { element: PsiElement, ) { DumbService.getInstance(project).smartInvokeLater { - val namedElement = element.parentOfType(true) ?: return@smartInvokeLater + val namedElement = element.parentOfType(true) ?: return@smartInvokeLater RefactoringFactory.getInstance(project).createRename(namedElement, newName).run() } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufBuiltInOptionReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufBuiltInOptionReference.kt deleted file mode 100644 index 015d3a61..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufBuiltInOptionReference.kt +++ /dev/null @@ -1,108 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.reference - -import com.intellij.codeInsight.lookup.LookupElementBuilder -import com.intellij.openapi.util.TextRange -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiManager -import com.intellij.psi.PsiReferenceBase -import com.intellij.psi.util.QualifiedName -import com.intellij.psi.util.parentOfType -import com.intellij.util.ArrayUtilRt -import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufBuiltInOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.isFieldDefaultOption -import io.kanro.idea.plugin.protobuf.lang.psi.isFieldJsonNameOption -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.realItems -import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver -import io.kanro.idea.plugin.protobuf.lang.support.Options - -class ProtobufBuiltInOptionReference(name: ProtobufBuiltInOptionName) : - PsiReferenceBase(name) { - private fun optionType(): String? { - val owner = element.parentOfType() ?: return null - return when (owner) { - is ProtobufFile -> Options.FILE_OPTIONS.messageName - is ProtobufMessageDefinition, is ProtobufGroupDefinition -> Options.MESSAGE_OPTIONS.messageName - is ProtobufFieldDefinition, is ProtobufMapFieldDefinition -> Options.FIELD_OPTIONS.messageName - is ProtobufOneofDefinition -> Options.ONEOF_OPTIONS.messageName - is ProtobufEnumDefinition -> Options.ENUM_OPTIONS.messageName - is ProtobufEnumValueDefinition -> Options.ENUM_VALUE_OPTIONS.messageName - is ProtobufServiceDefinition -> Options.SERVICE_OPTIONS.messageName - is ProtobufRpcDefinition -> Options.METHOD_OPTIONS.messageName - else -> null - } - } - - override fun resolve(): PsiElement? { - if (element.isFieldJsonNameOption()) { - return ProtobufSymbolResolver.resolveInScope( - descriptor() ?: return null, - QualifiedName.fromComponents("FieldDescriptorProto", "json_name"), - ) - } - if (element.isFieldDefaultOption()) { - return element.parentOfType() as? ProtobufFieldLike - } - - return ProtobufSymbolResolver.resolveInScope( - descriptor() ?: return null, - QualifiedName.fromComponents(optionType(), element.text), - ) - } - - override fun getVariants(): Array { - val type = optionType() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY - val descriptor = descriptor() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY - val message = - ProtobufSymbolResolver.resolveInScope( - descriptor, - QualifiedName.fromComponents(type), - ) as? ProtobufMessageDefinition ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY - val fields: MutableList = - message.realItems().mapNotNull { - if (it !is ProtobufFieldDefinition) return@mapNotNull null - (it as? ProtobufLookupItem)?.lookup()?.withInsertHandler(optionInsertHandler) - }.toMutableList() - if (Options.FIELD_OPTIONS.messageName == type) { - fields += - LookupElementBuilder.create("default") - .withTypeText("option") - .withIcon(ProtobufIcons.FIELD) - .withInsertHandler(optionInsertHandler) - fields += - LookupElementBuilder.create("json_name") - .withTypeText("option") - .withIcon(ProtobufIcons.FIELD) - .withInsertHandler(optionInsertHandler) - } - return fields.toTypedArray() - } - - override fun calculateDefaultRangeInElement(): TextRange { - return element.identifierLiteral!!.textRangeInParent - } - - private fun descriptor(): ProtobufFile? { - return ProtobufRootResolver.findFile("google/protobuf/descriptor.proto", element).firstOrNull()?.let { - PsiManager.getInstance(element.project).findFile(it) as? ProtobufFile - } - } - - companion object { - private val optionInsertHandler = SmartInsertHandler(" = ") - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufFieldReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufFieldReference.kt deleted file mode 100644 index a8fff98f..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufFieldReference.kt +++ /dev/null @@ -1,55 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.reference - -import com.intellij.openapi.util.TextRange -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiReferenceBase -import com.intellij.psi.impl.source.tree.LeafElement -import com.intellij.util.ArrayUtilRt -import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.message -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.realItems - -class ProtobufFieldReference(field: ProtobufFieldName) : - PsiReferenceBase(field) { - override fun resolve(): PsiElement? { - val message = element.message() ?: return null - message.items { - if (it.fieldName() == element.text) { - return it - } - } - return null - } - - override fun calculateDefaultRangeInElement(): TextRange { - return TextRange.create(0, element.textLength) - } - - override fun getVariants(): Array { - val message = element.message() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY - return message.realItems().mapNotNull { - (it as? ProtobufFieldLike)?.lookup()?.let { - when (element.parent) { - is ProtobufFieldAssign -> it.withInsertHandler(fieldInsertHandler) - is ProtobufOptionName -> it.withInsertHandler(optionInsertHandler) - else -> it - } - } - }.toTypedArray() - } - - override fun handleElementRename(newElementName: String): PsiElement { - (element.identifierLiteral?.node as? LeafElement)?.replaceWithText(newElementName) - return element - } - - companion object { - private val fieldInsertHandler = SmartInsertHandler(": ") - private val optionInsertHandler = SmartInsertHandler(" = ") - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufGotoSymbolContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufGotoSymbolContributor.kt index 5af85c00..1d5c0eea 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufGotoSymbolContributor.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufGotoSymbolContributor.kt @@ -5,8 +5,8 @@ import com.intellij.navigation.NavigationItem import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.stubs.StubIndex -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex class ProtobufGotoSymbolContributor : ChooseByNameContributor { override fun getNames( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufRefactoringSupportProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufRefactoringSupportProvider.kt index 5284c171..773658b0 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufRefactoringSupportProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufRefactoringSupportProvider.kt @@ -2,13 +2,13 @@ package io.kanro.idea.plugin.protobuf.lang.reference import com.intellij.lang.refactoring.RefactoringSupportProvider import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement class ProtobufRefactoringSupportProvider : RefactoringSupportProvider() { override fun isMemberInplaceRenameAvailable( elementToRename: PsiElement, context: PsiElement?, ): Boolean { - return elementToRename is ProtobufNamedElement + return elementToRename is NamedElement } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolFilters.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolFilters.kt index a48b3ed0..61db2a94 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolFilters.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolFilters.kt @@ -2,111 +2,69 @@ package io.kanro.idea.plugin.protobuf.lang.reference import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiElementFilter +import com.intellij.psi.util.QualifiedName import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendBody -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendBody +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName import io.kanro.idea.plugin.protobuf.lang.support.Options -import io.kanro.idea.plugin.protobuf.lang.util.and import io.kanro.idea.plugin.protobuf.lang.util.or object ProtobufSymbolFilters { - val packagePart = + val packageName = PsiElementFilter { it is ProtobufPackageName } - fun extensionOptionName(owner: ProtobufOptionOwner?): PsiElementFilter { - return when (owner) { - is ProtobufFile -> fileExtensionOptionName - is ProtobufMessageDefinition, is ProtobufGroupDefinition -> messageExtensionOptionName - is ProtobufFieldDefinition, is ProtobufMapFieldDefinition -> fieldExtensionOptionName - is ProtobufOneofDefinition -> oneofExtensionOptionName - is ProtobufEnumDefinition -> enumExtensionOptionName - is ProtobufEnumValueDefinition -> enumValueExtensionOptionName - is ProtobufServiceDefinition -> serviceExtensionOptionName - is ProtobufRpcDefinition -> methodExtensionOptionName - else -> extensionOptionName + val fieldType = + PsiElementFilter { + it is ProtobufEnumDefinition || it is ProtobufMessageDefinition } - } - private val extensionOptionName = + val message = PsiElementFilter { - (it is ProtobufFieldDefinition || it is ProtobufGroupDefinition) && it.parent is ProtobufExtendBody + it is ProtobufMessageDefinition } - private val fileExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.FILE_OPTIONS) - private val messageExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.MESSAGE_OPTIONS) - private val fieldExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.FIELD_OPTIONS) - private val oneofExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.ONEOF_OPTIONS) - private val enumExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.ENUM_OPTIONS) - private val enumValueExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.ENUM_VALUE_OPTIONS) - private val serviceExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.SERVICE_OPTIONS) - private val methodExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.METHOD_OPTIONS) - fun extensionOptionNameVariants(owner: ProtobufOptionOwner?): PsiElementFilter { - return when (owner) { - is ProtobufFile -> fileExtensionOptionNameVariants - is ProtobufMessageDefinition, is ProtobufGroupDefinition -> messageExtensionOptionNameVariants - is ProtobufFieldDefinition, is ProtobufMapFieldDefinition -> fieldExtensionOptionNameVariants - is ProtobufOneofDefinition -> oneofExtensionOptionNameVariants - is ProtobufEnumDefinition -> enumExtensionOptionNameVariants - is ProtobufEnumValueDefinition -> enumValueExtensionOptionNameVariants - is ProtobufServiceDefinition -> serviceExtensionOptionNameVariants - is ProtobufRpcDefinition -> methodExtensionOptionNameVariants - else -> extensionOptionNameVariants + val extendMessage = + PsiElementFilter { + it is ProtobufMessageDefinition || it is ProtobufGroupDefinition } - } - private val extensionOptionNameVariants = extensionOptionName or packagePart - private val fileExtensionOptionNameVariants = fileExtensionOptionName or packagePart - private val messageExtensionOptionNameVariants = messageExtensionOptionName or packagePart - private val fieldExtensionOptionNameVariants = fieldExtensionOptionName or packagePart - private val oneofExtensionOptionNameVariants = oneofExtensionOptionName or packagePart - private val enumExtensionOptionNameVariants = enumExtensionOptionName or packagePart - private val enumValueExtensionOptionNameVariants = enumValueExtensionOptionName or packagePart - private val serviceExtensionOptionNameVariants = serviceExtensionOptionName or packagePart - private val methodExtensionOptionNameVariants = methodExtensionOptionName or packagePart + val messageTypeName = message or packageName - val fieldTypeName = + val field = PsiElementFilter { - it is ProtobufEnumDefinition || it is ProtobufMessageDefinition + it is ProtobufFieldDefinition || it is ProtobufGroupDefinition } - val fieldTypeNameVariants = packagePart or fieldTypeName - - val rpcTypeName = + val extensionField = PsiElementFilter { - it is ProtobufMessageDefinition + (it is ProtobufFieldDefinition || it is ProtobufGroupDefinition) && it.parent is ProtobufExtendBody } - val rpcTypeNameVariants = packagePart or rpcTypeName + fun extensionField(message: QualifiedName): PsiElementFilter = MessageExtensionFilter(message) - val extendTypeName = - PsiElementFilter { - it is ProtobufMessageDefinition - } + fun extensionField(option: Options): PsiElementFilter = MessageExtensionFilter(option.qualifiedName) + + val extensionFieldQualifiedName = extensionField or packageName + + fun extensionFieldQualifiedName(message: QualifiedName) = extensionField(message) or packageName - val extendTypeNameVariants = packagePart or extendTypeName + fun extensionFieldQualifiedName(option: Options) = extensionField(option) or packageName val alwaysFalse = PsiElementFilter { false } - private class TargetOptionFilter(private val option: Options) : PsiElementFilter { + private class MessageExtensionFilter(private val message: QualifiedName) : PsiElementFilter { override fun isAccepted(element: PsiElement): Boolean { val extend = element.parentOfType() ?: return false val name = - (extend.typeName?.reference?.resolve() as? ProtobufMessageDefinition)?.qualifiedName() ?: return false - return name == option.qualifiedName + (extend.typeName?.resolve() as? ProtobufMessageDefinition)?.qualifiedName() ?: return false + return name == message } } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolReferenceContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolReferenceContributor.kt index bbc73c5e..14af4ed5 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolReferenceContributor.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolReferenceContributor.kt @@ -1,55 +1,43 @@ package io.kanro.idea.plugin.protobuf.lang.reference -import com.intellij.patterns.PlatformPatterns -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiReference -import com.intellij.psi.PsiReferenceContributor -import com.intellij.psi.PsiReferenceProvider -import com.intellij.psi.PsiReferenceRegistrar -import com.intellij.psi.util.CachedValueProvider -import com.intellij.psi.util.CachedValuesManager -import com.intellij.psi.util.PsiModificationTracker -import com.intellij.util.ProcessingContext -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost -import io.kanro.idea.plugin.protobuf.lang.support.BuiltInType - -class ProtobufSymbolReferenceContributor : PsiReferenceContributor() { - override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { - registrar.registerReferenceProvider( - PlatformPatterns.psiElement(ProtobufSymbolReferenceHost::class.java), - ProtobufSymbolReferenceProvider, - ) - } -} - -object ProtobufSymbolReferenceProvider : PsiReferenceProvider() { - override fun getReferencesByElement( - element: PsiElement, - context: ProcessingContext, - ): Array { - element as ProtobufSymbolReferenceHost - return CachedValuesManager.getCachedValue(element) { - val hover = - element.referencesHover() - ?: return@getCachedValue CachedValueProvider.Result.create( - PsiReference.EMPTY_ARRAY, - PsiModificationTracker.MODIFICATION_COUNT, - ) - val symbol = hover.symbol() - if (!hover.absolutely() && symbol.componentCount == 1 && BuiltInType.isBuiltInType(symbol.firstComponent!!)) { - return@getCachedValue CachedValueProvider.Result.create( - PsiReference.EMPTY_ARRAY, - PsiModificationTracker.MODIFICATION_COUNT, - ) - } - var reference: ProtobufTypeNameReference? = null - val result = - symbol.components.reversed().mapIndexed { index, name -> - ProtobufTypeNameReference(element, hover, symbol.componentCount - 1 - index, reference).apply { - reference = this - } - }.toTypedArray() - CachedValueProvider.Result.create(result, PsiModificationTracker.MODIFICATION_COUNT) - } - } -} +// +// class ProtobufSymbolReferenceContributor : PsiReferenceContributor() { +// override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { +// registrar.registerReferenceProvider( +// PlatformPatterns.psiElement(ProtobufSymbolReferenceHost::class.java), +// ProtobufSymbolReferenceProvider, +// ) +// } +// } +// +// object ProtobufSymbolReferenceProvider : PsiReferenceProvider() { +// override fun getReferencesByElement( +// element: PsiElement, +// context: ProcessingContext, +// ): Array { +// element as ProtobufSymbolReferenceHost +// return CachedValuesManager.getCachedValue(element) { +// val hover = +// element.referencesHover() +// ?: return@getCachedValue CachedValueProvider.Result.create( +// PsiReference.EMPTY_ARRAY, +// PsiModificationTracker.MODIFICATION_COUNT, +// ) +// val symbol = hover.symbol() +// if (!hover.absolutely() && symbol.componentCount == 1 && BuiltInType.isBuiltInType(symbol.firstComponent!!)) { +// return@getCachedValue CachedValueProvider.Result.create( +// PsiReference.EMPTY_ARRAY, +// PsiModificationTracker.MODIFICATION_COUNT, +// ) +// } +// var reference: ProtobufTypeNameReference? = null +// val result = +// symbol.components.reversed().mapIndexed { index, name -> +// ProtobufTypeNameReference(element, hover, symbol.componentCount - 1 - index, reference).apply { +// reference = this +// } +// }.toTypedArray() +// CachedValueProvider.Result.create(result, PsiModificationTracker.MODIFICATION_COUNT) +// } +// } +// } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolResolver.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolResolver.kt index 5858775b..1daf0cb1 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolResolver.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolResolver.kt @@ -3,13 +3,14 @@ package io.kanro.idea.plugin.protobuf.lang.reference import com.intellij.psi.util.PsiElementFilter import com.intellij.psi.util.QualifiedName import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope -import io.kanro.idea.plugin.protobuf.lang.psi.public -import io.kanro.idea.plugin.protobuf.lang.psi.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.public +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufMultiNameDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope import io.kanro.idea.plugin.protobuf.lang.util.AnyElement import java.util.Stack @@ -127,7 +128,13 @@ object ProtobufSymbolResolver { filter: PsiElementFilter = AnyElement, ): ProtobufElement? { scope.items { - if (it.name() == symbol.firstComponent) { + val matched = + if (it is ProtobufMultiNameDefinition) { + symbol.firstComponent in it.names() + } else { + it.name() == symbol.firstComponent + } + if (matched) { if (symbol.componentCount == 1) { return it.takeIf { filter.isAccepted(it) } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufTypeNameReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufTypeNameReference.kt deleted file mode 100644 index 2cf6766e..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufTypeNameReference.kt +++ /dev/null @@ -1,196 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.reference - -import com.intellij.codeInsight.completion.CompletionUtilCore -import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.codeInsight.lookup.LookupElementBuilder -import com.intellij.openapi.util.TextRange -import com.intellij.patterns.PlatformPatterns -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiReference -import com.intellij.psi.PsiReferenceBase -import com.intellij.psi.impl.source.resolve.ResolveCache -import com.intellij.psi.stubs.StubIndex -import com.intellij.psi.util.PsiElementFilter -import com.intellij.psi.util.QualifiedName -import com.intellij.psi.util.parentOfType -import com.intellij.util.ArrayUtilRt -import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler -import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtensionOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcIO -import io.kanro.idea.plugin.protobuf.lang.psi.prev -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScopeItem -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ShortNameIndex -import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver -import io.kanro.idea.plugin.protobuf.lang.util.AnyElement -import io.kanro.idea.plugin.protobuf.lang.util.removeCommonPrefix - -class ProtobufTypeNameReference( - element: ProtobufSymbolReferenceHost, - val hover: ProtobufSymbolReferenceHover, - val symbolIndex: Int, - val child: ProtobufTypeNameReference?, -) : PsiReferenceBase(element) { - private object Resolver : ResolveCache.Resolver { - override fun resolve( - ref: PsiReference, - incompleteCode: Boolean, - ): PsiElement? { - ref as ProtobufTypeNameReference - val resolveName = ref.hover.symbol().subQualifiedName(0, ref.symbolIndex + 1) - val filter = - when (ref.element.parent) { - is ProtobufExtensionOptionName -> ProtobufSymbolFilters.extensionOptionNameVariants(ref.element.parentOfType()) - is ProtobufFieldDefinition, - is ProtobufMapFieldDefinition, - -> ProtobufSymbolFilters.fieldTypeNameVariants - is ProtobufRpcIO -> ProtobufSymbolFilters.rpcTypeNameVariants - is ProtobufExtendDefinition -> ProtobufSymbolFilters.extendTypeNameVariants - else -> AnyElement - } - return if (ref.hover.absolutely()) { - ProtobufSymbolResolver.resolveAbsolutely(ref.element, resolveName, filter) - } else { - ProtobufSymbolResolver.resolveRelatively(ref.element, resolveName, filter) - } - } - } - - override fun resolve(): PsiElement? { - when (val childResult = child?.resolve()) { - is ProtobufScopeItem -> { - val owner = childResult.owner() - if (owner is ProtobufFile) { - return owner.packageParts().last() - } - return owner - } - is ProtobufPackageName -> return childResult.prev() - } - - return ResolveCache.getInstance(element.project) - .resolveWithCaching(this, Resolver, false, false) - } - - override fun calculateDefaultRangeInElement(): TextRange { - val part = hover.symbolParts()[symbolIndex] - return TextRange.from( - part.startOffset, - part.value.length, - ) - } - - override fun getVariants(): Array { - val result = mutableListOf() - val addedElements = mutableSetOf() - val filter = element.referencesHover()?.variantFilter() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY - val pattern = element.text - getVariantsInCurrentScope(pattern, filter, result, addedElements) - getVariantsInStubIndex(pattern, filter, result, addedElements) - return result.toTypedArray() - } - - private fun getVariantsInCurrentScope( - pattern: String, - filter: PsiElementFilter, - result: MutableList, - elements: MutableSet, - ) { - val targetName = pattern.substringBeforeLast('.', "").trim('.') - val targetScope = - if (targetName.isEmpty()) { - QualifiedName.fromComponents() - } else { - QualifiedName.fromDottedString(targetName) - } - if (hover.absolutely()) { - ProtobufSymbolResolver.collectAbsolute(element, targetScope, filter) - } else { - ProtobufSymbolResolver.collectRelatively(element, targetScope, filter) - }.forEach { - if (it in elements) return@forEach - result += lookupFor(it, targetScope) ?: return@forEach - elements += it - } - } - - private fun getVariantsInStubIndex( - pattern: String, - filter: PsiElementFilter, - result: MutableList, - elements: MutableSet, - ): Array { - if (pattern.contains('.')) return ArrayUtilRt.EMPTY_OBJECT_ARRAY - if (!pattern.endsWith(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED)) return ArrayUtilRt.EMPTY_OBJECT_ARRAY - val searchName = pattern.substringBefore(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED) - val scope = ProtobufRootResolver.searchScope(element) - val matcher = PlatformPatterns.string().contains(searchName) - val currentScope = element.parentOfType()?.scope() - return StubIndex.getInstance().getAllKeys(ShortNameIndex.key, element.project).asSequence().filter { - matcher.accepts(it) - }.flatMap { - StubIndex.getElements(ShortNameIndex.key, it, element.project, scope, ProtobufElement::class.java) - .asSequence() - }.filter { - filter.isAccepted(it) - }.mapNotNull { - if (it in elements) return@mapNotNull null - result += lookupForStub(it, currentScope) ?: return@mapNotNull null - elements += it - }.toList().toTypedArray() - } - - override fun handleElementRename(newElementName: String): PsiElement { - hover.renamePart(symbolIndex, newElementName) - return element - } - - private fun lookupFor( - element: ProtobufElement, - scope: QualifiedName, - ): LookupElement? { - var builder = (element as? ProtobufLookupItem)?.lookup() ?: return null - builder = builder.withLookupString(scope.append(builder.lookupString).toString()) - if (element is ProtobufPackageName) { - builder = builder.withInsertHandler(packageInsertHandler) - } - return builder - } - - private fun lookupForStub( - element: ProtobufElement, - currentScope: QualifiedName?, - ): LookupElement? { - if (element !is ProtobufDefinition) return null - val qualifiedName = element.qualifiedName() ?: return null - - val targetName = - if (currentScope != null) { - qualifiedName.removeCommonPrefix(currentScope) - } else { - qualifiedName - } - return LookupElementBuilder.create(targetName) - .withLookupString(qualifiedName.lastComponent!!) - .withPresentableText(qualifiedName.lastComponent!!) - .withIcon(element.getIcon(false)) - .withTailText("${element.tailText() ?: ""} (${qualifiedName.removeTail(1)})", true) - .withTypeText(element.type()) - .withInsertHandler(AddImportInsertHandler(element)) - } - - companion object { - private val packageInsertHandler = SmartInsertHandler(".", 0, true) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/support/Options.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/support/Options.kt index 778daf7a..f4817465 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/support/Options.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/support/Options.kt @@ -11,6 +11,7 @@ enum class Options(val messageName: String) { ENUM_VALUE_OPTIONS("EnumValueOptions"), SERVICE_OPTIONS("ServiceOptions"), METHOD_OPTIONS("MethodOptions"), + EXTENSION_RANGE_OPTIONS("ExtensionRangeOptions"), ; val qualifiedName by lazy { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufDocumentationProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufDocumentationProvider.kt index 3f16e228..8073f994 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufDocumentationProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufDocumentationProvider.kt @@ -6,10 +6,10 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiManager import com.intellij.psi.stubs.StubIndex -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocument -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocumented -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver @@ -21,8 +21,8 @@ class ProtobufDocumentationProvider : DocumentationProvider { element: PsiElement?, originalElement: PsiElement?, ): String? { - (originalElement as? ProtobufDocumented)?.navigateInfo()?.let { return it } - (element as? ProtobufDocumented)?.navigateInfo()?.let { return it } + (originalElement as? DocumentOwner)?.navigateInfo()?.let { return it } + (element as? DocumentOwner)?.navigateInfo()?.let { return it } return null } @@ -30,8 +30,8 @@ class ProtobufDocumentationProvider : DocumentationProvider { element: PsiElement?, originalElement: PsiElement?, ): String? { - (originalElement as? ProtobufDocumented)?.document()?.let { return it } - (element as? ProtobufDocumented)?.document()?.let { return it } + (originalElement as? DocumentOwner)?.document()?.let { return it } + (element as? DocumentOwner)?.document()?.let { return it } return null } @@ -39,8 +39,8 @@ class ProtobufDocumentationProvider : DocumentationProvider { element: PsiElement, originalElement: PsiElement?, ): String? { - (originalElement as? ProtobufDocumented)?.hoverDocument()?.let { return it } - (element as? ProtobufDocumented)?.hoverDocument()?.let { return it } + (originalElement as? DocumentOwner)?.hoverDocument()?.let { return it } + (element as? DocumentOwner)?.hoverDocument()?.let { return it } return null } @@ -60,14 +60,14 @@ class ProtobufDocumentationProvider : DocumentationProvider { } override fun generateRenderedDoc(comment: PsiDocCommentBase): String? { - return (comment as? ProtobufDocument)?.render() + return (comment as? DocumentElement)?.render() } override fun collectDocComments( file: PsiFile, sink: Consumer, ) { - file.walkChildren { + file.walkChildren { if (it.owner != null) { sink.accept(it) } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufElementDescriptionProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufElementDescriptionProvider.kt index 888e5547..e811430e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufElementDescriptionProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufElementDescriptionProvider.kt @@ -6,7 +6,7 @@ import com.intellij.psi.PsiElement import com.intellij.usageView.UsageViewLongNameLocation import com.intellij.usageView.UsageViewShortNameLocation import com.intellij.usageView.UsageViewTypeLocation -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition class ProtobufElementDescriptionProvider : ElementDescriptionProvider { override fun getElementDescription( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufIconProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufIconProvider.kt index b2651f28..612ca202 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufIconProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufIconProvider.kt @@ -3,18 +3,18 @@ package io.kanro.idea.plugin.protobuf.lang.ui import com.intellij.ide.IconProvider import com.intellij.psi.PsiElement import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition import javax.swing.Icon class ProtobufIconProvider : IconProvider() { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufStructureViewFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufStructureViewFactory.kt index d99403eb..30b5c1cc 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufStructureViewFactory.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufStructureViewFactory.kt @@ -12,9 +12,9 @@ import com.intellij.navigation.ItemPresentation import com.intellij.openapi.editor.Editor import com.intellij.psi.NavigatablePsiElement import com.intellij.psi.PsiFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScopeItemContainer +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItemContainer class ProtobufStructureViewFactory : PsiStructureViewFactory { override fun getStructureViewBuilder(psiFile: PsiFile): StructureViewBuilder? { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufFindUsageProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufFindUsageProvider.kt index d30e543d..48d3dc8e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufFindUsageProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufFindUsageProvider.kt @@ -8,8 +8,8 @@ import com.intellij.psi.PsiElement import com.intellij.psi.tree.TokenSet import io.kanro.idea.plugin.protobuf.lang.ProtobufParserDefinition import io.kanro.idea.plugin.protobuf.lang.lexer.ProtobufLexer -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufFindUsageProvider : FindUsagesProvider { override fun getWordsScanner(): WordsScanner { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufUsageTypeProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufUsageTypeProvider.kt index 43de6e2b..aa8bdd1a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufUsageTypeProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufUsageTypeProvider.kt @@ -4,37 +4,34 @@ import com.intellij.psi.PsiElement import com.intellij.usages.impl.rules.UsageType import com.intellij.usages.impl.rules.UsageTypeProvider import io.kanro.idea.plugin.protobuf.ProtobufBundle -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufBuiltInOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtensionOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcIO -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufSymbolName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcIO +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFieldName class ProtobufUsageTypeProvider : UsageTypeProvider { override fun getUsageType(element: PsiElement): UsageType? { return when (element) { - is ProtobufFieldName -> ASSIGN_USAGE_TYPE - is ProtobufBuiltInOptionName -> OPTION_USAGE_TYPE - is ProtobufSymbolName -> - when (element.parent.parent) { + is ProtoTextFieldName -> ASSIGN_USAGE_TYPE + is ProtobufOptionName -> OPTION_USAGE_TYPE + is ProtobufTypeName -> + when (element.parent) { is ProtobufRpcIO -> METHOD_PARAMETER_USAGE_TYPE - is ProtobufExtensionOptionName -> OPTION_USAGE_TYPE is ProtobufFieldDefinition, is ProtobufMapFieldDefinition -> FIELD_DECLARATION_USAGE_TYPE is ProtobufExtendDefinition -> EXTEND_DECLARATION_USAGE_TYPE else -> null } + else -> null } } - - companion object { - val FIELD_DECLARATION_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.field.declaration")) - val METHOD_PARAMETER_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.method.parameter")) - val EXTEND_DECLARATION_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.extend.declaration")) - val OPTION_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.option")) - val ASSIGN_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.assign")) - } } + +val FIELD_DECLARATION_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.field.declaration")) +val METHOD_PARAMETER_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.method.parameter")) +val EXTEND_DECLARATION_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.extend.declaration")) +val OPTION_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.option")) +val ASSIGN_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.assign")) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/CommonMark.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/CommonMark.kt index 5ddfdfa0..ff1dbd0b 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/CommonMark.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/CommonMark.kt @@ -1,7 +1,7 @@ package io.kanro.idea.plugin.protobuf.lang.util import com.intellij.codeInsight.documentation.DocumentationManagerProtocol -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement import org.commonmark.ext.autolink.AutolinkExtension import org.commonmark.ext.gfm.tables.TablesExtension import org.commonmark.internal.InlineParserImpl diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcEndpointsProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcEndpointsProvider.kt index cc7fe265..01f4410c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcEndpointsProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcEndpointsProvider.kt @@ -19,7 +19,7 @@ import com.intellij.psi.search.GlobalSearchScope import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.lang.ProtobufFileType import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile import io.kanro.idea.plugin.protobuf.microservices.model.ProtobufRpcModel import io.kanro.idea.plugin.protobuf.microservices.model.ProtobufServiceModel @@ -49,7 +49,7 @@ class GrpcEndpointsProvider : EndpointsUrlTargetProvider { return when (filter) { is SearchScopeEndpointsFilter -> { - val scope = filter.searchScope + val scope = filter.contentSearchScope FileTypeIndex.getFiles(ProtobufFileType.INSTANCE, scope).flatMap { val psi = PsiManager.getInstance(project).findFile(it) as? ProtobufFile diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcUrlTargetInfo.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcUrlTargetInfo.kt index fa07bbd0..be4fc7fd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcUrlTargetInfo.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcUrlTargetInfo.kt @@ -5,7 +5,7 @@ import com.intellij.microservices.url.UrlPath import com.intellij.microservices.url.UrlTargetInfo import com.intellij.psi.PsiElement import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition import javax.swing.Icon @Suppress("UnstableApiUsage") diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufRpcModel.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufRpcModel.kt index b87f8205..bc7f2efa 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufRpcModel.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufRpcModel.kt @@ -1,7 +1,7 @@ package io.kanro.idea.plugin.protobuf.microservices.model import com.intellij.psi.SmartPsiElementPointer -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition class ProtobufRpcModel(private val pointer: SmartPsiElementPointer) { fun getPsi(): ProtobufRpcDefinition? { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufServiceModel.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufServiceModel.kt index 1ed61ba2..1e14bc1b 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufServiceModel.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufServiceModel.kt @@ -2,8 +2,8 @@ package io.kanro.idea.plugin.protobuf.microservices.model import com.intellij.psi.SmartPointerManager import com.intellij.psi.SmartPsiElementPointer -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class ProtobufServiceModel(private val pointer: SmartPsiElementPointer) { fun getMethods(): List { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Extensions.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Extensions.kt index 35a51c35..640dd7de 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Extensions.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Extensions.kt @@ -9,12 +9,12 @@ import com.intellij.psi.search.GlobalSearchScope import io.kanro.idea.plugin.protobuf.java.findJavaClass import io.kanro.idea.plugin.protobuf.java.fullClassName import io.kanro.idea.plugin.protobuf.java.getterName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike fun ProtobufMessageDefinition.toClass(): PsiClass? { return findJavaClass(fullClassName()) @@ -56,6 +56,7 @@ fun ProtobufFieldLike.toGetters(): Array { is ProtobufMessageDefinition -> owner.toMutableClass()?.findMethodsByName(getterName(), true) ?: PsiMethod.EMPTY_ARRAY + else -> PsiMethod.EMPTY_ARRAY } } @@ -65,6 +66,7 @@ fun ProtobufFieldLike.toSetters(): Array { is ProtobufMessageDefinition -> owner.toMutableClass()?.findMethodsByName(getterName(), true) ?: PsiMethod.EMPTY_ARRAY + else -> PsiMethod.EMPTY_ARRAY } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Names.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Names.kt index 0596344f..f502253a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Names.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Names.kt @@ -3,20 +3,19 @@ package io.kanro.idea.plugin.protobuf.sisyphus import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.java.javaPackage import io.kanro.idea.plugin.protobuf.java.jsonName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumValueStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufFieldLikeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumValueStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufFieldLikeStub import io.kanro.idea.plugin.protobuf.lang.util.toQualifiedName import io.kanro.idea.plugin.protobuf.string.toCamelCase import io.kanro.idea.plugin.protobuf.string.toScreamingSnakeCase @@ -25,7 +24,7 @@ fun ProtobufFile.fullPackageName(): QualifiedName? { return javaPackage()?.toQualifiedName() ?: scope() } -fun ProtobufFileStub.fullPackageName(): QualifiedName? { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.fullPackageName(): QualifiedName? { return javaPackage()?.toQualifiedName() ?: scope() } @@ -33,7 +32,7 @@ fun ProtobufFile.fullInternalPackageName(): QualifiedName { return fullPackageName()?.append("internal") ?: QualifiedName.fromComponents("internal") } -fun ProtobufFileStub.fullInternalPackageName(): QualifiedName { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.fullInternalPackageName(): QualifiedName { return fullPackageName()?.append("internal") ?: QualifiedName.fromComponents("internal") } @@ -60,6 +59,7 @@ fun ProtobufMessageDefinition.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } @@ -71,6 +71,7 @@ fun ProtobufMessageStub.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } @@ -81,6 +82,7 @@ fun ProtobufMessageDefinition.fullMutableClassName(): QualifiedName? { is ProtobufMessageDefinition -> owner.fullClassName()?.append(mutableClassName()) ?: QualifiedName.fromComponents(mutableClassName()) + else -> null } } @@ -91,6 +93,7 @@ fun ProtobufMessageStub.fullMutableClassName(): QualifiedName? { is ProtobufMessageDefinition -> owner.fullClassName()?.append(mutableClassName()) ?: QualifiedName.fromComponents(mutableClassName()) + else -> null } } @@ -166,6 +169,7 @@ fun ProtobufEnumDefinition.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } @@ -177,6 +181,7 @@ fun ProtobufEnumStub.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusFindUsageFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusFindUsageFactory.kt index 7536b047..8b67523d 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusFindUsageFactory.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusFindUsageFactory.kt @@ -3,13 +3,13 @@ package io.kanro.idea.plugin.protobuf.sisyphus import com.intellij.find.findUsages.FindUsagesHandler import com.intellij.find.findUsages.FindUsagesHandlerFactory import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike class SisyphusFindUsageFactory : FindUsagesHandlerFactory() { override fun canFindUsages(element: PsiElement): Boolean { @@ -28,30 +28,36 @@ class SisyphusFindUsageFactory : FindUsagesHandlerFactory() { is ProtobufMessageDefinition -> { ProtoDefinitionFindUsage(element, listOfNotNull(element.toClass()).toTypedArray()) } + is ProtobufEnumDefinition -> { ProtoDefinitionFindUsage(element, listOfNotNull(element.toClass()).toTypedArray()) } + is ProtobufServiceDefinition -> { ProtoDefinitionFindUsage( element, listOfNotNull(element.toClass(), element.toClientClass()).toTypedArray(), ) } + is ProtobufEnumValueDefinition -> { ProtoDefinitionFindUsage(element, listOfNotNull(element.toEnumConstant()).toTypedArray()) } + is ProtobufRpcDefinition -> { ProtoDefinitionFindUsage( element, listOfNotNull(element.toMethod(), element.toClientMethod()).toTypedArray(), ) } + is ProtobufFieldLike -> { ProtoDefinitionFindUsage( element, (element.toGetters() + element.toSetters()) as Array, ) } + else -> null } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusIndexProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusIndexProvider.kt index 6b61c347..b6942ea3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusIndexProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusIndexProvider.kt @@ -1,14 +1,13 @@ package io.kanro.idea.plugin.protobuf.sisyphus import com.intellij.psi.stubs.IndexSink -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufIndexProvider -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufIndexProvider +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub class SisyphusIndexProvider : ProtobufIndexProvider { override fun buildIndex( - stub: ProtobufStub<*>, + stub: io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub<*>, sink: IndexSink, ) { when (stub) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusKotlinLineMarkerProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusKotlinLineMarkerProvider.kt index 4ac814bd..c138bb77 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusKotlinLineMarkerProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusKotlinLineMarkerProvider.kt @@ -8,10 +8,10 @@ import com.intellij.psi.stubs.StubIndex import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition import io.kanro.idea.plugin.protobuf.lang.psi.firstLeaf -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.uast.UClass @@ -35,6 +35,7 @@ class SisyphusKotlinLineMarkerProvider : RelatedItemLineMarkerProvider() { .setTooltipText("Implementing") result.add(builder.createLineMarkerInfo(element.firstLeaf())) } + is UMethod -> { val method = findMethodProtobufDefinition(parent) ?: return val builder: NavigationGutterIconBuilder = diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusNameIndex.kt index d3110eba..409d100c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.sisyphus import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class SisyphusNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusProtobufLineMarkerProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusProtobufLineMarkerProvider.kt index 942666a3..ae0c65c6 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusProtobufLineMarkerProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusProtobufLineMarkerProvider.kt @@ -7,9 +7,9 @@ import com.intellij.psi.PsiElement import com.intellij.psi.search.searches.DirectClassInheritorsSearch import com.intellij.psi.search.searches.OverridingMethodsSearch import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIdentifier -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIdentifier +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class SisyphusProtobufLineMarkerProvider : RelatedItemLineMarkerProvider() { override fun collectNavigationMarkers( @@ -28,6 +28,7 @@ class SisyphusProtobufLineMarkerProvider : RelatedItemLineMarkerProvider() { .setTooltipText("Implemented") result.add(builder.createLineMarkerInfo(element.identifierLiteral ?: element)) } + is ProtobufServiceDefinition -> { val clazz = owner.toClass() ?: return val apis = DirectClassInheritorsSearch.search(clazz).findAll().toList() diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/Util.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/Util.kt index 0b494e5b..4749c468 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/Util.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/Util.kt @@ -71,6 +71,7 @@ fun CharSequence.lineCommentRanges(): List { start = pos } } + else -> { start = pos pos++ @@ -85,6 +86,7 @@ fun CharSequence.lineCommentRanges(): List { } start = null } + else -> { pos++ } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/case/CommonWordSplitter.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/case/CommonWordSplitter.kt index 83a39763..bc998cdc 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/case/CommonWordSplitter.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/case/CommonWordSplitter.kt @@ -23,15 +23,19 @@ object CommonWordSplitter : WordSplitter { ch.isDigit() -> { handleDigital(string, pos, stack, result) } + ch.isLowerCase() -> { handleLowerCase(string, pos, stack, result) } + ch.isUpperCase() -> { handleUpperCase(string, pos, stack, result) } + ch.isDelimiter() -> { handleDelimiter(string, pos, stack, result) } + else -> { handleUnknown(string, pos, stack, result) } @@ -55,11 +59,13 @@ object CommonWordSplitter : WordSplitter { digital.append(ch) index++ } + ch.isUpperCase() -> { digital.append(ch) index++ return handleUpperCaseAfterDigital(string, index, stack, digital, result) } + ch.isLowerCase() -> { digital.append(ch) index++ @@ -73,6 +79,7 @@ object CommonWordSplitter : WordSplitter { handleLowerCase(string, index, stack, result) } } + else -> { stack.append(digital) return entryPoint(string, index, stack, result) @@ -96,9 +103,11 @@ object CommonWordSplitter : WordSplitter { stack.append(ch) index++ } + ch.isDigit() -> { return handleDigital(string, index, stack, result) } + else -> { return entryPoint(string, index, stack, result) } @@ -121,6 +130,7 @@ object CommonWordSplitter : WordSplitter { stack.append(ch) index++ } + ch.isLowerCase() -> { val last = stack.last() stack.deleteCharAt(stack.length - 1) @@ -128,9 +138,11 @@ object CommonWordSplitter : WordSplitter { stack.append(last) return handleLowerCase(string, index, stack, result) } + ch.isDigit() -> { return handleDigital(string, index, stack, result) } + else -> { return entryPoint(string, index, stack, result) } @@ -154,6 +166,7 @@ object CommonWordSplitter : WordSplitter { digital.append(ch) index++ } + ch.isLowerCase() -> { val last = digital.last() digital.deleteCharAt(digital.length - 1) @@ -169,6 +182,7 @@ object CommonWordSplitter : WordSplitter { stack.append(last) return handleLowerCase(string, index, stack, result) } + else -> { if (!digital.last().isDigit()) { result.append(stack) @@ -194,6 +208,7 @@ object CommonWordSplitter : WordSplitter { ch.isUpperCase() || ch.isLowerCase() || ch.isDigit() || ch.isDelimiter() -> { return entryPoint(string, index, stack, result) } + else -> { stack.append(ch) index++ @@ -216,6 +231,7 @@ object CommonWordSplitter : WordSplitter { ch.isDelimiter() -> { index++ } + else -> { return entryPoint(string, index, stack, result) } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index ec08fe3b..13585f5c 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -26,15 +26,15 @@ dynamic="true" name="rootProvider"/> + - - @@ -78,9 +76,9 @@ + implementationClass="io.kanro.idea.plugin.protobuf.lang.highlight.ProtobufHighlighter"/> - @@ -135,13 +133,15 @@ + - - - + class="io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes"/> + + + + + + + + + + + + + + + + + + + + - - - - + + + + - + - - - - + + + + - + diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/procedureHttp_dark.svg b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/procedureHttp_dark.svg index 6ba60f08..80050c63 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/procedureHttp_dark.svg +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/procedureHttp_dark.svg @@ -1,6 +1,7 @@ - + @@ -14,7 +15,8 @@ - + diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file.svg b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file.svg new file mode 100644 index 00000000..e76202b2 --- /dev/null +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file_dark.svg b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file_dark.svg new file mode 100644 index 00000000..80050c63 --- /dev/null +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file_dark.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/icon/protobuf_text_file.svg b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/protobuf_text_file.svg new file mode 100644 index 00000000..b0327051 --- /dev/null +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/protobuf_text_file.svg @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/any.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/any.proto index f14a478e..4387d3a0 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/any.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/any.proto @@ -32,12 +32,12 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/anypb"; option java_package = "com.google.protobuf"; option java_outer_classname = "AnyProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // `Any` contains an arbitrary serialized protocol buffer message along with a // URL that describes the type of the serialized message. @@ -63,6 +63,10 @@ option objc_class_prefix = "GPB"; // if (any.is(Foo.class)) { // foo = any.unpack(Foo.class); // } +// // or ... +// if (any.isSameTypeAs(Foo.getDefaultInstance())) { +// foo = any.unpack(Foo.getDefaultInstance()); +// } // // Example 3: Pack and unpack a message in Python. // @@ -93,7 +97,6 @@ option objc_class_prefix = "GPB"; // in the type URL, for example "foo.bar.com/x/y.z" will yield type // name "y.z". // -// // JSON // ==== // The JSON representation of an `Any` value uses the regular @@ -146,7 +149,8 @@ message Any { // // Note: this functionality is not currently available in the official // protobuf release, and it is not used for type URLs beginning with - // type.googleapis.com. + // type.googleapis.com. As of May 2023, there are no widely used type server + // implementations and no plans to implement one. // // Schemes other than `http`, `https` (or the empty scheme) might be // used with implementation specific semantics. diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/api.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/api.proto index 27da82a8..dc4ac4b3 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/api.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/api.proto @@ -35,11 +35,11 @@ package google.protobuf; import "google/protobuf/source_context.proto"; import "google/protobuf/type.proto"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option java_package = "com.google.protobuf"; option java_outer_classname = "ApiProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/apipb"; // Api is a light-weight descriptor for an API Interface. @@ -82,7 +82,6 @@ message Api { // be omitted. Zero major versions must only be used for // experimental, non-GA interfaces. // - // string version = 4; // Source context for the protocol buffer service represented by this @@ -167,7 +166,7 @@ message Method { // The mixin construct implies that all methods in `AccessControl` are // also declared with same name and request/response types in // `Storage`. A documentation generator or annotation processor will -// see the effective `Storage.GetAcl` method after inheriting +// see the effective `Storage.GetAcl` method after inherting // documentation and annotations as follows: // // service Storage { diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/cpp_features.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/cpp_features.proto new file mode 100644 index 00000000..00134599 --- /dev/null +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/cpp_features.proto @@ -0,0 +1,58 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +syntax = "proto2"; + +package pb; + +import "google/protobuf/descriptor.proto"; + +extend google.protobuf.FeatureSet { + optional CppFeatures cpp = 1000; +} + +message CppFeatures { + // Whether or not to treat an enum field as closed. This option is only + // applicable to enum fields, and will be removed in the future. It is + // consistent with the legacy behavior of using proto3 enum types for proto2 + // fields. + optional bool legacy_closed_enum = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + edition_deprecated: EDITION_2023, + deprecation_warning: "The legacy closed enum treatment in C++ is " + "deprecated and is scheduled to be removed in " + "edition 2025. Mark enum type on the enum " + "definitions themselves rather than on fields.", + }, + edition_defaults = {edition: EDITION_PROTO2, value: "true"}, + edition_defaults = {edition: EDITION_PROTO3, value: "false"} + ]; + + enum StringType { + STRING_TYPE_UNKNOWN = 0; + VIEW = 1; + CORD = 2; + STRING = 3; + } + + optional StringType string_type = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "STRING"}, + edition_defaults = {edition: EDITION_2024, value: "VIEW"} + ]; +} diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/descriptor.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/descriptor.proto index 1e276a96..11ec2bf6 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/descriptor.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/descriptor.proto @@ -36,7 +36,6 @@ // A valid .proto file can be translated directly to a FileDescriptorProto // without any other information (e.g. without reading its imports). - syntax = "proto2"; package google.protobuf; @@ -58,6 +57,42 @@ message FileDescriptorSet { repeated FileDescriptorProto file = 1; } +// The full set of known editions. +enum Edition { + // A placeholder for an unknown edition value. + EDITION_UNKNOWN = 0; + + // A placeholder edition for specifying default behaviors *before* a feature + // was first introduced. This is effectively an "infinite past". + EDITION_LEGACY = 900; + + // Legacy syntax "editions". These pre-date editions, but behave much like + // distinct editions. These can't be used to specify the edition of proto + // files, but feature definitions must supply proto2/proto3 defaults for + // backwards compatibility. + EDITION_PROTO2 = 998; + EDITION_PROTO3 = 999; + + // Editions that have been released. The specific values are arbitrary and + // should not be depended on, but they will always be time-ordered for easy + // comparison. + EDITION_2023 = 1000; + EDITION_2024 = 1001; + + // Placeholder editions for testing feature resolution. These should not be + // used or relyed on outside of tests. + EDITION_1_TEST_ONLY = 1; + EDITION_2_TEST_ONLY = 2; + EDITION_99997_TEST_ONLY = 99997; + EDITION_99998_TEST_ONLY = 99998; + EDITION_99999_TEST_ONLY = 99999; + + // Placeholder for specifying unbounded edition support. This should only + // ever be used by plugins that can expect to never require any changes to + // support a new edition. + EDITION_MAX = 0x7FFFFFFF; +} + // Describes a complete .proto file. message FileDescriptorProto { optional string name = 1; // file name, relative to root of source tree @@ -86,8 +121,13 @@ message FileDescriptorProto { optional SourceCodeInfo source_code_info = 9; // The syntax of the proto file. - // The supported values are "proto2" and "proto3". + // The supported values are "proto2", "proto3", and "editions". + // + // If `edition` is present, this value must be "editions". optional string syntax = 12; + + // The edition of the proto file. + optional Edition edition = 14; } // Describes a message type. @@ -129,6 +169,51 @@ message ExtensionRangeOptions { // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; + message Declaration { + // The extension number declared within the extension range. + optional int32 number = 1; + + // The fully-qualified name of the extension field. There must be a leading + // dot in front of the full name. + optional string full_name = 2; + + // The fully-qualified type name of the extension field. Unlike + // Metadata.type, Declaration.type must have a leading dot for messages + // and enums. + optional string type = 3; + + // If true, indicates that the number is reserved in the extension range, + // and any extension field with the number will fail to compile. Set this + // when a declared extension field is deleted. + optional bool reserved = 5; + + // If true, indicates that the extension must be defined as repeated. + // Otherwise the extension must be defined as optional. + optional bool repeated = 6; + + reserved 4; // removed is_repeated + } + + // For external users: DO NOT USE. We are in the process of open sourcing + // extension declaration and executing internal cleanups before it can be + // used externally. + repeated Declaration declaration = 2 [retention = RETENTION_SOURCE]; + + // Any features defined in the specific edition. + optional FeatureSet features = 50; + + // The verification state of the extension range. + enum VerificationState { + // All the extensions of the range must be declared. + DECLARATION = 0; + UNVERIFIED = 1; + } + + // The verification state of the range. + // TODO: flip the default to DECLARATION once all empty ranges + // are marked as UNVERIFIED. + optional VerificationState verification = 3 + [default = UNVERIFIED, retention = RETENTION_SOURCE]; // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; @@ -153,9 +238,10 @@ message FieldDescriptorProto { TYPE_BOOL = 8; TYPE_STRING = 9; // Tag-delimited aggregate. - // Group type is deprecated and not supported in proto3. However, Proto3 + // Group type is deprecated and not supported after google.protobuf. However, Proto3 // implementations should still be able to parse the group wire format and - // treat group fields as unknown fields. + // treat group fields as unknown fields. In Editions, the group wire format + // can be enabled via the `message_encoding` feature. TYPE_GROUP = 10; TYPE_MESSAGE = 11; // Length-delimited aggregate. @@ -172,8 +258,11 @@ message FieldDescriptorProto { enum Label { // 0 is reserved for errors LABEL_OPTIONAL = 1; - LABEL_REQUIRED = 2; LABEL_REPEATED = 3; + // The required label is only allowed in google.protobuf. In proto3 and Editions + // it's explicitly prohibited. In Editions, the `field_presence` feature + // can be used to get this behavior. + LABEL_REQUIRED = 2; } optional string name = 1; @@ -199,7 +288,6 @@ message FieldDescriptorProto { // For booleans, "true" or "false". // For strings, contains the default text contents (not escaped in any way). // For bytes, contains the C escaped value. All bytes >= 128 are escaped. - // TODO(kenton): Base-64 encode? optional string default_value = 7; // If set, gives the index of a oneof in the containing type's oneof_decl @@ -217,12 +305,12 @@ message FieldDescriptorProto { // If true, this is a proto3 "optional". When a proto3 field is optional, it // tracks presence regardless of field type. // - // When proto3_optional is true, this field must be belong to a oneof to - // signal to old proto3 clients that presence is tracked for this field. This - // oneof is known as a "synthetic" oneof, and this field must be its sole - // member (each proto3 optional field gets its own synthetic oneof). Synthetic - // oneofs exist in the descriptor only, and do not generate any API. Synthetic - // oneofs must be ordered after all "real" oneofs. + // When proto3_optional is true, this field must belong to a oneof to signal + // to old proto3 clients that presence is tracked for this field. This oneof + // is known as a "synthetic" oneof, and this field must be its sole member + // (each proto3 optional field gets its own synthetic oneof). Synthetic oneofs + // exist in the descriptor only, and do not generate any API. Synthetic oneofs + // must be ordered after all "real" oneofs. // // For message fields, proto3_optional doesn't create any semantic change, // since non-repeated message fields always track presence. However it still @@ -306,7 +394,6 @@ message MethodDescriptorProto { optional bool server_streaming = 6 [default = false]; } - // =================================================================== // Options @@ -347,7 +434,6 @@ message FileOptions { // domain names. optional string java_package = 1; - // Controls the name of the wrapper Java class generated for the .proto file. // That class will always contain the .proto file's getDescriptor() method as // well as any top-level extensions defined in the .proto file. @@ -366,15 +452,18 @@ message FileOptions { // This option does nothing. optional bool java_generate_equals_and_hash = 20 [deprecated = true]; - // If set true, then the Java2 code generator will generate code that - // throws an exception whenever an attempt is made to assign a non-UTF-8 - // byte sequence to a string field. - // Message reflection will do the same. - // However, an extension field still accepts non-UTF-8 byte sequences. - // This option has no effect on when used with the lite runtime. + // A proto2 file can set this to true to opt in to UTF-8 checking for Java, + // which will throw an exception if invalid UTF-8 is parsed from the wire or + // assigned to a string field. + // + // TODO: clarify exactly what kinds of field types this option + // applies to, and update these docs accordingly. + // + // Proto3 files already perform these checks. Setting the option explicitly to + // false has no effect: it cannot be used to opt proto3 files out of UTF-8 + // checks. optional bool java_string_check_utf8 = 27 [default = false]; - // Generated classes can be optimized for speed or code size. enum OptimizeMode { SPEED = 1; // Generate complete code for parsing, serialization, @@ -391,9 +480,6 @@ message FileOptions { // - Otherwise, the basename of the .proto file, without extension. optional string go_package = 11; - - - // Should generic services be generated in each language? "Generic" services // are not specific to any particular RPC system. They are generated by the // main code generators in each language (without additional plugins). @@ -407,7 +493,8 @@ message FileOptions { optional bool cc_generic_services = 16 [default = false]; optional bool java_generic_services = 17 [default = false]; optional bool py_generic_services = 18 [default = false]; - optional bool php_generic_services = 42 [default = false]; + reserved 42; // removed php_generic_services + reserved "php_generic_services"; // Is this file deprecated? // Depending on the target platform, this can emit Deprecated annotations @@ -419,7 +506,6 @@ message FileOptions { // only to generated classes for C++. optional bool cc_enable_arenas = 31 [default = true]; - // Sets the objective c class prefix which is prepended to all objective c // generated classes from this .proto. There is no default. optional string objc_class_prefix = 36; @@ -452,6 +538,8 @@ message FileOptions { // determining the ruby package. optional string ruby_package = 45; + // Any features defined in the specific edition. + optional FeatureSet features = 50; // The parser stores options it doesn't recognize here. // See the documentation for the "Options" section above. @@ -524,6 +612,20 @@ message MessageOptions { reserved 8; // javalite_serializable reserved 9; // javanano_as_lite + // Enable the legacy handling of JSON field name conflicts. This lowercases + // and strips underscored from the fields before comparison in proto3 only. + // The new behavior takes `json_name` into account and applies to proto2 as + // well. + // + // This should only be used as a temporary measure against broken builds due + // to the change in behavior for JSON field name conflicts. + // + // TODO This is legacy behavior we plan to remove once downstream + // teams have had time to migrate. + optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true]; + + // Any features defined in the specific edition. + optional FeatureSet features = 12; // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -535,13 +637,21 @@ message MessageOptions { message FieldOptions { // The ctype option instructs the C++ code generator to use a different // representation of the field than it normally would. See the specific - // options below. This option is not yet implemented in the open source - // release -- sorry, we'll try to include it in a future version! + // options below. This option is only implemented to support use of + // [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of + // type "bytes" in the open source release -- sorry, we'll try to include + // other types in a future version! optional CType ctype = 1 [default = STRING]; enum CType { // Default mode. STRING = 0; + // The option [ctype=CORD] may be applied to a non-repeated field of type + // "bytes". It indicates that in C++, the data should be stored in a Cord + // instead of a string. For very large strings, this may reduce memory + // fragmentation. It may also allow better performance when parsing from a + // Cord, or when parsing with aliasing enabled, as the parsed Cord may then + // alias the original buffer. CORD = 1; STRING_PIECE = 2; @@ -550,7 +660,9 @@ message FieldOptions { // a more efficient representation on the wire. Rather than repeatedly // writing the tag and type for each element, the entire array is encoded as // a single length-delimited blob. In proto3, only explicit setting it to - // false will avoid using packed encoding. + // false will avoid using packed encoding. This option is prohibited in + // Editions, but the `repeated_field_encoding` feature can be used to control + // the behavior. optional bool packed = 2; // The jstype option determines the JavaScript type used for values of the @@ -593,19 +705,18 @@ message FieldOptions { // call from multiple threads concurrently, while non-const methods continue // to require exclusive access. // - // - // Note that implementations may choose not to check required fields within - // a lazy sub-message. That is, calling IsInitialized() on the outer message - // may return true even if the inner message has missing required fields. - // This is necessary because otherwise the inner message would have to be - // parsed in order to perform the check, defeating the purpose of lazy - // parsing. An implementation which chooses not to check required fields - // must be consistent about it. That is, for any particular sub-message, the - // implementation must either *always* check its required fields, or *never* - // check its required fields, regardless of whether or not the message has - // been parsed. + // Note that lazy message fields are still eagerly verified to check + // ill-formed wireformat or missing required fields. Calling IsInitialized() + // on the outer message would fail if the inner message has missing required + // fields. Failed verification would result in parsing failure (except when + // uninitialized messages are acceptable). optional bool lazy = 5 [default = false]; + // unverified_lazy does no correctness checks on the byte stream. This should + // only be used where lazy with verification is prohibitive for performance + // reasons. + optional bool unverified_lazy = 15 [default = false]; + // Is this field deprecated? // Depending on the target platform, this can emit Deprecated annotations // for accessors, or it will be completely ignored; in the very least, this @@ -615,6 +726,70 @@ message FieldOptions { // For Google-internal migration only. Do not use. optional bool weak = 10 [default = false]; + // Indicate that the field value should not be printed out when using debug + // formats, e.g. when the field contains sensitive credentials. + optional bool debug_redact = 16 [default = false]; + + // If set to RETENTION_SOURCE, the option will be omitted from the binary. + // Note: as of January 2023, support for this is in progress and does not yet + // have an effect (b/264593489). + enum OptionRetention { + RETENTION_UNKNOWN = 0; + RETENTION_RUNTIME = 1; + RETENTION_SOURCE = 2; + } + + optional OptionRetention retention = 17; + + // This indicates the types of entities that the field may apply to when used + // as an option. If it is unset, then the field may be freely used as an + // option on any kind of entity. Note: as of January 2023, support for this is + // in progress and does not yet have an effect (b/264593489). + enum OptionTargetType { + TARGET_TYPE_UNKNOWN = 0; + TARGET_TYPE_FILE = 1; + TARGET_TYPE_EXTENSION_RANGE = 2; + TARGET_TYPE_MESSAGE = 3; + TARGET_TYPE_FIELD = 4; + TARGET_TYPE_ONEOF = 5; + TARGET_TYPE_ENUM = 6; + TARGET_TYPE_ENUM_ENTRY = 7; + TARGET_TYPE_SERVICE = 8; + TARGET_TYPE_METHOD = 9; + } + + repeated OptionTargetType targets = 19; + + message EditionDefault { + optional Edition edition = 3; + optional string value = 2; // Textproto value. + } + repeated EditionDefault edition_defaults = 20; + + // Any features defined in the specific edition. + optional FeatureSet features = 21; + + // Information about the support window of a feature. + message FeatureSupport { + // The edition that this feature was first available in. In editions + // earlier than this one, the default assigned to EDITION_LEGACY will be + // used, and proto files will not be able to override it. + optional Edition edition_introduced = 1; + + // The edition this feature becomes deprecated in. Using this after this + // edition may trigger warnings. + optional Edition edition_deprecated = 2; + + // The deprecation warning text if this feature is used after the edition it + // was marked deprecated in. + optional string deprecation_warning = 3; + + // The edition this feature is no longer available in. In editions after + // this one, the last default assigned will be used, and proto files will + // not be able to override it. + optional Edition edition_removed = 4; + } + optional FeatureSupport feature_support = 22; // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -622,10 +797,14 @@ message FieldOptions { // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; - reserved 4; // removed jtype + reserved 4; // removed jtype + reserved 18; // reserve target, target_obsolete_do_not_use } message OneofOptions { + // Any features defined in the specific edition. + optional FeatureSet features = 1; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -647,6 +826,17 @@ message EnumOptions { reserved 5; // javanano_as_lite + // Enable the legacy handling of JSON field name conflicts. This lowercases + // and strips underscored from the fields before comparison in proto3 only. + // The new behavior takes `json_name` into account and applies to proto2 as + // well. + // TODO Remove this legacy behavior once downstream teams have + // had time to migrate. + optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true]; + + // Any features defined in the specific edition. + optional FeatureSet features = 7; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -661,6 +851,17 @@ message EnumValueOptions { // this is a formalization for deprecating enum values. optional bool deprecated = 1 [default = false]; + // Any features defined in the specific edition. + optional FeatureSet features = 2; + + // Indicate that fields annotated with this enum value should not be printed + // out when using debug formats, e.g. when the field contains sensitive + // credentials. + optional bool debug_redact = 3 [default = false]; + + // Information about the support window of a feature value. + optional FieldOptions.FeatureSupport feature_support = 4; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -670,6 +871,9 @@ message EnumValueOptions { message ServiceOptions { + // Any features defined in the specific edition. + optional FeatureSet features = 34; + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC // framework. We apologize for hoarding these numbers to ourselves, but // we were already using them long before we decided to release Protocol @@ -712,6 +916,9 @@ message MethodOptions { optional IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN]; + // Any features defined in the specific edition. + optional FeatureSet features = 35; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -719,7 +926,6 @@ message MethodOptions { extensions 1000 to max; } - // A message representing a option the parser does not recognize. This only // appears in options protos created by the compiler::Parser class. // DescriptorPool resolves these when building Descriptor objects. Therefore, @@ -730,8 +936,8 @@ message UninterpretedOption { // The name of the uninterpreted option. Each string represents a segment in // a dot-separated name. is_extension is true iff a segment represents an // extension (denoted with parentheses in options specs in .proto files). - // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents - // "foo.(bar.baz).qux". + // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents + // "foo.(bar.baz).moo". message NamePart { required string name_part = 1; required bool is_extension = 2; @@ -748,6 +954,178 @@ message UninterpretedOption { optional string aggregate_value = 8; } +// =================================================================== +// Features + +// TODO Enums in C++ gencode (and potentially other languages) are +// not well scoped. This means that each of the feature enums below can clash +// with each other. The short names we've chosen maximize call-site +// readability, but leave us very open to this scenario. A future feature will +// be designed and implemented to handle this, hopefully before we ever hit a +// conflict here. +message FeatureSet { + enum FieldPresence { + FIELD_PRESENCE_UNKNOWN = 0; + EXPLICIT = 1; + IMPLICIT = 2; + LEGACY_REQUIRED = 3; + } + optional FieldPresence field_presence = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "EXPLICIT"}, + edition_defaults = {edition: EDITION_PROTO3, value: "IMPLICIT"}, + edition_defaults = {edition: EDITION_2023, value: "EXPLICIT"} + ]; + + enum EnumType { + ENUM_TYPE_UNKNOWN = 0; + OPEN = 1; + CLOSED = 2; + } + optional EnumType enum_type = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "CLOSED"}, + edition_defaults = {edition: EDITION_PROTO3, value: "OPEN"} + ]; + + enum RepeatedFieldEncoding { + REPEATED_FIELD_ENCODING_UNKNOWN = 0; + PACKED = 1; + EXPANDED = 2; + } + optional RepeatedFieldEncoding repeated_field_encoding = 3 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "EXPANDED"}, + edition_defaults = {edition: EDITION_PROTO3, value: "PACKED"} + ]; + + enum Utf8Validation { + UTF8_VALIDATION_UNKNOWN = 0; + VERIFY = 2; + NONE = 3; + reserved 1; + } + optional Utf8Validation utf8_validation = 4 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "NONE"}, + edition_defaults = {edition: EDITION_PROTO3, value: "VERIFY"} + ]; + + enum MessageEncoding { + MESSAGE_ENCODING_UNKNOWN = 0; + LENGTH_PREFIXED = 1; + DELIMITED = 2; + } + optional MessageEncoding message_encoding = 5 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "LENGTH_PREFIXED"} + ]; + + enum JsonFormat { + JSON_FORMAT_UNKNOWN = 0; + ALLOW = 1; + LEGACY_BEST_EFFORT = 2; + } + optional JsonFormat json_format = 6 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "LEGACY_BEST_EFFORT"}, + edition_defaults = {edition: EDITION_PROTO3, value: "ALLOW"} + ]; + + reserved 999; + + extensions 1000 to 9994 [ + declaration = { + number: 1000, + full_name: ".pb.cpp", + type: ".pb.CppFeatures" +}, + declaration = { + number: 1001, + full_name: ".pb.java", + type: ".pb.JavaFeatures" +}, + declaration = {number: 1002, full_name: ".pb.go", type: ".pb.GoFeatures"}, + declaration = { + number: 9990, + full_name: ".pb.proto1", + type: ".pb.Proto1Features" +} +]; + + extensions 9995 to 9999; // For internal testing + extensions 10000; // for https://github.com/bufbuild/protobuf-es + } + +// A compiled specification for the defaults of a set of features. These +// messages are generated from FeatureSet extensions and can be used to seed +// feature resolution. The resolution with this object becomes a simple search +// for the closest matching edition, followed by proto merges. +message FeatureSetDefaults { + // A map from every known edition with a unique set of defaults to its + // defaults. Not all editions may be contained here. For a given edition, + // the defaults at the closest matching edition ordered at or before it should + // be used. This field must be in strict ascending order by edition. + message FeatureSetEditionDefault { + optional Edition edition = 3; + + // Defaults of features that can be overridden in this edition. + optional FeatureSet overridable_features = 4; + + // Defaults of features that can't be overridden in this edition. + optional FeatureSet fixed_features = 5; + + reserved 1, 2; + reserved "features"; + } + repeated FeatureSetEditionDefault defaults = 1; + + // The minimum supported edition (inclusive) when this was constructed. + // Editions before this will not have defaults. + optional Edition minimum_edition = 4; + + // The maximum known edition (inclusive) when this was constructed. Editions + // after this will not have reliable defaults. + optional Edition maximum_edition = 5; +} + // =================================================================== // Optional source code info @@ -803,8 +1181,8 @@ message SourceCodeInfo { // location. // // Each element is a field number or an index. They form a path from - // the root FileDescriptorProto to the place where the definition. For - // example, this path: + // the root FileDescriptorProto to the place where the definition appears. + // For example, this path: // [ 4, 3, 2, 7, 1 ] // refers to: // file.message_type(3) // 4, 3 @@ -858,13 +1236,13 @@ message SourceCodeInfo { // // Comment attached to baz. // // Another line attached to baz. // - // // Comment attached to qux. + // // Comment attached to moo. // // - // // Another line attached to qux. - // optional double qux = 4; + // // Another line attached to moo. + // optional double moo = 4; // // // Detached comment for corge. This is not leading or trailing comments - // // to qux or corge because there are blank lines separating it from + // // to moo or corge because there are blank lines separating it from // // both. // // // Detached comment for corge paragraph 2. @@ -904,8 +1282,20 @@ message GeneratedCodeInfo { optional int32 begin = 3; // Identifies the ending offset in bytes in the generated code that - // relates to the identified offset. The end offset should be one past + // relates to the identified object. The end offset should be one past // the last relevant byte (so the length of the text = end - begin). optional int32 end = 4; + + // Represents the identified object's effect on the element in the original + // .proto file. + enum Semantic { + // There is no effect or the effect is indescribable. + NONE = 0; + // The element is set or otherwise mutated. + SET = 1; + // An alias to the element is returned. + ALIAS = 2; + } + optional Semantic semantic = 5; } } diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/duration.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/duration.proto index 584e305b..07fa248f 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/duration.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/duration.proto @@ -32,13 +32,13 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; option go_package = "google.golang.org/protobuf/types/known/durationpb"; option java_package = "com.google.protobuf"; option java_outer_classname = "DurationProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // A Duration represents a signed, fixed-length span of time represented // as a count of seconds and fractions of seconds at nanosecond @@ -99,7 +99,6 @@ option objc_class_prefix = "GPB"; // be expressed in JSON format as "3.000000001s", and 3 seconds and 1 // microsecond should be expressed in JSON format as "3.000001s". // -// message Duration { // Signed seconds of the span of time. Must be from -315,576,000,000 // to +315,576,000,000 inclusive. Note: these bounds are computed from: diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/empty.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/empty.proto index 5f992de9..b87c89dc 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/empty.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/empty.proto @@ -32,12 +32,12 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/emptypb"; option java_package = "com.google.protobuf"; option java_outer_classname = "EmptyProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; // A generic empty message that you can re-use to avoid defining duplicated @@ -48,5 +48,4 @@ option cc_enable_arenas = true; // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); // } // -// The JSON representation for `Empty` is empty JSON object `{}`. message Empty {} diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/field_mask.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/field_mask.proto index 66493052..c33a9207 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/field_mask.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/field_mask.proto @@ -32,11 +32,11 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option java_package = "com.google.protobuf"; option java_outer_classname = "FieldMaskProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; option cc_enable_arenas = true; diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/java_features.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/java_features.proto new file mode 100644 index 00000000..d314b886 --- /dev/null +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/java_features.proto @@ -0,0 +1,71 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +syntax = "proto2"; + +package pb; + +import "google/protobuf/descriptor.proto"; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "JavaFeaturesProto"; + +extend google.protobuf.FeatureSet { + optional JavaFeatures java = 1001; +} + +message JavaFeatures { + // Whether or not to treat an enum field as closed. This option is only + // applicable to enum fields, and will be removed in the future. It is + // consistent with the legacy behavior of using proto3 enum types for proto2 + // fields. + optional bool legacy_closed_enum = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + edition_deprecated: EDITION_2023, + deprecation_warning: "The legacy closed enum treatment in Java is " + "deprecated and is scheduled to be removed in " + "edition 2025. Mark enum type on the enum " + "definitions themselves rather than on fields.", + }, + edition_defaults = {edition: EDITION_PROTO2, value: "true"}, + edition_defaults = {edition: EDITION_PROTO3, value: "false"} + ]; + + // The UTF8 validation strategy to use. See go/editions-utf8-validation for + // more information on this feature. + enum Utf8Validation { + // Invalid default, which should never be used. + UTF8_VALIDATION_UNKNOWN = 0; + // Respect the UTF8 validation behavior specified by the global + // utf8_validation feature. + DEFAULT = 1; + // Verifies UTF8 validity overriding the global utf8_validation + // feature. This represents the legacy java_string_check_utf8 option. + VERIFY = 2; + } + optional Utf8Validation utf8_validation = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + edition_deprecated: EDITION_2023, + deprecation_warning: "The Java-specific utf8 validation feature is " + "deprecated and is scheduled to be removed in " + "edition 2025. Utf8 validation behavior should " + "use the global cross-language utf8_validation " + "feature.", + }, + edition_defaults = {edition: EDITION_PROTO2, value: "DEFAULT"} + ]; +} diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/source_context.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/source_context.proto index 07a0cc35..8d25f486 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/source_context.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/source_context.proto @@ -32,11 +32,11 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option java_package = "com.google.protobuf"; option java_outer_classname = "SourceContextProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; // `SourceContext` represents information about the source of a diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/struct.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/struct.proto index b4fd6357..8cec1e1c 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/struct.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/struct.proto @@ -32,13 +32,13 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; option go_package = "google.golang.org/protobuf/types/known/structpb"; option java_package = "com.google.protobuf"; option java_outer_classname = "StructProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // `Struct` represents a structured data value, consisting of fields // which map to dynamically typed values. In some languages, `Struct` @@ -55,8 +55,8 @@ message Struct { // `Value` represents a dynamically typed value which can be either // null, a number, a string, a boolean, a recursive struct value, or a -// list of values. A producer of value is expected to set one of that -// variants, absence of any variant indicates an error. +// list of values. A producer of value is expected to set one of these +// variants. Absence of any variant indicates an error. // // The JSON representation for `Value` is JSON value. message Value { @@ -80,7 +80,7 @@ message Value { // `NullValue` is a singleton enumeration to represent the null value for the // `Value` type union. // -// The JSON representation for `NullValue` is JSON `null`. +// The JSON representation for `NullValue` is JSON `null`. enum NullValue { // Null value. NULL_VALUE = 0; diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/timestamp.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/timestamp.proto index 5b6e50f7..e509315a 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/timestamp.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/timestamp.proto @@ -32,13 +32,13 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; option go_package = "google.golang.org/protobuf/types/known/timestamppb"; option java_package = "com.google.protobuf"; option java_outer_classname = "TimestampProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // A Timestamp represents a point in time independent of any time zone or local // calendar, encoded as a count of seconds and fractions of seconds at @@ -90,7 +90,6 @@ option objc_class_prefix = "GPB"; // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) // .setNanos((int) ((millis % 1000) * 1000000)).build(); // -// // Example 5: Compute Timestamp from Java `Instant.now()`. // // Instant now = Instant.now(); @@ -99,7 +98,6 @@ option objc_class_prefix = "GPB"; // Timestamp.newBuilder().setSeconds(now.getEpochSecond()) // .setNanos(now.getNano()).build(); // -// // Example 6: Compute Timestamp from current time in Python. // // timestamp = Timestamp() @@ -129,10 +127,9 @@ option objc_class_prefix = "GPB"; // [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with // the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use // the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D +// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime() // ) to obtain a formatter capable of generating timestamps in this format. // -// message Timestamp { // Represents seconds of UTC time since Unix epoch // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/type.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/type.proto index 9f2d457c..1c320ee8 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/type.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/type.proto @@ -35,12 +35,12 @@ package google.protobuf; import "google/protobuf/any.proto"; import "google/protobuf/source_context.proto"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; option java_package = "com.google.protobuf"; option java_outer_classname = "TypeProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/typepb"; // A protocol buffer message type. @@ -57,6 +57,8 @@ message Type { SourceContext source_context = 5; // The source syntax. Syntax syntax = 6; + // The source edition string, only valid when syntax is SYNTAX_EDITIONS. + string edition = 7; } // A single field of a message type. @@ -151,6 +153,8 @@ message Enum { SourceContext source_context = 4; // The source syntax. Syntax syntax = 5; + // The source edition string, only valid when syntax is SYNTAX_EDITIONS. + string edition = 6; } // Enum value definition. @@ -184,4 +188,6 @@ enum Syntax { SYNTAX_PROTO2 = 0; // Syntax `proto3`. SYNTAX_PROTO3 = 1; + // Syntax `editions`. + SYNTAX_EDITIONS = 2; } diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/wrappers.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/wrappers.proto index 92b1d1d4..b3ec6cd4 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/wrappers.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/wrappers.proto @@ -27,7 +27,7 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - +// // Wrappers for primitive (non-message) types. These types are useful // for embedding primitives in the `google.protobuf.Any` type and for places // where we need to distinguish between the absence of a primitive @@ -42,13 +42,13 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; option java_package = "com.google.protobuf"; option java_outer_classname = "WrappersProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // Wrapper message for `double`. //